Add cmd/diagnose_scope_test.go that exports a JSON snapshot of all API
methods and shortcuts with their minimum-privilege scopes, identity
support, auto-approve status, and scope_priorities coverage. Consumed
by scripts/scope_audit.py for diff and reporting.
* fix(mail): replace os.Exit with graceful shutdown in mail watch
The signal handler in mail +watch called os.Exit(0), which bypassed all
deferred cleanup functions, made the code path untestable, and did not
follow Go's idiomatic context cancellation pattern.
Key changes:
- Remove os.Exit(0) and use context.WithCancel to propagate shutdown
- Run cli.Start in a separate goroutine so the main goroutine can return
immediately on signal receipt (the Lark WebSocket SDK does not return
promptly after context cancellation)
- Extract handleMailWatchSignal as a testable standalone function
- Use sync.Once + defer for idempotent cleanup on all exit paths
- Fix eventCount data race with atomic.Int64
- Add signal.Reset to support forced termination via a second Ctrl+C
Closes#268
* docs: add docstrings to handleMailWatchSignal test functions
* fix(mail): cancel watch context on signal handler panic
If handleMailWatchSignal panics, the recover block now calls
cancelWatch() to unblock the main select. Without this, a panic
would leave shutdownBySignal unclosed and watchCtx uncancelled,
causing the process to hang.
* fix(mail): use triggerShutdown to unblock main select on signal handler panic
The previous panic recovery only called cancelWatch(), but since the
WebSocket SDK does not return promptly after context cancellation,
the main select could still hang waiting on startErrCh.
Introduce triggerShutdown() that closes shutdownBySignal (via
sync.Once) and cancels the watch context, used by both the normal
signal path and the panic recovery path. This ensures the main
select unblocks immediately regardless of how the signal goroutine
exits.
Add regression test that forces a panic and asserts shutdownBySignal
is closed promptly.
* feat(mail): add --page-token and --page-size pagination support to mail +triage
Support external pagination for mail +triage with two new flags:
- --page-token: resume from a previous response's page token
- --page-size: alias for --max
Token carries a "search:" or "list:" prefix to identify the API path,
with strict validation: conflicting parameters (e.g. list: token with
--query) fail fast, and bare tokens without prefix are rejected.
JSON/data output now returns an object with messages, total, has_more,
and page_token fields. Table output shows next-page hint on stderr.
* fix(mail): address PR review — keep data format as array, fix whitespace query edge case
- --format data preserves backward-compatible flat array output
- --format json returns the new envelope object with pagination fields
- Align search: prefix guard with TrimSpace(query) to match usesTriageSearchPath
* fix(mail): simplify page-token format and fix page-size change data loss
- Remove page_size encoding from token (search:abc → not search:5:abc)
The search API token is a session cursor; page_size only controls how
many items to return, not the cursor position. Encoding page_size
caused data loss when users changed --page-size between requests.
- Token format is now simply "search:<raw>" / "list:<raw>"
- Add parseTriagePageToken/encodeTriagePageToken helpers for clean
token handling with proper validation
- next page hint in table output now includes --query and --filter
for easy copy-paste continuation
* docs(mail): update triage skill doc for json/data format split and search pagination note
- Separate --format json (object with pagination) and --format data (array) examples
- Update table next-page hint example to show --query/--filter inclusion
- Add search pagination caveat about cross-session result ordering
* fix(mail): make --format data include pagination fields same as json
* fix(mail): address remaining PR review comments
- Reject empty prefixed tokens (search: / list:) in parseTriagePageToken
- Shell-escape query/filter in next-page hint to handle single quotes
- Fix doc caption mismatch (data → json/data) and add language tag to code block
- Fix test comment for TestResolveTriagePageSizeDefaultMax
* fix(mail): rename total to count in triage pagination output
total was misleading — it represented the current page count, not the
global total. Renamed to count to match len(messages) semantics.
* fix(mail): improve dry-run desc when using --page-token
* fix(base): improve --json help examples and group guide
* fix(base): unify --json help tips format
* docs(base): fix view-set-group schema with group_config
* fix(base): remove array wording from view-set-group json help
---------
Co-authored-by: kongenpei <kongenpei@users.noreply.github.com>
* fix(api): add stdin and single-quote support for --params/--data on Windows (#64)
Windows PowerShell 5.x mangles JSON double-quotes when passing arguments
to native executables, causing --params and --data to fail with
"invalid JSON format". This commit adds two mitigations at the framework
level:
- stdin piping: `echo '{"k":"v"}' | lark-cli --params -` bypasses
shell argument parsing entirely and works on all platforms/shells.
- single-quote stripping: cmd.exe passes literal single quotes which
are now transparently removed before JSON parsing.
Implementation:
- New `cmdutil.ResolveInput(raw, stdin)` handles `-` (stdin), strip
surrounding `'...'`, and plain passthrough.
- `ParseJSONMap` and `ParseOptionalBody` now accept an `io.Reader` and
delegate to `ResolveInput` before JSON unmarshalling.
- `cmd/api` and `cmd/service` pass `IOStreams.In` and guard against
simultaneous stdin usage by --params and --data.
- Empty stdin is rejected with a clear error message.
Closes#64
Change-Id: If21e735d0aed5c6a2d6674c1e6c898186fca3aba
* test: add stdin e2e regression coverage
Change-Id: I4e00bf1c6b6f3259f503e3414cae10fa4b34ba75
New capabilities:
1. Alias (send_as) sending for all compose shortcuts (+send, +reply, +reply-all,
+forward, +draft-create, +draft-edit):
- New --mailbox flag separates mailbox routing from sender identity, enabling
alias sending where --mailbox specifies the owning mailbox and --from
specifies the alias address in the From header.
- Example: --mailbox me --from alias@example.com --to bob@example.com
- --mailbox priority: --mailbox > --from > "me"
- --from priority: --from > --mailbox > profile("me")
2. Discovery APIs for available mailboxes and sender addresses:
- accessible_mailboxes: lists all mailboxes the user can access (primary + shared)
- send_as: lists available sender addresses for a mailbox (primary, aliases, mailing lists)
3. Mail rules API:
- user_mailbox.rules resource: create, delete, list, reorder, update
4. Reply-all self-exclusion improvement:
fetchSelfEmailSet now also excludes the --from alias address, preventing the
sender from appearing in the recipient list when replying via an alias.
No breaking changes — omitting --mailbox preserves existing behavior.
When config.json is hand-edited, the appId field can become out of sync
with the appSecret keychain reference (e.g. appId changed but
appSecret.id still points to the old app). This causes silent auth
failures at API call time. Add a pre-flight check in
ResolveConfigFromMulti that compares the two before any keychain lookup
or OAPI request, failing fast with actionable guidance.
Change-Id: I74b9ab640642dde3df1ad70890b93b91ee422022
- Add depguard linter to block shortcuts/ from importing internal/vfs
directly (must use runtime.FileIO() instead)
- Add forbidigo rules for os.* filesystem ops, IO streams, os.Exit,
and filepath.* functions that bypass vfs
- Split os.Remove / os.RemoveAll into separate patterns with accurate
guidance (RemoveAll not yet in vfs)
- Use compact regex groups for maintainability, no duplicate or
shadowed patterns
Change-Id: I9e45ab07ca58a61b86bdcea9f1f2cc6181c974bc
* feat(auth): improve scope handling and output in login flow
- Add scope validation to check for missing requested scopes
- Implement detailed scope breakdown in login success output
- Add new message strings for scope-related output
- Refactor login success output to handle both JSON and text formats
- Add tests for scope validation and output scenarios
* feat(auth): add requested scope caching for device code login
Implement caching of requested scopes during device code login flow to ensure proper scope validation after authorization. The cache is stored in JSON files under config directory and automatically cleaned up after successful or failed authorization.
Add tests for scope caching functionality and verify proper integration with existing login flow.
* docs(auth): add function comments for login scope handling
Add detailed doc comments to all functions in login scope cache and result handling files to improve code documentation and maintainability.
* refactor(auth): remove pending scopes and improve json output stability
- Remove PendingScopes field and related logic as it's no longer needed
- Add emptyIfNil helper to ensure nil slices are normalized to empty slices in JSON output
- Update tests to verify JSON output stability and fix expected text outputs
* refactor(auth): extract device token polling function for testability
Move device token polling to a package-level variable to enable mocking in tests
Add test case for scope cleanup when token is nil
* fix(auth): return JSON write errors instead of ignoring them
Previously, JSON write errors were only logged to stderr but not returned, causing tests to pass when they should fail. Now properly propagate these errors to callers and update tests to verify error handling.
* refactor(auth): simplify scope handling and improve user messaging
remove redundant scope display and consolidate hint messages to focus on actionable guidance
* refactor(auth): improve scope handling and messaging in login flow
remove ShortHint field and simplify scope hint messages
always display missing scopes section with consistent formatting
add StatusHint for successful login with no missing scopes
update tests to reflect new message structure and content
* refactor: migrate vc/minutes shortcuts to FileIO
- vc_notes: replace vfs.Stat + validate.SafeOutputPath + validate.AtomicWrite
with FileIO.Stat/Save for transcript download
- minutes_download: replace validate.SafeOutputPath + validate.AtomicWriteFromReader
with FileIO.Save, use FileIO.Stat for overwrite checks
- Use WrapSaveError to preserve original error messages
* fix: resolve concurrency races in RuntimeContext
- getAPIClient: replace check-then-act with sync.OnceValues, matching
the factory_default.go convention; use NewAPIClientWithConfig to avoid
post-construction config override; fall back to direct construction
for test contexts that bypass newRuntimeContext.
- outputErr: guard first-error capture with sync.Once to prevent data
races if Out() is ever called from concurrent goroutines.
Change-Id: I99c94c3dcb7663fa61571c9720163e41a5fc0e36
* fix: use tenant token for auth scopes
Change-Id: I83bb677e9a33e906e207679b2ba8d0364bc20fe3
* refactor: migrate common/client/im to FileIO and add localfileio tests
- runner resolveInputFlags: replace validate.SafeInputPath + vfs.ReadFile
with FileIO.Open + io.ReadAll
- SaveResponse: delegate to FileIO.Save + ResolvePath
- cmd/api, cmd/service: pass FileIO to ResponseOptions
- im: replace validate.SafeLocalFlagPath with RuntimeContext.ValidatePath,
migrate download/upload to FileIO.Save/Open/Stat
- Add path_test.go and atomicwrite_test.go for localfileio
- Add validate_media_test.go for im media flag validation
- Adapt test mocks to fileio.FileInfo interface
* fix: reject positional arguments in shortcuts with clear error
Shortcuts silently ignored positional arguments (e.g. `lark-cli docs
+search "hello"`), causing empty results. Add Args validator to all
declarative shortcuts so cobra prints usage and a clear error message
telling users to pass values via flags instead.
Change-Id: I7579f9c871138cf91dd5f5d8c1d51bda3f77a1db
* fix: address PR review comments
- Remove unused *Shortcut parameter from rejectPositionalArgs
- Show all positional args in error message instead of only the first
- Add test case for multiple positional arguments
Change-Id: Ifea92d09ddabcd35fbf2db98d9888d18af59b894
All draft-related shortcuts now support <img src="./local.png"> in --body,automatically resolving relative paths into cid: inline MIME parts. Only relative paths are supported; absolute paths are rejected. Previously only +draft-edit supported this; now extended to +draft-create, +send, +reply, +reply-all, and +forward.
- Add internal/client/api_errors.go with WrapDoAPIError and WrapJSONResponseParseError to classify JSON decode issues vs generic network errors
- Route cmd/api DoAPI errors and HandleResponse JSON parse errors through the new helpers
- Add regression tests in cmd/api and internal/client
Related: https://github.com/larksuite/cli/issues/215
* feat: add FileIO extension for file transfer abstraction
Introduce extension/fileio package with Provider/FileIO/File interfaces
and a global registry, following the same pattern as extension/credential.
- Add LocalFileIO default implementation with path validation and atomic writes
- Wire FileIOProvider into Factory and resolve at runtime via RuntimeContext.FileIO()
- Factory holds Provider (not resolved instance), deferring resolution to execution time
* feat: linux support custom data dir via environment variable
* feat(keychain): support custom log directory via LARKSUITE_CLI_LOG_DIR
* feat(security): validate env dir paths for security
Add validation for environment variable directory paths to ensure they are absolute and safe. This prevents potential security issues from malformed paths. Also add corresponding tests to verify the validation behavior.
* docs(validate): add function and test documentation comments
Add missing documentation comments for SafeEnvDirPath function and related test cases to improve code clarity and maintainability
* refactor(keychain): remove warning logs for invalid env vars
* feat(vc): add +recording shortcut for meeting_id to minute_token conversion
* fix(vc): address PR review feedback for +recording shortcut
* docs(vc): merge Recording and Minutes in resource diagram as they share minute_token
* docs(vc): simplify resource diagram to use Minutes only
* test(vc): add integration eval for +recording execute paths
* docs(vc): fix +recording description to include both input modes
* fix(vc): address review findings for +recording docs and code consistency
+update already calls normalizeDocsUpdateResult to surface board_tokens when
markdown contains mermaid/plantuml/whiteboard blocks. +create was missing the
same call, so callers could not know how many whiteboards were created or
retrieve their tokens. One-line fix: call normalizeDocsUpdateResult after
CallMCPTool in DocsCreate.Execute.
* docs: add v1.0.5 changelog
Change-Id: Ia2c5e8f3d3e5fb95b4509e2f5d62a1ee253cd679
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: bump version to v1.0.5
Change-Id: I8d19ec44311f9bf0e700152beab1fd8d261c3f73
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>