/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.
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.
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.
* 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
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.
* 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>
* 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>
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
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
* 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
- 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
- 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.
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.
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
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
* 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.
* 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.
* 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
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.
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.
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
- 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
* 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>
* 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>
* 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>
- 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