mirror of
https://github.com/larksuite/cli.git
synced 2026-09-14 18:42:53 +08:00
fix-chart-layout-data-source-check-cli
1096 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
6c9126e8de | fix(sheets): validate chart data sources in layout check | ||
|
|
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> |
||
|
|
da371dc242 |
feat(base): add dashboard and form share shortcuts (#2282)
- preserve explicit false values and validate partial share updates - add dry-run and deployment-gated live E2E coverage - document share routing in the bundled Base skill |
||
|
|
bbcdf65110 | test(drive): retry transient async cleanup contention (#2397) | ||
|
|
f28a418019 |
feat(base): add --position and statistics number_format to dashboard-block create/update (#2118)
* feat(base): add --position and statistics number_format to dashboard-block create/update
Add an optional top-level --position flag ({x,y,w,h} JSON, parsed but not
coordinate-validated, passed through as a sibling of name/type/data_config) and
optional statistics data_config.number_format ({formatName,precision}) with
light enum + 0-9 integer validation. Both are backward compatible. Body
assembly is unified in a shared buildDashboardBlockBody helper so DryRun and
Execute stay isomorphic. Adds toIntStrict for strict precision parsing, focused
helper/execute/dry-run tests, an E2E dry-run test, and syncs the lark-base
dashboard + data-config skill references.
Co-authored-by: TRAE CLI <noreply@bytedance.com>
* fix(base): validate number_format on update path and add symmetry tests
The dashboard-block-update command parsed data_config but never ran the
statistics number_format check, so an illegal formatName/precision slipped
through locally while create rejected it — violating the SSOT + backend-design
§4.5 promise of CLI-side interception on BOTH paths. Update has no --type flag
(block type is immutable) and intentionally skips strong type validation, so it
now reuses the shared validateNumberFormat sub-validator that
validateBlockDataConfig delegates to, keeping create/update symmetric without
demanding table_name/series on a number_format-only update.
Also: add tests for the --no-validate bypass on create+update, a combined
update carrying position + number_format + name, and extend the DryRun/Execute
body isomorphism assertion to the update path. Clarify the --position flag Desc
that coordinate bounds are advisory (not validated locally or server-side) and
sync the lark-base SKILL.md routing table for --position / number_format.
Co-authored-by: TRAE CLI <noreply@bytedance.com>
* fix(base): align dashboard block validation paths
Validate dashboard block JSON consistently across dry-run and execute paths, enforce statistics number_format boundaries, and add layout precision workflow coverage and documentation.
* fix(base): resolve dashboard layout doc contradictions and harden isomorphism test
Follow-up to the --position / number_format feature, addressing review findings.
Docs (SSOT contradictions):
- SKILL.md:135 and lark-base-dashboard.md still told agents that dashboard
shortcuts cannot set x/y/w/h and to offer auto-layout instead, which would
have left --position unreachable through the skill. Both statements are now
scoped to +dashboard-arrange, which genuinely cannot take coordinates.
- number_format was documented as supporting sub-field merge on update. That
contradicts the update Tips and lark-base-dashboard.md's own data_config
rule ("每个传入的字段内部是全量替换"). Documented as whole-key replacement
and made the update Tip example carry formatName back.
- Trimmed both reference sections: dropped the duplicated field table, the
restated validation blockquote, the standalone bash example and the 4-column
comparison table; kept the enum table and the two load-bearing gotchas.
Reformatted the example to the file's multi-line JSON style, and generalized
the 场景 3 --position argument to '{...}' like its neighbours.
Tests:
- The isomorphism check called buildDashboardBlockBody twice with the same
arguments, so it could never fail. Replaced with an end-to-end comparison of
the --dry-run preview body against the body captured from Execute; verified
it fails under single-path fault injection.
- The live workflow now updates to values distinct from the create call and
asserts them on read-back, instead of asserting substrings that the created
state already satisfied. Dropped the position read-back assertion: this
iteration does not contract get to echo coordinates.
- Filled in the two missing --no-validate cells (create data-config, update
position).
Cleanup:
- Deleted the inline DryRun closures; both commands now point at the
dryRunDashboardBlock* functions, matching the DryRun: dryRunX convention used
across the package and removing the second body-assembly site.
- Rewrote the update comment that referenced review-round codenames and an
external design doc section to be self-contained.
* fix(base): keep dashboard dry-run previews free of empty identifiers
Wiring the block create/update commands to the shared dryRunDashboardBlock*
functions routed them through dryRunDashboardBase, which Set all three
identifiers unconditionally. A create preview has no block_id yet, so it began
advertising "block_id": "" — an argument that reads as failed to resolve.
Skip empty values in the shared helper rather than special-casing create, which
also clears the same pre-existing noise from the +dashboard-arrange preview.
Pinned with a test asserting a create preview carries base_token and
dashboard_id and no block_id.
* fix(base): require complete --position objects and close the arrange/position gap
Round-2 review follow-up. Three findings, all one-liners in effect, that
compounded into a real failure mode: an agent told to "move this chart to the
right half" could send a partial position, have it accepted, and silently
resize the block to nothing — with no coordinate read-back to diagnose it.
- --position now requires all four of x/y/w/h. The server fills missing
coordinates with zero rather than leaving them alone, so a partial object is
a resize disguised as a move. Only the object's shape is checked; coordinate
VALUES stay unvalidated (out-of-range, negative and overlapping still pass
through) as documented. The check is semantic, so --no-validate skips it
while the JSON parse still runs — the same split the rest of this command
pair already uses. Rejected the alternative of validating ranges too: that
would contradict the documented dws-aligned pass-through contract.
- +dashboard-arrange's Tips now point at --position. The cross-reference was
one-directional: create/update told agents about arrange, but arrange — the
command an agent reaches for first when asked to "fix the layout" — never
mentioned that exact placement had become possible.
- Documented that coordinates are write-only this iteration. The reference doc
offered "replicate an existing dashboard's layout" as a use case while the
PR itself scopes out coordinate read-back, sending agents to look for x/y/w/h
that get/list do not return.
Also from the same review:
- The dry-run builders no longer discard buildDashboardBlockBody's error. It is
unreachable while Validate parses the same flags first, but returning nil
makes the runner fail loudly instead of previewing a body with a field
silently missing.
- Added precision cases that run through the real command. The existing
table-driven ones decode with UseNumber and hit toIntStrict's json.Number
branch, which production never takes — parseJSONObject uses a plain
json.Unmarshal, so precision always arrives as float64.
- coverage.md now says which four commands rest solely on the credential-gated
live test that has not been executed yet.
- Marked the number_format fallback claim as unverified against the backend.
* fix(base): close the position guard's null hole and the contract drift it left behind
Round-3 review follow-up. Two of these were introduced by the previous
follow-up commit, not by the original feature.
- The --position completeness guard only asked whether the key was present,
and a JSON null key IS present. `{"x":6,"y":null,"w":null,"h":null}` sailed
through the very check meant to stop it — the exact scenario the guard's own
comment describes. Each coordinate must now actually decode as a number, so
null, strings, objects and bools are rejected alongside missing keys. This is
still a shape check: out-of-range, negative and fractional values keep
passing through as documented. The package's neighbours (`cfg["text"].(string)`,
`table_name`) already validate required fields with a type assertion; this
was the one place that did not. Mutation-verified: reverting the assertion
turns the explicit-nulls case red.
- coverage.md claimed `+dashboard-block-get` "reads back position" while the
test it cites deliberately stopped asserting coordinates — a line the
previous commit invalidated and did not update. It now says number_format
only. The `+dashboard-block-update` row also claimed dry-run coverage for
number_format that only the unexecuted live test provides.
- dashboard-block-data-config.md still said the update path does no local
validation, which commit bb7d8fbc made false in this same PR. An agent
reading it would not expect exit 2 and might reach for --no-validate, which
now also disables the position guard.
Also from that review:
- --no-validate's flag Desc only mentioned data_config; it silently covers the
--position check too. Said so, in both commands.
- Four places stated unverified backend behaviour as fact — including a claim
that the server zeroes missing coordinates, which was the guard's entire
premise, and a "backend defaults to digital" line 23 lines above a blockquote
saying that very fallback was unverified. All reworded to what is actually
known; the guard's rationale is now stated in terms of the request we send.
- E2E dry-run assertions were whole-output substring matches (`"w": 6` could
match anywhere); switched to clie2e.DryRunGet path assertions like the
sibling suites, which also lets them prove position is a top-level sibling
rather than nested in data_config.
- Documented that formatName is case-sensitive, unlike rollup which is
normalized — same object, two conventions, worth saying out loud.
- The --position canonical rewrite's comment claimed it kept Validate/DryRun/
Execute consistent; they re-parse anyway. Its real job is folding @file input
inline so the two paths cannot read a changed file. Comment now says that.
- Named buildDashboardBlockBody's bool at the call sites; covered all three
branches of the identifier skip, not just block_id.
* fix(base): stop dry-run previews leaking route templates; finish the unverified-claim sweep
Round-4 review follow-up. Both findings trace back to earlier follow-up commits
rather than the original feature, and both are the same failure shape: fixing
the instance instead of the class.
- 68bdaccd made dryRunDashboardBase skip empty identifiers, but Set() doubles as
the substitution source for :param placeholders in the URL. Skipping a
declared-but-empty identifier therefore printed the raw route template —
`.../blocks/:block_id` — while also removing `"block_id": ""`, the one signal
that told the caller their argument was empty. An agent whose `$BLOCK_ID` did
not expand would see a preview that looks like the CLI failed to substitute,
with nothing pointing at the real cause. The condition is now whether the
command declares the flag, which is what the comment claimed all along: create
genuinely has no block-id, and that is the case worth omitting.
Not fixed here: a declared-but-empty required identifier still reaches the
wire as a request to the collection endpoint (`baseV3Path` drops empty
segments). That predates this PR and spans the whole base package — worth its
own change rather than guarding two commands and leaving nine inconsistent.
- The isomorphism test only compared bodies, so a preview could target a
different endpoint than Execute and still pass. It now compares method and URL
as well, and rejects any leftover ":" placeholder — that is the mechanism that
would have caught the above.
- 82f72540's message claimed all four unverified backend statements had been
reworded; five survived, three of them in `--help`, where the --position Desc
said server-side acceptance was unverified two lines above a Tip asserting
overlaps are not server-checked. All five now match the wording already used
in lark-base-dashboard.md, and the PR body Summary no longer contradicts its
own Known limitations.
The rejected-alternative for the first item: guarding empty required identifiers
in Validate would be the root-cause fix, but applying it to the two commands
this PR owns while nine sibling dashboard commands keep the old behaviour trades
one inconsistency for another.
* fix(base): stabilize dashboard block validation inputs
* docs(base): clarify precise dashboard layout workflow
* docs(base): align dashboard live coverage status
* docs(base): soften absolute dashboard layout phrasing in skill
Replace "run exactly once / stop" wording for +dashboard-arrange and
--position with intent-based guidance (prefer whole-dashboard arrange,
generally no need to re-read position) so the skill routes agents away
from per-block churn and useless retries without forbidding legitimate
user-driven follow-up adjustments.
Co-authored-by: TRAE CLI <traecli@bytedance.com>
* docs(base): clarify dashboard layout guidance
* docs(skills): move dashboard layout guidance to reference
* docs(base): verify dashboard number format defaults
---------
Co-authored-by: wanglei.75 <wanglei.75@bytedance.com>
Co-authored-by: TRAE CLI <noreply@bytedance.com>
Co-authored-by: TRAE CLI <traecli@bytedance.com>
|
||
|
|
ca35f60616 |
fix(apps): make cache-clear ask first, and make apps failures classifiable (#2415)
* docs(skills): require explicit confirmation before apps +cache-clear
Asked to clear an app's online cache, an agent read `Risk: high-risk-write` from
--help and then supplied `--yes` itself on the first call, wiping production
cache without ever hitting the confirmation gate.
The CLI gate is fine: no --yes -> exit 10 confirmation_required, and --dry-run ->
exit 0 without triggering it. The wording was not. It only forbade appending
`--yes` *after* an exit-10, and said "已明确授权可直接带 --yes" without defining
authorization — so "clear my cache" read as authorization.
- `+cache-clear` gets a CAUTION block: never self-supply `--yes` on the first
call; without confirmation, either --dry-run or ask, then stop and wait. exit
10 is not a signal to retry with --yes.
- Add a zero-ambiguity table separating a *request* to clear ("clear the online
cache") from a *confirmation* ("我确认清 dev"), so blocking the accidental wipe
does not also kill the cases that were already correct: an explicit
confirmation still goes straight to `--yes`, and a request with no environment
named still has to ask instead of picking one.
- Note that online needs a confirmation phrase even when named explicitly.
`+cache-delete` gains the response field an agent has to read
(`deleted_key_count`): 0 means the key never existed, not "deleted
successfully", plus the get -> delete -> get chain needed to prove a delete took
effect — a single miss afterwards cannot tell the two apart.
SKILL.md: add +cache-clear to 禁止预授权判定底线, the one list a pre-authorized
run cannot skip; a reference-level rule alone would be bypassed there. The
routing table is left alone — no other row annotates risk, including
+file-delete, +role-delete and +member-remove.
* fix(apps): stop attaching request-shaped hints to precondition failures
`+db-execute` against a tenant that never activated Miaoda returns code 221800
"miaoda UAT not activated" with the hint "verify table/column names with
`+db-table-get` ... target the dev database with --environment dev". Neither step
can help: the failure is tenant-level, so a caller following the hint loops over
table lookups and env retries that fail identically.
Two causes. 221800 was unregistered, so it degraded to api/unknown — nothing in
the envelope distinguished "your tenant is not activated, stop" from "your SQL
was wrong, fix it and retry". And withAppsHint filled the caller's hint whenever
the server sent none, without looking at what failed: the hints are
command-scoped ("verify --app-id", "verify table/column names", "list releases"),
so every one of them describes the request, and the request is exactly what
failed_precondition says was fine.
Register 221800 as validation/failed_precondition (same shape as 400002465 "app
has no database yet") and gate the hint fallback on the subtype.
Blast radius is two codes, since that is all the subtype covers here:
- 221800 — now withheld; message and code still carry the meaning.
- 400002655 "no running container" — only when it reaches a non-observability
command; the observability pair rewrites it first, and "verify --app-id" was
never the fix for an undeployed app.
400002465 / 500002759 are intercepted by the isAppNoDatabaseError branch above
the gate, and 400002479 is served by withDBSyncHint, which does not delegate
here. The other 78 call sites take the original path for every input.
Gate on the one subtype, not on Category: this package asserts on purpose that an
authentication failure on +role-list (99991663) keeps the app-access hint and a
503 on credential issuance keeps the developer-access hint. Those hints are broad
enough to survive a caller-standing failure; only the precondition class is
misdescribed by construction. A test pins that, so widening the gate to Category
fails loudly instead of silently dropping those hints.
The gate is asserted on the real classification path (BuildAPIError -> the code
table -> withAppsHint), not only on a hand-built Problem. Constructing
SubtypeFailedPrecondition directly feeds the gate the input it wants and passes
whether or not 221800 is registered, so the registration itself has to be part of
what the test covers.
No recovery hint for 221800 — the activation path is a product procedure, and
guessing one is what made this failure misleading in the first place.
* fix(apps): classify file-storage and app-level failures
Five Spark business codes reached the CLI unregistered, so every one of them came
out as api/unknown with exit 1: a caller could not tell "your app id is wrong"
from "you lack permission" from "the upstream is having a bad minute", and the
exit code offered no way to branch either.
400002484 app not found -> validation/invalid_argument exit 2
400002467 no admin/developer perm -> authorization/permission_denied exit 3
500002761 ditto, pre-4xx renumber -> same
400000034 file not found/no access -> api/not_found exit 1
500000034 ditto, pre-4xx renumber -> same
400002467 is not file-specific: db commands (+db-table-list, +db-table-get,
+db-quota-get, +db-changelog-list) return it for an app the caller cannot access,
so registering it fixes both domains at once.
400002484 covers a well-formed id that does not exist AND a malformed one
("notanappid", "app_1" return it too), so the argument itself is the failure ->
invalid_argument, whose exit 2 separates "you passed the wrong id" from an
upstream fault. Environments that have not picked it up answer with 400002465
instead, conflating it with "app has no database yet"; the CLI cannot tell those
apart on the old code, so nothing here keys on that.
Both the current and the pre-4xx number are registered for each file failure.
The domain is moving its client-class errors from the 5xxxxxxxx band into
4xxxxxxxx, rolled out per environment, so both are live at once and dropping the
old one would silently return the un-migrated half to api/unknown — the same trap
that made the no-database recovery flow disappear when the server renumbered it
(see appNoDatabaseCode). The new number is not derivable from the old either:
500002761 became 400002467, tail digits included.
No hints added: permission_denied already has framework recovery wording, and a
domain-specific one would have to invent a remedy.
|
||
|
|
755daa4de3 | feat: add minutes transcript degradation logic (#2404) | ||
|
|
de45ec61e6 | fix: honor recovered E2E retries (#2400) | ||
|
|
2829ecd188 | chore: release v1.0.88 (#2394) v1.0.88 | ||
|
|
e0867e6ebb | feat: support separate and suite skill layouts (#2211) | ||
|
|
679ebd5289 | fix(api): reject query strings and fragments in paths (#2375) | ||
|
|
9b231d9825 |
fix(base): improve record history output and validation (#2298)
* fix(base): make record history queries explicit and readable
1. Require an explicit confirmed record ID and document deterministic record resolution
2. Add shared-format pretty history output and projection aliases without changing default JSON
3. Reject explicitly non-positive history cursors and cover request, help, formatting,
and dry-run behavior
```ai-signature
改动范围: 将 Codebase MR 1438 的最终十文件差异移植到 GitHub PR 2298,覆盖 record history 命令、record list 投影别名、Base 引导文档与对应单元及 dry-run 回归测试
思考过程: 以 GitHub 最新 main 为基线执行三方内容合并,保留 GitHub 独立演进;删除原 PR 针对 base_history_003 的 Skill 改动,并仅按 GitHub 当前分母重算 coverage 指标
改动原因: GitHub PR 原先承载的是已确认应撤回的单题文档方案,需要由已评审的 MR 1438 最终通用实现完整替换,同时避免复制 Codebase 的多轮提交与 revert 历史
Break Change: 行为 breaking | record history 要求显式确认的 record ID,且显式非正 --max-version 现在返回 typed validation error
```
Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
AI-SHA256: 5bf66267670f435c7d577d2444b61b209322eb5a73f15e47e671a5b8dd2603bf
* fix(base): validate history cursors and NDJSON dry runs
1. Reject missing or invalid next_max_version values before emitting pagination guidance
2. Use the execution page size in NDJSON dry runs and assert the requested output path
3. Cover valid and invalid history cursors and prove a 2000-row request is capped to a 500-row first
page
```ai-signature
改动范围: shortcuts/base/record_history_list.go、record_ops.go 及邻近单元和 dry-run E2E 测试,仅处理 PR 2298 中有效 CodeRabbit 评论,不新增 live E2E 或修改主 Skill
思考过程: 分页提示只接受解码后的正整数游标;NDJSON dry-run 复用执行阶段的五百行页大小,并以两千行请求验证真实截断而非相等值偶然通过,同时直接断言导出路径契约
改动原因: 原实现可能把不可用的服务端游标打印成命令,同时 dry-run 对 201 到 500 条请求报告的首屏大小与真实执行不一致,初版测试也未真正证明五百行上限或 search 输出路径
Break Change: 否
```
Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
AI-SHA256: a362c47d739d6de5676b87431fbc015d1eaa3d47d46d711e2535baa4dad7ffce
* docs(base): simplify record history prerequisites
1. Condense the record history prerequisites into generic record selection rules.
2. Remove the positive and negative examples from the reference.
```ai-signature
改动范围: 仅修改 skills/lark-base/references/lark-base-record-history-list.md,精简使用前置并删除正反例章节。
思考过程: 保留调用前确认同表 record_id、不得自行选择记录或扩展整表扫描的核心约束,移除具体链接、视图位置和命令示例以提升通用性。
改动原因: 用户要求使用前置更精简、表述更通用,并删除正反例;本次不涉及命令行为或测试。
Break Change: 否
```
Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
AI-SHA256: 7e69951d47c1535cd5fe0fa9ebd7018af2e17373e5851c229dac46d68eaefa84
* fix(base): align history guidance with affordance
* fix(base): keep history guidance in the existing reference
1. Remove the new Base affordance file and its Markdown-only tests
2. Keep selection and field quoting guidance in the existing record history reference
3. Restore the pre-existing command tips and retain only behavior-focused regressions
```ai-signature
改动范围: 删除新增 affordance/base.md 与对应 source/help 文案测试,调整 record-history 现有 reference、覆盖说明和原命令 Tips
思考过程: 用户要求不新增 Base affordance 文件且 Markdown 不需要专门测试,因此保留运行时代码测试,把跨命令选行和字段引号说明收敛到已有 reference
改动原因: 新增 affordance 与文案测试扩大了 PR 改动面,并重复承载已有 history reference 的 agent 工作流说明
Break Change: 否
```
Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
AI-SHA256: 4c7e3db10025f412d4b2cb4443d94724b5997b72b7e8f97fafdae2f08633b5a2
* docs(base): clarify record history target selection
1. Describe the record ID as uniquely resolving the user-selected target
2. Avoid implying that users must confirm an opaque internal record ID directly
```ai-signature
改动范围: 仅调整现有 lark-base record-history reference 的一处目标记录选择表述
思考过程: CLI 运行时只要求有效 record_id,agent 工作流要求用户确认目标而不是直接确认内部 ID,因此需要区分产品事实和操作约束
改动原因: 原表述可能被误解为 base-cli 能验证 record_id 的用户确认来源,与实际产品边界不一致
Break Change: 否
```
Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
AI-SHA256: bd6c9584cc38689e1c3d9f26514425e3e38ffe2f2cff7b2bb0c65ff316aaf8dc
* docs(base): preserve serial history queries
---------
Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
|
||
|
|
27ed082520 | feat(slides): add kickoff reminder for empty presentations (#2367) | ||
|
|
b6d04738e5 |
test(docs): align fetch help comment expectations (#2363)
* fix(docs): restore fetch comment help guidance * test(docs): align fetch help comment expectations |
||
|
|
327874c8f4 |
docs(lark-shared): split SKILL.md into a slim core plus references (#2226)
* docs(lark-shared): split SKILL.md into a slim core plus references
lark-shared is force-loaded by nearly every lark-* skill (26 skills, 190
references), so its body is paid on almost every task. Split the 211-line
monolith into a slim always-loaded core plus references/ that are read only
when relevant.
This is deliberately a move, not a rewrite. Existing wording is carried over
as-is wherever possible so the change stays easy to regression-test. The core
keeps the rules whose violation is silent or has no self-announcing trigger:
identity semantics, the ok == true success contract, non-blocking auth
split-flow, QR forwarding, write/delete intent confirmation, the exit-10
approval gate, path handling and the no-secrets rule. Mechanics, field paths
and step-by-step flows move to references/.
New references, all carrying over existing text:
- lark-shared-identity-and-permissions.md
- lark-shared-auth-split-flow.md
- lark-shared-high-risk-approval.md
- lark-shared-output-contract.md
- lark-shared-update-notice.md
- lark-shared-config-init.md
Wording changes are confined to lark-shared-high-risk-approval.md, where the
exit-10 guidance was generalized to match the implementation: the recovery
flag is read from hint rather than assumed to be --yes, and --dry-run is
suggested only where the target command supports it.
* docs(lark-shared): tighten the resident rule set
Regroup the always-loaded body so the safety rules read as one block: the
no-secrets rule leads, write/delete intent confirmation and --dry-run preview
follow, and the exit-10 approval gate and path handling close it out.
Trim wording that restated consequences already covered by the linked
reference, and align a few reference passages with the command surface
(`config init` without the flag, envelope phrasing).
* docs(lark-shared): make reference loading trigger-driven
Replace the loose "other scenarios" link list with an explicit trigger index:
each row names the conditions that oblige the agent to open that reference
before taking the next step, and the table covers all six references rather
than the three the list happened to mention.
Trigger conditions beat prose pointers here because the failure mode is an
agent that never opens the reference at all — a link it reads as optional is
a link it skips. Emphasis markers on individual rules are dropped in favour of
plain arrows, since the obligation now lives in the index.
* docs(lark-shared): describe the notice trigger by effect
Name what the three `_notice` keys mean for the agent rather than listing the
keys themselves, so the trigger reads as a condition to recognize instead of a
field spec to memorize.
* docs(lark-shared): phrase triggers the way tasks arrive
Restate the identity trigger in the terms an agent actually encounters ("who am
I", "get the fields of the current identity") rather than in diagnostic
vocabulary, and gloss high-risk-write so the row is readable without already
knowing the term.
Use MUST for the read obligation, matching how the rest of the skill set marks
non-negotiable steps.
* docs(lark-shared): scope the credential-reuse ban to across flows
The split-flow steps require carrying device_code from the first turn into the
second, so a flat ban on caching it contradicted the procedure it accompanied.
Scope the ban to reuse across flows, which is the case that actually matters.
Also match the trigger table to the field name the error envelope carries
(missing_scopes), keeping it consistent with the reference it routes to.
* docs(lark-shared): restore the silent-empty warning and complete the scope flags
Bring back the note that a bot reading user resources returns an empty success
rather than an error. That failure is silent, so it belongs in the body: an
agent that never learns it reads the empty result as "the user has no data".
Also list --recommend alongside --scope and --domain as a way to specify the
authorization range, matching what auth login actually accepts.
* docs(lark-shared): fold the split-flow steps into identity-and-permissions
Auth split-flow and identity/permission recovery are consulted in the same
situation — an agent about to obtain or repair authorization — so a separate
file bought a second hop without buying separation. Merge the split-flow steps
into identity-and-permissions as its agent-initiated-auth section, and route
its trigger row there.
The non-blocking rule leaves the resident body with this merge; the trigger
index already forces the read before any auth login is initiated, which is the
moment the rule matters.
Also reword the _notice.skills gloss to "out of sync" — the mismatch is
bidirectional, not only the skills lagging the CLI.
* docs(lark-shared): make the identity-continuity kernel resident
Omitting --as does not keep the current identity — it hands the choice back
to the profile default, and nothing errors when that happens. That silent
switch is exactly the class of rule the resident body exists for, so state
the kernel in rule 2; the mechanics and examples stay in the
identity-and-permissions reference brought in from main.
* docs(lark-shared): show full reference filenames in link text
Weaker models transcribe the visible link text when deciding what to read,
and short aliases made them reconstruct the real filename — a step that
misspells. Display the exact filename everywhere so copying the visible text
yields a resolvable path.
* docs(lark-shared): route --as selection questions to the identity reference
The resident body states that identity is workflow state but keeps the
selection mechanics in the reference, so an agent asking "which --as here"
had no trigger word to match. Name it in the identity row.
* docs(lark-shared): distill identity continuity, drop the ACL table
State identity continuity as its decision rule — omitting --as hands the
choice to the CLI (whoami shows the outcome and why), so spell --as out
whenever one identity must persist — instead of restating the resolution
chain, whose details belong to the implementation. Route the new trigger
word to the reference.
Drop the missing-scope vs resource-ACL recovery table: resource-ACL
recovery is domain-specific, not a cross-cutting rule, so it does not
belong in the shared skill. Update the lark-minutes pointers that named
the removed table.
* docs(lark-vc): update the last pointer to the removed recovery table
Same companion fix as the lark-minutes references: the recording error
table pointed readers at the recovery table that left lark-shared, so name
the surviving permission-management section instead.
|
||
|
|
525a98270f |
feat(docs): support comments and block mutation ranges (#2341)
* feat(docs): support comments and block mutation ranges * fix(docs): address CI and review feedback |
||
|
|
0c5530dc63 |
feat(slides): auto-upload @path images in +update-slide (#2346)
Bring +update-slide in line with +create and +add-slide: <img src="@local"> placeholders in --content are now extracted, validated, uploaded to the target presentation, and rewritten to file_token before the page is replaced. This removes the manual +media-upload round-trip that was tripping agents into passing unresolved local paths to the backend. - Validate rejects missing files and directory placeholders locally, before any API call, and gates docs:document.media:upload as a conditional scope. - Execute uploads once per unique path (deduped) and, on partial failure, appends a progress hint so a retry does not silently re-upload every image. - DryRun plans the upload steps ahead of the replace and reports images_to_upload so the irreversible half is visible up front. - Skill reference documents the placeholder pipeline, CWD resolution, the docs:document.media:upload scope on 1061004/403, and images_uploaded output. The command Description and skill intro stay scoped to WHAT the command does; the @path capability is surfaced through the flag help, Tips, and the reference section rather than restated in the one-line Description or a cross-command note. |