mirror of
https://github.com/larksuite/cli.git
synced 2026-09-14 18:42:53 +08:00
feat/kb-bootstrap-workflow
1111 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
177ef1c7cf | chore: release v1.0.92 (#2553) | ||
|
|
3109a56671 |
feat(im): support rich-text message attachment zone in send/reply/mge… (#2515)
* feat(im): support rich-text message attachment zone in send/reply/mget/edit Support the post message attachment zone (top-level files array) end to end: - +messages-send / +messages-reply: repeatable --attachment file_key flags merged into the post content's files array (deduplicated). - +messages-mget: render attachment-zone files/folders as <file>/<folder> tags in content, extract file keys for --download-resources. - +messages-edit: new shortcut (PUT /open-apis/im/v1/messages/:id) with --set-attachments / --clear-attachments; body-only edits preserve the attachment zone by default. - Attachment flags are mutually exclusive with --content carrying a files array (declare the zone via one or the other, not both). - bot-only identity, matching server behavior (user token rejected). - Fixes from review: attachments no longer bypass content mutual-exclusion validation (P1); merge dedups by key. - Docs (SKILL.md, references, affordance) and unit tests updated. * fix(im): address design-review findings (auto-infer post, dedup set, doc routing) - --attachment/--set-attachments/--clear-attachments now infer msg_type=post automatically; only an explicit incompatible --msg-type conflicts. --text is rejected with attachments (text is a standalone message, not a post body) with a hint to use --markdown or --content. - --set-attachments deduplicates repeated keys (docs promised this; the replace helper now enforces it). - Shortcut Description no longer leaks the HTTP path or the raw server error phrase; it describes the command semantically. - affordance/im.md +messages-edit now routes WHEN: interactive cards go to messages.patch, corrected messages go to +messages-send, and attachment tri-state tips are listed. - mget doc no longer claims --format json exposes raw wire fields (the output is the rendered content); download eligibility clarified. |
||
|
|
ea088f4283 |
fix(sheets): suppress multipart stderr noise and tighten e2e boundary test (#2550)
Add a Quiet flag to DriveMediaMultipartUploadConfig so callers whose success contract forbids non-empty stderr (the sheets shortcuts) can suppress the chunk-plan and per-block progress lines the multipart path writes unconditionally on success. Both uploadSheetImage and the deprecated uploadSheetMediaFile pass Quiet: true. Also simplify isLocallyOpenedOfficeToken to two HasPrefix calls instead of a loop over an inline slice, so the two-prefix invariant stays in one expression rather than drifting from common. Finally, fix the e2e "at the ceiling stays single-part" test case: the small.png fixture was 9 bytes, not the 20 MB the name implied. Truncate it to singlePartCeiling so the boundary is actually pinned. |
||
|
|
cb02853f15 |
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 |
||
|
|
3fcc4e337d |
fix(sheets): make image-upload previews match what Execute sends (#2537)
* fix(sheets): repair the build after the local-office detection move main does not compile: shortcuts/sheets/lark_sheet_workbook.go references isOfficeSpreadsheet and officePrefixes, which no longer exist in the package. Neither PR was wrong on its own. #2531 (merged 10:39) moved local-office token detection into common.IsLocalOfficeToken and deleted the sheets-local copies; #2533 (merged 12:48) added errLocalOfficeExportUnsupported, which calls them. #2533's branch predated the move, so its CI was green against a base that still had the symbols, and merging it left main broken. Repoints both references at the moved API. Behaviour is unchanged: common.IsLocalOfficeToken is the same predicate #2531 moved, and the prefix pair is the exported form of the same two constants. #2533's own coverage — TestWorkbookExport_LocalOfficeTokenRejected across the local_office_ prefix, the fake_office_ prefix, and an interleaved OFL0X token, plus the wiki-node and dry-run cases — passes unchanged, which is what pins the equivalence. * fix(sheets): derive dry-run image parent_type from the ref kind, not the token A `/wiki/` URL reaches a DryRun hook as the wiki node_token: resolving it to the backing spreadsheet needs the get_node call a preview must not make. Both image-upload previews fed that node_token straight to sheetMediaParentType, so the parent_type they showed was derived from a token that is not the one Execute uploads against. A node_token shaped like an imported office token previewed office_sheet_file for a spreadsheet that will upload as sheet_image. sheetsDryRunParentType decides from the ref's kind instead. A wiki ref is native by construction, not by default: resolveWikiNodeToSpreadsheetToken rejects any node whose obj_type is not "sheet", and a spreadsheet backed by an imported office file sits in drive as a "file" node, so it never survives that gate to reach an upload. Execute is unaffected either way — it derives from the resolved token. This mirrors slidesDryRunParentType, which the slides domain already applies for the same reason. The hooks now hold the parsed ref rather than re-deriving the token from it, so the kind is visible where the preview is built. Also records, at uploadSheetMediaFile, that office_sheet_file survives the multipart path. Slides caps image uploads at 20 MB because upload_prepare rejects its parent types outright, which raised the question for sheets, whose deprecated +media-upload has no such cap. Verified against the live API: upload_prepare accepts both sheet_image and office_sheet_file, and a 20.6 MB file uploaded with office_sheet_file completes prepare -> 6 x upload_part -> upload_finish and returns a file_token a float image then accepts. Tests: sheetsDryRunParentType over both ref kinds, including wiki refs carrying office-shaped and office-prefixed node tokens; dry-run coverage through the public flags for +cells-set-image and +float-image-create, each checked against the identical token as a /wiki/ URL and as a raw spreadsheet token so the two rows differ only in kind; the same pair added to the e2e dry-run lane. All four fail against the previous behaviour. * fix(sheets): send oversized images through the chunked upload, not upload_all uploadSheetImage always used the single-part endpoint, so an image past the 20 MB ceiling failed with a bare 1061002 "upload media failed: params error" naming neither the size nor the limit. The capability was already in the domain: the deprecated sheets +media-upload has dispatched by size since it was written (backward.uploadSheetMediaFile), which left the same image succeeding through the old shortcut and failing through +cells-set-image and +float-image-create, the ones meant to replace it. uploadSheetImage now picks the endpoint by size the way doc and the deprecated shortcut already do. The parent_type is unchanged and still comes from sheetMediaParentType, so the office/native split rides along either branch. The preview follows the same branch. appendSheetImageUploadDryRun renders one upload_all under the ceiling and the upload_prepare / upload_part / upload_finish trio above it, and both image-write hooks now build their upload step through it rather than each spelling out an upload_all. A preview that promised a single-part upload for a file the CLI will send in chunks is a preview of a different request. Verified against the live API with a 20.6 MB PNG: +cells-set-image and +float-image-create both complete, the cell reads back holding the uploaded image_token at the file's real 3000x2400 dimensions, and the dry-run shows the three chunked steps Execute hits. The same file failed with 1061002 before. Tests: the chunked branch at exactly one byte past the ceiling, asserted through upload_prepare's parent_type with upload_all deliberately left unstubbed so a regression fails loudly; the preview's step list on both sides of the boundary, as a unit test and in the e2e dry-run lane. All fail against the previous behaviour. |
||
|
|
da24f05064 |
refactor(sheets): keep the success path off stderr (#2533)
* feat(sheets): reject local-office tokens in +workbook-export
A locally opened Office file (a local_office_ / fake_office_ token, or an
interleaved OFL0X one) names a file the Lark client is showing, not a cloud
document, so the drive export task can only fail on the backend -- and it
fails late, after the create and poll round trips, with an opaque message.
Refuse it up front with a typed failed_precondition that says the workbook is
already a file on disk, and points at +workbook-import for callers who want a
cloud spreadsheet they can export later. The check runs in Validate (so
--dry-run is covered too) and again after the wiki hop in Execute, where the
real spreadsheet token is first known.
* refactor(sheets): report success-path advisories in the result, not on stderr
Every sheets shortcut that had something to say on a successful run said it on
stderr: ignored sub-op locators, emulated dimension semantics, the deprecated
--dimension/--count and +cells-batch-set-style spellings, the dropdown
option-error steer, and the upload/export stage lines in the compatibility
layer. PowerShell's native-command handling and most agent harnesses read
non-empty stderr as failure, so a working call reported itself as an error --
and the facts a caller actually needed sat outside the JSON they parse.
Pure stage text ("Writing image", "Waiting for export task") is deleted: it
duplicates what the result already proves. Everything decision-relevant moves
into the payload:
- data.warnings ignored locators, colliding freezes, the dropdown
option-error steer (also shown in --dry-run now)
- data.effective_operation +dim-insert's anchor shift under --inherit-style
before, and the whole (rows, cols) state a freeze
leaves behind
- data.deprecation +cells-batch-set-style and +dim-freeze's legacy
flag pair, under a key of its own rather than
mixed into warnings
- data.upload how +media-upload sent the file
Clean calls keep their exact previous payload shape: every field above is
added only when it has something to report.
Scope is shortcuts/sheets/** on purpose. The remaining success-path stderr in
this domain comes from shared code (the drive export/import core behind
+workbook-export / +workbook-import, the multipart media helper, the auto-grant
helper), which other domains share; cleaning those up belongs to their own
change. The one sheets-owned exception is +workbook-import's extension
correction, which has no slot in the import core's output envelope -- it is
documented at the call site and allowlisted in the guard test.
Tests pin the contract (a successful run leaves stderr empty) and each new
field, plus a source scan that stops new direct ErrOut writes from appearing.
* docs(sheets): point the dropdown option-error warning at data.warnings
The --source-range flag help still told callers the option-error steer arrives
on stderr; it now rides in the result. Mirrors the same edit in the upstream
spec (canonical-spec/spec-tables/flags.json), so the next sync is a no-op.
* fix(sheets): keep export identifiers in +export output, tighten the stderr guard
Review follow-ups on the success-path stderr change:
- +export --output-path lost file_token: on the download branch the token
reached the caller only through the deleted "Export complete: file_token=…"
stderr line, and the payload carried just saved_path and size_bytes. Both
file_token and ticket now ride in the download result, so a caller can
re-download or resume without re-running the export.
- The stderr guard allowlisted a whole file, hiding any future write in it.
It now matches one exact statement in one file and asserts that write still
exists, so both a new write and a stale exception fail the test.
- The contract comments claimed more than the tests prove. They now state
that only sheets-OWNED code is silent, name the three commands whose noise
comes from shared implementations (+workbook-export, +workbook-import,
+media-upload over 20MB), and a new test pins that the shared export core
does still write -- failing, by design, once that core is cleaned up.
* fix(drive): keep the export and import cores off stderr on success
+workbook-export and +workbook-import delegate to drive.RunExport /
drive.RunImport, so the sheets success-path contract could not hold while
those cores narrated every step: task creation, each poll attempt, completion,
"still in progress", and the import's media upload. Callers that read
non-empty stderr as failure saw a finished export report itself as an error.
The stage text is deleted -- ticket, ready, status, file_token, token and
next_command are all already in the payload. What the narration alone carried
moves into the result:
- poll attempts / transient_failures / last_error, added only
when a poll actually had to be retried, so a caller can
tell a clean run from one that limped to the finish
- warnings markdown export falling back to the token as file name
after a failed title lookup
- input_corrections a caller-supplied record of inputs the CLI rewrote
before the request ran; sheets +workbook-import uses it
for a mislabeled .xls that is really an .xlsx, which was
its last stderr write
drive +export / +import get the same treatment, since they share these cores.
Clean runs keep their exact previous payload shape.
With this, the sheets stderr guard needs no allowlist, and the contract test
covers both workbook commands end to end. Two shared paths a sheets caller can
still reach stay noisy and are named in the contract comment: multipart media
upload over 20MB, and the bot-identity auto-grant warning.
* test(sheets): cover the annotation shapes and both guard call sites
Review follow-ups, all test-side except one comment:
- +dim-insert's effective_operation had no test: a regression could drop the
emulated-anchor block and still keep stderr empty. Now asserted field by
field, plus the negative case (--inherit-style after rewrites nothing, so it
must not gain the block).
- The local-office guard's second call site had no test. A /wiki/ URL only
reveals its backing token after get_node runs in Execute, so that branch is
now covered, asserting both the typed rejection and that no export task was
created.
- annotateSheetsResult's three payload shapes are pinned: object annotated in
place, array/scalar preserved under `result`, and an empty tool result left
without an invented `result: null`. The doc comment now spells out that last
case instead of lumping it in with non-object output.
- The export poll summary test asserted transient_failures but not attempts,
so a wrong or missing count would have passed.
* fix: preserve recovery state on failure paths and TTY liveness during polls
Review round 2. Removing the success-path narration also removed information
from paths that fail after remote work has started, and removed the only
liveness signal an interactive user had:
- drive +import / sheets +workbook-import: once the import task exists, the
ticket is the only handle back to it. A poll failure returned bare, so the
ticket -- previously visible through the polling line -- was lost. It now
rides on the typed error together with the +task_result command.
- sheets +export --output-path: a download or save failure happens after the
artifact is ready, so the error now carries ticket, file_token and the
+export-download command; re-running the whole export is not the recovery.
A poll timeout carries the ticket for the same reason.
- sheets +batch-update / +batch-chart-*: batch_update is fail-fast without
rollback, so the ignored-locator and colliding-freeze advisories matter most
exactly when the call fails part-way -- they decide the safe retry set. They
are now attached to the typed error's hint as well as the success payload.
- Bounded polls and the import upload are wrapped in RuntimeContext.StartSpinner,
which is gated on StderrIsTerminal and is a strict no-op for pipes, CI and
captured output. A human terminal gets liveness back; a machine caller's
stderr stays empty (the contract tests, which capture stderr, still pass).
+workbook-export's rejection of Office tokens also stopped assuming the caller
holds the file: a local_office_ / fake_office_ prefix means the workbook is
already on their disk, but an interleaved OFL0X token is a file stored in Lark
that may never have been downloaded, so that class is now pointed at
drive +download (then +workbook-import if they want a Lark spreadsheet).
Each behaviour above has a regression test; httpmock's CapturedBodies doc
comment is corrected, since it is appended on every match, not only for
Reusable stubs.
|
||
|
|
96a975e1de |
fix(slides): relax office token length check from 28 to >=25 (#2531)
* fix(slides): relax office token length check from 28 to >=25 The interleaved "OFL0X" product/region marker is read at fixed positions (1-based 5/10/15/20/25), so a token only has to be long enough to hold it. Pinning the total length to exactly 28 silently reclassified every other length as native. 28 is already stale: per #2509 the local-office format is "OFL0X + 21 random + 1 office type enum" = 27 characters, and sheets relaxed the identical guard to >= 25 in that PR. Slides was missed, so an imported office deck at the current length uploaded with parent_type "slide_file" instead of "office_slide_file". The marker positions are unchanged. Relaxing the length is only safe because of them: a false positive is the dangerous direction, since the drive backend does not validate that parent_node actually names an office file, so a misclassified native deck uploads successfully and only surfaces later as an image that will not render. The interleaved native token cases (same length, different marker) are what keep the floor honest. Tests: replaced two mislabelled rows with five verified ones covering 27, 29, 25, 24 characters and a 28-character token carrying the ppt office type enum. #2509's own labels were off by one or two characters and it never covered the 25/24 boundary; this does. * refactor(common): extract local-office token detection into common The office token shape existed in three identical copies: shortcuts/sheets/helpers.go, shortcuts/sheets/backward, and shortcuts/slides. Every copy is somewhere a format change has to be found again, and that is not hypothetical — #2509 had to apply the same 28-to->=25 relaxation twice inside sheets, and missed slides entirely. Moved the shape to common.IsLocalOfficeToken. It belongs there because recognising a local-office document is a drive-level property, not a per-domain one: an imported office file is an imported office file whether it backs a spreadsheet or a deck. What genuinely differs per domain is the parent_type the answer selects — office_sheet_file vs office_slide_file — so those mappings stay with each domain. The name deliberately matches the vocabulary #2509 already used ("local-office format"). Its doc comment calls out that "local office" is the whole category and not the LocalOfficeTokenPrefix case, since the two now share a word stem while the predicate also accepts FakeOfficeTokenPrefix and the interleaved marker. Only slides is rewired here. The two sheets copies are left alone on purpose to keep this reviewable as a pure no-op for them; they can follow separately. The marker offsets are now an array whose length is tied to the marker string, so adding a character to one without the other stops compiling, and TestOfficeTokenMinLenMatchesMarkerOffsets pins the length floor to one past the last offset rather than letting the two merely agree by coincidence. Behaviour is unchanged, verified by diffing dry-run parent_type between the pre-refactor and post-refactor binaries across 13 tokens covering both prefixes, the 24/25 boundary, 27/28/29 characters, interleaved native pptcn/shtcn markers, a leading-but-misaligned OFL0X, and an off-by-one offset: 13/13 identical. * refactor(sheets): route local-office detection through common Deletes the last two copies of the token shape, both byte-identical to the one now in common: shortcuts/sheets/helpers.go and shortcuts/sheets/backward/lark_sheets_float_images.go. sheetMediaParentType keeps owning the sheets half of the decision — which parent_type the answer selects — and only the shape moves. Equivalence was not assumed from reading. A throwaway fuzz test compared isOfficeSpreadsheet against common.IsLocalOfficeToken in both packages over an alphabet biased toward the characters that can actually disagree (OFL0X plus the native product markers), every single-byte mutation of a known office token at all 28 positions, and 400k fixed-seed random tokens of length 0-33. Zero disagreements in either package. Dry-run parent_type was then diffed binary-to-binary against origin/main across 11 tokens covering the 24/25 boundary, 27/28/29 characters, interleaved native shtcn/pptcn markers, a leading-but-misaligned OFL0X and an off-by-one offset: sheets identical on all 11. Two comment fixes that the extraction made unavoidable: The const-block doc in both files still described "a 28-character token". That was already wrong on main — #2509 relaxed the guard to >= 25 and left the comment behind — and the shape is no longer described here at all now, so both defer to common.IsLocalOfficeToken. Four rows in TestSheetMediaParentType were mislabelled: "25 char, at boundary" held a 27-character token and the three "new 27-char" rows held 28-character ones, so the floor those labels claimed to cover was never tested. Relabelled by measured length, and the real 25/24 boundary added. |
||
|
|
c9adda7b37 |
chore: release v1.0.91 (#2542)
Co-authored-by: lark-cli-external-pr-digest[bot] <305837809+lark-cli-external-pr-digest[bot]@users.noreply.github.com> |
||
|
|
6bbb929c1e |
docs(im): document chat.join_requests in the lark-im skill (#2395)
Add the chat.join_requests resource (list / handle) and its two scope
rows, matching the registry-side whitelist. Both methods are user
identity only and require the caller to be the chat owner or an admin.
The list entry records a pagination trap verified against the live API:
page_token is returned even when has_more is false, so an agent that
pages while page_token is present never terminates. The handle entry
records that results[] mirrors items[] in count and order and that exit
0 does not mean every item succeeded.
Written by hand rather than via gen-skills. skill-template/domains/im.md
last changed in
|
||
|
|
b540fc747d |
docs(drive): address knowledge_base_bootstrap review comments
- outputs: load in OUTLINE_PROPOSE as well (align progressive loading) - entry: narrow pre-write gate to docs +update; allow node-create only after separate outline confirmation - entry: resolve root nodes for bare space targets via wiki +node-list (space root = top-level nodes, empty parent) - entry: triage every non-docx origin node (incl. file); exhaustive classification so no node slips through - outputs/entry: WRITE_CONFIRM shows node_token, command family and exact content/diff before the R2 write - outputs: tag plain-text fences as text (markdownlint MD040) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
ac3efc0bb2 |
docs(drive): add knowledge_base_bootstrap workflow
Register a new lark-drive workflow that authors maintenance standards into an existing Wiki knowledge base: read node tree and drafts, optionally propose and create an outline when the structure is too sparse, then write general standards to the root node and per-node requirements to each sub-node after confirmation. - entry + outputs reference docs (R2/S2), no phase files - node type triage: docx writable, non-docx/shortcut skipped or new_docx - default append (keep drafts), overwrite only placeholders - OUTLINE_PROPOSE state supports root-only knowledge bases - register in workflow registry; route from lark-drive and lark-wiki Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
0d5334a0cd | docs(approval): document keyword search and add-sign flow (#2388) | ||
|
|
b45d4cbb1c | feat: add im message patch meta api (#2407) | ||
|
|
93817909cb |
feat(base): add field extension shortcuts (#2463)
Co-authored-by: yballul-bytedance <273011618+yballul-bytedance@users.noreply.github.com> Co-authored-by: TRAE CLI <traecli@bytedance.com> |
||
|
|
84f9414311 | feat(base): streamline record workflows (#2529) | ||
|
|
1c4f7588dd |
feat(calendar): add +join-event shortcut and share token support (#2508)
* feat(calendar): add +join-event shortcut for joining via share token Add a share-token-only join path so callers cannot forge a plaintext event id, wire it into Shortcuts(), and document the flow in the lark-calendar skill. * docs(calendar): document sharing events via share_info link - Route "share event to person/group" intent to calendar events share_info then lark-im, clarifying the share link is not an applink * fix(im): preserve calendar share token in shortcuts --------- Co-authored-by: 张哲伟 <zhangzhewei@bytedance.com> |
||
|
|
971e639622 |
feat(sheets): relax local-office token length check from 28 to >=25 (#2509)
The local-office token format is changing from 28 to 27 characters per the new rule (OFL0X + 21 random + 1 office type enum). Relax the guard from to so 27-char tokens can reach the OFL0X interleaved marker check. All legacy detection paths (fake_office_ prefix, local_office_ prefix, OFL0X marker) are preserved unchanged. |
||
|
|
d0158ab289 |
fix(docs): recover PowerShell-dequoted presentation JSON (#2501)
* fix(docs): recover PowerShell-dequoted presentation JSON * fix(docs): recover quoted-key shell JSON |
||
|
|
0f9553385c |
feat(im): add chat AppLink output (#2491)
Add chat AppLink fields to IM chat outputs and update lark-im guidance to prefer CLI-provided links. |
||
|
|
c8f06cd167 | chore: release v1.0.90 (#2503) v1.0.90 | ||
|
|
8493800ebf | feat(config): support keychain-backed tenant access tokens (#2488) | ||
|
|
36c7291cc1 |
fix(auth): exclude im:message.send_as_user from batch scope sets (#2471)
* fix(auth): exclude im:message.send_as_user from batch scope sets * test(auth): isolate requested-scope cache in batch-exclusion test * fix(auth): validate --exclude against pre-filter scope universe The batch-exclusion filter dropped im:message.send_as_user before --exclude was validated, so `--domain im --exclude im:message.send_as_user` returned invalid_argument and never sent the device authorization request. That broke automations relying on --exclude to skip the send-as-user approval. Validate --exclude against the selected universe (post recommend/common filter, pre batch exclusion) plus --scope; the wire request still uses the batch-filtered effective scopes. Excluding a batch-withheld scope is now a valid no-op, while excluding a scope outside the selection still errors so typos are not widened. * test(auth): assert exact scope membership in exclude regression test |
||
|
|
083f0f4719 | feat(drive): support appid in member-remove (#2499) | ||
|
|
6952d3aa7f |
feat(extension): add business command extension v1 (#2308)
* feat(shortcuts): import typed shortcut framework from |
||
|
|
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 |
||
|
|
62f270afd6 | fix(skills): scope markdown routing to Lark resources (#2497) | ||
|
|
faa2f8d3e0 | fix(docs): continue media downloads on permission scope errors (#2498) | ||
|
|
36cd24aa73 |
fix(slides): avoid PID variable in examples (#2496)
Replace `$PID` with `$PRES_ID` in Slides Skill examples to avoid conflicts with PowerShell’s read-only `$PID` variable. This only updates embedded Skill documentation. CLI flags, API fields, runtime behavior, and historical Skills remain unchanged. Validation: - Skill format check passed - Quality gate passed |
||
|
|
f09414f9d5 | fix(wiki): keep node-get stderr machine-readable (#2449) | ||
|
|
aec659c461 | feat: words replace and minutes fix (#2490) | ||
|
|
e668fff669 | fix(drive): continue downloads on permission scope errors (#2494) | ||
|
|
a06d87333d |
feat(slides): add marginRight attribute to <p> element schema (#2493)
Add marginRight property to the paragraph element in slides XML schema definition, matching the existing marginLeft attribute to support right-side paragraph indentation. This resolves the xml_lint error "unsupported SXSD attribute "marginRight" on <p>". |
||
|
|
1d24a39659 |
fix(slides): strip stale <note> id in +update-slide to avoid backend crash (#2475)
* fix(slides): strip stale <note> id in +update-slide to avoid backend crash
A +update-slide carrying a <note id="..."> that is not the page's current
note block makes RewriteSlideBySXSD reject the whole page with
"block is not NoteBlock". This happens when the XML is copied from another
page, or written over a page that was re-created (add-slide reassigns ids,
so the note block's id no longer matches).
Drop only the <note> id before sending. The backend then targets the page's
own note block and the write succeeds. Every visible element keeps its id,
so it is updated in place rather than rebuilt — text layout is preserved and
there is no risk to svg-internal id references.
* fix(slides): strip single-quoted and spaced note id too
The note-id strip only matched id="...". A single-quoted or spaced form
(id='...', id = "...") slipped through. Both are valid XML, and the backend
accepts single-quoted markup — verified on ppe: an all-single-quote page
updates fine, and a single-quoted stale note id reproduces the exact
"block is not NoteBlock" crash this strip is meant to prevent, while the
double-quoted equivalent is stripped and succeeds.
Widen the regex to `\s+id\s*=\s*("[^"]*"|'[^']*')` so any quote style and
whitespace around '=' are covered. Still a targeted edit on the <note> tag,
not a re-serialization, so the caller's bytes are otherwise preserved.
Add regression cases: single quotes, whitespace around '=', single-quote
attribute order, and a single-quoted visible-element id left untouched.
Addresses CodeRabbit review on #2475.
* test(slides): assert the note id attribute is removed, not just a value
The strip tests checked that a specific id value ("blw") disappeared, which
would also pass if the implementation swapped the id for another value.
Assert on the <note> opening tag carrying no id attribute at all (any quote
style / spacing) via a noteTagHasID helper, so the removal itself is verified.
Addresses CodeRabbit review on #2475.
* fix(slides): locate the <note> tag with the XML tokenizer before stripping id
The raw regex parsed XML as plain text, so it could miss or mis-edit valid
input: an id after an attribute whose value contains '>', and note-like text
inside comments or CDATA. It also had no notion of where the note sat in the
tree.
Walk the document with encoding/xml to find the start tag of the <note> that
is a direct child of the root <slide>, then delete the id attribute by editing
only that tag's bytes. Nothing is re-serialized, so quote style, attribute
order, whitespace, and every other element (notably inline <svg> namespaces,
whose round-tripping is a known source of "embed missing inner svg") survive
untouched — the same byte-preservation contract ensureXMLRootID keeps.
This covers the cases the regex could not: '>' in an attribute value, and
comment/CDATA text that merely looks like a <note>; and it scopes the edit to
the slide-level note only. Regression cases added for each.
Addresses CodeRabbit review on #2475.
* test(slides): assert everything but the note id survives byte-for-byte
Existing tests spot-checked that individual elements survived. Add exact-equality
cases asserting the output equals the input with only the one note id removed —
proving nothing else moves: inline svg subtrees, CDATA, a '>'-bearing attribute,
quote style, attribute order, and whitespace all stay verbatim.
Addresses CodeRabbit review on #2475.
* style: gofmt slides_update_slide.go
* test(slides): cover numeric char refs — InputOffset must not drift the note span
|
||
|
|
35bd5ecfcd |
feat(vc): add agent meeting control shortcuts (#2466)
* feat(vc): add agent calendar meeting actions * feat(vc): add meeting screenshot shortcut for visual context * feat(vc): add meeting countdown commands and events * fix(skills): avoid screenshot recall from meeting description * fix(vc): omit screenshot log ID on success --------- Co-authored-by: renaocheng <renaocheng@bytedance.com> Co-authored-by: shike.11 <shike.11@bytedance.com> |
||
|
|
0679884761 | fix(base): hide dashboard auto analysis setting (#2465) | ||
|
|
7874dc144b | feat(slides): add media download shortcut (#2446) | ||
|
|
8ebdc3f193 |
feat(slides): un-deprecate +replace-pages shortcut (#2470)
Remove deprecation markers from +replace-pages: the command is now a supported shortcut again, not a deprecated compatibility shim. Delete the deprecation-note constant and the "deprecated" output field from dry-run, validate-only, and real-run envelopes, update the command description and comments, and remove the deprecation-specific test. |
||
|
|
e0e90a4e1b |
fix(apps): classify the online DDL ban and the file storage quota failure (#2460)
* fix(apps): classify the online DDL/DCL ban on +db-execute
Running DDL against the online branch of a multi-env app came back as
api/server_error with exit 1, hinted "fix the SQL and re-run", and carried a
statement position that did not exist. All three point the caller the wrong way:
- server_error means "upstream 5xx, retryable"; this is a product rule and no
number of retries changes it;
- the SQL is fine — the target environment is what has to change;
- "(at statement 1 of 1)" is fabricated. The server pre-validates the whole
batch and returns a single ERROR sentinel, so a 5-statement request with the
DDL in position 4 still rendered as "1 of 1". The CLI does not split the SQL,
so it cannot know the real count and cannot detect the mismatch generally —
only codes known to be batch-level rejections can drop the suffix.
Give code 4000001 its own arm: validation/failed_precondition (exit 2, "change
the environment, do not retry"), a hint pointing at dev plus +db-env-migrate, and
no statement position. Every other code keeps its current classification, wording
and position suffix; a test pins that.
4000001 is a dedicated server-side code (ErrOnlineEnvForbidDDLDCL, client-error
band), raised only by the pre-validation pass when env==online on a multi-env
workspace. Syntax errors and PG errors use different codes, so keying on it is
safe. Matching on the numeric value also covers the "k_dl_4000001" wire form,
since codeString already strips that prefix — both forms are tested.
"No statements were applied" is stated rather than inferred here: the validator
walks every statement and rejects the batch on the first DDL, so nothing lands.
The default arm would have inferred the opposite for a DDL in a later position
("Earlier statements were committed"), which is wrong for this code.
* fix(apps): classify tenant file storage quota exceeded
+file-upload against a tenant whose file storage is full returned api/unknown with
no hint at all, so a caller could not tell "the quota is full, stop" from "the
upstream had a bad minute, retry" — and had no next step either.
Register 400000055 as api/quota_exceeded. That is a dedicated server-side code
(ErrTenantStorageQuotaExceeded, client-error band) raised only on the upload path,
and the subtype already carries "retrying will not help", so the framework's
existing quota wording is enough and no domain-specific hint is added.
Left in CategoryAPI (exit 1) rather than Validation (exit 2): a full quota is not
something a different argument fixes, and exit 2 would imply it is.
The test asserts the hint is non-empty on purpose. The wording comes from the
shared APIHint table, so if quota_exceeded is ever dropped from there this fails
and says the code now needs its own wording, instead of silently shipping an
empty hint.
|
||
|
|
1f53f6e2f5 |
refactor(slides): assert dry-run parent_type instead of deriving it from a placeholder (#2461)
* refactor(slides): assert dry-run parent_type instead of deriving it from a placeholder A wiki --presentation cannot be resolved during a dry-run: the real presentation token only exists after a get_node call a preview must not make, so parent_node shows a "<resolved_slides_token>" placeholder. appendSlidesUploadDryRun derived parent_type from parent_node, which sent that placeholder through the office-token check. The value it produced was correct. A placeholder matches no office token shape, so it fell through to slide_file, and slide_file is right here: a wiki ref that reaches an upload is native by construction, because resolvePresentationID rejects any wiki node whose obj_type is not "slides" and an imported office deck sits in drive as a "file" node. It was correct by accident, though, which left the preview hostage to the placeholder's spelling and to every rule later added to isOfficePresentation. Pass parent_type in explicitly instead, so slidesDryRunParentType states the wiki case as a decision with its reason recorded, and the placeholder is never classified. No behaviour change: dry-run output is byte-identical for native tokens, imported office tokens, legacy office prefixes, slides URLs, wiki URLs, and +create, across +media-upload / +add-slide / +update-slide. Tests pin the contract the refactor protects, including a wiki ref whose node token is itself office-shaped -- a wiki node token and the deck token it points at are different tokens in different namespaces, so classifying ref.Token would be wrong for a wiki ref even though it is right for every other kind. That is the regression this makes impossible. * test(slides): use the fixture hostname for the wiki dry-run probes domaincontract rejects "bytedance.larkoffice.com": it is in neither allowlist, and a real tenant host does not belong in a fixture. Use example.feishu.cn, already in fixture-domains.txt and the hostname the rest of the slides wiki tests use. The URL is only a parse fixture -- nothing resolves it -- so only the hostname changes. |
||
|
|
b624948e48 |
Support repeated mail compose flags (#2271)
* feat: support repeated mail compose flags * fix(mail): address review feedback for repeatable inline flags Change-Type: ci-fix * test(mail): cover inline validation and upload assertions Change-Type: ci-fix * test(mail): assert inline validation category Change-Type: ci-fix * fix(mail): preserve inline compatibility cases * test(mail): strengthen inline compatibility coverage * docs(mail): prefer one repeatable flag form * docs(mail): keep skill references unchanged * docs(mail): drop skill reference edits * docs(mail): document repeatable mail flags consistently * docs(mail): standardize quoted flag examples * docs(mail): keep inline flag constraints in help * fix(mail): validate template inline cids * fix(mail): preserve recipient names and validate template cids * fix(mail): support repeated recipient parsing Normalize repeated recipient values through ParseMailboxList for every flag occurrence so legacy comma lists still split, quoted display-name commas stay intact, and Unicode display names remain raw before final header rendering. Local check: gofmt -l shortcuts/mail/helpers.go shortcuts/mail/mail_repeatable_flags_test.go * fix(mail): scope template inline update validation --------- Co-authored-by: bubbmon233 <272202079+bubbmon233@users.noreply.github.com> |
||
|
|
33cfa46a8f |
feat(base): document app default page reuse (#2436)
Co-authored-by: yballul-bytedance <273011618+yballul-bytedance@users.noreply.github.com> |
||
|
|
56ad837c3d | feat: event organizer transfer bot to user (#2448) | ||
|
|
423e81fcc6 | chore: release v1.0.89 (#2447) v1.0.89 | ||
|
|
52f970f23e | refactor(shortcuts): remove MCP text location paths (#2439) | ||
|
|
fbd1aa49cd | feat: add IM read status shortcuts (#2318) | ||
|
|
b343e67639 |
feat(slides): use office_slide_file parent_type for imported office presentations (#2441)
Image uploads to a presentation hard-coded parent_type=slide_file at every
entry point. Imported "office" presentations carry either a legacy synthetic
token prefix ("fake_office_" / "local_office_") or a 28-character token whose
interleaved product/region marker is "OFL0X", and for those the drive backend
requires parent_type=office_slide_file. This mirrors the office_sheet_file rule
the sheets domain already applies: the token shapes are identical, because an
imported office file is an imported office file whether it backs a spreadsheet
or a deck.
Funnel the selection through one slides-domain helper so the rule lives in a
single place and every image-upload path stays consistent with its own dry-run
preview. As in sheets, the rule stays inside the domain rather than leaking
into common.UploadDriveMediaAllTyped, which mail/doc/drive/base/calendar share.
- Replace the slidesMediaParentType const with slidesMediaParentType(token),
backed by isOfficePresentation(token); keep the native and office values as
named constants.
- Route both parent_type call sites through it: uploadSlidesMedia (the Execute
path shared by +media-upload and the <img src="@path"> placeholder pipeline
behind +create / +add-slide / +update-slide) and appendSlidesUploadDryRun.
- Known gap, documented at the helper: when --presentation is a wiki URL the
dry-run only has a "<resolved_slides_token>" placeholder, since the real
token needs a get_node call the preview must not make, so such a preview
shows slide_file regardless. Execute is unaffected -- it resolves first.
The negative half of the mapping is what the tests weight most heavily. The
backend does not validate parent_node against parent_type, so a native deck
misread as office still uploads successfully and only surfaces later as an
image that will not render, far from its cause; the marker check is therefore
pinned at its exact length and offsets rather than a looser "contains OFL0X".
Tests:
- shortcuts/slides/slides_media_parent_type_test.go: 14-case pure-function
table (off-by-one length, prefix appearing mid-string, wiki placeholder),
a real-multipart Execute assertion across four token shapes, and the
+add-slide / +update-slide placeholder dry-run previews.
- tests/cli_e2e/slides/slides_image_upload_dryrun_test.go: five cases through
the built binary, covering every surface a local file can enter through.
- Verified non-vacuous: short-circuiting the office branch fails all three
package tests plus the e2e lane.
Evidence note: office_slide_file is confirmed accepted by upload_all, and the
symmetry with office_sheet_file is exact, but this has not been exercised
against a real imported-pptx presentation to confirm slide_file fails there.
|
||
|
|
cc015bac28 | feat(skills): extend slides XML schema (#2442) | ||
|
|
79b8647196 |
feat(base): add template discovery and form question field reuse (#2340)
Co-authored-by: yballul-bytedance <273011618+yballul-bytedance@users.noreply.github.com> Co-authored-by: TRAE CLI <noreply@bytedance.com> |
||
|
|
42060154dd | feat(base): support button workflow bindings (#2437) | ||
|
|
e525beb8d6 |
feat(skills): unify meeting related skills (#2387)
* feat(skills): unify meeting guidance * fix(meeting): restore domain boundary guidance * docs(meeting): remove agent rollout qualification guidance * docs(meeting): front-load skill routing description * docs(meeting): refine identity and command guidance * docs(meeting): clarify identity and pagination guidance * docs(meeting): fix minutes todo detail command * fix(meeting): clarify artifact query routing * fix(meeting): improve live meeting skill recall * fix(qualitygate): generate valid minute token placeholders * fix(meeting): address unified skill review findings * docs(meeting): add minutes permission guidance * docs(lark-meeting): 更新SKILL.md并新增会议问答引导脚本 1. 优化SKILL.md表格排版与快速行动章节内容,新增批量获取当日会议脚本的使用说明 2. 新增meeting_qa_bootstrap.py脚本,实现一站式采集当日进行中、已结束会议及未来日程,生成可直接执行的命令引导 * docs(calendar): clarify today's meeting lookup * revert(meeting): remove meeting Q&A bootstrap guidance * fix(skills): register lark-meeting suite keywords --------- Co-authored-by: maozhixiang <maozhixiang@bytedance.com> |