Commit Graph

16 Commits

Author SHA1 Message Date
evandance
99e314fe0b feat(errs): typed envelope contract for auth-domain errors (#1135)
Every failure on the authentication, authorization, and configuration
path now surfaces as a typed structured error instead of an ad-hoc
envelope. Users and scripts that consume CLI output get:

  - a fixed nine-category taxonomy on the wire, each mapped to a
    stable shell exit code (authentication/authorization/config = 3,
    network = 4, internal = 5, policy = 6, confirmation = 10)
  - identity-aware detail fields (missing_scopes, requested_scopes,
    granted_scopes, console_url, log_id, retryable, hint) carried
    uniformly on the envelope
  - a single canonical policy envelope at exit 6; the legacy
    auth_error carve-out is retired
  - per-subtype canonical message + hint that preserves Lark's
    diagnostic phrasing and routes recovery to the right actor:
    app developer (app_scope_not_applied), user (missing_scope,
    token_scope_insufficient, user_unauthorized), or tenant admin
    (app_unavailable, app_disabled)
  - wrong app credentials classify as config/invalid_client whether
    surfaced by the Open API endpoint (99991543) or the tenant
    access-token mint endpoint (10003 / 10014), instead of
    collapsing to a transport error or api/unknown
  - local shortcut scope preflight emits the same
    authorization/missing_scope envelope (identity + deterministic
    missing-scope set) used by the post-call permission path, so AI
    consumers read the same structured shape from precheck and from
    server-returned permission denial
  - streaming download/upload failures keep the same network subtype
    split (timeout / TLS / DNS / transport) as the non-stream path
    instead of collapsing every cause to a generic transport failure
  - console_url is carried only on the bot-perspective
    app_scope_not_applied envelope (where the recovery action is
    "developer applies the scope at the developer console"); the
    user-perspective missing_scope envelope drops the field, since
    the only actionable user recovery is `lark-cli auth login --scope`
    and pointing an end user at a console they cannot modify is
    misleading
  - bind workflows (Hermes / OpenClaw / lark-channel) flatten dynamic
    Type tags to wire 'config' with the original module name kept
    as a metric label

All 10 typed errors are cause-bearing, nil-safe on .Error() and
.Unwrap(), and defensively clone slice setter inputs. Four lint
rules (CheckNilSafeError / CheckBuilderImmutable / CheckUnwrapSymmetry
/ CheckBuildAPIErrorArms) lock these invariants on migrated paths.
2026-05-30 19:08:41 +08:00
xukuncx
ab94ee9f54 feat(mail): add +draft-send shortcut for batch draft sending (#1017)
Add `lark-cli mail +draft-send` shortcut that takes one or more existing
draft IDs and sends each via POST /drafts/:draft_id/send sequentially.
Per-draft failures are isolated and aggregated into a structured output;
fatal failures (auth, permission, network, mailbox quota) abort the
entire batch immediately while recoverable failures honor --stop-on-error.

Also extend internal/output with six mail-send-specific errno constants
(LarkErrMailboxNotFound=4013, LarkErrMailSendQuota{User,UserExt,TenantExt},
LarkErrMailQuota, LarkErrTenantStorageLimit) consumed by isFatalSendErr.

Risk is "high-risk-write" so the framework's --yes gate applies; the
shortcut declares only the minimal mail:user_mailbox.message:send scope
to avoid asking users for permissions it does not need.
2026-05-27 18:12:41 +08:00
evandance
fe72e41fb2 feat(errs): add structured CLI error contract (#984)
Introduce a typed error contract framework for lark-cli so in-process
Go callers can branch via errors.As(&errs.XxxError{}) and shell scripts,
AI agents, and protocol adapters can branch on stable JSON type/subtype
fields instead of regex-parsing free-form messages.

Adds:
- Canonical taxonomy under errs/ (9 categories + typed Error structs
  embedding a shared Problem, RFC 7807-aligned)
- Centralized Lark code metadata + identity-aware BuildAPIError dispatch
- Typed JSON envelope writer alongside the legacy envelope writer
- MCP / OAuth (RFC 6750 Bearer) projection adapters
- Five CI lint guards preventing ad-hoc taxonomy drift

Backward compatibility: legacy *output.ExitError producers (ErrAPI,
ErrWithHint, Errorf, ErrBare) and business shortcuts that use them
continue to render the legacy envelope unchanged. SecurityPolicyError
wire format and exit code are preserved via a carve-out; taxonomy
migration is deferred to PR 2. Domain-specific business migration is
staged across PR 3+.

Framework-direct paths now return typed *errs.*Error: ErrAuth /
ErrValidation / ErrNetwork emit category literals on the wire
(authentication / validation / network), *core.ConfigError is promoted
at the cmd/root boundary with exit code aligned from 2 to 3, and Lark
API permission denials classified by BuildAPIError exit 3.

At the SDK boundary, WrapDoAPIError preserves any already-classified
error (legacy *output.ExitError or typed *errs.*) so output.ErrAuth
from missing credentials surfaces with the auth category and exit 3
intact instead of being downgraded to a network error. Policy responses
classified by BuildAPIError (codes 21000 / 21001) extract challenge_url
and the canonical hint from the response body, matching what the
auth transport already surfaces at the HTTP layer; non-https
challenge URLs are dropped.

First PR in the feat/error-contract-* series.
2026-05-26 11:42:33 +08:00
郭立lee
f2a4c95665 fix(output): classify wiki lock-contention error (131009) with retry hint (#1014)
Wiki write-path operations (most commonly `wiki +node-create` against the
same parent) surface code 131009 "lock contention" under concurrent calls.
Currently this falls through to the generic "api_error" classification,
giving users no hint that it is transient and safe to retry.

Mirror the existing `LarkErrDriveResourceContention` (1061045) treatment:
add a named constant, classify as "conflict", and emit a hint that points
the caller toward exponential backoff or serializing sibling-node writes.

Refs: #1012
2026-05-25 15:50:45 +08:00
JackZhao10086
15ae1fabec fix(auth): handle missing scopes and device flow improvements (#752)
* 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
2026-05-06 17:10:27 +08:00
liangshuo-1
f7a56f38b1 feat(contact +search-user): add --queries multi-name fanout (#707)
Add --queries CSV flag to lark-cli contact +search-user for parallel
multi-name fanout (up to 20 entries, partial-failure tolerant).

Output shape in fanout mode:
- data.users[] rows carry matched_query (string)
- data.queries[] sidecar lists each input with {query, error?, has_more}
- top-level data.has_more removed (per-query in queries[])
- error is omitempty; absent on success

Single --query mode is byte-for-byte unchanged (regression-guarded).
--queries is mutually exclusive with --query and --user-ids; bool
filters propagate to every sub-request.

Workers run with WaitGroup + buffered semaphore + index-slot writes;
each has defer recover() converting panics to internal error: ... in
the sidecar (no stack to stderr). Pre-canceled context returns
context canceled without making the request.

All-failed exit propagates first failure's HTTP/API code via ErrAPI;
falls back to ExitInternal for transport/parse/panic/ctx-canceled
(avoids emitting code 0, which means success in the Lark protocol).
HTTP non-200 ErrMsg now includes truncated response body for diagnosis.

Drive-by: signature field is now omitempty (mostly empty in practice).

Infrastructure:
- internal/httpmock gains BodyFilter/OnMatch/Reusable/CapturedBodies
  hooks to support concurrent stub-driven tests
- internal/output adds 'users' to knownArrayFields so CSV picks the
  primary array correctly

Change-Id: I3c14195fb8e094ae150002d90c36a0e4a0cc97d0
2026-04-29 17:03:21 +08:00
chenxingtong-bytedance
0bbd0f2c7d feat(im): add recovery hint for cross-identity message resources (#652)
Change-Id: I8a43486333638271f0fbbcffca81a60c9f9d2060
2026-04-28 20:16:39 +08:00
sang-neo03
9ba0d15161 Feat/risk tiering (#633)
* feat(risk): implement confirmation for high-risk write operations

* feat(risk): streamline confirmation for high-risk write operations

* feat(risk): document approval protocol for high-risk write operations

* feat(risk): refine confirmation protocol for high-risk write operations

* feat(risk): remove redundant variable declaration in risk test

* feat(risk): add 'Yes' flag to various test cases for confirmation
2026-04-28 18:15:56 +08:00
SunPeiYang996
e42033f5b5 feat(doc): add v2 API for docs +create / +fetch / +update (#638)
Adds an `--api-version v2` path to the docs shortcuts, backed by the
`docs_ai/v1/documents` OpenAPI. DocxXML is the default document format
and Markdown is available as an alternative. Content input is unified
across the three shortcuts via `--content` + `--doc-format`. The v1
(MCP) path is preserved for backward compatibility and now prints a
deprecation notice on use.

Shortcuts:

  - `docs +create --api-version v2`: create a document from XML or
    Markdown, with optional `--parent-token` or `--parent-position`.
    Bot identity continues to auto-grant the current CLI user
    full_access on the new document.

  - `docs +fetch --api-version v2`: adds `--detail simple|with-ids|full`
    for export granularity and `--scope full|outline|range|keyword|section`
    for partial reads, along with `--context-before` / `--context-after`,
    `--max-depth`, and `--revision-id`.

  - `docs +update --api-version v2`: introduces structured operations
    via `--command`: `str_replace`, `block_delete`, `block_insert_after`,
    `block_copy_insert_after`, `block_replace`, `block_move_after`,
    `overwrite`, `append`.

Framework support in `shortcuts/common`:

  - `OutRaw` / `OutFormatRaw` emit the JSON envelope with HTML escaping
    disabled so XML/HTML document bodies are preserved verbatim.
  - New `Shortcut.PostMount` hook runs after a cobra.Command is fully
    configured; used here to install a version-aware help function
    that hides flags belonging to the inactive `--api-version`.

Also refreshes the lark-doc skill pack (SKILL.md, create/fetch/update
references, new lark-doc-xml and lark-doc-md references, style and
workflow guides), README examples, and downstream skill call sites
(lark-drive, lark-vc, lark-whiteboard, lark-workflow-meeting-summary,
lark-event).

Change-Id: Ide2d86b190a4e21095ae29096e7fb00031d80489
2026-04-23 23:24:30 +08:00
MaxHuang22
600fa50517 feat: add configurable content-safety scanning (#606)
* feat(contentsafety): add extension interface layer with Provider, Alert, and registry

Change-Id: Ibeac6366c7201293057bc3b063f75ac34565bcd5

* feat(contentsafety): add normalize utility for JSON type conversion

Change-Id: I7d4729a5ddcab2553abc110f8f6ecc88435ae921

* feat(contentsafety): add tree walker and regex scanner

Change-Id: I215dad7cf3072711d05e45f7d384162e1f8752d4

* feat(contentsafety): add config loading with lazy creation, default rules, and allowlist matching

Change-Id: I75e10df28f1f8d4f433cb2b469a0ff317af3bf70

* feat(contentsafety): add regex provider with config-driven scanning and allowlist

Change-Id: I658889b3647cbbbde6881e0c5f7c13887a1eb1d4

* feat(contentsafety): add output core with mode parsing, path normalization, and scan orchestration

Change-Id: I1cb9df75f1a4d176d660e2e7a9561314c3787191

* feat(contentsafety): add ScanForSafety entry point and Envelope alert field

Change-Id: I5fdb311e1c8d983a35a58667970b9fd3ac729a5c

* feat(contentsafety): integrate scanning into shortcut Out() and OutFormat()

Change-Id: I33eef1dba14c8a9bd1998857311bdd611f33b916

* feat(contentsafety): integrate scanning into API/service output paths and register provider

Change-Id: Ic3981db6c546a19eadea095d82175f92f4783bec

* fix(contentsafety): emit stderr notice when lazy-creating default config

Change-Id: Ia2491f7a17caceea3125ff9fb58d750dc196d7e7

* style: gofmt factory_default and exitcode

Change-Id: I86c5afdfbbdb68d8137f0ca09ef3b5a1139f4b4e

* fix(contentsafety): vfs for config I/O, mutex for lazy-create, sort matched rules, emit warn on --output path

Change-Id: Ib4982cd54e1bfe0580a0eb03368e6ca818304e1b

* fix(contentsafety): isolate scan goroutine errOut to prevent race on timeout

Change-Id: Ia5a770d7387ba6d3b7fa318fc5f1384214ea10b7

* fix(contentsafety): deep-normalize typed slices so scanner can walk shortcut data

Change-Id: I641e89113d1a2f2285ac6109bd3d7264f5845ea7

* fix(contentsafety): file perms 0600/0700, no result mutation, timeout test, scanTimeout comment

Change-Id: Ie45a2e365ee7098e214e94f8871026cc12029d83
2026-04-23 17:18:29 +08:00
caojie0621
7e9beec422 feat(drive): add +apply-permission to request doc access (#588)
Wrap the POST /drive/v1/permissions/:token/members/apply endpoint as a
user-only shortcut. --token accepts either a bare token or a document
URL, with type auto-inferred from the URL path (/docx/, /sheets/,
/base/, /bitable/, /file/, /wiki/, /doc/, /mindnote/, /minutes/,
/slides/); an explicit --type always wins. --perm is limited to view or
edit; full_access is rejected client-side to match the spec.

Classifier gains two domain-specific hints for the endpoint's newly
documented error codes: 1063006 (per-user-per-document quota of 5/day
reached) and 1063007 (document does not accept apply requests — covers
disallow-external-apply, already-has-access, and unsupported-type).

test(drive): add dry-run E2E for +apply-permission

Invoke the real CLI binary via clie2e.RunCmd under --dry-run and
parse the rendered request JSON with gjson to lock in method, URL
path (including the token segment), type query parameter (auto-inferred
for docx / sheet / slides URLs, taken from explicit --type for bare
tokens), perm body field, and remark presence/omission. A separate
test asserts --perm full_access is rejected by the enum validator
before reaching the server. Fake LARKSUITE_CLI_APP_ID / APP_SECRET /
BRAND are enough because dry-run short-circuits before any API call.

Update drive coverage.md to add a row and refresh metrics.

test(drive): isolate E2E dry-run subprocess from local CLI config

Set LARKSUITE_CLI_CONFIG_DIR to t.TempDir() in both +apply-permission
dry-run tests so the subprocess can't read a developer's real
credentials/profile instead of the fake env vars the tests inject.

test(drive): add E2E case that exercises URL inference override

Previous "bare token with explicit type wins over inference" row used a
bare token, which has no URL-derived type to override. Replace it with
a /docx/ URL + --type wiki combo that actually forces the explicit flag
to win over URL inference, and add a separate bare-token row to keep
the simpler path covered. Refresh coverage.md wording to match.
2026-04-22 16:28:48 +08:00
caojie0621
abb02cd46c feat(sheets): add float image shortcuts (#494)
Implement +create-float-image, +update-float-image, +get-float-image,
+list-float-images, and +delete-float-image shortcuts wrapping the v3
spreadsheet float_image API. The create reference doc includes the
prerequisite media upload step with the correct parent_type
(sheet_image) to avoid common token mismatch errors.
2026-04-18 23:27:11 +08:00
Tsai_Hui
3917b77e91 feat: add drive create-shortcut shortcut (#432) 2026-04-13 11:54:31 +08:00
MaxHuang22
7baba213bc feat: add --jq flag for filtering JSON output (#211)
* feat: add --jq flag for filtering JSON output across all command types

Add jq expression filtering (--jq / -q) to api, service, and shortcut
commands using gojq. Includes early expression validation, mutual
exclusion checks with --output and non-json --format, pagination+jq
aggregation path, and comprehensive test coverage.

* fix: correct gofmt alignment in jq_test.go struct literal


* fix: downgrade gojq to v0.12.17 to keep Go 1.23 compatibility

gojq v0.12.18 requires Go 1.24, which unnecessarily bumped the project
minimum version. v0.12.17 requires only Go 1.21 and provides the same
jq functionality needed.


* refactor: consolidate jq validation and pagination logic

Extract ValidateJqFlags() and PaginateWithJq() shared functions to
eliminate duplicated jq logic across api, service, and shortcut commands.

* fix: reject --jq for non-JSON responses and propagate shortcut jq errors

- HandleResponse now returns a validation error when --jq is used with
  a non-JSON Content-Type instead of silently falling through to binary save.
- Shortcut runtime jq errors are captured in RuntimeContext.outputErr
  and propagated as the command exit code, matching api/service behavior.
2026-04-02 18:36:59 +08:00
MaxHuang22
27139a0919 feat: add automatic CLI update detection and notification (#144)
Add non-blocking update check that queries the npm registry for the
latest @larksuite/cli version. Results are cached locally (24h TTL)
to avoid repeated network requests.

When a newer version is detected, a `_notice.update` field is injected
into all JSON output envelopes (success, error, and shortcut responses),
enabling AI agents and scripts to surface upgrade prompts.

Key changes:
- New `internal/update` package: registry fetch, semver compare, cache
- Async check in root command (cache-first, then background refresh)
- `_notice` field added to Envelope/ErrorEnvelope structs
- `PrintJson` injects notice into map-based envelopes with "ok" key
- `doctor` command gains cli_version and cli_update checks
- Suppressed for CI, DEV builds, shell completion, and git-describe versions
2026-03-31 19:01:39 +08:00
梁硕
83dfb068ad feat: open-source lark-cli — the official CLI for Lark/Feishu
Change-Id: I113d9cdb5403cec347efe4595415e34a18b7decf
2026-03-28 10:36:25 +08:00