Commit Graph

563 Commits

Author SHA1 Message Date
zhoule.hhh 24e0bb38eb fix(whiteboard): register +media-upload shortcut and add whiteboard parent type
- Register DocMediaUpload in doc/shortcuts.go (was defined but never
  registered, so lark-cli docs +media-upload was unavailable)
- Rename MediaUpload to DocMediaUpload for consistency with
  DocMediaInsert/DocMediaPreview/DocMediaDownload
- Add whiteboard to --parent-type flag description
- Update --parent-node description to mention board_token for whiteboard

Drive +upload (parent_type=explorer) produces file tokens that the
whiteboard API does not recognize (500 error). The correct approach
is docs +media-upload with parent_type=whiteboard.
2026-04-21 11:31:10 +08:00
河伯 9057299430 feat(doc): add --selection-with-ellipsis position flag to +media-insert (#335)
* feat(doc): add --after-keyword/--before-keyword flags to +media-insert

Allows inserting images/files at a position relative to the first block
whose plain text matches a keyword (case-insensitive substring match).

- Add --after-keyword: insert after the matched root-level block
- Add --before-keyword: insert before the matched root-level block
- Flags are mutually exclusive; default behavior (append to end) unchanged
- fetchAllBlocks: paginated block listing (up to 50 pages × 200 blocks)
- extractBlockPlainText: covers text, heading1-9, bullet, ordered, todo, code, quote
- findInsertIndexByKeyword: walks parent_id chain to resolve nested blocks to their root-level ancestor
- DryRun updated to show block-listing step when keyword flag is set

* test(doc): add fetchAllBlocks pagination and keyword dry-run coverage

- TestFetchAllBlocksPaginationViaExecute: exercises fetchAllBlocks via a
  full Execute flow with --after-keyword, covering multi-page block listing
  (fetchAllBlocks was previously at 0% coverage)
- TestDocMediaInsertDryRunWithAfterKeyword: verifies that the dry-run output
  includes a block-listing step and mentions "search blocks" in the
  description when --after-keyword is provided

fetchAllBlocks coverage: 0% → 76.2%

* refactor(doc): use MCP locate-doc for keyword-based block positioning

Replace fetchAllBlocks + keyword scan with MCP locate-doc tool,
consistent with DriveAddComment. Flags changed from --after-keyword /
--before-keyword to --selection-with-ellipsis + --before.

* fix(doc): show <locate_index> in dry-run create-block when selection is set

When --selection-with-ellipsis is provided, the create-block step in dry-run
now shows index: "<locate_index>" instead of "<children_len>" to accurately
reflect that the insertion position is computed from MCP locate-doc, not
appended to end.

* fix(doc): address CodeRabbit review on +media-insert selection feature

- Validate: reject blank/whitespace --selection-with-ellipsis unconditionally
  so a mis-typed empty value cannot silently fall back to append-mode.
- Redact the raw selection string when logging to stderr and when emitting
  error messages. --selection-with-ellipsis is copied verbatim from document
  content and may contain confidential text; the new redactSelection helper
  keeps a short prefix and rune count so operators can still identify the
  failing selection.
- Harden the after/before mode tests: root children now have three entries
  so the two modes land on different indices, and the tests decode the
  create-block request body to assert the computed `index` actually reaches
  the /children API. A regression that ignored --before would now fail.
- Harden the nested-block test so it exercises the fallback parent-walk:
  the anchor is now two levels deep (blk_grandchild under blk_section_child
  under blk_section), which forces the walk to fetch the intermediate block
  via GET /blocks/{id} to discover the root-level ancestor.

* fix(doc): harden +media-insert selection UX on top of #335 (#577)

Follow-up to #335 review: closes a handful of UX and robustness gaps in
the new --selection-with-ellipsis flow.

- Flag description rewritten to make the "insert at the top-level
  ancestor" semantics explicit — when the selection is inside a callout,
  table cell, or nested list, media lands outside that container, not
  inside. Also calls out the 'start...end' disambiguator.

- locate-doc is now called with limit=2 so an ambiguous selection
  (same phrase in more than one block) surfaces a stderr warning
  pointing at 'start...end', instead of silently picking the first
  match. The first-match return behaviour is unchanged.

- When the anchor is nested below the root, locateInsertIndex now
  logs a note to stderr naming the walk depth and the root-level
  ancestor's insert index. Users don't have to guess why the image
  landed outside the callout they were editing.

- maxDepth bumped 8 → 32 with a comment explaining the invariants:
  `visited` is the real cycle guard, `maxDepth` is belt-and-suspenders.
  32 comfortably exceeds real docx nesting depth so a deeply-nested
  but well-formed anchor is no longer silently rejected.

- Comment added before the parent-walk loop noting why the API calls
  are serial (each level's parent_id is only known after the previous
  GET returns; can't be batched or parallelised).

Tests:

- TestLocateInsertIndexWarnsOnMultipleMatches: stubs two matches,
  asserts the stderr warning names the ambiguity and mentions
  'start...end', and that the first-match insert index is unchanged.
- TestLocateInsertIndexLogsNestedAnchor: anchor two levels below root,
  asserts stderr carries the "nested … top-level ancestor" note.
- TestLocateInsertIndexCycleDetection: malformed parent chain with
  blk_x.parent = blk_y and blk_y.parent = blk_x, neither reachable
  from root. Registering a single GET /blocks/blk_y stub also bounds
  the call count — a regression that broke `visited` tracking would
  either hang or fail via httpmock's extra-call guard.

Co-authored-by: fangshuyu-768 <shuyufang768@outlook.com>
2026-04-20 23:24:11 +08:00
fangshuyu-768 9e891b758e test(doc): harden markdown_fix pipeline with invariant tests (#576)
Adds 5 invariant-level tests on top of #469's transforms:

- TestFixExportedMarkdownIdempotent — f(f(x)) == f(x) across rich
  fixtures (kitchen sink, CJK, nested containers). Protects the core
  round-trip promise from future transform interactions that rewrite
  their own output.
- TestFixExportedMarkdownPreservesFencedCodeByteForByte — packs every
  pipeline-touching shape into a fence and asserts byte-identical output.
  Code samples must never be silently rewritten by a formatting pass.
- TestFixExportedMarkdownPreservesCRLF — CRLF input preserves line
  endings AND still triggers transforms. Windows-authored markdown
  should not be silently LF-normalized.
- TestFixExportedMarkdownTransformInteractions — composition regressions:
  nested-list + trailing-space bold, text→list transition, callout
  containing list with emphasis, heading vs paragraph bold.
- TestNormalizeNestedListIndentationDocumentedSkips — locks in the
  deliberate no-op branches (odd-space indent, blank-line loose-list
  sibling, 4-space indented code block, parentless two-space) as an
  explicit spec so future heuristic tweaks surface in the test diff.

All transforms, fixtures, and expectations are derived from the head of
PR #469. No production code changes.

Co-authored-by: fangshuyu-768 <shuyufang768@outlook.com>
2026-04-20 22:54:51 +08:00
高春晖 293a9f896f fix(doc): preserve round-trip formatting in fetch output (#469)
* fix(doc): preserve round-trip formatting in fetch output

- trim leading spaces inside bold and italic emphasis exported by docs +fetch

- normalize nested list indentation to avoid flattening and literal text on re-import

- add regression tests for emphasis spacing and nested list indentation

* fix(doc): avoid false positives in markdown spacing fixes

- keep literal * x * and ** x ** text unchanged

- only normalize indented nested list markers when a parent list item exists

- add regression coverage for both CodeRabbit findings

* fix(doc): 修正嵌套列表缩进的空行误判

- 遇到空行时停止向上查找父级列表项,避免把 loose list sibling 误改成嵌套列表
- 避免把列表项中的四空格缩进代码块误改成 tab 缩进列表项
- 补充两个回归测试,并更新 fixBoldSpacing 注释使其与当前实现一致

* fix(doc): 修复 Markdown emphasis 空格回写

- 将 fixBoldSpacingLine 改为按星号 run 扫描,修复 ** hello **、* hello * 和同一行多个 italic span 的空格清理
- 保留 inline code、heading 和 *** hello** 这类近邻字面量,避免误改 emphasis nesting
2026-04-20 22:40:56 +08:00
kongenpei cd666422ac fix(base): preserve attachment metadata on base uploads (#563)
* fix: preserve attachment metadata on base uploads

* test: cover attachment mime detection

* fix: address attachment upload review feedback

* fix: preserve source extension for attachment mime detection

* fix: avoid registry test refresh data race

* Revert "fix: avoid registry test refresh data race"

This reverts commit c1d12d0cf1.

---------

Co-authored-by: kongenpei <kongenpei@users.noreply.github.com>
2026-04-20 19:14:45 +08:00
caojie0621 1262aac480 fix(sheets): normalize single-cell range in +set-style and +batch-set-style (#548)
/style and /styles_batch_update require full "A1:A1" form and reject
single-cell shorthand "A1". +set-style was using normalizeSheetRange
(prefix-only) and +batch-set-style passed --data through unchanged,
so both failed with `wrong range` when callers supplied a single cell.

Switch +set-style to normalizePointRange, and walk each ranges[]
entry in +batch-set-style through normalizePointRange before sending.
Multi-cell spans pass through unchanged.
2026-04-18 23:29:14 +08:00
caojie0621 abb02cd46c feat(sheets): add float image shortcuts (#494)
Implement +create-float-image, +update-float-image, +get-float-image,
+list-float-images, and +delete-float-image shortcuts wrapping the v3
spreadsheet float_image API. The create reference doc includes the
prerequisite media upload step with the correct parent_type
(sheet_image) to avoid common token mismatch errors.
2026-04-18 23:27:11 +08:00
haozhenghua-code db7d3cb64d fix(im): cap basic_batch user_ids at 10 per API limit (#551)
The POST /contact/v3/users/basic_batch endpoint caps user_ids at 1~10
per request, but batchResolveByBasicContact was chunking by 50. When
user identity needed to resolve >10 unresolved sender names, the
single oversized request was rejected, causing the batch resolver to
bail out and leave sender names empty for the rest.

Lower batchSize to 10 and add a unit test that exercises 25 missing
IDs and asserts they are sent as 10 / 10 / 5.
2026-04-18 18:41:30 +08:00
chanthuang 6212513c43 feat(mail): add email priority support for compose and read (#538)
* feat(mail): add email priority support for compose and read

Write: all compose shortcuts (+send, +reply, +reply-all, +forward,
+draft-create) accept --priority (high/normal/low) which sets the
X-Cli-Priority EML header. +draft-edit accepts --set-priority.

Read: normalizeMessage now infers priority from label_ids
(HIGH_PRIORITY/LOW_PRIORITY), with priority_type as fallback.

Change-Id: Ib5bc4e99331c6ce0d3850865825fcd1ff2183f0c
Co-Authored-By: AI

* docs(mail): add --priority and --set-priority to skill references

Update 6 skill reference docs: +send, +reply, +reply-all, +forward,
+draft-create add --priority param; +draft-edit adds --set-priority.

Change-Id: I75d13fbf6a5ca4dfbf76e84fe39e4ee55b689751
Co-Authored-By: AI

* test(mail): add unit and integration tests for --priority

- helpers_test.go: cover parsePriority (valid/invalid/case/whitespace)
  and applyPriority (empty vs non-empty) end-to-end via EML builder
- mail_draft_create_test.go: verify --priority propagates to X-Cli-Priority
  header in the built EML, and no header when priority is empty

Change-Id: I62ca96b3e296b5898798cfa681f5efd4f101cb40
Co-Authored-By: AI

* test(mail): cover buildDraftEditPatch --set-priority and label-based priority

- helpers_test.go: TestBuildMessageOutput_PriorityFromLabels verifies
  HIGH_PRIORITY/LOW_PRIORITY labels map to priority_type_text, and that
  label values override the priority_type fallback field
- mail_draft_edit_test.go (new): cover --set-priority high/low/normal
  (set_header vs remove_header), invalid value rejection, and absence
  of priority op when the flag is unused

Change-Id: Idd5ace2fb812cf3eb329c79eeab3c8b9808fcf0b
Co-Authored-By: AI

* fix(mail): write priority_type to output when inferred from label_ids

buildMessageOutput only wrote priority_type_text but not priority_type
when priority was inferred from HIGH_PRIORITY/LOW_PRIORITY labels.
Also covers the case where label overrides an explicit priority_type field.

Change-Id: I7879976d21235b8006b5c8ebe6a413e2815354e1

* fix(mail): validate --priority in Validate so invalid values fail before dry-run/Execute

Change-Id: Ic277ab683967c47f28c892d3512b0ab745bd86f6

* test(mail): add TestValidatePriorityFlag to cover invalid --priority rejected in Validate

Change-Id: I7f12c0a0b0d15c491c28fdcb8729f2f648ba0244
2026-04-17 20:49:32 +08:00
caojie0621 e8df0ea63e feat(drive): support sheet cell comments in +add-comment (#518)
Extend +add-comment to accept sheet URLs and wiki URLs that resolve
to sheets. Reuse --block-id with <sheetId>!<cell> format (e.g.
a281f9!D6) for sheet cell positioning.

Wiki links resolving to sheet type are handled by first calling
get_node, then redirecting to the sheet comment path with proper
parameter validation.
2026-04-17 20:05:08 +08:00
nickzhang 6d0d687be2 feat(doc): add --file-view flag to +media-insert (#419)
* feat(doc): add --file-view flag to +media-insert for file block rendering

The docx File block supports three render modes via view_type
(1=card, 2=preview inline player, 3=inline), but --type=file today
always creates with the default card view. Because view_type can only
be set at creation time (PATCH replace_file ignores it), callers
wanting an inline audio/video player had to abandon the shortcut and
reimplement the full 4-step orchestration manually.

Add --file-view card|preview|inline that threads into file.view_type
on block creation. Omitting the flag preserves the exact request body
that the shortcut sends today, so existing users are unaffected.

--file-view is rejected when combined with --type=image (images have
their own rendering) and when an unknown value is passed.

* refactor(doc): narrow view_type gate and relax file-view test

Address review feedback from automated reviewers on #419:

- Replace `fileViewType > 0` with an explicit 1|2|3 whitelist inside
  buildCreateBlockData so a stray positive int cannot escape into the
  request payload if a future caller bypasses Validate.
- Relax TestFileViewMapCoversDocumentedValues to assert only the
  documented keys rather than full-map equality, so future aliases
  (e.g. a "player" synonym for preview) do not falsely break the test.

No behaviour change for any existing --file-view input.

* test(doc): cover --file-view Validate contract and explicit card path

Pins down the two CLI guard branches (unknown --file-view value and
--file-view passed with --type!=file) that were previously only covered
indirectly through buildCreateBlockData. Also adds the --file-view card
case so the explicit view_type=1 payload (different from the legacy
file: {} shape when the flag is omitted) is locked in as part of the
public flag contract.

* fix: repair unit tests

Change-Id: I8c6bb69bfa22c9455a2cbb0f46b401e2cbe87762

---------

Co-authored-by: Nick Zhang <nickzhangcomes@users.noreply.github.com>
Co-authored-by: wangweiming <wangweiming@bytedance.com>
2026-04-17 19:27:00 +08:00
syh-cpdsss 148a04a7f8 Feat: Add OKR business domain (#522)
* feat: okr domain

Change-Id: I1877c56e33e3620b696351ed9e4c8615dbe17c4b

* feat: okr skill update

Change-Id: I1877c56e33e3620b696351ed9e4c8615dbe17c4b
2026-04-17 18:04:15 +08:00
feng zhi hao be79485fe3 feat: mail support scheduled send (#534)
feat: mail support scheduled send (#534)
2026-04-17 15:41:42 +08:00
zgz2048 94bba91224 feat(base): auto grant current user for bot create and copy (#497)
* feat(base): auto grant current user for bot create and copy

* fix(base): declare auto-grant permission scope

* Apply suggestion from @kongenpei

Co-authored-by: kongenpei <kongenpei.jojo@bytedance.com>

* Apply suggestion from @kongenpei

Co-authored-by: kongenpei <kongenpei.jojo@bytedance.com>

* style(base): format auth-specific scope declarations

* fix(base): use bitable permission target for auto-grant

---------

Co-authored-by: kongenpei <kongenpei.jojo@bytedance.com>
2026-04-17 14:30:47 +08:00
ILUO 35a8288baf feat: default skip_task_detail in docs +fetch (#471) 2026-04-16 19:15:57 +08:00
tuxedomm 79379fbc6f fix(im): preserve original URL filename for uploaded file messages (#514)
mediaBuffer.FileName() returned a hardcoded "media"+ext, so IM file
messages sent via URL displayed generic names like "media.pdf" instead
of the filename parsed from the URL. This regressed the pre-refactor
tempfile path which at least carried a unique basename.

Store fileNameFromURL(rawURL) on the buffer and return it from
FileName(). Split newMediaBuffer so the URL-to-filename wiring is
reachable from tests without going through the hardened download
transport.

Also lock in that the local upload branch keeps filepath.Base(filePath)
as file_name, so the URL fix cannot silently regress the local branch
later.

Change-Id: I729b217e9dc9237aeb89c2b89df86a37ad64a840
2026-04-16 19:01:21 +08:00
syh-cpdsss c1d6042552 fix: add atomic overwrite for whiteboard +update (#483) 2026-04-16 14:06:36 +08:00
chenxingtong-bytedance 656c16a47f feat(im): support user access token upload file/media/audio/image and send the resource message (#474)
The /open-apis/im/v1/images and /open-apis/im/v1/files APIs now support User Access Token (UAT) in addition to Tenant Access Token (TAT). Previously the upload helpers forced bot identity unconditionally; this PR aligns them with the surrounding shortcut's --as flag so uploads and sends share the same identity.

Change-Id: I3d7fd528dd30fef9aea2d88100ceb03db4c7c3ac
2026-04-16 14:04:25 +08:00
wittam-01 9dfaff4664 feat: add drive create-folder shortcut and wiki node auto-grant (#470)
Change-Id: I1acd001a1d4616bc5a957cad437e5aa4f1afeb51
2026-04-16 11:19:19 +08:00
chanthuang 03ba542a60 Revert "feat: mail support scheduled send (#449)" (#492)
This reverts commit 44e7b5b477.

Change-Id: I0b0c6454cf5ea4c15169a3c683b91795ef880478
2026-04-15 21:04:27 +08:00
chanthuang 5fa68ccaa0 feat(mail): add email signature support (#485)
* feat(mail): add signature foundation, draft exports, and +signature shortcut

- Add signature data model, API provider, and template variable
  interpolation with tests (shortcuts/mail/signature/)
- Export signature-related symbols from draft package (SignatureWrapperClass,
  BuildSignatureHTML, FindMatchingCloseDiv, SplitAtQuote, RemoveSignatureHTML,
  SignatureSpacing, SignatureImage) for use by compose shortcuts
- Add +signature shortcut for listing and viewing email signatures
- Add signature reference documentation

Change-Id: I62525e7b475692ada9ec8590b6d0252cf5afcdbc
Co-Authored-By: AI

* feat(mail): add --signature-id to all compose shortcuts

- Add --signature-id flag to +draft-create, +send, +reply, +reply-all,
  +forward for inserting a signature into the email body
- Add signature image download with SSRF protection (https enforcement,
  no token leak, context timeout, size limit)
- Add signature HTML insertion with quote-aware placement
- Update compose shortcut reference docs

Change-Id: Ic5606bab7826a20364084898ad1714778e5a8bd0
Co-Authored-By: AI

* feat(mail): add signature insert/remove ops for +draft-edit

- Add insert_signature and remove_signature patch operations with
  old-signature MIME cleanup and case-insensitive CID matching
- Expose signature ops in supported_ops flat list
- Update SKILL.md and draft-edit reference docs

Change-Id: I74affbf555e32351520f610ef42195f399a265d9
Co-Authored-By: AI

* test(mail): add unit tests for signature patch operations

Test insert_signature and remove_signature ops:
- Insert into basic HTML body
- Insert before quote block (reply/forward)
- Replace existing signature
- Error on plain-text-only draft
- Remove existing signature
- Error when no signature present

Change-Id: Icd713552b130d6eb461ef1cabca61e82327f4f0b
Co-Authored-By: AI

* fix(mail): address reviewer findings on signature PR

- Remove --device flag and device field from docs (not exposed in CLI)
- Fix signature interpolation to match --from alias address in send_as
  list, instead of always using the primary mailbox address
- Update lark-mail-signature.md reference doc

Change-Id: I65f41a029cd33b17785e2355a99d042063962d23
Co-Authored-By: AI

* fix(mail): resolve lint issues — remove unused code, fix gofmt

- Remove unused cidSrcRe, collectSignatureCIDs, isCIDReferencedInHTML
  from signature_html.go (CID logic lives in draft/patch.go)
- Remove unused strings import
- Run gofmt on all affected files

Change-Id: Ie142744a7ab17acf440dc69a5a78cefb3ce6c341
Co-Authored-By: AI

* fix(mail): use draft From address for signature interpolation in +draft-edit

Moved signature resolution after draft fetch+parse so insert_signature
reads the From header from the existing draft. This ensures alias and
shared-mailbox senders get correct template variable values (B-NAME,
B-ENTERPRISE-EMAIL) instead of falling back to the primary address.

Change-Id: I917016b17176090124814f30e8e15c67f1604de0
Co-Authored-By: AI
2026-04-15 17:44:59 +08:00
feng zhi hao 44e7b5b477 feat: mail support scheduled send (#449)
feat: mail support scheduled send
2026-04-15 14:11:19 +08:00
chanthuang 162c25527b feat(mail): support recall sent email (#481)
- Add buildSendResult helper that includes recall_available/recall_tip
  when backend returns recall_status in send response
- Update +send, +reply, +reply-all, +forward to use buildSendResult
- Add "Recall Email" section to mail skill template with recall and
  get_recall_detail command examples
- Regenerate SKILL.md

Change-Id: I44317ead8f8a65db81e874cfc3529ffeb21e1384
Co-Authored-By: AI
2026-04-15 12:31:25 +08:00
ViperCai ec9e67c21a feat(slides): add image upload via +media-upload and @path placeholders in +create (#450)
- New `slides +media-upload` shortcut: upload a local image to a slides
  presentation and return the file_token for use in <img src="...">.
- `slides +create --slides` now supports `@./path.png` placeholders that
  are auto-uploaded and replaced with file_tokens.
- Reject images >20 MB (multipart upload not supported for slide_file).
- Support wiki URL resolution for --presentation flag.
2026-04-15 11:44:11 +08:00
kongenpei 052e2112bf fix: validate base shortcut JSON object inputs (#458)
* fix: validate base shortcut JSON object inputs

* fix: reject null in base JSON object parser

---------

Co-authored-by: kongenpei <kongenpei@users.noreply.github.com>
2026-04-14 19:30:23 +08:00
caojie0621 76a834e928 feat(sheets): add dropdown shortcuts and formula reference docs (#461)
Implement +set-dropdown, +update-dropdown, +get-dropdown, and
+delete-dropdown shortcuts wrapping the v2 dataValidation API.
This resolves the issue where multipleValue writes silently
became plain text because the prerequisite dropdown configuration
step was not exposed as a CLI command.

Also add lark-sheets-formula.md reference for Lark-specific formula
rules (ARRAYFORMULA, native array functions, date diff, etc.) and
update the dropdown limitation note in SKILL.md to link to the new
+set-dropdown shortcut.
2026-04-14 18:48:07 +08:00
ILUO 20761fa56a feat(task): add task shortcuts with skill docs and tests (#377)
* feat(task): add task shortcuts with skill docs and tests

* docs(task): document task event payload shape

* refactor(task): remove unused buildUserIDs helper

* fix(task): handle api error codes in set-ancestor

* docs(task): clarify get-related-tasks page-token unit

* feat(task): support bot identity for subscribe-event

* docs(task): clarify bot subscribe-event scope

* docs(task): clarify related-task pagination semantics

* docs(task): add BOE selftest report (boe_task_tasklist_oapi_support)

* docs(task): prefer related-task shortcuts over search for scoped queries

* docs(task): clarify tasklist search routing

* docs(task): route keywordless tasklist queries to list API

* docs(task): refine search routing heuristics

* feat(event): include task user-access updates in catch-all subscribe

* docs(task): remove auth status --json guidance
2026-04-14 17:24:38 +08:00
chenxingtong-bytedance 06e7ae267c (im) support im oapi range download large file (#283)
Add range download support for IM OAPI resources so lark-cli can reliably download large files. This improves stability for large payloads and network interruptions.

Change-Id: I38e6f6f9cf8b8711dc40650d19c77503f4e44989
2026-04-13 22:02:34 +08:00
caojie0621 74f7de386a feat(sheets): add filter view and condition shortcuts (#422)
Add 10 new sheet shortcuts for filter view management:

Filter views:
- +create-filter-view, +update-filter-view, +list-filter-views
- +get-filter-view, +delete-filter-view

Filter view conditions:
- +create-filter-view-condition, +update-filter-view-condition
- +list-filter-view-conditions, +get-filter-view-condition
- +delete-filter-view-condition

Includes unit tests (39 cases, 88-93% coverage) and skill reference docs.
2026-04-13 21:41:28 +08:00
liujinkun2025 88fd3bdab8 feat(wiki): add wiki move shortcut with async task polling (#436)
Change-Id: I58400054e6c3c3c8e7b0cf72b874602b22fa287d
2026-04-13 19:33:53 +08:00
kongenpei c70c3fdce2 fix: support large base attachment uploads (#441)
Co-authored-by: kongenpei <kongenpei@users.noreply.github.com>
2026-04-13 19:32:05 +08:00
haozhenghua-code 25534d72b5 fix(im): reject --user-id under bot identity for chat-messages-list (#340)
The chat_p2p/batch_query endpoint that resolves a user's p2p chat_id
requires user identity. Calling +chat-messages-list with --user-id
under bot identity previously failed silently or returned wrong
results.

- Validate: reject --user-id when runtime.IsBot(), with a hint to
  pass --as user or use --chat-id instead
- resolveP2PChatID: add defensive guard for the same condition in
  case the helper is reached via another path
- Update --user-id flag description and the lark-im skill reference
  to note the user-identity requirement
- Tests: add bot-rejection cases for Validate and resolveP2PChatID,
  switch p2p happy-path tests to a user-identity runtime helper
2026-04-13 17:54:10 +08:00
chenhuang 815db0c866 fix(mail): add missing scopes for mail +watch shortcut (#357)
* fix(mail): add missing event scope for mail watch

The mail +watch shortcut requires scope
mail:user_mailbox.event.mail_address:read to receive the mail_address
field in WebSocket event payloads, but this scope was neither declared
in the shortcut's Scopes list nor included in the auto-approve
(recommend.allow) set.

Without this scope, +watch events arrive without the mail_address field,
which breaks mailbox filtering and fetch-mailbox resolution.

- Add scope to mail +watch Scopes declaration
- Add scope to scope_overrides.json recommend.allow list so that
  auth login --recommend requests it automatically

* fix(mail): add missing mailbox profile scope for mail watch

The +watch shortcut calls fetchMailboxPrimaryEmail (GET
user_mailboxes/me/profile) to resolve the mailbox address for event
filtering, which requires scope mail:user_mailbox:readonly. All other
mail shortcuts that call this API (send, reply, forward, draft-create,
draft-edit) already declare this scope, but +watch did not.

* fix(mail): remove event scope from scope_overrides.json

The mail:user_mailbox.event.mail_address:read scope only needs to be
declared in the +watch shortcut's Scopes list, not in the global
recommend.allow set.
2026-04-13 17:22:28 +08:00
Tsai_Hui 3917b77e91 feat: add drive create-shortcut shortcut (#432) 2026-04-13 11:54:31 +08:00
wangzhengkui dc0d92708b fix(mail): restrict --output-dir to current working directory (#376)
* fix(mail): restrict --output-dir to current working directory

Previously, mail +watch --output-dir accepted absolute paths (e.g.
/etc, /tmp) and home directory paths (~/), allowing writes to arbitrary
locations. Since mail content is sender-controlled, this posed a risk
of writing attacker-influenced data to sensitive system directories.

Now all --output-dir values go through validate.SafeOutputPath which:
- Rejects absolute paths and ~ expansion
- Resolves .. and symlinks
- Enforces the result stays under CWD

* fix(mail): reject tilde paths in --output-dir explicitly

SafeOutputPath treats ~/x as a literal relative path, silently creating
a directory named "~" under CWD. Reject ~ prefixed paths with a clear
error message instead.

* fix(mail): reject all tilde-prefixed paths and use ErrValidation

- Broaden ~ check from "~ || ~/" to "~" prefix, covering ~user/path forms
- Use output.ErrValidation for consistent error type (exit code 2)

* fix(mail): add post-mkdir EvalSymlinks + CWD re-verification (TOCTOU)

SafeOutputPath validates before MkdirAll, but an attacker could replace
the newly created directory with a symlink between mkdir and the first
write. Add EvalSymlinks after MkdirAll and re-verify the resolved path
is still under CWD.

Also broaden ~ rejection to all tilde-prefixed paths (~user/path) and
use output.ErrValidation for consistent error types.

* fix(mail): use validate.SafeOutputPath for post-mkdir TOCTOU check

Replace direct os.Getwd and filepath.EvalSymlinks calls with a second
SafeOutputPath call after MkdirAll. This satisfies the forbidigo lint
rule (no direct os/filepath calls in shortcuts/) while maintaining the
same TOCTOU protection.

* fix(mail): use original relative path for post-mkdir re-validation

SafeOutputPath rejects absolute paths, but after the first call
outputDir was already resolved to an absolute path. Pass the original
relative path to the second SafeOutputPath call so it can properly
re-validate after MkdirAll.

* fix(mail): remove redundant post-mkdir SafeOutputPath call

The second SafeOutputPath call after MkdirAll provided no real TOCTOU
protection: mail +watch is long-running, so the directory could be
replaced at any point during the session, not just between mkdir and
the check. The first SafeOutputPath already validates and resolves
the path; one call is sufficient.
2026-04-13 10:53:08 +08:00
zero-my f6b8091843 Feat/task section updates (#430)
* docs(task): document sections API resources and add URL parsing reminder

* feat(task): support --section-guid flag in tasklist-task-add shortcut

* docs(task): document sections API resources, permissions, and URL parsing
2026-04-12 16:12:16 +08:00
ViperCai e07842d3b5 feat(slides): return presentation URL in slides +create output (#425)
After creating the presentation, call drive batch_query (with_url=true)
to fetch the document URL and include it in the output. The fetch is
best-effort so it won't break creation if the API call fails.

Also update the skill reference doc to document the new optional url
return field.
2026-04-11 21:19:31 +08:00
ethan-zhx a9c07cebb6 feat(slides): add slides +create shortcut with --slides one-step creation (#389)
Co-authored-by: caichengjie.viper <caichengjie.viper@bytedance.com>
2026-04-11 18:37:11 +08:00
caojie0621 f6a31e0853 feat(sheets): add dimension shortcuts for row/column operations (#413)
Add 5 new sheet shortcuts for row/column management:
- +add-dimension: append rows/columns at the end
- +insert-dimension: insert rows/columns at a position
- +update-dimension: update visibility and size
- +move-dimension: move rows/columns to a new position
- +delete-dimension: delete rows/columns

Includes unit tests (89-100% coverage) and skill reference docs.
2026-04-11 17:21:21 +08:00
liujinkun2025 bd5a33c0b7 feat(drive): add drive folder delete shortcut with async task polling (#415)
Change-Id: Ifb34f67296b800501a1b4960e02d5fed3382b84a
2026-04-11 16:47:03 +08:00
caojie0621 3242ca6f7f feat(sheets): add cell operation shortcuts for merge, replace, and style (#412)
Add 5 new sheet shortcuts for cell operations:
- +merge-cells: merge cells with MERGE_ALL/MERGE_ROWS/MERGE_COLUMNS
- +unmerge-cells: split merged cells
- +replace: find and replace cell values
- +set-style: set cell style (font, color, alignment, border)
- +batch-set-style: batch set styles for multiple ranges

Includes unit tests (81-89% coverage) and skill reference docs.
2026-04-11 16:45:14 +08:00
liangshuo-1 9f81e7e567 feat: add RuntimeContext.BotInfo() for lazy bot identity retrieval (#409)
Add BotInfo() method on RuntimeContext that lazily fetches the current
app's bot open_id and display name from /bot/v3/info on first call,
cached via sync.OnceValues for the lifetime of the process.

- BotInfo struct (OpenID, AppName) in Identity section of runner.go
- fetchBotInfo() uses DoAPIAsBot for consistent header injection
- CanBot() on CliConfig gates the call when bot identity is unavailable
- Nil guard prevents panic in test contexts
- Full test coverage via httpmock.Registry + mounted shortcuts

Change-Id: I40ac710fb52d13939853f71827a5cbdbddd4f80f
2026-04-11 11:53:02 +08:00
zhicong666-bytedance a00dfad56a feat: support minutes search (#359)
* feat: support minutes search by keyword and owner

* fix(minutes): align search output fields and clarify same-day queries

* fix(minutes): tighten search validation and output

* docs(vc): clarify recording usage examples

* test(minutes): remove redundant loop variable copies

* test(minutes): add docstrings for search tests

* refine minutes search params and skill routing

* minutes: refine search params payload and dry-run params feed

* skills: fix minutes search reference wording and vc link

* fix(minutes): align page-size cap to 30 and update tests

* skills: route meeting minutes lookup via vc first

* docs(skills): require shortcut reference reads
2026-04-11 06:31:10 +08:00
huangxincola e8e0c6fc5a Add +dashboard-arrange command for auto-arranging dashboard blocks layout and introduce text block type with Markdown support for dashboard visualization. (#388)
- Add `+dashboard-arrange` command that triggers server-side smart layout optimization via POST /open-apis/base/v3/bases/{token}/dashboards/{id}/arrange
- Add `text` block type support for dashboard blocks with Markdown syntax (headers, bold, italic, strikethrough, lists)
- Update `validateBlockDataConfig()` to handle text-specific validation rules
- Update documentation (SKILL.md, lark-base-dashboard.md, dashboard-block-data-config.md, lark-base-dashboard-arrange.md)
- Add comprehensive unit tests for new commands and block type
- [x] Unit tests pass (`go test ./shortcuts/base/...`)
- [x] All dashboard-related tests pass including new `TestBaseDashboardExecuteArrange`
- [x] Text block type validation tests pass
- None
2026-04-10 21:05:37 +08:00
calendar-assistant b8f71d50d1 feat(calendar): add room find workflow (#403)
Fix room-find multi-slot verification.

Change-Id: I3ba4c8dbe30bbb1eb12c0996bb8bc5d54e6339ca
2026-04-10 21:01:00 +08:00
syh-cpdsss 46468a900c feat: Add whiteboard +query shortcut and enhance +update with Mermaid/PlantUML support (#382)
Change-Id: I719935bb8fee337908ec99d59f1dfaae0df74874
2026-04-10 19:40:29 +08:00
kongenpei fa16fe1976 feat(base): add record batch add/set shortcuts (#277)
* feat(base): add record batch add/set shortcuts

* docs: clarify record batch add/set input guidance

* docs: mark base shortcut references as required before calling

* fix(base): remove stale token stub calls in batch record tests

* feat(base): rename record batch add/set to create/update

* refactor(base): remove noop record json validators

* test(base): align record validate test with nil hooks

* fix: align base record batch shortcuts with openapi routes

* fix(base): pass parse context for record batch JSON parsing

* docs: move base record batch JSON guidance to tips

* refactor: remove noop record validate

* docs: remove has_more from batch update guide

---------

Co-authored-by: kongenpei <kongenpei@users.noreply.github.com>
2026-04-10 17:39:54 +08:00
kongenpei d8b0865814 feat(base): add +record-search for keyword-based record search (#328)
* feat(base): add +record-search json passthrough shortcut

* docs(base): refine record-search wording and field constraints

* docs(base): prefer record-list unless keyword is explicit

* refactor(base): inline record-search parsing and align tests

* refactor(base): remove noop record validate hook

* docs(base): unify record example token placeholders

* fix: align record search JSON parsing with parse context

* feat: add help tips for base record search

* docs: refine base record search reference

---------

Co-authored-by: kongenpei <kongenpei@users.noreply.github.com>
2026-04-10 17:18:41 +08:00
kongenpei d026741532 feat(base): add view visible fields get/set shortcuts (#326)
* feat: add base view visible fields shortcuts and docs

* docs: add view-create guidance for visible fields read

* docs(base): refine visible fields reference wording

* refactor(base): remove noop validate hook from view-set-visible-fields

* docs: unify view-set-visible-fields example placeholders

* docs: update visible fields example field placeholder

* fix(base): pass parse context in view-set-visible-fields

* feat: add tips for view-set-visible-fields json usage

---------

Co-authored-by: kongenpei <kongenpei@users.noreply.github.com>
2026-04-10 16:37:08 +08:00
kongenpei cd7a2363e5 feat(base): add record field filters (#327)
* feat(base): add record field filters

* fix(base): align record field filter flags with OpenAPI params

* fix: scope record dry-run field filters and align docs

* docs(base): clarify record-list field_scope priority

* refactor(base): remove field-id from record-get

---------

Co-authored-by: zgz2048 <zhonggangzhi.tim@bytedance.com>
Co-authored-by: kongenpei <kongenpei@users.noreply.github.com>
2026-04-10 16:30:54 +08:00