Files
larksuite-cli/AGENTS.md
niuchong 8f410ab140 feat: add skills version drift notice and unify update flow (#723)
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)
2026-05-07 10:52:35 +08:00

5.2 KiB

AGENTS.md

Goal (pick one per PR)

  • Make CLI better: improve UX, error messages, help text, flags, and output clarity.
  • Improve reliability: fix bugs, edge cases, and regressions with tests.
  • Improve developer velocity: simplify code paths, reduce complexity, keep behavior explicit.
  • Improve quality gates: strengthen tests/lint/checks without adding heavy process.

Build & Test

make build          # Build (runs fetch_meta first)
make unit-test      # Required before PR (runs with -race)
make test           # Full: vet + unit + integration

Notification Opt-Outs

lark-cli emits two notice types into JSON envelope _notice to nudge AI agents toward fixes:

  • _notice.update — a newer binary is available on npm
  • _notice.skills — locally installed skills are out of sync with the running binary

To suppress them in non-CI scripts (CI envs are auto-skipped):

Env var Effect
LARKSUITE_CLI_NO_UPDATE_NOTIFIER=1 Suppress _notice.update
LARKSUITE_CLI_NO_SKILLS_NOTIFIER=1 Suppress _notice.skills

Both notices recommend the same fix command: lark-cli update. The skills notice's current field is "" when skills have never been synced (cold start) and a version string when synced for an older binary (drift).

Pre-PR Checks (match CI gates)

  1. make unit-test
  2. go vet ./...
  3. gofmt -l . — must produce no output
  4. go mod tidy — must not change go.mod/go.sum
  5. go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.6 run --new-from-rev=origin/main
  6. If dependencies changed: go run github.com/google/go-licenses/v2@v2.0.1 check ./... --disallowed_types=forbidden,restricted,reciprocal,unknown

Commit & PR

  • Conventional Commits in English: feat:, fix:, docs:, test:, refactor:, chore:, ci:
  • PR title in the same format. Fill .github/pull_request_template.md completely.
  • Never commit secrets, tokens, or internal sensitive data.

Source Layout

Path What it does
cmd/root.go Entry point, command registration, strict mode pruning
cmd/profile/ Multi-profile management (add/list/use/rename/remove)
cmd/config/ Config init, show, strict-mode
cmd/service/ Auto-registered API commands from embedded metadata
shortcuts/common/runner.go Shortcut execution pipeline, Flag.Input (@file/stdin) resolution
shortcuts/ Domain-specific shortcut implementations
internal/cmdutil/factory.go Factory pattern — identity resolution, credential, config
internal/cmdutil/factory_default.go Production factory wiring
internal/credential/ Credential provider chain (extension → default)
extension/credential/ Plugin-facing credential interfaces and env provider
internal/client/client.go APIClient: DoSDKRequest, DoStream
internal/core/config.go Multi-profile config loading/saving
internal/vfs/ Filesystem abstraction (use vfs.* instead of os.*)
internal/validate/path.go Path safety validation

Who Uses This CLI

This CLI's primary consumers include AI agents (Claude Code, Cursor, Gemini CLI). Your code is read by machines — error messages, output format, and flag design all directly affect agent success rates.

The one rule to internalize: every error message you write will be parsed by an AI to decide its next action. Make errors structured, actionable, and specific.

Code Conventions

Structured errors in commands

RunE functions must return output.Errorf / output.ErrWithHint — never bare fmt.Errorf. AI agents parse stderr as JSON; bare errors break this contract.

stdout is data, stderr is everything else

Program output (JSON envelopes) goes to stdout. Progress, warnings, hints go to stderr. Mixing them corrupts pipe chains.

Use vfs.* instead of os.*

All filesystem access goes through internal/vfs. This enables test mocking.

Validate paths before reading

CLI arguments are untrusted (they come from AI agents). Call validate.SafeInputPath before any file I/O.

Tests

  • Every behavior change needs a test alongside the change.
  • cmdutil.TestFactory(t, config) for test factories.
  • t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir()) to isolate config state.

E2E Testing

Dry-run E2E (required for every shortcut change)

  • Validates request structure without calling real APIs
  • Place in tests/cli_e2e/dryrun/ or the corresponding domain directory
  • Set env vars LARKSUITE_CLI_APP_ID/APP_SECRET/BRAND, use --dry-run, assert method/URL/params
  • No secrets needed — runs on fork PRs
  • Explore correct params with lark-cli <domain> --help and lark-cli schema first

Live E2E (required for new flows or behavior changes)

  • Validates real API round-trips
  • Place in tests/cli_e2e/<domain>/
  • Must be self-contained: create -> use -> cleanup
  • Needs bot credentials (CI secrets, skipped on fork PRs)
  • Reference: tests/cli_e2e/task/task_status_workflow_test.go
Change Dry-run E2E Live E2E
New shortcut Required Required
Modify shortcut flags/params Required If behavior changes
Shortcut bug fix Required If regression risk
Internal refactor (no shortcut impact) Not needed Not needed