* docs: rewrite lark-shared update section to recommend lark-cli update
Change-Id: Ie043b1a32675dcd041f9123503fcccb791cccd07
* feat: add command field to _notice JSON for AI agents
Change-Id: I04b069880f7dca8db384ba8a6919e5682c0382be
* feat: demote npm install to fallback with skills-not-synced warning
Change-Id: If21c3ef6cd1818b28f5578078a04c3627128c6d0
* fix: address CodeRabbit review — guard type assertions, remove npm fallback from SKILL.md
- Add t.Fatalf guards before type-asserting notice sub-maps in
TestSetupNotices_BothUpdateAndSkills to prevent nil-panic on
unexpected shapes.
- Remove the npm fallback section from SKILL.md entirely so AI agents
only see `lark-cli update` as the update path.
- Strip remaining npm mentions from the "重要" note.
Change-Id: Ieb124763b918093e1dcae06f5ea7428dbc248d5f
* fix: add npx skills add hint alongside npm fallback in update paths
When npm is shown as a fallback (manual update path and rollback hint),
append the npx skills add command so users know how to sync skills
separately.
Change-Id: I454172be51073d35def635613a23ad35ba68b5fb
Add im +chat-list shortcut wrapping GET /open-apis/im/v1/chats (previously not exposed via lark-cli).
Add --exclude-muted to both +chat-search and +chat-list: client-side filter that calls POST /open-apis/im/v1/chat_user_setting/batch_get_mute_status after each page and drops is_muted=true chats.
Introduce shortcuts/im/mute_filter.go with pure helpers and an orchestrator (MaybeApplyMuteFilter) shared by both shortcuts.
Change-Id: I22221ac5835667f58cbd40b34de75825d2445d1c
Adds --chat-mode group|topic to lark-cli im +chat-create so users and AI agents can create 话题群 (topic chats) directly via the CLI. Without this, requests to create a topic chat silently fall back to a normal conversation group. Default remains group; chat_mode is now always emitted in the POST /open-apis/im/v1/chats request body.
Change-Id: I79385e2e8606f84e3f27de240d1b41037bf51261
`lark-cli auth login --scope "a,b"` previously sent the raw comma-joined
string to the device authorization endpoint, which treats it as a single
malformed scope and fails with:
device authorization failed: The provided scope list contains invalid
or malformed scopes.
OAuth 2.0 (RFC 6749 §3.3) requires space-delimited scopes on the wire,
but commas are the more natural separator for users typing on a shell
(quoting whitespace is awkward, especially for AI-agent generated
commands). Accept both: split on commas/whitespace, trim, dedupe, then
re-join with single spaces.
Also adds unit tests covering single, comma, space, mixed, dedupe, and
trailing-separator inputs.
Co-authored-by: aj <2072584+meijing0114@users.noreply.github.com>
Five tests in cmd/update mocked SkillsUpdateOverride to return success
and let runSkillsAndStamp call WriteStamp, but did not isolate
LARKSUITE_CLI_CONFIG_DIR. Each run clobbered the real
~/.lark-cli/skills.stamp with the mock version ("2.0.0" or "1.0.0"),
causing skillscheck to fire a misleading drift notice on every
subsequent lark-cli invocation.
Add t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir()) at the top of:
- TestUpdateNpm_JSON
- TestUpdateNpm_Human
- TestUpdateForce_JSON
- TestUpdateDevVersion_JSON
- TestUpdateWindows_NpmSuccess_JSON
Scope is limited to tests that mock SkillsUpdateOverride to success;
tests that invoke real npx are pre-existing and out of scope here.
Change-Id: I7a78a6c70f276b51333253acc115e0109c01a851
OpenClaw stores secret file paths in user-authored ~/-relative form so
the configuration stays portable across machines. lark-cli config bind
previously rejected these as non-absolute, blocking users until they
rewrote the OpenClaw config with literal absolute paths.
bind now resolves ~ to the OpenClaw home directory (OPENCLAW_HOME if
set, otherwise the OS home) before the path audit runs, mirroring how
OpenClaw itself reads the same field. Cwd-relative paths and other
unsafe locations are still rejected as before.
Adds shortcuts/mail/flag_suggest.go (~120 LOC) implementing a cobra
FlagErrorFunc hook for the mail subcommand tree. On 'unknown flag: --X'
or 'unknown shorthand flag: "X" in -X', it collects flags from the
current command via cmd.Flags().VisitAll, runs bidirectional prefix
match + Levenshtein DP (threshold=max(1,len/3+1), cap 4), and returns
top-5 candidates inside the existing ErrorEnvelope JSON:
error.type = "unknown_flag"
error.detail.{unknown, command_path, candidates}
error.detail.candidates[*] = {flag, shorthand, distance, reason}
Exit code stays 1 (ExitAPI), not ExitValidation - no breaking change for
CI/agent scripts that check non-zero exit. stderr switches from plain
'Error: unknown flag: --X' to JSON envelope, aligning with the existing
'errors = JSON envelope on stderr' convention; mail unknown-flag was the
last gap.
Scope is strictly the mail subcommand tree: shortcuts/register.go gains
a single 'if service == "mail" { mail.InstallOnMail(svc) }' branch
after the existing Mount loop. Other domains (calendar / im / api /
auth / ...) keep cobra's default FlagErrorFunc and unchanged plain-text
stderr behavior.
Covers:
- shortcuts/mail/flag_suggest.go (new, ~120 LOC)
- shortcuts/mail/flag_suggest_test.go (new, 12 table-driven tests)
- shortcuts/register.go (+3 lines after mail Mount loop)
No changes to cmd/root.go or internal/output/* - ErrDetail.Detail is
already interface{}, handleRootError already routes *ExitError via
WriteErrorEnvelope.
* feat(vc): agent join meeting basic shortcuts structure
Change-Id: Ic5d64067eb48670fa6636841cd00cbfa9b0bf3e7
* docs: add skill references for vc +meeting-join and +meeting-leave
* feat(vc): add meeting events shortcut
Add vc +meeting-events for bot meeting activity queries with page-all pagination support and tested pretty/json output.
* feat(vc): refine meeting events pagination and output
* test: add unit tests for vc +meeting-join and +meeting-leave shortcuts
* feat(vc): improve meeting events pretty timeline
* feat(vc): refine meeting events pretty output
* docs(skill): add vc meeting events shortcut guide
* docs(skill): clarify vc meeting events output guidance
* docs: clarify participant-snapshot vs meeting-events routing
* refactor: split lark-vc-agent from lark-vc
* docs: drop nonexistent workflow skill reference and fix identity
* docs: fix cross-links in lark-vc-agent references after split
* fix(vc): send meeting join password at top level
* docs: rewrite lark-vc-agent description in user-facing language
* docs: tighten lark-vc-agent description to descriptive neutral tone
* fix: use Chinese quotes in vc/vc-agent description YAML frontmatter
* docs: downgrade dry-run from mandatory to optional for vc-agent writes
* docs: clarify pretty vs json format choice by processing depth
* docs: systematic review of lark-vc-agent SKILL for clarity and precision
* feat(vc): print meeting event page token in pretty output
* docs(skill): refine vc agent meeting guidance
* revert: restore CRITICAL banner in lark-vc-agent to match repo convention
* docs: replace inaccurate no-replay warning with real social-cost risk
* docs: tighten meeting-join risk warning to single sentence
* docs: tighten vc-agent references - remove redundancy and fix vague wording
* Revert "docs: tighten vc-agent references - remove redundancy and fix vague wording"
This reverts commit 9845fc40622c65b0811da1c9ae4902434377f33e.
* docs(skill): refine vc meeting events paging guidance
* fix(vc): keep meeting event count aligned with events list
* docs(skill): tighten vc agent meeting events workflow
* refactor(vc): simplify meeting events pagination
* docs(skill): tighten vc agent meeting guidance
* docs(skill): require reading shared docs for meeting summaries
* chore(env): switch default feishu endpoints to pre
* fix(env): use feishu accounts host
* docs(vc): use explicit date in recording example
* revert(env): remove default ppe request header
* chore(env): switch default feishu endpoints to pre
* docs(skill): guide users to early-bird group on agent meeting gray miss
Teach the lark-vc-agent skill to recognize OAPI's new gray-miss signal for
the three agent meeting commands (`+meeting-join`, `+meeting-leave`,
`+meeting-events`) and route the user to the early-bird group instead of
treating it as a permission error.
When CLI stderr JSON returns `error.code=20017 / ErrNotInGray`, the agent
renders the fixed early-bird invite link
`https://go.larkoffice.com/join-chat/2f4nb0e1-fe00-4f67-bed7-25beaf533fbd`.
The user manual is intentionally not surfaced yet.
Scope-related errors still follow the existing `auth login --scope` flow
with no early-bird copy mixed in. lark-shared and other skills are not
touched, so the guidance stays scoped to the agent meeting commands only.
* chore(env): switch endpoints to boe for agent meeting gray testing
* chore(vc-agent): update gray guide and boe endpoints
* docs(vc-agent): refine gray guidance flow
* docs(vc-agent): centralize gray guidance
* fix(ci): stabilize vc output and skill frontmatter
* fix(vc): address review feedback
---------
Co-authored-by: zhaolei.vc <zhaolei.vc@bytedance.com>
Co-authored-by: renaocheng <renaocheng@bytedance.com>
Remove the cold-start _notice.skills that fires whenever
~/.lark-cli/skills.stamp is missing. The stamp is written
exclusively by `lark-cli update`, so users who installed skills via
`npx skills add larksuite/cli -g` (the documented path) saw the
notice on every run despite a fully populated ~/.agents/skills/.
The version-drift notice (stamp != binary) is preserved unchanged
for users who opted into tracking by running `lark-cli update`.
- internal/skillscheck/check.go: Init returns silently on empty stamp
- internal/skillscheck/notice.go: drop dead cold-start branch in Message;
Current field is now guaranteed non-empty
- tests updated in skillscheck package + cmd/root_integration_test.go
to assert the new contract
No new files, no env vars, no JSON schema change. The _notice.skills
shape stays {current, target, message} — only the cold-start message
string is no longer possible.
The +chat-search row in lark-im SKILL.md described the search as
"by keyword and/or member open_ids", which doesn't match the real
flag names (--query, --member-ids). Naming them inline avoids
agents guessing --keyword from the prose, matching the style
already used by +chat-messages-list.
Change-Id: Ife8668d9b13ee66711bc4e81a7b2bcc7f05d9586
Add IM flag shortcut commands to lark-cli, enabling users to create, list, and cancel bookmarks on messages and threads via +flag-create, +flag-list, and +flag-cancel.
Change-Id: I8f87f0eadf83fb59b024a3b9fe67b23d363abe0a
- Assemble applinks via net/url to ensure proper encoding
- Normalize message position values across more numeric types
- Avoid leaking null message_app_link; assemble when missing
- Update unit tests to assert URL semantics and cover edge cases
Change-Id: Ic473cb563c8a648c4f6677c32b25b9f371a0f84e
Adds a new top-level safety section "数据真实性与操作合规" to the
lark-mail skill via the canonical generation pipeline:
- skill-template/domains/mail.md (source) — adds the section to the
domain introduction file that gen-skills.py renders into SKILL.md.
- skills/lark-mail/SKILL.md (regenerated product) — produced by
`make gen-skills project=mail` from larksuite-cli-registry against
the modified mail.md source.
Why both files: skills/lark-mail/SKILL.md is auto-generated from
skill-template/domains/mail.md + registry-conf/skill-meta.yaml +
output/from_meta/mail.json. Editing only SKILL.md would be reverted on
the next `make gen-skills` run because SKILL.md has no AUTO-GENERATED
markers and falls into the "no markers -> overwrite whole file" branch
in scripts/gen-skills.py.
The section adds 3 hard constraints on agent behavior:
- empty result is a valid answer; do not fabricate IDs or placeholders
- explicit action preview before destructive write operations
(delete / trash / batch_trash / cancel_scheduled_send / rules.*)
- reversible modifications (label / read state / folder move) are
exempt from the preview requirement
Addresses recurring evaluation failures (c03/c04/c06/c09/c14/c19~c24/c40)
where the agent fabricated IDs or auto-executed destructive operations.
The --as flag displayed (default "bot"), (default "user"), or
(default "auto") in help text, but ResolveAs() never uses the cobra
default — it resolves identity via credential config and auto-detect.
The displayed default misled users into thinking a fixed identity was
used when --as was omitted.
Set cobra default to empty string so no (default ...) suffix appears.
Also remove "auto" from visible options since --as auto is equivalent
to omitting --as entirely.
Change-Id: I51ba550a6697eb3675a29f5cee4d0010e0a1cc16
Users who install or upgrade lark-cli via make install, go install, or
direct binary download end up with a binary but no AI agent skills,
degrading agent UX. This PR adds a startup-time skills version drift
notice (injected into JSON envelope _notice.skills, mirroring the
existing _notice.update pattern) and unifies lark-cli update's skills
sync across all three branches (npm / manual / already-latest) with
stamp-based dedup, so any explicit update invocation keeps skills in
sync regardless of how the binary was installed.
Changes:
- new internal/skillscheck package: notice (StaleNotice + atomic
pending), stamp (~/.lark-cli/skills.stamp), skip (CI / DEV /
non-release / LARKSUITE_CLI_NO_SKILLS_NOTIFIER opt-out), check
(synchronous Init)
- cmd/root.go: rename setupUpdateNotice -> setupNotices, compose
output.PendingNotice returning {update?, skills?}; capture
build.Version locally before spawning the async update goroutine
- cmd/update/update.go: add runSkillsAndStamp helper with stamp-based
dedup; rewire the three branches through shared applySkillsResult /
emitSkillsTextHints helpers; add skills_status block to --check JSON
output as a pure report (no side effects)
- internal/update: export IsRelease(version) bool / IsCIEnv() bool
for cross-package reuse; refresh UpdateInfo.Message to append
', run: lark-cli update' so both notices recommend the same fix
- AGENTS.md: add Notification Opt-Outs section documenting
LARKSUITE_CLI_NO_UPDATE_NOTIFIER and LARKSUITE_CLI_NO_SKILLS_NOTIFIER
- internal/binding/types.go: bump default exec-provider timeout from
5s to 10s (out-of-scope flake fix for TestResolveExecRef_JSONResponse
under heavy parallel test load)
AI agents running inside OpenClaw / Hermes were routinely creating a parallel
app via `config init --new` instead of binding to the agent's existing app,
because every "not configured" hint and several deny errors hard-coded
`config init` regardless of workspace. Once bound, the same agents could
silently grant themselves user identity (impersonation) without the user
ever seeing a risk message in chat.
Changes:
- Introduce `core.NotConfiguredError` / `NoActiveProfileError` /
`reconfigureHint` helpers that branch on `CurrentWorkspace()`. In agent
workspaces they point at `lark-cli config bind --help` (a help page, not
a ready-to-run command) so AI must read the binding workflow and confirm
identity preset with the user before acting. In local terminals they
preserve the previous `config init --new` guidance.
- Migrate every `config init` hint that should be workspace-aware:
RequireConfigForProfile, default credential provider, credential provider
fallback, secret-resolve mismatch, config show, strict-mode entry-point
errors, default-as, profile use/rename/remove, auth list, doctor's
config_file check (which now also wraps the OS-level "no such file"
noise into the user-shaped "not configured" message).
- Refuse `config init` when run inside an OpenClaw / Hermes workspace by
default; add `--force-init` for the rare case the user genuinely wants
a parallel app. Without this guard, hint fixes were undone the moment
AI ignored them.
- Rewrite the strict-mode deny errors in cmd/auth/login.go, cmd/prune.go,
and internal/cmdutil/factory.go. The previous "AI agents are strictly
prohibited from modifying this setting" terminated AI reasoning while
providing no real gate. New errors point at `config strict-mode --help`
with the legitimate confirmation flow and explicitly note that switching
does NOT require re-bind. Integration test envelopes updated.
- Tighten `config bind --help` and `config strict-mode --help` to encode
the user-confirmation discipline directly: identity preset semantics
(bot-only vs user-default), "DO NOT switch without explicit user
confirmation", and a cross-reference clarifying that `config bind` is
for changing the underlying app while `config strict-mode` is the
policy-only switch (resolves an ambiguity an audit run found).
- Surface user-identity (impersonation) risk at every config write that
newly grants it, by reusing the canonical IdentityEscalationMessage
string from bind_messages.go:
- `noticeUserDefaultRisk` fires on flag-mode bind landing on
user-default, including the first-time case `warnIdentityEscalation`
misses (it requires a previous bot lock).
- `setStrictMode` warns when transitioning bot → user or bot → off
(newly permits user identity); stays quiet on narrowing changes
and on off → user (off already permitted user).
- Add tests: notconfigured_test.go (workspace branches),
init_guard_test.go (refuse + --force-init bypass), bind_warning_test.go
(user-default warning fires; bot-only does not), strict_mode_warning_test.go
(5 transitions covering both warn and no-warn paths).
Two follow-ups intentionally deferred: the keychain master-key hint at
internal/keychain/keychain.go:42 still suggests `config init` because the
keychain package can't import core (would be circular); fixing requires
either parameterizing the hint via callback or extracting workspace into
its own package. The lark-shared skill doc still tells AI to run
`config init` for first-time setup; updating the skill is in scope for
a follow-up PR.
Change-Id: I02273e044d9e061d211ceaa4f3ed5a3fb28325b3
* fix(auth): handle missing scopes and device flow improvements
* fix: remove redundant error return in login scope handler
* test(auth): rename test for zero interval default case
* fix: increase device code polling timeout from 180 to 600 seconds