Skill references written before the typed-error refactor still taught retired envelope shapes. AI agents following them now read what the CLI actually emits:
- permission recovery reads error.missing_scopes instead of the upstream permission_violations detail
- confirmation gates use type=confirmation, subtype=confirmation_required, and flat risk/action fields
- drive duplicate-remote failures are typed validation envelopes (failed_precondition with params[]), not duplicate_remote_path with error.detail
- drive batch partial failures are ok:false results on stdout, not an error.type=partial_failure stderr envelope
- minutes edit-permission and word-replace misses branch on error.subtype, not retired error.type values
- slides replace failures are stderr typed envelopes only; no raw backend response is printed to stdout
- slides command outputs show the ok/identity/data success envelope instead of the raw {code,msg} OpenAPI wrapper
* fix: unify dry-run output contract
* fix: address dry-run review feedback
* fix(dryrun): tighten preview contract and unify data shape
- transcribe HTTP method verbatim in previews (HEAD/OPTIONS were
reported as GET); reject an empty method in api with a typed error
- unify the dry-run data payload across api/service/shortcut paths:
{api, context?: {app_id, user_open_id}}; drop data.as — the envelope
top-level identity is the single identity source
- mark pretty dry-run stdout with '# dry-run: request not sent' so logs
that drop stderr still show it was a preview
- extract the shared preview builder, collapse PrintDryRunWithFile's
loose params into FileUploadMeta, and fail loudly on nil previews
- revert description-marker identity parsing: stale prose must not
override corrected accessTokens (blocks legal user calls on
images.create); identity gating keys off accessTokens only
- pin the new contracts with tests: verbatim method, three-way context
parity, nil-preview error, empty-context omission, marker line
* docs(agents): add typed-data, faithful-transcription, and contract-test conventions
- typed struct at the boundary over map[string]interface{} threading;
distinct types where values could swap silently (internal/meta.Token)
- transcribe input verbatim in previews/transformations; reject
unhonorable flag combinations with typed errors instead of silently
substituting behavior
- contract tests must fail when the implementation is reverted
* test: migrate dry-run tests grown on main to the envelope format
main gained raw-format dry-run readers while the PR was in flight
(wiki drive export #1802, drive list comments #1845, slash commands,
sheets history, docs fetch, mail draft-send/triage, vc meeting events).
Migrate them to the envelope accessors (clie2e.DryRunGet / data-wrapped
decoders) and drop the now-redundant DryRunData extractions in files
unified on DryRunGet.
---------
Co-authored-by: guokexin.02 <264159873+Tantanz20020918@users.noreply.github.com>
* feat(sheets): support font_family in cell styles (#1549)
Add a font_family field to cell_styles so a cell's font name can be set
and read back through every style entry point:
- +cells-set (--cells JSON) and +cells-set-style / +cells-batch-set-style
gain a font_family field / --font-family flat flag
- +workbook-create / +table-put --styles accept font_family in cell_styles
- +cells-get returns font_family
helpers.go buildCellStyleFromFlags reads the --font-family flag;
lark_sheet_workbook.go allows font_family in the --styles cell_styles
whitelist; data/ + skills/ are synced from sheet-skill-spec.
* docs(sheets): inline editing rules into SKILL.md and clarify flag descriptions
- Move cross-cutting editing rules and execution notes into the root
SKILL.md and drop the now-redundant core-operations reference
- Clarify flag descriptions: offset must be explicit inside +batch-update,
range prefixes written bare (no quotes), chart requires a dim index,
untyped --values lose date/number types, ungroup level semantics
- Sync the corresponding reference docs
* feat(sheets): add --type bitable to +sheet-create for creating bitable sub-sheets (#1520)
* perf(sheets): cap fan-out cell-matrix materialization to prevent OOM (#1578)
* perf(sheets): cap fan-out cell-matrix materialization to prevent OOM
The +cells-set-style / +dropdown-set / +cells-batch-set-style /
+dropdown-update shortcuts expand a single A1 range into a rows×cols
matrix of per-cell maps client-side (the backing set_cell_range tool
takes an explicit cells matrix). rangeDimensions() had no upper bound,
so a tiny input like "A1:Z100000" balloons into ~2.6M heap maps (~900MB,
doubled again by json.Marshal) and can OOM the process before the
request is even sent.
Add a 50000-cell safety cap (checkStampMatrixBudget) gating every
fan-out materialization point, matching the documented but never-wired
--max-cells default. Oversized ranges now fail fast with a clear
validation error instead of allocating. Also preallocate the per-op
slices now that the range count is known up front.
Adds benchmarks + a boundary test as regression guards.
* perf(sheets): cap table-put/batch fan-out materialization (siblings of the cell-matrix cap)
The single-range fan-out cap (maxStampMatrixCells) left three sibling
ingress paths uncapped, each able to materialize an unbounded matrix or
op set in memory before the request leaves:
- +table-put / +workbook-create --sheets/--values: buildSheetMatrix
builds the whole rows×cols matrix before slicing it into per-write
batches; tablePutMaxCellsPerWrite only bounds the batch size, not the
total input. Add tablePayload.checkCellBudget (1M-cell guardrail),
enforced in validate() and in buildValuesPayload (the --values path
bypasses validate()).
- batch fan-out (+cells-batch-set-style / +dropdown-update): per-range
checkStampMatrixBudget can't stop many ranges from summing past the
cap. Add an aggregate cell budget (checkBatchStampBudget) and a shared
maxBatchRanges (100) count cap in validateDropdownRanges — covering
all fan-out commands and replacing the now-redundant +dropdown-delete
count check.
- +batch-update: cap --operations at maxBatchOperations (100) in
translateBatchOperations.
Adds boundary regression tests for each cap. go vet + gofmt clean; full
shortcuts/sheets + backward suites green.
* test(sheets): measure table-put matrix materialization cost
Add BenchmarkBuildSheetMatrix_* and TestTablePutMatrixPeakMemory mirroring
the fan-out probes. Confirms the +table-put/+workbook-create ingress has the
same OOM profile as the single-range stamp: 2.6M cells → ~917 MB / 5.3M allocs
(+875 MB resident heap) materialized before the first write — now rejected up
front by checkCellBudget.
* feat(pivot): lark-sheets pivot reference 补 +pivot-list info 说明与落点覆盖校验
+pivot-list 返回 info(page_range/content_range/error_state 等):
1) 判断目标单元格在透视表内(改配置 +pivot-update)还是区域外(改值 +cells-set);
2) 透视表展开后会覆盖已有数据,落点强烈优先默认自动新建子表;
3) 创建后用 info.error_state / content_range 校验有没有覆盖/冲突。
* feat(sheets): add +formula-verify shortcut for verify_formula tool
Wraps the new verify_formula read tool in a CLI shortcut so AI agents
can run write-then-zero-error verification end-to-end:
lark-cli sheets +formula-verify --url <url>
Scans formulas + cell error states across one or more sub-sheets and
returns a JSON status report (success / errors_found / partial).
Aggregates all 7 Excel error categories (#REF! / #DIV/0! / #VALUE! /
#NAME? / #NULL! / #NUM! / #N/A) plus compile failures into one
envelope; the tool always reports every error in the scan window —
callers needing a subset filter the returned error_summary
client-side. The internal scan cap is hidden from callers; when it
trips the response sets has_more=true and includes a warning_message
asking the caller to narrow --range / split --sheet-id and continue.
Flags follow the lark-sheets convention:
- --url / --spreadsheet-token (XOR public)
- --sheet-id / --sheet-name (repeat or comma-separate; mutually
exclusive)
- --range (repeatable A1)
- --max-locations (default 20)
- --exit-on-error (CI gate: status='errors_found' → exit 2 with
failed_precondition)
Generated artifacts (skills/lark-sheets/{SKILL.md, references/
lark-sheets-formula-verify.md}, shortcuts/sheets/data/flag-defs.json,
shortcuts/sheets/flag_defs_gen.go) are mirrored from sheet-skill-spec
generated/ via 'npm run sync:cli'. shortcuts.go registers
FormulaVerify alongside the other lark_sheet_formula_verify skill
shortcuts so +formula-verify is discoverable from
'lark-cli sheets --help'.
Tests cover the dry-run wire shape (excel_id + sheet_ids/sheet_names/
ranges/max_locations packing), the read scope (invoke_read URL), the
mutually-exclusive selector validation, the non-positive
--max-locations guard, and the --exit-on-error status matrix
(success/partial/errors_found/unknown).
* feat(sheets): add +history-list / +history-revert / +history-revert-status shortcuts
BE-1 + BE-2 (larksuite/cli lark-sheets) for spec sheet-history-revert.
Three thin callTool wrappers over facade-agg history tools, following the
existing sheets Validate/DryRun/Execute + --url/--spreadsheet-token(/--token)
locator convention:
- +history-list (read, history_list): passes the tool output through verbatim;
facade-agg already does the minor_histories/4-field/RFC3339 transform.
- +history-revert (write, history_revert): --history-version-id required,
enforced at Validate stage with a typed *errs.ValidationError (no request on
missing); returns the async receipt.
- +history-revert-status (read, history_revert_status): polls in-progress /
success / failure.
Flags declared inline (not via *_gen.go) — flag_defs_gen.go / data/flag-defs.json
are synced from sheet-skill-spec (BE-3) and must not be hand-edited.
Notes:
- history_revert / history_revert_status depend on facade-agg's downstream RPC
wiring, a DEFERRED follow-up; the tools return a "not wired yet" guard today.
These CLI wrappers are correct and go live when the backend follow-up lands.
+history-list is fully functional now.
- TestFlagDefsGen_MatchesJSON fails on baseline (pre-existing BE-3 gen/json
drift); resolves once BE-3 sync:cli regenerates flag defs for these shortcuts.
Validation: go build ./shortcuts/sheets/... PASS; new tests
(TestHistoryShortcuts_DryRun, TestHistoryRevert_MissingVersionID) PASS.
Spec source: active@2acd94a24ac3f835357a274a02344f78435bcc1c39ad0d695ce587f0cbddfb21
* chore(sheets): sync lark_sheet_history skill + flag defs from sheet-skill-spec (BE-3)
Synced artifacts for the history shortcuts from ee/sheet-skill-spec (SSOT),
landed surgically (history-only) to avoid regressing this branch's newer
skills/lark-sheets content:
- skills/lark-sheets/references/lark-sheets-history.md (new, mirrored).
- skills/lark-sheets/SKILL.md: + Lark Sheet History references-table row only.
- shortcuts/sheets/data/flag-defs.json: + 3 history shortcuts (additive; no existing entries touched).
- shortcuts/sheets/flag_defs_gen.go: regenerated via go generate ./shortcuts/sheets/...
(this also resolves the pre-existing flag-defs/gen drift — TestFlagDefsGen_MatchesJSON now passes).
NOT a full mirror: the rest of skills/lark-sheets/ + flag-schemas.json on this
branch (feat/lark-sheets-develop) are NEWER than the sheet-skill-spec worktree's
canonical (e.g. /wiki/ URL support, schema_version 3). A wholesale sync:cli would
have reverted them, so only the history delta is taken here. Full re-sync should
happen once sheet-skill-spec canonical is realigned with this branch.
Validation: go generate clean; go test ./shortcuts/sheets/
(TestFlagDefsGen_MatchesJSON, TestHistory*) PASS.
Spec source: active@2acd94a24ac3f835357a274a02344f78435bcc1c39ad0d695ce587f0cbddfb21
* fix(sheets): +history-revert-status keys on --transaction-id, not version id
BE-2 gap surfaced by PPE E2E: +history-revert-status sent history_version_id,
but the facade-agg history_revert_status tool keys on transaction_id (the async
receipt returned by +history-revert), so it returned "[40400] transaction_id is
required". Give the status shortcut its own --transaction-id flag + input
(excel_id + transaction_id); revert keeps --history-version-id. Tests updated.
* fix(sheets): align history flag-defs with inline shortcuts (green TestFlagsFor)
TestFlagsFor_EveryRegisteredCommandHasDefs was RED: generated flag-defs drifted
from the hand-written history shortcuts.
- +history-revert-status: flag-defs had --history-version-id; the BE-2 fix switched
the shortcut to --transaction-id. Updated the entry to transaction-id.
- +history-revert / -status --history-version-id were marked required="required",
but the inline flags are cobra-optional (requiredness enforced in Validate).
Set required="optional" to match. Regenerated flag_defs_gen.go.
NOTE: canonical source is sheet-skill-spec (BE-3); apply the same change upstream
or the next sync:cli will regress this.
* chore(sheets): sync lark-sheets-history reference from spec (BE-2 transaction-id)
Mirror the upstream BE-2 fix in canonical-spec/references/lark_sheet_history/
cli-reference.md: +history-revert-status now uses --transaction-id (taken from
the async receipt returned by +history-revert), and +history-revert's
--history-version-id flips required→optional (Validate enforces requiredness
at runtime).
This file is the only history-only delta from the upstream sheet-skill-spec
sync; the rest of skills/lark-sheets/ stays on the cli's newer baseline
(/wiki/ URL support, +cells-set-image / +float-image-create, etc.) to match
commit 8ae516db's history-only mirror policy.
Spec source companion change: feat/sheet-history-revert in
ee/sheet-skill-spec, canonical-spec/{tool-shortcut-map.json,references/
lark_sheet_history/cli-reference.md}.
* feat(sheets): +history-list --end-version for backward pagination
Spec follow-up sheet-history-revert: thread the history_list pagination
contract through the +history-list shortcut.
- shortcuts/sheets/lark_sheet_history_list.go:
+ --end-version (int, optional). Mapped to the tool input's `end_version`
only when explicitly set (so the server treats absence as
"first page / latest"), via runtime.Changed / runtime.Int (matches the
+formula-verify --max-locations precedent).
+ Tip: pass next_end_version from the response on the next call;
capture exits the pagination loop when the server omits the field.
- shortcuts/sheets/lark_sheet_history_test.go: + dry-run case asserting
--end-version 12345 lands as input.end_version=12345 (post-JSON
unmarshal float64).
- skills/lark-sheets/references/lark-sheets-history.md: synced from
ee/sheet-skill-spec (commit 39c6b61). Adds the "倒序分页" caveat row +
--end-version flag + pagination Examples line. Drops the internal
MajorHistory.Version implementation detail per spec follow-up.
- shortcuts/sheets/data/flag-defs.json: synced from spec (+history-list
+--end-version int optional).
- shortcuts/sheets/flag_defs_gen.go: regenerated via
`go generate ./shortcuts/sheets/...`.
Companion changes:
- ee/sheet-skill-spec MR !37: spec-tables + tool-schemas pagination
contract (commits 09e8604, 39c6b61).
- ee/sheet-facade-agg MR !1028: history_list tool plumbs end_version,
emits next_end_version + has_more (omitted at earliest page),
defaults PageSize=20 to datarpc.
Validation:
- go build ./shortcuts/sheets/... PASS
- go test ./shortcuts/sheets/... PASS (sheets + backward)
- TestHistoryShortcuts_DryRun (5 cases incl. new --end-version case): PASS
- TestHistoryRevert_MissingRequiredFlag: PASS
- TestFlagsFor_EveryRegisteredCommandHasDefs: PASS
- TestFlagDefsGen_MatchesJSON: PASS
* fix(sheets): make +history-revert --history-version-id cobra-required + revert max-cells default drift
Two issues surfaced during MR !37 review:
1) +history-revert --history-version-id requiredness was set as
"optional" in the spec table (BE-2 fix dc5fe0ea) so cobra wouldn't
block before Validate. Per upstream review the flag should be
required-by-cobra so the user gets the standard "required flag(s)"
gate immediately and the runtime contract matches the JSON shape.
- shortcuts/sheets/lark_sheet_history_revert.go: historyVersionIDFlag
now sets Required: true. Validate keeps a trim/empty-string guard
so '--history-version-id ""' still fails as a typed
*errs.ValidationError (cobra accepts empty strings as "set").
- shortcuts/sheets/data/flag-defs.json: +history-revert
--history-version-id required: optional -> required.
- shortcuts/sheets/flag_defs_gen.go: regenerated.
- shortcuts/sheets/lark_sheet_history_test.go:
TestHistoryRevert_MissingRequiredFlag split into per-shortcut
subtests; +history-revert asserts cobra's "required flag(s)"
contract (raw err — the test rig calls cmd.Execute directly so it
doesn't see the cmd dispatcher's typed envelope wrap);
+history-revert-status keeps the typed *errs.ValidationError
contract (its --transaction-id stays cobra-optional + Validate-enforced).
2) max-cells safety cap was accidentally rewritten from 200000 to
50000 by the last sync from sheet-skill-spec (the spec canonical
side fell out of date — fixed separately on the spec MR follow-up).
Restore desc: "Safety cap; default 200000" / default: "200000" so
+cells-get / +csv-get keep the documented cap.
Validation:
- go test ./shortcuts/sheets/... PASS
- TestHistoryRevert_MissingRequiredFlag (both subtests) PASS
- TestHistoryShortcuts_DryRun (incl. +history-list pagination case) PASS
- TestFlagsFor_EveryRegisteredCommandHasDefs PASS
- TestFlagDefsGen_MatchesJSON PASS
* fix(sheets): make +history-revert-status --transaction-id cobra-required (match +history-revert)
Companion to commit 6ca35b06: same gating model now applies to both history
receipts.
- shortcuts/sheets/lark_sheet_history_revert.go: transactionIDFlag.Required=true.
Validate keeps a trim/empty-string guard for '--transaction-id ""'.
- shortcuts/sheets/data/flag-defs.json: +history-revert-status --transaction-id
required: optional -> required (synced from sheet-skill-spec @9ca814d).
- shortcuts/sheets/flag_defs_gen.go: regenerated.
- shortcuts/sheets/lark_sheet_history_test.go:
TestHistoryRevert_MissingRequiredFlag/+history-revert-status moved to the
cobra "required flag(s)" text contract (the test rig invokes the shortcut
via cmd.Execute, which sees the raw cobra error directly without the
dispatcher's typed wrap). Drop now-unused `errors` and `errs` imports.
Validation:
- go test ./shortcuts/sheets/... PASS (sheets + backward)
- TestFlagsFor_EveryRegisteredCommandHasDefs: PASS
- TestFlagDefsGen_MatchesJSON: PASS
- TestHistoryRevert_MissingRequiredFlag (both subtests): PASS
* docs(sheets): sync history skill reference required badges from spec
Companion to commit 9fa73312 (transaction-id) and 6ca35b06
(history-version-id): the two flag tables in
skills/lark-sheets/references/lark-sheets-history.md still showed
'optional' even though the canonical contract — and shortcuts/sheets/data/
flag-defs.json — already moved to 'required'. The earlier syncs only
picked up the data file from spec; the skill markdown drift slipped
through. Pull in the spec-side regenerated reference (ee/sheet-skill-spec
@9ca814d) so the human-readable doc matches the wire contract.
* fix(sheets): lower cells-set --max-cells default to 50000
* docs(sheets): clarify workbook-import over read-then-recreate in skill
* docs(sheets): bump lark-sheets skill version to 3.0.1
* docs(sheets): clarify number-vs-text typing and copy-to-range template guidance in references
* docs(sheets): type by data nature, add pre-write reference column and chart/cond-format/filter rows
- SKILL.md quick-reference: add a "read before acting" column pointing each
intent at its reference doc; add chart / cond-format / filter rows.
- Reframe number-vs-text decision to follow the data's nature (measure vs
identifier), not whether the current task happens to sort/sum; a
leaderboard/report "display only" use does not make a percentage text.
- write-cells reference: mirror the same rule and the +cells-set fallback
for layouts +table-put cannot express.
* docs(sheets): tighten number-vs-text guidance and dedupe write-cells reference
* Feat/lark sheets develop wzz (#1719)
* feat(sheets): add +changeset-get shortcut for changeset review
Wrap the get_changeset read tool: fetch the raw changeset (edit actions)
between two versions to review whether an AI edit fulfilled the request.
--start-revision required, --end-revision optional (defaults to latest),
gap capped at 100. Adds flag-defs entry + regenerated gen, the ChangesetGet
shortcut + tests, and skill docs.
* feat(sheets): add +get-revision shortcut
Return a spreadsheet's current document revision without pulling the full
sub-sheet listing. +get-revision is a read-only derivative over
get_workbook_structure (the lightest read — token only, no range) that
projects the response down to the single revision field.
Adds flag-defs entries and a unit test for the projection helper.
* feat: 同步 spec 修改
* feat(sheets): rename +get-revision to +revision-get
* feat: 移除 ppe 环境请求头
---------
Co-authored-by: wenzhuozhen <wenzhuozhen@bytedance.com>
* docs(sheets): dedupe +changeset-get flag def and skill reference entry
* feat(sheets): accept local_office_ token prefix for image parent_type
The synthetic token prefix for imported office spreadsheets is being
renamed from fake_office_ to local_office_. Accept either prefix when
mapping a spreadsheet token to the drive media parent_type so image
uploads keep working across the rename (main package and backward
compat copy).
* fix(sheets): replace undefined common.FlagErrorf with sheetsValidationForFlag
changesetRevisions called common.FlagErrorf, which does not exist,
breaking the build. Use sheetsValidationForFlag so the errors carry the
offending flag param like the rest of the sheets validation paths.
Also reword two doc comments in lark_sheet_history_revert.go that used
'' for an empty shell string: gofmt (Go 1.19+) rewrites '' in doc
comments to a curly quote, leaving the file permanently unformatted.
* fix(sheets): satisfy errs-no-bare-wrap forbidigo and errorlint rules from main
main introduced the errs-no-bare-wrap forbidigo rule and errorlint
coverage that flag 27 issues in existing sheets code after the merge:
- Replace direct *errs.ValidationError type assertions with errors.As
in sheetsInputStatError and validateSheetMediaUploadFile so wrapped
errors still match (errorlint).
- Type the embedded flag-schemas.json parse failure as an InternalError
with cause; it reaches the user directly via --print-schema.
- Annotate genuine intermediate errors (recursive schema validator,
batch sub-op raw type checks, A1 range/position parsers) with
//nolint:forbidigo; every caller wraps them into typed flag
validation errors.
* docs: tighten formula verify workflow guidance
* docs: align formula verify refs with file names
* feat(sheets): let typed writes style blank cells past the data extent
+workbook-create / +table-put apply cell_styles by writing them into the
in-memory matrix, whose size was fixed to the data (cols × rows). A style
range reaching past that extent was rejected as "outside the write range",
so blank cells (reserved regions, decorative headers, empty borders) could
not be styled on the typed --sheets path — only the untyped --values path
padded for it.
Pad the matrix down/right to cover every cell_styles range before applying
(empty cells appended for the uncovered positions), mirroring the --values
behavior. writeSheetData now derives the written width/range from the padded
matrix; both dry-run previews and sheetCreateDims account for the style
extent so the physical grid and the plan match Execute. Ranges above/left of
the write anchor stay rejected (the matrix only grows down/right).
* docs(sheets): warn that +csv-put silently coerces numeric-looking labels
Add guidance that +csv-put numericizes date-like/ID-like columns whose values are all digits (12.10 becomes 12.1 losing the trailing zero, 001 becomes 1 losing the leading zero); recommend +table-put with dtypes=object/datetime64 or +cells-set + number_format="@". Also fix the batch-update example to use sheet_name instead of sheet_id.
* docs(sheets): steer import-vs-append onto sheet-copy for existing workbooks
* docs(sheets): warn that cells-clear --scope all is irreversibly destructive
* docs(sheets): sync chart schema and labels guidance (#1716)
* chore(sheets): update chart flag schema
* docs(sheets): clarify chart labels field is presence-toggle, not value-toggle
Synced from sheet-skill-spec. Chart labels (plotArea.plot.labels and per-series
labels) are toggled by object existence — passing labels at all turns data
labels on, even when value/category/series/percentage are all false (server
falls back to showing value). Models repeatedly try `{ value: false, category:
false, series: false }` to disable, which silently shows the value fallback.
The reference doc now spells out both directions: pass labels to show, omit
the whole labels field to hide.
Also picks up earlier spec-side drift not yet propagated:
- pivot-table reference: +pivot-list info return + overlap validation
- flag-defs: cell-matrix fan-out cap default 200000 -> 50000 (#1578)
* feat(sheets): drop pre-refactor aliases from `sheets --help` listing
The refactored + commands have been the default for over a month. Hide the
deprecated pre-refactor aliases from `sheets --help` via a custom cobra
usage template that skips the deprecated group. Aliases stay registered
and executable: their own `sheets <alias> --help` still shows the
(→ +new-command) pointer, unknown-subcommand suggestions still span them,
and execution still returns the _notice.
* feat(sheets): let +csv-put fall back to piped stdin when --csv is omitted
Agents routinely redirect a CSV into stdin but forget the `--csv -`, so
`+csv-put ... < data.csv` failed its first try on a missing --csv and cost
an extra round-trip (error, then --help, then retry).
Relax --csv's cobra required-gate in the shortcut's PostMount and install a
PreRunE that defaults an omitted --csv to "-" when stdin is a non-interactive
pipe, so the standard stdin-resolution path reads it. The pipe guard keeps an
interactive terminal from blocking on stdin, and a genuine miss (no piped
data) still surfaces csvPutInput's typed "--csv is required" instead of
cobra's bare "required flag(s) ... not set".
Scoped entirely to the sheets domain — no changes to the shared runner or the
flag schema.
* feat(sheets): rework +rows-resize / +cols-resize to --height / --width
从上游 sheet-skill-spec 同步:+cols-resize 用 --width、+rows-resize 用 --height 直接给像素值,
--type 变为可选(省略等价于 pixel)。--type standard/auto 走非像素模式,不能与像素 flag 同传;
--type pixel 与 --width/--height 共存时视为等价形式。--size 已删除。
* docs(sheets): 更新 lark-sheets skill 版本至 3.0.2
将 SKILL.md 版本号从 3.0.1 升至 3.0.2,同步近期 sheets
命令改动(+rows-resize/+cols-resize 改 --height/--width、
+csv-put 支持 stdin 回退等)后的技能版本。
* feat(sheets): add --widths / --heights map form for per-column/row sizes
从上游 sheet-skill-spec 同步:+cols-resize --widths / +rows-resize --heights 接收
JSON map(键为单行列或闭区间,值为像素或 "standard"/"auto"),CLI 按起始位置排序后
展开为一次原子 batch_update 的多个 resize_range 操作,多列不同宽 / 多行不同高一次
调用完成,不再需要 +batch-update。map 形态与 --range/--width/--height/--type 互斥,
不可作为 +batch-update 子操作嵌入(batch_update 不支持嵌套)。列宽 < 20px 拒绝并提示
Excel 字符单位换算(px ≈ 字符数×8+16);--print-schema --flag-name widths/heights
可查 schema。
* fix(sheets): sync flag input/enum fixes from sheet-skill-spec
上游修复 spec-table 的 Input/Enum 字符串惯例后重新生成:--widths/--heights 现在带
file/stdin 输入声明,+sheet-create --type 的枚举正确进入 flag defs 与文档。
* feat(sheets): add sheets-scoped flag ergonomics via PostMount
Two recovery loops from the edit-eval traces burn agent round-trips:
hallucinated flag names (--cols for --range) whose unknown-flag error
only points at --help, and enum values imported from CSS/Excel
vocabulary ("center" for the vertical alignment Lark spells "middle").
- unknown-flag errors now inline the full valid-flag list (semantic
guesses aren't rankable by edit distance; kills the --help round trip)
- enum values with an unambiguous canonical form (casing, known alias)
are normalized in place and the call proceeds; edit-distance typos
stay errors with a did-you-mean hint and are never auto-applied
Both ride the existing PostMount composition (same pattern as
withTokenAlias), so the common framework is untouched and no other
domain's behavior shifts.
* feat(sheets): make validation errors prescriptive for hot failure modes
Driven by the edit-eval-extra-35Q reports: ~70% of lark-cli sheets
errors were missing-required / JSON-shape / wrong-value classes whose
messages said what broke but not how to fix it, pushing agents into
--help / --print-schema probe loops.
- composite JSON shape errors inline a compact skeleton auto-generated
from the schema (e.g. --cells -> [[{"value": ...}]]) when the type
mismatch is shallow container confusion
- +batch-update: missing 'shortcut' shows the entry template; a
disallowed shortcut inlines the full allow-list; exceeding the
100-op cap says how many batches to split into; sub-op translator
failures append the shortcut's complete input-key contract
- +table-put: dtypes/formats keys that miss every column call out the
A1-letter habit and inline the declared column names; empty cells in
a date-typed column name the three ways out
- schema enum errors suggest across casing, vocabulary aliases, and
edit distance
* fix(common): steer rejected @file paths to stdin instead of cd
The absolute-path rejection hint said "cd to the target directory
first" - advice the lark-sheets skill explicitly tells agents not to
follow (it pollutes the working directory). The stdin-contention hint
also demonstrated @file with an absolute path, which would itself be
rejected.
- @file failures on stdin-capable flags now show the equivalent stdin
invocation (--csv - < /tmp/x.csv)
- the path error recommends a relative path or stdin, not cd
- the stdin-contention example uses a relative @file path
Message-text only; no control-flow change for any domain.
* chore(sheets): suppress forbidigo on csv-put stdin pipe detection
os.Stdin.Stat is intentional here - pipe detection needs the real
process fd; IOStreams.In is a plain io.Reader without Stat. Clears the
lint failure left by the stdin-fallback commit.
* fix(sheets): pass spreadsheet token to changeset tool (#1839)
* fix(sheets): hide bitable sheet creation (#1843)
* fix(sheets): resolve revision wiki URLs
* fix(sheets): reject overlapping resize ranges
* fix(sheets): address remaining review feedback
* fix(sheets): avoid credential scanner false positive
* fix(sheets): import mislabeled .xls workbooks by sniffing content
Local .xls files that are actually OOXML (an .xlsx exported or renamed to
.xls) failed +workbook-import with a cryptic backend
"xml_version_not_support" because the CLI trusted the file name extension.
+workbook-import now sniffs the file's leading magic bytes (PK -> xlsx,
OLE2 -> xls) and passes the true extension to the drive import core via a
new optional ImportParams.FileExtension override, correcting both the
file_extension and the staged media file name (the latter avoids the
backend's "import file extension not match", code 1069910). A declared
Excel file whose bytes match neither container is rejected locally with a
prescriptive error instead of the opaque backend failure.
The drive import core gains only the neutral FileExtension override
(empty = infer from the file name, i.e. unchanged behavior for
drive +import); all Excel sniffing/correction policy lives in the sheets
shortcut.
* fix(ci): keep semantic waiver fixture active
* fix(sheets): close remaining safety gaps
* fix(sheets): align history shortcuts with generated flags
Use generated flag defs for history revert commands, enforce control-character validation, and sync the refreshed lark-sheets references from sheet-skill-spec.
* fix(sheets): require confirmation for history revert
* fix(sheets): require explicit csv input
---------
Co-authored-by: xiongyuanwen-byted <xiongyuanwen@bytedance.com>
Co-authored-by: wuyanchun.anunwu <wuyanchun.anunwu@bytedance.com>
Co-authored-by: wenzhuozhen <wenzhuozhen@bytedance.com>
This PR improves the im.message.receive_v1 event output by exposing structural
metadata fields (reply context, sender type, mentions) that were previously only
available in the raw V2 envelope. It also syncs the same structural fields to the legacy
+subscribe --compact pipeline.
Previously, keys longer than the OpenAPI uuid limit were sent to the server and returned a generic field validation failed error. This change rejects overlong keys locally with a typed validation error that identifies
--idempotency-key and the 50-character limit.
Read the server-provided sender_name for both user and bot senders (previously
only users resolved) so message-read commands display bot names instead of raw
ids. The CLI opts into server-side name filling by sending with_sender_name=true
on chat-messages-list, threads-messages-list, messages-mget and messages-search,
as well as on the inline fetches that render nested senders: merge_forward
sub-messages and auto-expanded thread replies. Without it those nested-only
senders carry no sender_name and, with no fallback, render as raw ids.
Names come solely from the server (single source of truth): there is no contact
or mention fallback, so the contact scope is dropped from these four commands and
the contact/mention resolution code is removed. A sender the server does not name
falls back to its id; system messages show no name. The resolved name is exposed
in the existing `name` field (backward compatible); the duplicate raw
`sender_name` is stripped while the full `sender_i18n_names` map and `open_bot_id`
are preserved for consumers. No new permission scope is required. Updates the
lark-im skill docs.
* feat(apps): read LARKSUITE_CLI_AGENT env var and pass app_source in +create
* feat(apps): add queryAppMeta shared function for app_type/arch_type lookup
* feat(apps): skip scaffold for legacy html apps, pass app_type/arch_type for arch_type=4 html in +init
* feat(apps): add zip packaging for arch_type=4 html publish path
* feat(apps): add TOS upload path for arch_type=4 html in +html-publish with arch_type-based routing
* refactor(apps): replace appMeta struct with queryAppType string for simpler routing
* refactor(apps): simplify to source_agent in +create, unified scaffold in +init, revert html-publish changes
* feat(apps): add --source-path flag to +init for existing source file incorporation
* fix(apps): align queryAppType with actual API path and response structure
* refactor(apps): use appInfo struct to parse GET /apps/{id} response
* test(apps): add full_stack scaffold test case
* feat(apps): surface sync field in +release-create response
* refactor(apps): remove --template flag from +init, derive template from queryAppType with full_stack fallback
* style(apps): fix gofmt formatting in apps_init.go
* test(apps): improve coverage for sync field, queryAppType, and scaffoldInitArgs
* chore(apps): pin miaoda-cli to alpha version 0.1.20-alpha.dd573f8
* feat(apps): add modern_html enum and pass --app-type instead of --template to miaoda-cli
* chore: add global PPE headers for testing (x-use-ppe, x-tt-env)
* feat(apps): add TOS upload path in +html-publish for modern_html, add --tos-path to +release-create
* feat(apps): unify html-publish output structure with app_id for both html and modern_html
* fix(apps): use newFileTransferClient for TOS presigned upload to satisfy forbidigo lint
* test(apps): add coverage for runHTMLPublishTOS success, errors, and upload failures
* fix(apps): change pre_release API method from POST to GET
* fix(apps): adapt pre_release response from map to list<KV> format
* fix(apps): use PUT method and Content-Length for TOS presigned upload
* fix(apps): use tos_path instead of tosPath in release-create request body
* chore(apps): add npmmirror registry for npx miaoda-cli, fix TOS upload test to expect PUT
* refactor(apps): use envvars.AgentName() for source_agent in +create
* feat(apps): integrate release-create into html-publish for modern_html, auto-detect modern_html from doubao agent env
* refactor(apps): remove --tos-path flag from +release-create (now internal to html-publish)
* refactor(apps): remove app_id from html-publish output, update skill doc
* docs(apps): update html-publish description to reflect dual return values
* refactor(apps): remove doubao app_type conversion in +create, let server decide via source_agent
* feat(apps): skip env-pull for modern_html apps in +init
* test(apps): add tests for modern_html env-pull skip in +init
* refactor(apps): introduce appTypePolicy for init control points (skipInstall, skipEnvPull, skipSkillsSync)
* feat(apps): add init step timing and default git config for +init
* feat(apps): add +get shortcut to fetch single app detail by app_id
* chore(apps): remove init step timing (not ready for production)
* test(apps): add coverage for +get shortcut
* chore: remove PPE headers and revert miaoda-cli to @latest for production
* refactor(apps): extract shared prepareHTMLPublishTarball, fix stale comments, simplify queryAppType
* fix(apps): update html-publish dry-run desc, remove hardcoded API path
* fix(apps): use rctx.IO().ErrOut instead of os.Stderr, remove unused appInfo struct
* fix(apps): restore dry-run API path output for E2E compatibility
* refactor(apps): move --source-path control char validation to Validate for dry-run coverage
* fix(apps): update stale --template comments to --app-type in init tests
* test(apps): explicitly unset agent env var for test isolation
* fix: decouple --json shorthand registration from default format injection
* fix: fold --json shorthand into format flag before consumption
* fix: enable --json shorthand for mail +triage and mail +watch
* fix: enable --json shorthand for base +record-list
* docs: document --json shorthand for triage, watch and record-list
* docs: clarify record-list JSON output for script consumption
* docs: guide agents to JSON output for machine consumption scenarios
* test: make test comments self-contained
* test: assert typed error metadata in enum validation test
* docs: correct mail +watch --format default and enum in skill doc
* docs: keep --json shorthand undocumented as a silent fallback
* chore: bump oapi-sdk-go/v3 to v3.7.2 for filename-aware multipart upload
* fix: preserve original filename in multipart file upload
BuildFormdata read local files into a bytes.Reader before handing them
to the SDK, so the SDK's part-filename detection (which only reads
*os.File) fell back to "unknown-file" for every local --file upload.
Use AddFileWithName with the file's basename instead.
Refine `vc +meeting-events` around a stable agent-facing output contract.
The command now exposes structured meeting metadata, current read identity, normalized event rows, warnings, and pagination fields across JSON/NDJSON/pretty output. Event rows include stable event identifiers, event time, actors, and event-specific payloads for participant, chat/reaction, transcript, and magic-share events.
Improve meeting status inference by treating participant-left events with meeting-ended leave reasons as an ended signal, and keep compatibility with payload-only event shapes by falling back to `payload.activity_event_type`.
Update `lark-vc-agent` guidance for forwarding meeting chat and reactions to IM. Agents should build Feishu post content from JSON events, emit IM `emotion` nodes only for whitelisted reaction keys, and fall back unsupported reaction keys to text.
Add focused unit and dry-run E2E coverage for the event-type fallback and `vc +meeting-events --dry-run` request shape.
* fix(apps): make db --environment optional, auto-select branch server-side
All db shortcuts defaulted --environment to "dev", which forced single-env
apps (whose DB lives on the online branch, with no dev branch) to fail with
"Invalid DB Branch: dev" unless the user explicitly passed --environment
online.
Change the default to empty: when --environment is omitted the CLI sends no
env, letting the server pick the branch by the app's multi-env state
(multi-env → dev, single-env → online), matching miaoda-cli's behavior of
not carrying dbBranch when unset. Explicit --environment dev|online is
unchanged; explicit dev on a single-env app still errors as expected.
- 10 db shortcuts: dbEnvFlags default "dev" → "" (+db-execute, +db-table-list,
+db-table-get, +db-quota-get, +db-data-export, +db-data-import,
+db-changelog-list, +db-audit-list/-set/-status)
- dry-run e2e assertions updated: default env is now unset, not "dev"
- skill docs (lark-apps-db, lark-apps-db-execute) describe the auto-select
* fix(apps): omit empty --environment param; refine dry-run tests and skill doc
Address PR #1735 review:
- omit-empty: when --environment is unset, drop the env query key entirely
instead of sending env="" — matches the family's omit-empty convention
(cf. page_token) and miaoda-cli's "no dbBranch when unset". Add dbEnvParams
helper; apply across all db shortcuts (execute, table-list/-get, quota-get,
changelog-list, audit-list/-set/-status, data-export/-import) plus the
export/import query params, queryExportTotal and audit-list table/status probes.
- e2e dry-run assertions pin env is omitted via .Exists() (was Equal "").
- skill doc (lark-apps-db): rewrite the --environment guidance from an agent's
decision POV — read vs write, single-env writes hit online prod, explicit dev
on single-env as a probe; drop redundant/changelog phrasing.
* fix(apps): db recovery --environment support + diff/migrate display fixes
- +db-recovery-diff/-apply: add --environment (env → query param on submit
and both status polls), aligned with the recovery env IDL
- recovery diff: parse string row counts (inserted/deleted arrive as strings)
so they render as "-N rows" instead of "no changes"; drop the redundant
per-table data-row line when a schema action (drop/restore/alter) exists for
the same table; count tables_affected by distinct tables
- +db-env-migrate: run a dry_run preview before apply to backfill the change
count when the server reports changes_applied=0 on a cold apply (matches
miaoda-cli's diff-then-apply)
- lark-apps-db.md: drop the redundant recovery clause (recovery follows the
standard --environment rule)
* test(apps): cover no-env dry-run defaults + numericAsFloat string path
Address CodeRabbit review threads on PR #1735:
- numericAsFloat: add numeric-string cases ("13.5", " 13.5 ", int, empty)
- db-data-import: assert dry-run omits env when --environment unset (table
still defaults to file basename)
- db-quota-get: assert dry-run omits env when --environment unset
feat: remove reference lark-sharded skill
docs: clarify calendar write feedback
docs: split calendar scheduling workflow
docs: tighten calendar skill references
docs: annotate +freebusy scope to avoid unnecessary reads in scheduling flow
When users express "find free time + create event" intent, AI would
previously read freebusy.md before entering the scheduling workflow.
Adding a scope note to the shortcut table directs AI to use +suggestion
instead, reducing token consumption.
feat: support calendar +get
fix: optimize calendar skill
fix: optimize shortcuts and meta api
fix: optimize skill
Co-authored-by: calendar-assistant <tangfengyuan@bytedance.com>
* fix(schema): fall back to runtime catalog when no embedded metadata
Binaries built from the bare Go module (plugin builds) embed only the
empty meta_data_default.json stub because meta_data.json is gitignored
and fetched at build time. The schema command, its completion, and the
affordance command-form resolver read the embedded-only catalog, so
every schema lookup failed with "Unknown service" even though the
runtime registry had already sync-fetched full metadata.
Add registry.SchemaCatalog(): embedded when compiled in (official
builds unchanged, still deterministic), otherwise the merged runtime
catalog seeded from cache or remote fetch. When neither source has
data (offline plugin build with a cold cache), schema now returns a
failed_precondition error with an actionable hint instead of
"Unknown service" with an empty candidate list.
* fix(registry): gate cached meta overlay on version newer than embedded
The cached remote meta was overlaid onto the embedded meta_data.json
unconditionally, so after a CLI upgrade an equal- or older-version
cache kept shadowing the freshly shipped embedded definitions until a
later refresh happened to rewrite it.
Only overlay when the cache version is strictly newer than the
embedded baseline. The bare-module stub baseline is "0.0.0", so plugin
builds without compiled metadata still take any real cached version
(TestOverlayGate_StubEmbedded_OverlaysRealCache) and the schema
runtime fallback keeps working offline from a warm cache.
Ports #1376 onto the typed meta model.
---------
Co-authored-by: liangshuo-1 <266696938+liangshuo-1@users.noreply.github.com>
* feat(envvars): add LARKSUITE_CLI_AGENT_NAME accessor
envvars.AgentName() reads LARKSUITE_CLI_AGENT_NAME so business code can identify the agent driving the CLI. Value is sanitised (trim, reject control chars, 128-byte cap) and returns "" when unset or invalid. Local-only; not sent to the server.
* refactor(envvars): consolidate agent env accessors, dedupe sanitize
Move agent-trace reading from cmdutil.AgentTraceValue into envvars.AgentTrace(), symmetric with AgentName and sharing one sanitizeSingleLine. secheader.go now only assembles headers (BaseSecurityHeaders calls envvars.AgentTrace()); the duplicated sanitize and its os/unicode imports are gone. The X-Agent-Trace header and its behaviour are unchanged.
---------
Co-authored-by: liangshuo-1 <266696938+liangshuo-1@users.noreply.github.com>
The stdout success envelope is {ok, identity, data, meta?} and carries no
top-level code/msg field, but wrappers following the raw OpenAPI convention
test code == 0 and misclassify every successful call as a failure. Around
write commands this defeats caller-side idempotency and causes duplicate
creates (see #1689).
Document the contract in ERROR_CONTRACT.md (success-envelope counterpart to
the error wire format), both READMEs (JSON Output Contract section), the
lark-shared skill (shared prerequisite for all skills), and add a success
response example to lark-task-create.md.
Closes#1689
Add docs +history-list, +history-revert, and +history-revert-status backed by docs_ai history OpenAPI endpoints.
Document the safe history workflow and extend dry-run/live E2E coverage for the new shortcuts.