mirror of
https://github.com/larksuite/cli.git
synced 2026-09-14 18:42:53 +08:00
docs/fix-task-shared-paths
7 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
62be9cf20e |
feat(sheets): add +cond-format-result-get and --include conditional_format (#2502)
* feat(sheets): add +cond-format-result-get shortcut and --conditional-format flag - lark_sheet_read_data.go: add CondFormatResultGet shortcut with include_conditional_format_style hardcoded to true - cellsGetInput(): add --conditional-format flag mapping - shortcuts.go: register CondFormatResultGet alongside existing cond-format shortcuts - lark_sheet_read_data_test.go: add dry-run test cases covering new shortcut and --conditional-format - flag-defs.json / flag_defs_gen.go: sync from sheet-skill-spec * fix(sheets): fold conditional format into include flag * refactor(sheets): isolate conditional format result output * fix(sheets): satisfy nested slice lint |
||
|
|
5f35c72bd3 |
feat(sheets): combine chart workflows and special chart types (#2374)
* feat(sheets): support partial chart snapshot schemas * feat(sheets): add semantic chart shortcuts * feat(sheets): improve semantic chart workflows * fix(sheets): prefer semantic chart shortcuts * fix(sheets): normalize chart range and flag inputs * fix(sheets): normalize irregular chart ranges * feat(sheets): add chart data update shortcut * feat(sheets): harden chart update workflows * feat(sheets): improve chart creation dimension handling * feat(sheets): add dedicated chart batch shortcuts * fix(sheets): allow chart color theme patches * fix(sheets): persist chart color theme updates * feat(sheets): simplify batch chart operations * fix(sheets): preserve batch scope and cross-sheet chart ranges * feat(sheets): support bubble waterfall and pareto charts * fix(sheets): sync special chart tool schema * feat(sheets): add semantic bubble chart indexes * docs(sheets): sync combined chart workflow guidance * fix(sheets): align combined chart artifacts * feat(sheets): add x-axis number interpretation flag * docs(sheets): validate chart axis semantics * fix(sheets): allow recursive chart update patches * test(sheets): isolate chart create schema check * feat(sheets): refine semantic chart creation * docs(sheets): sync semantic chart guidance * docs(sheets): remove unrelated label position guidance * fix(sheets): support all chart data label combinations * fix(sheets): support numeric x-axis bounds * feat(sheets): support chart y-axis bounds * feat(sheets): add last-point chart label flag * fix(sheets): preserve disabled waterfall stacking * fix(sheets): nest last-point chart label property * fix(sheets): resolve lint and dead-code CI failures - lark_sheet_chart.go: drop redundant chartConfigUpdateInput / chartDataUpdateInput calls in Execute whose result is immediately overwritten by the *FromSnapshot variant (ineffassign); the snapshot variants already re-run the same validation internally. - lark_sheet_chart_test.go: remove Go 1.22+ redundant loop-variable copies (copyloopvar). - batch_op_dispatch.go / lark_sheet_batch_update.go: remove unreachable allowedBatchShortcuts and batchUpdateInput; callers use the lower-level allowedShortcuts and buildBatchUpdatePlan directly. * fix(sheets): validate chart config updates * fix(sheets): sync skill specs and chart schema validation * fix(sheets): resolve chart review follow-ups * fix(sheets): restore the two-color contract * fix(sheets): require at least two chart colors * docs(sheets): expose advanced chart shortcut flags * fix(sheets): address chart review feedback * fix(sheets): surface ignored batch locators * chore(sheets): bump skill version to 3.1.6 * fix(sheets): surface batch warnings consistently * test(sheets): satisfy copyloopvar lint * docs(sheets): sync skill from spec * fix(sheets): harden chart batch updates * fix(sheets): tighten chart update validation * fix(sheets): canonicalize chart ranges and batch targets |
||
|
|
be2a96f490 |
feat(sheets): harden error prescriptions, batch updates, and read workflows
Aggregate the sheets work from feat/lark-sheets-develop: - Improve validation errors with schema hints, aggregated issues, enum guidance, and prescriptive flag/style-field messages. - Harden +batch-update input contracts, key normalization, style vocabulary handling, and resource-budget checks. - Add read offload and truncation handling for cells, csv, and table-get, with typed output-path errors and safer jq/output-path semantics. - Correct freeze semantics by emitting full-state freeze/unfreeze operations and adding --rows/--cols for +dim-freeze. - Improve +styles-put and shared --styles parsing for styles, merges, row/column sizing, freeze, and sheet-prefixed range validation. - Fix dim-insert inherit-style mapping, table-get date/time handling, table-put style anchors, and CSV path-shaped input guards. - Update lark-sheets skill docs, scripts, tests, and generated flag data. Tested with: - go test ./shortcuts/common ./shortcuts/sheets/... - go test ./shortcuts/... ./internal/... - python3 -m py_compile skills/lark-sheets/scripts/*.py |
||
|
|
e79d49e7e4 |
Merge lark sheets development branch (#1833)
* 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> |
||
|
|
bd898a1d74 |
feat(sheets): typed table I/O & error contract, workbook import/export, skill refresh (#1355)
* feat(sheets): add +sheet-show-gridline / +sheet-hide-gridline shortcuts
* docs(sheets): strengthen lark-sheets references for common editing pitfalls
Add targeted guidance to six lark-sheets references to reduce frequent
mistakes when editing spreadsheets through the CLI:
- write-cells: sanity-check units / dimension conversion / quantity factors
before formula writes (formulas can run clean yet be off by a factor);
keep derived output off original data columns to avoid clobbering source
- core-operations: prefer live formulas for derived values even when "live
update" is not explicitly requested; scope rewrite/transform precisely so
rows/columns that should stay unchanged are kept 1:1; treat header-stated
format rules as checklist items; confirm the artifact file actually exists
before finishing; write back bare values from local scripts
- visual-standards: apply border/header formatting on explicit request and
identify the real header row; keep font size consistent with the source
- range-operations: keep total column width within A4 for printing
- read-data: dedup/compare long numbers via raw values, not csv formatted
display (scientific notation collapses distinct numbers and causes false
duplicates)
- chart: format date/number axes via source-cell number_format; place charts
outside the data area so they do not cover existing data
* feat(sheets): implement table-put/table-get and sync skill specs
- Add lark_sheet_table_io.go with +table-put / +table-get and tests
- Refactor read-data; extend workbook; register new shortcuts
- Sync generated flag defs/schemas (go:embed) from sheet-skill-spec
- Sync skill references (write-cells numeric-column guidance, plus
read-data / workbook / chart updates)
* docs(sheets): surface typed-write path at the write-decision point
Quick-ref table (SKILL.md, the first decision point) had no +table-put and
gated typed writes on "DataFrame", so a model holding a Counter/list/dict
would fall back to +csv-put and silently lose number/date fidelity.
- split csv-put row to plain-text values (no numeric/date semantics)
- add +table-put row for typed writes into an existing sheet
- add +workbook-create --sheets row for create + typed write in one shot
- add judgment note: number/amount/date/percent/count -> +table-put
(or +workbook-create --sheets when the workbook does not exist yet);
plain text -> +csv-put
- reframe write-cells scenario row to lead with numeric semantics
- point new-table writes at +workbook-create --sheets (one shot) instead
of the create-empty-then-table-put two-step
Synced from sheet-skill-spec canonical (generate:cli + sync:cli).
* docs(sheets): sync SKILL.md (drop "not for local Excel" caveat)
Mirror the upstream sheet-skill-spec change removing the "not applicable to local Excel files" tail from the sheets skill and reference descriptions.
* docs(sheets): sync SKILL.md (drop "Feishu sheets only" caveat)
Mirror the upstream sheet-skill-spec change removing the "applies to Feishu sheets only" tail from the 14 sheet reference descriptions.
* feat(sheets): add +workbook-import wrapping the drive import core
Import a local xlsx/xls/csv as a new spreadsheet by delegating to the shared drive import flow with the target type pinned to sheet. Refactor drive +import to expose ImportParams / ValidateImport / PlanImportDryRun / RunImport (behavior unchanged, existing drive tests still cover it); sheets reuses them. Regenerate flag_defs_gen.go and sync the spec mirror.
* refactor(sheets): reuse the drive export core in +workbook-export
Replace +workbook-export's parallel export-task implementation with the shared drive ExportParams/RunExport core (pinned to type=sheet). Drops ~90 lines of duplicated poll/download code; +workbook-export now inherits drive's ctx cancellation, resume-on-timeout, filename sanitize/overwrite, and the full set of export status labels. The output contract aligns with drive's (adds ready/downloaded/doc_type; saved_path preserved). Also normalize an empty drive --output-dir to "." so drive +export behavior is unchanged, and fix the sheets export e2e to call +workbook-export instead of a nonexistent +export.
* docs(sheets): keep original column widths; align chart axis with requested metric
- range-operations: only widen new / overflowing columns; never recompute or
shrink the widths of existing columns (any blanket resize, even by 1px,
breaks the original visual format)
- chart: when the user asks for a share / percentage, the value axis should be
a percentage (pie, or stack.percentage on bar/column) rather than raw counts
* docs(sheets): reword guidance to avoid eval-specific phrasing
Replace scoring-framework wording in the examples with plain functional
consequences (e.g. "not delivered", "goes stale when the source changes",
"breaks the original visual format"), so the references stay agent-facing.
* docs: add lark sheets financial modeling guidance
* docs(sheets): align write-cells reference with the generated output
Bring the hand-applied write-cells example in line with the spec-generated
reference so the CLI mirror is byte-identical to the canonical source.
* docs(sheets): align +csv-put help with formula support
Sync the formula-support wording from sheet-skill-spec (flag-defs, skill
references) and update the hand-authored cobra Description and comment for
+csv-put. +csv-put evaluates a leading-= cell as a formula via
set_range_from_csv; descriptions only, no behavior change.
* docs(sheets): fix invalid +dim-insert example in chart reference
The chart reference's placement example used non-existent flags
--dimension/--start/--end for +dim-insert. The real signature is
--position (required) + --count (required); copying the example
fails Validate with "--position is required". Replace it with
+dim-insert --position V --count 6 (insert 6 columns before V,
i.e. after U), aligning with the sheet-structure reference.
* docs(sheets): chart coordinate base / quoting + filter condition enums
Sync three reference-doc corrections from the spec source:
1. chart: label position.row as 0-based (first row = row:0), distinct
from the 1-based row numbers used by A1 ranges and +dim-insert
--position, removing the row-base ambiguity.
2. chart: convert the three runnable examples whose JSON contains a
quoted sheet prefix ('Sheet1'!A1) from inline single-quoted
--properties '{...}' to a stdin heredoc (--properties - <<'JSON').
Inside an inline single-quoted string bash strips the inner quotes
around the sheet name (and splits names with spaces into words),
corrupting the JSON; a quoted heredoc delimiter performs no shell
substitution and preserves it. Adds a short note on the pitfall.
3. filter / filter-view: add the full conditions[].type x compare_type
enum table (text / number / multiValue / color and their respective
compare_type values and values shape), and call out the
equals/notEquals (with s) vs equal/notEqual (no s) gotcha. The docs
previously only showed two values via examples.
* docs(sheets): label +sheet-create --index as 0-based
The base flag description for +sheet-create's --index omitted the
coordinate base, while its siblings +sheet-move ("Target position
(0-based)") and +sheet-copy already state 0-based. Align the description
so the index base is unambiguous. Synced from the spec source
(flag-defs.json + workbook reference).
* fix(sheets): regenerate flag defs and fix asasalint in table io
* feat(sheets): add counta to chart aggregateType enum
Add `counta` (count non-empty cells, incl. text) to manage_chart_object
dim2.series[].aggregateType in the chart flag schema. `count` only counts
numeric cells, so counting occurrences of a text/category column renders an
empty chart; `counta` enables category frequency counts. Synced from the
sheet-skill-spec canonical schema.
* feat(sheets): make --target-position and --range mutually exclusive on +pivot-create
Both flags map to the same wire field (properties.range), so passing
non-default values for both is ambiguous. Mirror the
--target-sheet-id / --target-sheet-name mutex pattern: --target-position
takes priority over --range, and supplying both with non-default values
is rejected up front with a typed FlagErrorf. --target-position=A1 is
the documented default and is treated as "not set".
Add a symmetric validateCreateInput hook on objectCRUDSpec (alongside
the existing validateUpdateInput), wire it into objectCreateInput, and
inject the pivot-specific check on pivotSpec.
* feat(sheets): rework +workbook-create flags and --styles
- --values builds a type-less typed payload, writing through --sheets' batched set_cell_range path (raw passthrough preserves auto-detect; large tables batch; big ints via json.Number)
- drop --headers (subsumed by --values first row) and --header-style (typed header no longer auto-bold; use --styles instead)
- styles: deep-merge overlapping cell_styles/border_styles fields (was wholesale-replace which dropped fields); add manual border_styles validation (style/weight enums + sides) since --styles is on parseJSONFlagSkip and bypasses the schema validator
- regenerate flag-defs/flag-schemas/skills mirror from sheet-skill-spec (--styles flag + full per-side border schema)
* fix(sheets): add mention_type enum to set_cell_range cells schema
Constrain rich_text mention_type to the proto MENTION_FILE_TYPE set so a
file @mention with an out-of-enum value (e.g. 6 = cloud shared folder) is
rejected by the schema validator before it reaches the server and fails
pb serialization ("mentionFileInfo.fileType: enum value expected").
- data/flag-schemas.json: mention_type gains enum + per-value description
- lark_sheet_write_cells_test.go: cover reject (6) + allow (0 / 2 / 22)
* feat(sheets): implement pandas-split --sheets protocol for +table-put/+table-get/+workbook-create
Synced from sheet-skill-spec canonical (cli:table_put schema +
references). +table-put/+workbook-create accept the new shape via a
tableSheetIn -> tableSheetSpec normalize step (dtype string -> internal
type/format mapping). +table-get emits the same shape so the writer's
df_to_sheet and the reader's sheet_to_df round-trip cleanly.
isoDateToSerial now accepts the full ISO datetime form
(2024-01-15T00:00:00.000, including timezone suffixes) emitted by
df.to_json(date_format="iso"), not just yyyy-mm-dd. End-to-end verified
by the spec repo's contracts/python_helper_roundtrip script against a
real Lark spreadsheet on pandas 2.2 and 3.0.
* feat(sheets): add --dataframe Arrow IPC input for +table-put/+table-get/+workbook-create
Introduce a binary-typed twin of --sheets: --dataframe accepts an Arrow IPC
(Feather v2) payload that pandas' df.to_feather() writes, deriving dtypes and
per-column number formats from the Arrow schema. The two producers are mutually
exclusive and funnel through a shared resolver so +table-put and
+workbook-create stay in lockstep; +table-get gains --dataframe-out for
single-sheet reads. Also auto-grow a sub-sheet's row/column count before
writing so blocks past the backend's default 200x20 bounds no longer fail with
range-exceeds-sheet-bounds.
* docs(lark-sheets): remove financial modeling standards reference
Drop the lark-sheets-financial-modeling-standards.md reference doc and all
pointers to it from SKILL.md, core-operations, and visual-standards. Bump
skill version to 3.0.0.
* docs(lark-sheets): clarify cell-image vs float-image routing and fix reference self-references
Synced from sheet-skill-spec.
- Add a binding-based decision (does the image belong to a record and move with its row?) to route +cells-set-image vs +float-image-create across the SKILL entry, float-image and write-cells references.
- Add routing rows to the SKILL command cheat-sheet and warn against defaulting to float-image out of familiarity.
- Replace mislabeled 本 skill / 子 skill / 跨 skill wording in references with 本文 / reference names, matching the existing convention.
* feat(sheets): add --styles to +table-put for one-step typed write with styling
+table-put now accepts --styles (same shape as +workbook-create's --styles):
cell_styles merge into the set_cell_range matrix, while cell_merges /
row_sizes / col_sizes apply as their own tool calls after the write. The
styles payload is name-matched against the written sheets and validated up
front, so a malformed or mismatched style fails before any write lands.
Also points +sheet-create users to +table-put (auto-creates missing sheets)
when they need data/styles, via a runtime Tip and the lark-sheets skill
references. Flag is sourced from the upstream Base table and regenerated
through sheet-skill-spec (flag-defs.json / flag-schemas.json / gen file).
Adds unit tests (dry-run styles, name-mismatch reject, execute) and a
dry-run E2E (tests/cli_e2e/sheets/sheets_table_put_dryrun_test.go).
* docs(lark-sheets): point read-data to +sheet-info for hidden row/col identification
skip-hidden defaults to false (lossless reads), but the read primitives don't mark which rows/cols are hidden. Cross-reference +sheet-info --include hidden_rows,hidden_cols + row_indices/col_indices so agents can identify hidden ranges when they need to filter or interpret hidden data.
Synced from sheet-skill-spec.
* feat(sheets): document link requirement for @document mentions in cells flag schema
@document mentions (mention_type != 0) must pass link (doc URL) to render a
clickable card; @user mentions (mention_type=0) don't need it. Synced from the
upstream tools-schema.
* fix(sheets): reject cond-format attrs whose shape mismatches rule_type
A conditional-format rule created with --rule-type colorScale but
cellIs-shaped attrs ({compare_type,value}, no color) was accepted by
the CLI and written through to the server, producing a color-less
color-scale segment. That dirty data crashes the frontend on snapshot
deserialization, so the spreadsheet can no longer be opened (5005).
The per-entry schema check can't catch this: properties.attrs.items is
a oneOf over all nine attr shapes and passes as soon as any branch
matches, blind to the sibling rule_type — {compare_type,value} matches
the cellIs branch even when rule_type says colorScale. The tool side
maps attrs blindly by rule_type and only validates dataBar count and
iconSet ordering, so the gap reaches the data layer.
Add a cross-field validator (validateCondFormatAttrs) wired into both
create and update via the new objectCRUDSpec.validateCreateInput hook
(twin of validateUpdateInput). It enforces, per rule_type, the keys
every attrs entry must carry — mirroring the tool's converter contract
— and treats an empty required string (notably color) as missing.
Rule types that take no attrs (duplicateValues / uniqueValues /
containsBlanks / notContainsBlanks) and updates that omit rule_type are
left to the server.
* test(sheets): guard condFormatAttrsRequired against flag-schemas drift
Add TestCondFormatAttrsRequired_MatchesSchemaOneOf, comparing the
hand-maintained condFormatAttrsRequired table against the embedded
flag-schemas.json attrs oneOf (multiset of required-key sets, for both
create and update). The cross-field validator only holds if its
per-rule_type required keys mirror the schema branches, and the two
share no compile-time link — this pins them together so a future schema
sync that adds/drops a required key can't silently desync the table.
* fix(sheets): default +table-get to full used range, not A1 current region
+table-get without --range anchored its current_region probe at A1, so an
internal blank row or column silently truncated everything past it — agents
then treated the partial data as complete (the pro016 / pro025 incident).
- Probe the used range over the full physical grid (row_count × column_count
from the workbook structure) so it spans internal blank rows/columns; fall
back to the legacy A1 anchor when dimensions are unknown.
- Emit the actually-read `range` on every sheet so callers can detect
truncation (get_cell_ranges has no has_more flag).
- Fix the same A1-anchor bug in append mode's last-data-row probe, which could
otherwise overwrite data past an internal blank row.
- Add unit + dry-run/live E2E coverage; refresh synced skill docs.
* docs(sheets): fix csv-get current_region guidance to cross-check row_count
current_region is a blank-row/column-bounded block, not the true sheet extent:
an internal blank row truncates it, so it can miss rows past the gap. The
read-data reference previously called it the "真实数据边界" and told agents to
prefer it over row_count — which drove the "read only to current_region's last
row, miss the tail" failure.
- current_region: warn it can be both smaller (internal blank rows truncate)
and larger (trailing summary/signature rows) than the real data range.
- csv-get output contract: clarify its row_count/col_count is the returned size
(= actual_range), not the physical sheet size; has_more only reflects the
current range, not whether the whole sheet was read.
- "确定数据范围的正确流程": add a step to cross-check against +workbook-info's
physical row_count and probe past current_region's last row for data beyond an
internal blank row.
* fix(sheets): collapse duplicate validateCreateInput from bad merge resolution
A prior merge kept both branches' independently-added validateCreateInput
fields on objectCRUDSpec with conflicting signatures (pivot's
func(rt, input) and cond-format's func(input)), plus both call sites in
objectCreateInput, which failed to compile (validateCreateInput redeclared).
Collapse to the single richer func(rt flagView, input) signature and one
call site. cond-format's validateCondFormatAttrs (func(input), still shared
with validateUpdateInput) is wrapped in a closure that ignores rt. Both
behaviors are preserved: pivot --target-position/--range mutex and
cond-format attrs-shape-vs-rule_type validation.
* refactor(sheets): migrate legacy error helpers to typed errs in sheets domain
golangci-lint forbidigo (errs-no-legacy-helper / errs-no-bare-wrap) flagged
the table I/O, workbook, and dataframe shortcuts that landed on this branch:
93 common.FlagErrorf and 48 fmt.Errorf calls.
- Replace every common.FlagErrorf with common.ValidationErrorf (typed
*errs.ValidationError, same signature) across workbook / table_io /
dataframe / object_crud.
- writeDataframeOut's two final --dataframe-out write failures become typed
errs.NewInternalError(SubtypeFileIO, ...).WithCause(err).
- applyWorkbookCreateVisualOps now passes the typed callTool error through
unchanged (re-wrapping would downgrade classification) and attaches the
failing op as a recovery hint only when none is set.
- The remaining fmt.Errorf are genuine intermediate errors that the command
layer re-wraps into typed validation errors (buildTypedCell / Arrow
decode-encode) or surfaces as a partial_success message string
(writeTypedSheets via tablePutPartial); each carries a //nolint:forbidigo
with that reason, per the lint guidance.
No behavior change: error messages and partial-success shapes are preserved;
gofmt, go vet, golangci-lint (0 issues) and sheets tests all pass.
* fix(shortcuts): clarify single-stdin constraint in flag help and error hint
Input flags advertised '(supports @file, - for stdin)' per flag, leading
AI agents to write '--a - <x --b - <y' where the second '<' silently
clobbers the first and the first flag reads the wrong payload. A process
has a single stdin, so at most one flag per call can use '-'.
- Reword the generated help hint to '- reads stdin (one flag per call;
use @file for others)'.
- Add an actionable .WithHint to the stdin-conflict validation error
pointing callers to @file for the extra flags.
- Assert the new hint in TestResolveInputFlags_DuplicateStdin.
* feat(sheets): +cells-get/+csv-get --max-chars 默认值 200000 → 500000
放宽默认防爆上限。flag_defs_gen.go 由 go generate 重生;flag_defs_test.go
的 expected default 同步;flag-schemas.json schema_version 2 → 3 是上游
spec-tables 架构调整带来的元数据 bump,与本业务改动无关、go:embed 不解析
该字段、无功能影响。
Synced from sheet-skill-spec@93f7a78.
* docs(lark-sheets): sync from spec — +csv-put 含逗号公式正例 + 收敛警示标签
源同步自 sheet-skill-spec:write-cells 补含逗号公式 RFC 4180 转义正例与结构化写入优先指引;全 reference 收敛「高频致命错误」类标签。
* docs(lark-sheets): sync from spec — --max-chars 放出为可见 flag + 落盘优先指引
源同步自 sheet-skill-spec:--max-chars 放出(默认 500000,可调小避免大输出被 Bash/终端转存为文件、改 has_more 分页);read-data 增「大数据优先落盘」指引。
* feat(sheets): 写操作报错增强 + --token 别名
- 复合 JSON shape 校验失败时报错附 --print-schema 提示,agent 可直接拿到精确结构(pro26 头号:+cells-set --cells 反复猜 shape)
- JSON 解析失败且该 flag 支持 stdin 时提示改用 stdin(公式/引号/逗号内联到 shell 被转义弄坏 JSON)
- --token 作为 --spreadsheet-token 的解析期别名:复用 sheets 已有 PostMount 钩子 + pflag normalize,仅 sheets 包,common 零改动
* docs(lark-sheets): sync from spec — set+H 改单引号 / 速查表补臆造命令名 / workbook-import 引导
* fix(sheets): migrate +table-put to typed error contract
The merge from main brought in #1449 (retire legacy error envelopes),
which removed output.ExitError / output.ErrDetail and forbids
constructing them. Port tablePutPartial off the legacy envelope:
- no sheets written -> typed errs.APIError (plain failure)
- some sheets written -> ok:false result via runtime.OutPartialFailure
carrying written_sheets, returning the partial-failure exit signal
Also fix two drifts the same merge introduced:
- regenerate flag_defs_gen.go to match the committed flag-defs.json
- update the --max-chars flag test to assert visible (no longer hidden)
* docs(lark-sheets): sync from spec — set+H 告诫通则化(移入 stdin 段)
* feat(sheets): styles 接受 halign/valign 等对齐字段别名
把模型常幻觉的 horizontal_align / halign / vertical_align / valign 映射到
规范字段 horizontal_alignment / vertical_alignment,覆盖 --styles 与 typed
--cells;与规范字段冲突时报错而非静默择一。同步 lark-sheets skill 文档补
对齐字段说明 + --print-schema --flag-name styles 提示。
* feat(sheets): resolve wiki URLs to the backing spreadsheet for --url
Sheets shortcuts only accepted /sheets/ and /spreadsheets/ URLs via --url.
A /wiki/<node_token> URL was rejected with "must be a spreadsheet URL"
because the wiki node_token is not a spreadsheet token: resolving it to the
backing spreadsheet needs a wiki get_node call, which Validate/DryRun (kept
network-free) must not make.
Mirror the existing slides/doc/drive two-stage pattern:
- parseSpreadsheetRef classifies --url / --spreadsheet-token network-free
into a sheet token or an (unresolved) wiki node_token.
- resolveSpreadsheetTokenExec (Execute only) resolves a /wiki/ node_token
via wiki get_node, verifies obj_type=sheet, and returns the obj_token.
The wiki:node:read scope is enforced on this path only, so non-wiki
invocations are unaffected.
- resolveSpreadsheetToken stays network-free for Validate/DryRun, passing
the node_token through unchanged.
All 47 Execute paths (including +batch-update and +workbook-export) switch
to the Exec resolver; Validate/DryRun keep the network-free one. No tool
schema change: the CLI feeds the resolved spreadsheet token as excel_id, so
this is a pure CLI-layer change.
Tested: unit (parse classification + wiki get_node e2e via httpmock) and
live end-to-end against a real wiki spreadsheet (read: +workbook-info,
+cells-get, +csv-get; write: +sheet-create, +sheet-rename, +csv-put).
* docs(sheets): note --url accepts wiki URLs (synced from spec)
* fix(sheets): match --url path segment via url.Parse, not substring
parseSpreadsheetRef classified /wiki/ with strings.Index over the whole URL, so a /sheets/ link whose query or fragment merely contained /wiki/ (e.g. .../sheets/sht?from=/wiki/x) was hijacked into a get_node call. Now parse the URL and match /sheets/, /spreadsheets/, /wiki/ only as a path prefix, mirroring slides parsePresentationRef which already fixed this class. Drop the substring helpers. Also align wiki resolution with slides: CallAPITyped (typed error + log_id) and classify an incomplete get_node response as InternalError instead of a --url validation error. Add regression tests for query/fragment /wiki/ and incomplete node.
* fix(sheets): satisfy errorlint/copyloopvar + regen flag defs
- helpers_test.go: drop the Go 1.22+ redundant `tc := tc` loop copy
(copyloopvar).
- lark_sheet_dataframe.go, lark_sheet_table_io.go: switch the
intermediate-error fmt.Errorf calls from %v to %w so errorlint passes.
Behavior unchanged — these errors are always rewrapped into typed
validation errors at the command layer.
- flag_defs_gen.go: regenerate from data/flag-defs.json (drift from the
wiki-URL merge).
* ci: allow Apache Arrow module in license check
Arrow is Apache-2.0 overall, but it vendors c-ares (LicenseRef-C-Ares,
ISC-like) inside the module which go-licenses classifies as Unknown and
the strict disallowed_types=...,unknown gate rejects.
Pass --ignore github.com/apache/arrow/go/v17 since Arrow is required by
sheets +table-put / +table-get / +workbook-create --dataframe (Arrow IPC
ingest) and the vendored c-ares is not redistributed by us.
* fix(sheets): resolve wiki URL in +range-move/+range-copy Execute
transformExecuteFn (the named Execute helper shared by +range-move and +range-copy) still called the network-free resolveSpreadsheetToken, so a /wiki/ URL reached transform_range as an unresolved node_token and failed. #1519's sweep over Execute hooks only rewrote inline closures; this is the only Execute backed by a named helper. Switch it to resolveSpreadsheetTokenExec (Validate/DryRun stay network-free) and add a +range-move wiki-URL regression test.
* refactor(sheets): drop +table-put manual capacity grow; rely on set_cell_range auto-grow
set_cell_range now auto-grows the sub-sheet to fit the write, so the
ensureSheetCapacity helper (and its modify_sheet_structure dim-insert
call before each write) is no longer needed. This also closes a data-
safety hole flagged in review: inserting before the last existing row
could push real data down into the area set_cell_range was about to
write, and allow_overwrite=false could not protect against it because
the structural insert had already mutated the sheet by the time the
write-collision check ran.
Verified end-to-end against a real spreadsheet: +table-put writing
300x25 into a fresh Sheet1 (default 200x20) succeeds in one write and
the sheet ends up 301x25.
* fix(sheets): close --dataframe stdin guard hole
--dataframe is binary and bypasses the common Input resolver, which is
where the existing single-stdin guard lives. Result: an invocation like
+table-put --dataframe - --styles - was accepted, then one of the two
consumers raced for stdin and the other silently saw an empty stream.
Add a stdinConsumed marker on RuntimeContext that both consumers share:
common.resolveInputFlags sets it when an Input flag uses '-', and
readDataframeBytes both checks and sets it. A second consumer is
rejected up front with an actionable hint pointing at @file.
Flagged in code review (lark_sheet_dataframe.go:93).
* fix(sheets): harden +table-put / +table-get input validation and round-trip safety
Four review-flagged correctness gaps in table I/O, all bundled because
they touch the same file:
1. --sheets accepted trailing data after the first JSON value
(json.Decoder does not surface that, unlike json.Unmarshal). A new
decoderExpectEOF helper rejects e.g. `--sheets '{...} oops'` with a
typed validation error instead of letting the leading object pass
through and surface as a confusing downstream failure.
2. +table-get with a duplicate header (e.g. `amount, amount`) used to
read back successfully — the dtypes map silently collapsed to one
entry — and only failed later on +table-put because the writer
rejects duplicate column names. Fail fast at read time with an
actionable hint to rename or pass --no-header. --no-header mode is
exempt (fallback col<N> names are always unique).
3. +table-put dry-run rendered an invalid range like A1:C0 when
header=false with rows=[]. tablePutFullRange returns "" for an
empty matrix or zero columns instead of building a degenerate
rectangle.
4. +table-get with --sheet-id and a get_workbook_structure miss (read
failure or selector mismatch) used to return a target with
name="", which then broke +table-get → +table-put round-trip (the
writer requires a non-empty sheet name). Fall back to using the id
as the name.
End-to-end verified against a real spreadsheet: trailing data, duplicate
header, and --no-header fallback all behave as advertised.
* fix(sheets): apply +workbook-create style-only ops instead of silently dropping them
A +workbook-create call carrying only cell_merges / row_sizes / col_sizes
(no --values / --sheets and no cell_styles) used to create the workbook
but silently drop the requested visual ops. Two reasons, both fixed:
- workbookCreateStyleDimensions only counted cell_styles when computing
the write extent, so cell_merges / row_sizes / col_sizes always
contributed 0 → buildValuesPayload returned a nil payload → Execute
skipped writeTypedSheets entirely → no visual ops ran. Extend the
helper to fold the merge / resize ranges in.
- Pure row_sizes / col_sizes payloads can never expand a cell rectangle
(they are dimension ranges, not cell ranges), so even with the extent
fix Execute would still skip the write path. Add a no-data branch:
when payload == nil but a styles item is present, look up the default
sheet and apply visual ops directly via applyWorkbookCreateVisualOps.
The dry-run plan mirrors this so the preview shows the visual ops.
Also picks up the --values trailing-JSON-data EOF check (mirror of the
--sheets one in lark_sheet_table_io.go).
End-to-end verified against a real spreadsheet: a cell_merges-only
+workbook-create now produces a sheet with merged_cells_count: 1.
* fix(sheets): preserve causes and render messages cleanly for typed validation errors
common.ValidationErrorf goes through fmt.Sprintf, which does not support
%w — the seven call sites that used `%w` were rendering the cause as
literal `%!w(*fmt.wrapError=&{...})` and dropping the cause from the
typed-error chain (so callers couldn't errors.As back to the underlying
error).
Switch each to `%v` for clean rendering and attach the cause via
.WithCause(err) so the typed contract is preserved. Touched call sites:
- lark_sheet_dataframe.go: --dataframe Arrow decode / stdin read / file
read failures (3 call sites).
- lark_sheet_table_io.go: --sheets invalid JSON, payload-validate
per-cell coercion error, buildSheetMatrix per-cell error,
--dataframe-out arrow encode failure (4 call sites).
End-to-end verified against a real spreadsheet: both invalid-JSON and
typed-cell errors now render readable messages instead of %!w(...).
* sync(sheets): pick up +sheet-{show,hide}-gridline in +batch-update schema
Mirror of the sheet-skill-spec change adding the two gridline shortcuts
to cli-schemas.json batch_update.operations.shortcut enum. Synced from
the upstream canonical via generate:cli + sync:cli.
Verified end-to-end on a real spreadsheet — +batch-update with a
+sheet-hide-gridline op passes schema validation and the backend run
returns succeeded: 1.
* sync(sheets): pick up +workbook-export UX clarification from spec
Mirror of the sheet-skill-spec update that documents +workbook-export's
default-no-download behavior and its relationship to drive +export
--doc-type sheet. Synced from canonical via generate:cli + sync:cli +
go generate.
End-to-end verified against a real spreadsheet:
- Omit --output-path → ok:true, downloaded:false, file_token returned
- Pass --output-path ./crfix_test.xlsx → ok:true, file saved
(17892 bytes), saved_path returned
The --help output for +workbook-export now states the default behavior
and points callers at `drive +export --doc-type sheet` when they need
the --output-dir / --file-name / --overwrite split.
* test(sheets): assert typed errs.Problem instead of err.Error() substrings
Per the coding guideline "Error-path tests must assert typed metadata via
errs.ProblemOf (category / subtype / param) and cause preservation, not
message substrings alone." — sweep through every error-path assertion in
the sheets domain and replace the
`strings.Contains(stdout+stderr+err.Error(), ...)` pattern with two
small helpers landed in helpers_test.go:
requireProblem(t, err, wantCategory, wantSubtype, msgContains)
-> *errs.Problem
requireValidation(t, err, msgContains)
-> *errs.ValidationError // shorthand for CategoryValidation +
// SubtypeInvalidArgument; lets callers
// also assert .Param / .Params / .Cause
~60 assertion sites across 18 test files now check the typed envelope
shape, with message-substring checks moved onto the returned Problem
(.Message / .Hint / .Param). The substring is preserved as a sanity
check rather than the sole assertion, so a category drift like
validation → internal would now fail loudly instead of slipping past.
Cases intentionally left as substring (each with a one-line reason):
- Errors that come straight from cobra's native flag parser (untyped
*errors.errorString — e.g. "required flag(s) ... not set", mutually-
exclusive groups). Re-typing these needs a custom FlagErrorFunc and
is out of scope here.
- Intermediate errors from decodeArrowToSheet that the caller wraps
into a typed envelope (`//nolint:forbidigo` reason). Those unit
tests assert the unwrapped intermediate directly.
One production tweak:
- shortcuts/sheets/flag_schema.go: printFlagSchemaFor returns typed
*errs.ValidationError (with WithParam("--flag-name") on the
unknown-flag branch) instead of raw fmt.Errorf. The framework
already wraps this when called via --print-schema, so user-facing
behaviour is unchanged; direct callers (and tests) now get the
typed envelope.
Verified: go test ./shortcuts/sheets/... passes; golangci-lint
--new-from-rev=origin/main reports 0 issues.
* test(common): assert typed errs.Problem instead of err.Error() substrings
Mirror of the sweep just landed in shortcuts/sheets: replace error-path
substring assertions with typed-envelope checks via two small helpers
landed in a new shortcuts/common/typed_error_assertions_test.go:
requireProblem(t, err, wantCategory, wantSubtype, msgContains)
-> *errs.Problem
requireValidation(t, err, msgContains)
-> *errs.ValidationError // shorthand for CategoryValidation +
// SubtypeInvalidArgument; lets callers
// also assert .Param / .Params / .Cause
8 sites moved to typed assertions across runner_jq_test.go,
mcp_client_test.go, drive_media_upload_typed_test.go, and
runner_input_test.go (the input tests already used a typed-param helper;
this just retargets the substring follow-up onto the typed Message).
Sites intentionally left as substring + comment (production returns raw
fmt.Errorf, not a typed envelope):
- runner_botinfo_test.go (6 sites): BotInfo / fetchBotInfo wrap upstream
errors with fmt.Errorf so the SDK-level message ([99991], 403,
invalid character, etc.) shows through.
- runner_args_test.go (4 sites in 2 tests): rejectPositionalArgs returns
raw fmt.Errorf to satisfy cobra's PositionalArgs contract.
- permission_grant_test.go (2 sites): assert on stderr / hint strings,
not error messages — already out of the err.Error() substring class.
No production code changes.
Verified: go test ./shortcuts/common/... passes;
golangci-lint --new-from-rev=origin/main ./shortcuts/common/... reports
0 issues.
* fix(sheets): plug four +table-put / +table-get correctness gaps flagged in CR
Four review-flagged bugs, all in lark_sheet_table_io.go (bundled because
they touch the same file and the same +table-put / +table-get domain):
1. +table-get --dry-run dropped the --sheet-id / --sheet-name selector
from the get_cell_ranges body, while Execute always passed it. Agents
that validate the dry-run shape and then run live would see a request
shape mismatch. The dry-run now calls sheetSelectorForToolInput so
the body matches Execute.
2. isDateNumberFormat used a simple `strings.ContainsRune(_, 'y')` so
number formats like "JPY #,##0" (a currency prefix that happens to
contain a lone 'Y') were misread as date formats — round-tripping
integer cells out as ISO dates. The detector is now token-aware:
it skips quoted "...", `\\x`-escaped, and `[...]` bracket sections,
and only fires on an unescaped `yy` (a real Excel year token).
3. sheetCreateDims sized new append-mode sheets by `headerOn(s)` only,
but writeSheetData forces a header on empty append sheets when
Header == nil. Near 50000 rows / 200 cols this created the sheet one
row short and the follow-up set_cell_range bounced off the backend
ceiling. Size now matches the forced-header logic exactly.
4. tableGetTargets fallback paths (read-failure / selector mismatch on
--sheet-id) returned a target with name="" — already corrected for
--sheet-id structure-success path in
|
||
|
|
b07be60068 |
feat(sheets): emit typed error envelopes across the sheets domain (#1348)
Emit structured validation, API, network, file, and internal error envelopes for Sheets shortcuts so users and agents can recover from failed spreadsheet workflows using stable type, subtype, param, and code fields. Add Sheets domain errscontract and golangci guards to prevent legacy envelope and common helper regressions. |
||
|
|
b07a6003f9 |
feat(sheets): spec-driven shortcut refactor with backward-compatible package (#1220)
* refactor(sheets): rebuild lark-sheets on sheet-skill-spec canonical + One-OpenAPI
Restart lark-sheets as a spec-driven downstream. Skill content (SKILL.md
and 16 references covering 13 operations skills + 3 workflow skills,
including the standalone filter-view skill) is mirrored from the
sheet-skill-spec canonical-spec; do not hand-edit, change upstream and
rerun npm run sync:consumers.
Drop the 11 legacy shortcut sources (spreadsheet / sheet management,
cell ops, dropdown, filter-view, float image, etc.) and 10 associated
tests. Wire up the new sheet_ai/v2 One-OpenAPI single entry that
dispatches by tool_name with JSON-string input/output, and land the
first canonical shortcut +workbook-info as a template that exercises
the public token XOR pair, Risk tiering, and zero-side-effect DryRun.
sheet_ai_api.go provides callTool / invokeToolDryRun and bypasses
runtime.CallAPI's silent swallowing of non-envelope responses so
gateway and business errors from the new endpoint surface precisely.
The remaining 55 shortcuts will be designed and landed separately,
canonical skill by canonical skill.
* feat(sheets): implement lark_sheet_workbook shortcuts (B1)
Land the 8 modify_workbook_structure shortcuts that round out the
lark_sheet_workbook canonical skill alongside the existing +workbook-info:
+sheet-create / +sheet-delete / +sheet-rename / +sheet-move / +sheet-copy
/ +sheet-hide / +sheet-unhide / +sheet-set-tab-color. All eight call
modify_workbook_structure via the One-OpenAPI invoke_write endpoint,
dispatched by the `operation` enum.
Helpers in helpers.go grow publicSheetFlags() / resolveSheetSelector() /
sheetSelectorForToolInput() / sheetSelectorPlaceholder() so future
sheet-level shortcuts share the public --sheet-id / --sheet-name XOR
treatment. +sheet-create intentionally drops the sheet selector pair since
create has no existing-sheet anchor (matches the spec fix in
tool-shortcut-map.json).
+sheet-delete is the first high-risk-write shortcut in the canonical
package; the framework requires --yes (exit code 10 otherwise).
+sheet-move's tool requires source_index in addition to target_index. The
CLI accepts an optional --source-index override and falls back to a
single get_workbook_structure read to derive it (and to resolve sheet_id
from --sheet-name). DryRun stays network-free by rendering <resolve>
placeholders for any field that would need that read.
* feat(sheets): implement lark_sheet_sheet_structure shortcuts (B2)
Add 8 shortcuts under the lark_sheet_sheet_structure canonical skill:
+sheet-info (get_sheet_structure) plus +dim-insert / +dim-delete /
+dim-hide / +dim-unhide / +dim-freeze / +dim-group / +dim-ungroup
(modify_sheet_structure, dispatched by operation enum).
Two reusable conversion helpers cover the impedance mismatch between
the CLI surface and the tool input:
- dimRange / dimPosition translate the CLI's 0-based exclusive-end
range into the tool's 1-based A1 notation. row 5..8 becomes
position "6" + count 3 (insert) or range "6:8" (range ops); column
26..29 becomes "AA:AC".
- infoTypeFromInclude maps the fine-grained --include vocabulary
(row_heights / col_widths / merges / hidden_rows / hidden_cols /
groups / frozen) to the coarse info_type enum the tool accepts;
mixed categories collapse to "all".
+dim-delete is high-risk-write (irreversible row/column removal).
+dim-freeze --count 0 auto-dispatches to operation=unfreeze. +dim-group
accepts --depth for forward-compat with a future server-side nested
group endpoint but does not pass it through today.
* feat(sheets): implement read_data / search_replace / write_cells shortcuts (B3)
Land 11 shortcuts across three canonical skills:
- lark_sheet_read_data (3): +cells-get / +csv-get / +dropdown-get
- lark_sheet_search_replace (2): +cells-search / +cells-replace
- lark_sheet_write_cells (6): +cells-set / +cells-set-style / +csv-put
/ +dropdown-set / +dropdown-update / +dropdown-delete
+dropdown-get reads the data_validation field via get_cell_ranges with
the range carrying its own sheet prefix (no --sheet-id needed). The
fine-grained --include vocabulary (value / formula / style / comment /
data_validation) maps to the tool's coarse include_styles bool plus
value_render_option enum. +csv-get's --include-row-prefix=false strips
the [row=N] prefix client-side because the tool only emits the
annotated form.
+cells-search / +cells-replace flatten the tool's options sub-object
into four independent flags (--match-case / --match-entire-cell /
--regex / --include-formulas) per the flat-flag rule, then repack them on the way
in.
+cells-set takes a raw --data JSON body whose `cells` array must match
the --range dimensions. +cells-set-style fans a single --style block
out to every cell in the range via a new fillCellsMatrix helper; the
range parser (rangeDimensions / splitCellRef / letterToColumnIndex)
only accepts rectangular A1:B2 forms — whole-column / whole-row need
sheet totals and are deferred.
+dropdown-set fans the validation block out to one range; +dropdown-
update / +dropdown-delete iterate sheet-prefixed --ranges and call
set_cell_range sequentially (partial failure leaves earlier ranges
already mutated; the Tip calls this out). +dropdown-delete is
high-risk-write and requires --yes.
+cells-set-image stays deferred to the cli-only batch (needs the
shared local-file upload helper alongside +workbook-create / +dim-move
/ +workbook-export).
* refactor(sheets): move +dropdown-update / +dropdown-delete to lark_sheet_batch_update
Follow-up to B3 after the spec re-mapped these two shortcuts to the
batch_update tool (atomic multi-range CRUD) instead of fan-out via
set_cell_range. Drop their Go implementations + helper validateDropdownRanges
+ splitSheetPrefixedRange from lark_sheet_write_cells.go and remove the
registrations from Shortcuts(); the shortcuts will reappear under
lark_sheet_batch_update during B7.
Also pull in the re-rendered reference docs:
- skills/lark-sheets/references/lark-sheets-write-cells.md
- skills/lark-sheets/references/lark-sheets-batch-update.md
* feat(sheets): implement lark_sheet_range_operations shortcuts (B4)
Land 8 shortcuts across four canonical tools:
- clear_cell_range → +cells-clear (high-risk-write)
- merge_cells → +cells-merge / +cells-unmerge
- resize_range → +dim-resize
- transform_range → +range-move / +range-copy / +range-fill / +range-sort
Three CLI↔tool vocabulary bridges live in this file:
- +cells-clear: --scope content normalizes to the tool's clear_type
"contents" (singular/plural spec mismatch is absorbed in the CLI).
- +dim-resize: --size <px> wraps as resize_{height,width}:{value:N};
--reset wraps as {reset:true}. The two flags are mutually exclusive
and at least one is required.
- +range-fill: CLI's five-valued --series-type collapses to the tool's
binary fill_type — `copy` → "copyCells", anything else → "fillSeries"
(the actual series progression is inferred server-side from the
seed cells in --source-range).
- +range-copy: --paste-type {values, formulas, formats} maps to the
tool's {value_only, formula_only, format_only}; "all" omits the
field entirely so the server applies its default.
+cells-clear is the second high-risk-write shortcut in the package;
the framework enforces --yes with exit code 10 as usual.
* feat(sheets): implement object-list shortcuts (B5)
Land 7 read shortcuts, one per object skill — chart / pivot table /
conditional format / filter / filter view / sparkline / float image. All
share the same shape (public sheet selector + optional <obj>-id filter)
so they're declared via newObjectListShortcut + an objectListSpec.
Notes:
- +cond-format-list exposes --rule-id, which is renamed to
conditional_format_id on the wire (the tool's full field name).
- +sparkline-list exposes --group-id (the higher-level handle); the
tool also accepts sparkline_id, intentionally not surfaced.
- +filter-list takes no id filter — at most one sheet-level filter
per sheet, so the listing is already unique.
- +filter-view-list is `cli_status: cli-only` but get_filter_view_objects
is in mcp-tools.json and dispatches through the same One-OpenAPI
endpoint; no special path required.
* feat(sheets): implement object CRUD shortcuts (B6)
Land 21 shortcuts — three (create / update / delete) per object skill —
backed by the manage_<obj>_object tools dispatched on the operation
enum. Five standard objects (chart / cond-format / sparkline /
float-image / filter-view) share an objectCRUDSpec factory; pivot and
filter are special-cased.
Shared wire contract:
excel_id + sheet_id|sheet_name + operation + [<obj>_id] + [properties]
CLI --data is passed through as the tool's `properties` field as-is, so
callers shape it per each object's spec doc.
Special cases:
- pivot adds optional --target-sheet-id / --target-position on create
(siblings of properties, not inside it).
- cond-format exposes --rule-id (short CLI name) wired to the tool's
conditional_format_id on the wire.
- sparkline uses --group-id (higher-level object handle) instead of
sparkline_id.
- filter has no separate id flag — at most one filter per sheet, so
filter_id is implicit. +filter-create promotes --range to a first-
class flag (instead of burying it inside --data).
- filter-view CRUD are `cli_status: cli-only` but
manage_filter_view_object is in mcp-tools.json, so they go through
callTool / One-OpenAPI alongside everything else.
All delete shortcuts are high-risk-write and require --yes.
* feat(sheets): implement lark_sheet_batch_update shortcuts (B7)
Land 4 shortcuts that all funnel through the batch_update tool's atomic
operations array:
- +batch-update raw passthrough; --data carries the full
{ operations: [{tool, params}, ...] } payload
plus optional continue_on_error. high-risk-write
since the caller may stuff anything inside.
- +cells-batch-set-style --data is [{ranges, style}, ...]; CLI flattens
each (entry × range) pair into a set_cell_range
op with a fan-out cells matrix carrying
cell_styles + border_styles.
- +dropdown-update --ranges + --options (+ --colors / --multiple /
--highlight) — installs/replaces one dropdown
across many ranges, each becoming a separate
set_cell_range op with data_validation in cells.
- +dropdown-delete --ranges — clears data_validation across many
ranges (high-risk-write).
Default is strict transaction: if any sub-tool fails the whole batch rolls
back. +batch-update exposes --continue-on-error to flip the policy; the
three fan-out shortcuts leave it strict (they're meant to be all-or-nothing).
Reinstates validateDropdownRanges + splitSheetPrefixedRange that were
removed during B3 → B7 relocation.
* feat(sheets): implement cli-only shortcuts (B8) — 70/70 complete
Land the four cli-only shortcuts that can't route through the One-OpenAPI
dispatcher (their backing capabilities aren't in mcp-tools.json):
- +workbook-create POST /open-apis/sheets/v3/spreadsheets
+ optional set_cell_range follow-up that zips
--headers and --data into the first sheet starting
at A1.
- +workbook-export POST /open-apis/drive/v1/export_tasks (type=sheet)
→ poll /export_tasks/:ticket up to ~30s
→ optional GET /export_tasks/file/:file_token/download.
CSV mode requires --sheet-id (single sheet export).
- +dim-move POST /open-apis/sheets/v2/spreadsheets/:token
/dimension_range
CLI is 0-indexed inclusive (--start / --end); the v2
endpoint expects half-open [startIndex, endIndex)
so the body uses endIndex = --end + 1. --sheet-name
is resolved client-side to sheet_id via
lookupSheetIndex when needed.
- +cells-set-image common.UploadDriveMediaAll
(parent_type=sheet_image, parent_node=token)
then callTool set_cell_range with cells carrying
rich_text: [{type:"embed-image", attachment_token, attachment_name}].
--range must be exactly one cell.
All four use runtime.CallAPI / DoAPI directly; only +cells-set-image
combines a legacy upload with the new One-OpenAPI for the second step
(set_cell_range is in mcp-tools.json so callTool is the right path).
This closes the migration: 70 shortcuts × 17 canonical skills × matching
the sheet-skill-spec v0.5.0 tool-shortcut-map.
* test(sheets): cover all 70 shortcuts with dry-run + execute-path tests
Twelve _test.go files alongside the implementation, mirroring the legacy
package's coverage style:
- testhelpers_test.go shared rig: TestFactory + Mount + dry-run
capture + JSON-input decode + envelope helpers.
- lark_sheet_*_test.go one test file per implementation file (9
files), table-driven dry-run cases per shortcut
plus targeted validation guards.
- execute_paths_test.go end-to-end execute paths via httpmock stubs.
Covers callTool unwrap, JSON-string output
decoding, two-step lookup (+sheet-move),
batch_update fan-out, dropdown atomic writes,
and the legacy OAPI shortcuts (+workbook-create,
+dim-move) including CLI inclusive → API
half-open index conversion.
Test coverage on the sheets package is 60.5 % of statements with -race
clean, meeting the dev manual's ≥ 60 % patch-coverage gate.
* refactor(sheets): inline cli-only shortcuts into their canonical skill files
Two naming cleanups:
- lark_sheet_cli_only.go is gone. The four shortcuts it grouped
(+workbook-create / +workbook-export / +dim-move / +cells-set-image)
were bundled by their implementation pattern (legacy OAPI direct
calls) rather than by canonical skill. The whole sheets package IS
the CLI implementation, so "cli only" wasn't a meaningful grouping
at the Go layer. Each shortcut now lives next to its skill peers:
+workbook-create / +workbook-export → lark_sheet_workbook.go
+dim-move → lark_sheet_sheet_structure.go
+cells-set-image → lark_sheet_write_cells.go
Per-skill shortcut counts now match tool-shortcut-map.json exactly
(workbook: 11, sheet_structure: 9, write_cells: 5). Helpers
(buildInitialFillInput, pollExportTask, downloadExportFile,
dimMoveBody) move with their shortcuts; nothing else in the package
referenced them.
- testhelpers_test.go → helpers_test.go. The _test.go suffix already
conveys "test"; the leading "test" was redundant. Matches the
helpers.go naming convention.
Behavior unchanged. go test -race -cover stays at 60.5 %.
* refactor(sheets): sync shortcut flags with sheet-skill-spec v0.5.0
Upstream hoisted a batch of high-frequency scalar fields out of --data
into independent flags and renamed several composite-JSON flags to
match their semantic content. CLI catches up.
Renames (drop-in, same payload semantics):
- +cells-replace --replace → --replacement
- +cells-set --data → --cells
- +workbook-create --data → --values
- +batch-update --data → --operations (now a bare array;
still accepts the envelope form for
back-compat with continue_on_error)
Flat-flag hoists out of --style / --data:
- +cells-set-style / +cells-batch-set-style
--style JSON drops; replaced by 11 flat style flags
(--background-color / --font-color / --font-size / --font-style /
--font-weight / --font-line / --horizontal-alignment /
--vertical-alignment / --word-wrap / --number-format) plus
--border-styles for the one field that's still nested. Both
shortcuts share styleFlatFlags() + buildCellStyleFromFlags().
- +cells-batch-set-style also drops the [{ranges, style}] array shape
in favor of one --ranges + the same flat style flags applied to
all of them.
Object CRUD --data → --properties everywhere (chart / pivot / cond-format
/ filter / filter-view / sparkline / float-image). Per-skill scalar
hoists merged into properties via an enhanceCreate/UpdateInput callback:
- +pivot-create adds --source (required), --range
(and continues to expose --target-sheet-id /
--target-position at top level)
- +cond-format-{create,update}
adds --rule-type (enum) + --ranges (JSON array);
merged into properties.rule.type and
properties.ranges respectively
- +filter-view-{create,update}
adds --view-name and --range; both override
their properties.* counterparts
- +filter-update adds first-class --range (was buried in --data)
Float-image is fully hoisted — no --properties flag at all. Ten flat
flags (--image-name / --image-token | --image-uri / --position-row /
--position-col / --size-width / --size-height / --offset-row /
--offset-col / --z-index) compose the properties block. Implemented as
its own factory (newFloatImageWriteShortcut) since it diverges from the
shared CRUD spec.
Tests track every flag renamed and add explicit cases for the new flag
combos. go test -race -cover stays at 60.3 %.
* refactor(sheets): align batch_update + cells-set with synced reference docs
Sync to upstream reference doc updates for 9 skills:
- batch_update sub-ops: rewrite wire fields tool/params -> tool_name/input
in CellsBatchSetStyle and DropdownUpdate/Delete fan-out (the actual
server contract per Schemas section); update --operations flag desc
and tests.
- +cells-set --cells: accept bare 2D matrix [[{cell},...],...] instead
of envelope {"cells":[[...]]}; spec example shows bare-array form.
- sparkline createDataDesc enum: win_loss -> winLoss (camelCase).
All other doc changes (float-image flat flags, cond-format
--rule-type/--ranges, pivot create-only --source/--range, filter /
filter-view extra flags, chart --properties) were already aligned in
commit
|