Commit Graph

636 Commits

Author SHA1 Message Date
ethan-zhx 05d8137c7d feat(drive): extend +add-comment to support slides targets (#674)
Change-Id: Id87ecce098d87f7db82389a73f3134b66fcd4814
2026-04-28 10:25:32 +08:00
liangshuo-1 17a85d319d fix(e2e/wiki): pass obj_type when deleting wiki nodes in cleanup (#687)
* fix(e2e/wiki): pass obj_type when deleting wiki nodes in cleanup

The wiki node DELETE endpoint now rejects requests without obj_type
(API error 99992402: "obj_type is required"), causing TestWiki_NodeWorkflow
cleanup to fail on every run. Forward the obj_type from the create/copy
response into the delete query params so cleanup succeeds.

* fix(e2e/wiki): delete cleanup wiki nodes via drive v1 endpoint

The wiki v2 DELETE /spaces/{space_id}/nodes/{node_token} endpoint is
undocumented and rejects requests with `obj_type is required` even when
obj_type is forwarded as a query parameter (see actions run #25005966144).

Switch cleanup to the documented path: delete the underlying drive file
via DELETE /drive/v1/files/{obj_token}?type=<obj_type>, which removes the
backing document and the wiki node in one call.

Change-Id: Ieb93b1f92ea758d8b80bcfdd4f20b2be8f35a0bd

* fix(e2e/wiki): pass obj_type to wiki delete in body, not query

Previous attempts:
- query (?obj_type=docx) → API still rejects with 99992402 obj_type
  required (the wiki delete-node endpoint reads it from the body, not
  the query string).
- drive v1 fallback → bot identity does not have drive write scope and
  returns 1061004 forbidden, so we cannot reuse drive's delete API for
  the cleanup helpers.
2026-04-28 00:53:40 +08:00
ethan-zhx a16eb24ba9 feat(slides):lark slides fonts (#681)
Change-Id: Ic59709f1720b1d9142b3c11ea373015557628af0
2026-04-27 20:48:46 +08:00
liangshuo-1 f6f242ed57 chore(release): v1.0.20 (#682)
Change-Id: I1fdfa09633bfbe385a191a95b605e1dbcf011768
v1.0.20
2026-04-27 20:15:38 +08:00
zhicong666-bytedance 7124b18baa docs(skills): clarify minutes routing semantics (#591) 2026-04-27 20:06:29 +08:00
calendar-assistant 78d92de6af feat: add calendar update shortcut (#678)
Change-Id: Ie2d4bde6cd28bbf4d7946db38c5c9be13edc6ba9
2026-04-27 19:27:20 +08:00
fangshuyu-768 8ec95a4e39 docs(lark-drive): add missing import command examples (#669)
Add example commands for file types declared in the supported-conversions
table but absent from the command examples section: .docx/.doc, .txt,
.html, .xls -> sheet, and .csv -> sheet.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 15:25:30 +08:00
sang-neo03 fe9dc4ce6a fix(strict-mode): reject explicit --as instead of silently overriding it (#673)
* fix(strict-mode): reject explicit --as instead of silently overriding it

ResolveAs checked strict mode before the --as flag, so `--as bot` under strict=user
  was silently rewritten to user. Reorder so explicit --as is returned as-is and CheckStrictMode rejects the conflict (exit=2). Implicit paths (--as auto / unset) are still forced by
   strict mode.

* fix(strict-mode): fix CI
2026-04-27 15:18:35 +08:00
Schumi Lin 1e2144ee08 docs(readme): add Project (Meegle) to Features table (#660)
Project management for Lark/Feishu is provided by the standalone
meegle-cli (https://github.com/larksuite/meegle-cli), which requires a
separate install. Surface it in the Features table so users can
discover the capability without expecting it to ship inside lark-cli.
2026-04-27 01:37:26 +08:00
zkh-bytedance 20fba1e601 chore(whiteboard): Manual disable edge case for svg compatible (#661) 2026-04-25 21:36:40 +08:00
arnold9672 97f817d088 feat(im): add at-chatter-ids filter to +messages-search (#612)
Add --at-chatter-ids flag to shortcuts/im/im_messages_search.go that
passes filter.at_chatter_ids to the search API, restricting results to
messages that @mention any of the given user open_ids. Messages that
2026-04-25 20:05:14 +08:00
sang-neo03 ddf6f0cb7d feat(pagination): preserve pagination state on truncation and natural… (#659)
* feat(pagination): preserve pagination state on truncation and natural end

* feat(pagination): drop page_token from merged output to reflect aggregate view
2026-04-25 17:54:52 +08:00
shifengjuan-dev 834a899e2b feat(lark-im): add chat.members.bots to skill docs (#616)
- Add chat.members.bots entry under chat.members API resources
- Add chat.members.bots -> im:chat.members:read scope mapping

Change-Id: I57039a9a8649d794bbda84a1e41fae9cc31d570a
2026-04-25 16:23:03 +08:00
liujinkun2025 aa48d70d7a feat(drive): add +search shortcut with flat filter flags (#658)
Expose doc_wiki/search v2 under the drive domain via explicit flags
(--query, --edited-since, --commented-since, --opened-since,
--created-since, --mine, --creator-ids, --doc-types, --folder-tokens,
--space-ids, ...) instead of a nested JSON filter, so natural-language
queries from AI agents map 1:1 to discrete flags.

Time handling:
- my_edit_time and my_comment_time are snapped to the hour (floor/ceil)
  with a stderr notice, since those fields are aggregated at hour
  granularity server-side. create_time passes through as-is.
- open_time has a server-side 3-month cap per request. When
  --opened-since / --opened-until span exceeds 90 days, the CLI narrows
  the request to the most recent 90-day slice and emits a stderr notice
  listing every remaining slice's --opened-* values so the agent can
  re-invoke for older ranges. Spans over 365 days are rejected up front
  to bound runaway slicing.

Flag ergonomics:
- --doc-types accepts mixed case; values are normalized to upper case
  before validation and before being sent to the server.
- --sort default is translated to the server enum DEFAULT_TYPE (every
  other sort value upper-cases 1:1).

Error hints:
- Lark code 99992351 (referenced open_id outside the app's contact
  visibility) is enriched with a +search-specific hint that
  distinguishes API scope from contact visibility and points at
  --creator-ids / --sharer-ids as the likely source.

Skill docs:
- new reference at skills/lark-drive/references/lark-drive-search.md,
  including the open_time slicing protocol and the paginate-within-
  slice-before-switching agent playbook.
- lark-drive/SKILL.md routes resource-discovery to drive +search.
- lark-doc/SKILL.md and lark-doc-search.md mark docs +search as
  deprecated and point users at drive +search.

Change-Id: I36d620045809b448446d4fdbdfa923b05794da19
2026-04-25 16:22:35 +08:00
chanthuang 2e7a11a8e8 feat(mail): support sharing emails to IM chats (#637)
* feat(mail): add +share-to-chat shortcut to share emails as IM cards

Two-step API (create share token → send card) wrapped in a single
shortcut. Supports message-id/thread-id, five receive-id-type variants
(chat_id, open_id, user_id, union_id, email), and dry-run mode.

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

* fix(mail): regenerate SKILL.md from skill-template instead of manual edit

Add missing safety rule 8 (draft link rule) to skill-template/domains/mail.md
so it survives regeneration. SKILL.md is now produced by `make gen-skills`
in the registry repo rather than hand-edited.

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

* fix(mail): add docstrings and use real validation path in tests

- Add Go doc comments to exported symbols for docstring coverage
- Rewrite tests to exercise MailShareToChat.Validate via RuntimeContext
  instead of duplicating validation logic
- Replace hand-rolled containsStr with strings.Contains
- Add httpmock stubs for execute and error path tests

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

* test(mail): add dry-run E2E test for +share-to-chat

Validate request shape (method, URL, mailbox path) under --dry-run
with fake credentials. Covers message-id, thread-id, and custom
mailbox variants.

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

* fix(mail): include request body and params in dry-run output

DryRun now mirrors Execute: the share-token POST shows message_id or
thread_id, and the send POST shows receive_id_type and receive_id.
E2E test updated to assert these fields. Also fix strconv.Itoa usage.

Change-Id: I00f8770fd5a12b7354986c5e5077f97cfe5d6653

* style(mail): gofmt dry-run test file

Change-Id: I47dc6a9a47252dcfb7853737f88dfdaef65a0ae7

* test(mail): assert exact API call count in dry-run test

Change-Id: I9f4a1a183b55d03f5248eb4adddfddb08037ca95
2026-04-24 21:11:48 +08:00
liangshuo-1 5d129314c0 chore(release): v1.0.19 (#656)
Change-Id: I551f756deb8e244cf9b4ba47720ef299195859ec
v1.0.19
2026-04-24 19:58:53 +08:00
MaxHuang22 7d0ceb5d58 feat: block auth/config when external credential provider is active (#627)
* feat(credential): add ActiveExtensionProviderName to detect external providers

Change-Id: Ie17a4b714e5eca17ae574ac188d570721790107d

* feat(cmdutil): add RequireBuiltinCredentialProvider guard for external credential providers

Change-Id: I8f2ea0af6fe6506b29beb69264b04c21c0f75da1

* feat(config): block all config subcommands when external credential provider is active

Change-Id: If215cb8f0a53cc92d623dd3d842e4465124af2be

* feat(auth): block all auth subcommands when external credential provider is active

Change-Id: Ia61184fb2daeb6a7a38d122c647b7cb67eaf8b1f

* fix(auth,config): silence usage in PersistentPreRunE to match root command behaviour

Change-Id: I6d4b3c7d9d9c7b10fc2482fdc80252bf051771ee

* test(auth,config,credential): address CodeRabbit review comments

- Use cmd.Find() to assert SilenceUsage on matched subcommand (not parent)
- Add TestRequireBuiltinCredentialProvider_PropagatesProviderError for error path
- Add 'external' fallback sentinel in ActiveExtensionProviderName

Change-Id: Iba35779ad2ed9807556264ba23db7096541e2bf3
2026-04-24 18:45:31 +08:00
zkh-bytedance fd4c35b10e feat(whiteboard): pin whiteboard-cli to v0.2.10 in lark-whiteboard skill (#649) 2026-04-24 15:27:36 +08:00
xzcong0820 d92f0a2204 feat(mail): add read receipt support (--request-receipt, +send-receipt, +decline-receipt)
End-to-end RFC 3798 Message Disposition Notification support, covering
  both sides of the receipt flow — requesting a receipt when composing, and                                                                                                                                             
  responding to one (send or decline) when reading.                                                                                                                                                                     
  
  Request side (compose)                                                                                                                                                                                                
  - New --request-receipt flag on +send / +reply / +reply-all / +forward /
    +draft-create / +draft-edit. When set, the outgoing EML carries a                                                                                                                                                   
    Disposition-Notification-To header (RFC 3798) addressed to the resolved
    sender. Recipient mail clients may prompt the user, auto-send a receipt,                                                                                                                                            
    or silently ignore — delivery is not guaranteed.                                                                                                                                                                    
  - requireSenderForRequestReceipt gates the flag against a controlled
    sender address resolved BEFORE the orig.headTo fallback in +reply /                                                                                                                                                 
    +reply-all / +forward, so the DNT cannot silently land on someone else
    in CC / shared-mailbox flows.                                                                                                                                                                                       
                                                                                                                                                                                                                        
  Response side                                                                                                                                                                                                         
  - +send-receipt: build a system-templated reply for messages carrying the                                                                                                                                             
    READ_RECEIPT_REQUEST label (-607). Subject / recipient / sent / read
    time layout matches the Lark client; body is non-customizable — receipt                                                                                                                                             
    bodies are system templates by industry convention; free-form notes
    belong in +reply. Risk:"high-risk-write" + --yes required.                                                                                                                                                          
  - +decline-receipt: clear READ_RECEIPT_REQUEST without sending anything
    (mirrors the client's "不发送" / "Don't send" button). Idempotent on                                                                                                                                                
    re-run; Risk:"write" — no --yes needed.                       
                                                                                                                                                                                                                        
  Read-path hints                                                                                                                                                                                                       
  - +message / +messages / +thread emit a stderr hint when surfacing a                                                                                                                                                  
    mail carrying READ_RECEIPT_REQUEST, exposing BOTH response paths                                                                                                                                                    
    (+send-receipt --yes / +decline-receipt) so agents present a real                                                                                                                                                   
    choice to the user instead of silently auto-sending.
                                                                                                                                                                                                                        
  Guard rails                                                     
  - +send / +reply / +reply-all / +forward stay draft-by-default and
    require --confirm-send to send, gated by a dynamic scope check for                                                                                                                                                  
    mail:user_mailbox.message:send (absent from the default scope set so
    draft-only flows don't need the sensitive permission).                                                                                                                                                              
  - All header-bound user input (sender / display name / recipient /                                                                                                                                                    
    subject) goes through CR/LF rejection plus Bidi / zero-width / line-                                                                                                                                                
    separator guards, mirroring emlbuilder.validateHeaderValue, to block                                                                                                                                                
    header injection and visual spoofing.                                                                                                                                                                               
  - Hint output strips terminal control characters (CR, LF) from any
    untrusted field embedded into the user-visible suggestion.                                                                                                                                                          
                                                                                                                                                                                                                        
  Backend coupling                                                                                                                                                                                                      
  - Outgoing receipt EML carries the private header                                                                                                                                                                     
    X-Lark-Read-Receipt-Mail: 1. The data-access backend parses it into
    BodyExtra.IsReadReceiptMail; DraftSend then applies READ_RECEIPT_SENT                                                                                                                                               
    (-608) and clears READ_RECEIPT_REQUEST (-607) from the original                                                                                                                                                     
    message, closing the client-side banner.                                                                                                                                                                            
  - en receipts require backend TCC SubjectPrefixListForAdvancedSearch to                                                                                                                                               
    include "Read Receipt:" for conversation-view aggregation; zh prefix                                                                                                                                                
    ("已读回执:") is already configured.                                                                                                                                                                               
                                                                                                                                                                                                                        
  Docs: new reference pages for +send-receipt / +decline-receipt;                                                                                                                                                       
  --request-receipt noted on each compose-side reference; SKILL.md
  workflow (section 9) describes the full privacy-safe decision tree on                                                                                                                                                 
  both sides.                                                                                                                                                                                                           
                                                                                                                                                                                                                        
  Tests cover emlbuilder DispositionNotificationTo / IsReadReceiptMail                                                                                                                                                  
  helpers, receiptMetaLabels (zh / en), buildReceiptSubject, text and HTML
  body generators (with HTML escaping and Bidi guards), header-injection                                                                                                                                                
  defenses, sender-resolution gating (CC-only / shared-mailbox regression),
  hint emission paths, and the full +send-receipt / +decline-receipt happy                                                                                                                                              
  + idempotent paths via httpmock.
2026-04-24 14:26:17 +08:00
YangJunzhou-01 6f444c5dc2 feat: request thread roots for chat message list (#635)
Update im +chat-messages-list to request only thread root messages from /open-apis/im/v1/messages by default. This aligns the shortcut request shape with topic-group usage and makes the intended API behavior explicit in both runtime params and dry-run output.

Change-Id: I3901b27e70b0e4db506ff199eb03c96fcf98671d
2026-04-24 10:40:35 +08:00
SunPeiYang996 e42033f5b5 feat(doc): add v2 API for docs +create / +fetch / +update (#638)
Adds an `--api-version v2` path to the docs shortcuts, backed by the
`docs_ai/v1/documents` OpenAPI. DocxXML is the default document format
and Markdown is available as an alternative. Content input is unified
across the three shortcuts via `--content` + `--doc-format`. The v1
(MCP) path is preserved for backward compatibility and now prints a
deprecation notice on use.

Shortcuts:

  - `docs +create --api-version v2`: create a document from XML or
    Markdown, with optional `--parent-token` or `--parent-position`.
    Bot identity continues to auto-grant the current CLI user
    full_access on the new document.

  - `docs +fetch --api-version v2`: adds `--detail simple|with-ids|full`
    for export granularity and `--scope full|outline|range|keyword|section`
    for partial reads, along with `--context-before` / `--context-after`,
    `--max-depth`, and `--revision-id`.

  - `docs +update --api-version v2`: introduces structured operations
    via `--command`: `str_replace`, `block_delete`, `block_insert_after`,
    `block_copy_insert_after`, `block_replace`, `block_move_after`,
    `overwrite`, `append`.

Framework support in `shortcuts/common`:

  - `OutRaw` / `OutFormatRaw` emit the JSON envelope with HTML escaping
    disabled so XML/HTML document bodies are preserved verbatim.
  - New `Shortcut.PostMount` hook runs after a cobra.Command is fully
    configured; used here to install a version-aware help function
    that hides flags belonging to the inactive `--api-version`.

Also refreshes the lark-doc skill pack (SKILL.md, create/fetch/update
references, new lark-doc-xml and lark-doc-md references, style and
workflow guides), README examples, and downstream skill call sites
(lark-drive, lark-vc, lark-whiteboard, lark-workflow-meeting-summary,
lark-event).

Change-Id: Ide2d86b190a4e21095ae29096e7fb00031d80489
2026-04-23 23:24:30 +08:00
wittam-01 24afe39516 feat: support wiki node targets in drive +upload (#611)
Change-Id: Iaf94270c0a2a2ac02af81c234553ac5850c0668b
2026-04-23 22:37:47 +08:00
Yuxuan Zhao d3340f5006 fix e2e pagination assumptions (#639) 2026-04-23 22:06:58 +08:00
liangshuo-1 d69d0a0bb7 chore: release v1.0.18 (#647)
Change-Id: Ibda8379838392a895f6afddb140fca7f06e5df50
v1.0.18
2026-04-23 21:33:12 +08:00
evandance ce80b3bc46 feat(config): add 'config bind' for per-Agent credential isolation (#515)
Give each AI Agent (OpenClaw, Hermes) its own lark-cli workspace so
its Feishu calls don't overwrite the developer's local config or
collide with other Agents.

    lark-cli config bind [--source openclaw|hermes] [--app-id <id>]
                         [--identity bot-only|user-default] [--force]

Key capabilities:

- Source auto-detected from OPENCLAW_* / HERMES_* env signals; config
  written to ~/.lark-cli/<agent>/, isolated per Agent.
- Two identity presets: 'bot-only' (flag-mode default) and
  'user-default'. Flag mode rejects silent bot→user escalation
  without --force; TUI prompts are exempt.
- Agent-friendly stdout JSON with 'identity' + 'message' for
  next-step branching.
- 'config show' and 'doctor' expose the bound 'workspace'.
- OpenClaw SecretRef resolution: plain / ${VAR} / file:+JSON Pointer
  / exec:.
2026-04-23 19:51:36 +08:00
MaxHuang22 593025d298 feat: add SHA-256 checksum verification to install.js (#592)
* refactor: make install.js side-effect-free on require

Change-Id: I5444e3f34642d7c0740b6422a70ca6921a85e363

* feat: add getExpectedChecksum with unit tests

Change-Id: I87548be25d30c384e743da17b1d161b9d9f0ea87

* feat: add verifyChecksum with unit tests

Change-Id: Ifc2067bf1b824b02257dba7b53716fbe18d0f6b6

* feat: harden download with host allowlist and checksum verification

Change-Id: I2580782866049f1f62a2597e86b7bf59d0e50925

* ci: bundle checksums.txt in npm package for install verification

Change-Id: I2d7c44d9d5b9075158f63c0f8cf66c1e0abe3d8d

* ci: use triggering tag and verify checksums.txt presence in release workflow

Address CodeRabbit review: use GITHUB_REF_NAME instead of parsing
package.json to avoid version drift, and add explicit file check to
fail loudly if checksums.txt is missing or empty.

Change-Id: I8a5658412b6afc338ad2a642baba146cceafd0fc

* feat: streaming hash, allowlist tests, and malformed-line coverage

- verifyChecksum: switch from readFileSync to streaming 64KB chunks
  to avoid loading entire archive (10-100MB) into memory
- Export and test assertAllowedHost: 7 cases covering allowed hosts,
  rejection, case normalization, port handling, invalid URL
- Add ALLOWED_HOSTS comment clarifying it only gates initial URL
- Add getExpectedChecksum tests for malformed/tab-separated lines

Change-Id: Ida639def89c242b3b261a76effae08fd414a10dc
2026-04-23 19:40:27 +08:00
zgz2048 f52ea47163 docs(base): refine record cell value guidance (#636)
* refactor(base): enforce field-map record upsert input

1. Reject top-level fields wrappers in base +record-upsert input and keep request bodies as field maps.

2. Replace record-upsert tests with Map<FieldNameOrID, CellValue> input and assert the outgoing body has no fields wrapper.

3. Consolidate Base record value documentation around lark-base-cell-value and update record command references.

* refactor(base): use common record JSON parsing for upsert

1. Remove the dedicated record-upsert parser and restore the shared record JSON object validation path.

2. Keep record-upsert dry-run and execution as raw JSON object passthrough.

3. Drop the test assertion that rejected a top-level fields key for record-upsert.

* docs(base): refine record cell value guidance

1. Align record CellValue examples with live behavior for date, URL, user, link, select, numeric styles, and readonly fields.

2. Remove misleading user_id_type and execution identity prompts from record-writing guidance.

3. Keep record JSON file input guidance generic and avoid documenting environment-specific stdin or path limits.
2026-04-23 19:18:14 +08:00
wittam-01 10f1f2e2ea fix: escape angle brackets in drive comment text (#632)
Change-Id: I25d05412bd0a2a9e32a517b1344533ad70cb072b
2026-04-23 18:06:53 +08:00
ViperCai 1df5094b46 feat(slides): add +replace-slide shortcut for block-level XML edits (#516)
Introduces `lark-cli slides +replace-slide`, a shortcut over the
native `xml_presentation.slide.replace` API for element-level editing
of existing Lark Slides pages. Callers pass a JSON array of parts and
the CLI handles URL resolution, XML hygiene, client-side validation,
and 3350001 hint enrichment.

Why a dedicated shortcut

The native API has three sharp edges every caller hits:

1. URL formats. Users have /slides/<token> or /wiki/<token> URLs, not
   bare xml_presentation_id.
2. Undocumented XML hygiene. `block_replace` requires id=<block_id> on
   the replacement root; <shape> requires <content/>. Missing either
   returns a catch-all 3350001 with no guidance.
3. 3350001 is a catch-all on the backend with no actionable message.

Code

shortcuts/slides/slides_replace_slide.go (new)
- Flags: --presentation (bare token | /slides/ URL | /wiki/ URL),
  --slide-id, --parts (JSON array, max 200), --revision-id (-1 for
  current, specific number for optimistic locking), --tid,
  --as user|bot.
- Validation (pre-API): [1,200] item cap; action restricted to
  block_replace / block_insert (str_replace rejected); per-action
  required fields (block_id for block_replace, insertion for
  block_insert); per-field string type-assertion guards on the
  decoded JSON so a numeric/bool payload fails fast with a targeted
  error.
- XML hygiene:
  * injects id="<block_id>" on block_replace replacement roots;
  * auto-expands self-closing <shape/> and injects <content/> on
    shapes for SML 2.0 compliance.
  Dry-run surfaces injection errors and renders the same
  path-encoded presentationID that Execute sends.
- On backend 3350001 attaches a generic common-causes checklist
  (missing block_id / invalid XML / coords out of 960×540).

shortcuts/slides/helpers.go
- ensureXMLRootID: regex tightened to `(?:^|\s)id` so data-id and
  xml:id are not matched as root id.
- ensureShapeHasContent: regex `<content(?:\s|/|>)` avoids false
  positives like <contention/>; self-closing branch preserves
  trailing siblings.

shortcuts/slides/shortcuts.go: register SlidesReplaceSlide.

Tests (package coverage 89.4%; parseReplaceParts and
injectBlockReplaceIDs both reach 100%)

- helpers_test.go: regex edge cases, id override semantics, content
  auto-inject across self-closing and open-tag shapes.
- slides_replace_slide_test.go: parameter validation table, URL
  resolution (slides / wiki), mixed block_replace + block_insert,
  size boundaries, auto-inject behavior, 3350001 hint enrichment,
  per-field type-assertion guards, whitespace-only --parts guard
  (distinct from the `[]` "at least 1 item" path), replacement
  without root element surfaces pre-flight instead of reaching the
  backend, and a tight negative assertion that non-3350001 errors
  get no slides-specific hint.

Docs (skills/lark-slides)

- SKILL.md: add +replace-slide to the Shortcuts table, register the
  new xml_presentation.slide.get / .replace native endpoints,
  update core rule 7 to prefer block-level replace over full-page
  rebuild now that element-level editing exists, extend the error
  table with 3350001 / 3350002 pointing at the replace-slide doc,
  add "add image to existing slide via block_insert" as an explicit
  Workflow step and symptom-table entry, and refresh the reference
  index to include the three new docs below. The old "整页替换" 4-rule
  checklist is retired — its one still-relevant guard (new <img>
  avoiding overlap) is preserved in the symptom table.
- New references:
  * lark-slides-replace-slide.md — flags, parts schema, auto-inject
    notes, mixed-action support, 200-item cap, revision_id
    semantics, error table, and a "合法根元素速查" cheatsheet for
    the eight supported root elements (shape / line / polyline /
    img / icon / table / td / chart) with minimal verified XML
    snippets. Explicit unsupported list: video / audio / whiteboard
    (these appear only as <undefined> export placeholders in SML 2.0).
  * lark-slides-edit-workflows.md — recipe-style edit flows covering
    the read → modify → write loop and the block_replace vs
    block_insert decision tree.
  * lark-slides-xml-presentation-slide-get.md — native read API with
    block_id extraction examples.
- Fixes across existing references:
  * replace / create / delete / presentations.get: add the .data
    wrapper in return-value examples, correct jq paths.
  * media-upload: fix jq path .file_token → .data.file_token.
  * examples.md: annotate auto-inject behavior, replace the
    incorrect failed_part_index example with the actual 3350001
    error shape.

Empirical corrections (BOE-verified)

- revision_id: stale-but-existing values are accepted; only values
  greater than current return 3350002.
- Wrong block_id returns 3350001, not a 200 with failed_part_index.
- Mixed block_replace + block_insert in one call is supported.
- Type-mismatched block_replace (e.g. shape id with a <td>
  replacement) is silently accepted by the backend and may destroy
  content; 3350001 specifically signals a missing block_id.
2026-04-23 18:04:59 +08:00
MaxHuang22 600fa50517 feat: add configurable content-safety scanning (#606)
* feat(contentsafety): add extension interface layer with Provider, Alert, and registry

Change-Id: Ibeac6366c7201293057bc3b063f75ac34565bcd5

* feat(contentsafety): add normalize utility for JSON type conversion

Change-Id: I7d4729a5ddcab2553abc110f8f6ecc88435ae921

* feat(contentsafety): add tree walker and regex scanner

Change-Id: I215dad7cf3072711d05e45f7d384162e1f8752d4

* feat(contentsafety): add config loading with lazy creation, default rules, and allowlist matching

Change-Id: I75e10df28f1f8d4f433cb2b469a0ff317af3bf70

* feat(contentsafety): add regex provider with config-driven scanning and allowlist

Change-Id: I658889b3647cbbbde6881e0c5f7c13887a1eb1d4

* feat(contentsafety): add output core with mode parsing, path normalization, and scan orchestration

Change-Id: I1cb9df75f1a4d176d660e2e7a9561314c3787191

* feat(contentsafety): add ScanForSafety entry point and Envelope alert field

Change-Id: I5fdb311e1c8d983a35a58667970b9fd3ac729a5c

* feat(contentsafety): integrate scanning into shortcut Out() and OutFormat()

Change-Id: I33eef1dba14c8a9bd1998857311bdd611f33b916

* feat(contentsafety): integrate scanning into API/service output paths and register provider

Change-Id: Ic3981db6c546a19eadea095d82175f92f4783bec

* fix(contentsafety): emit stderr notice when lazy-creating default config

Change-Id: Ia2491f7a17caceea3125ff9fb58d750dc196d7e7

* style: gofmt factory_default and exitcode

Change-Id: I86c5afdfbbdb68d8137f0ca09ef3b5a1139f4b4e

* fix(contentsafety): vfs for config I/O, mutex for lazy-create, sort matched rules, emit warn on --output path

Change-Id: Ib4982cd54e1bfe0580a0eb03368e6ca818304e1b

* fix(contentsafety): isolate scan goroutine errOut to prevent race on timeout

Change-Id: Ia5a770d7387ba6d3b7fa318fc5f1384214ea10b7

* fix(contentsafety): deep-normalize typed slices so scanner can walk shortcut data

Change-Id: I641e89113d1a2f2285ac6109bd3d7264f5845ea7

* fix(contentsafety): file perms 0600/0700, no result mutation, timeout test, scanTimeout comment

Change-Id: Ie45a2e365ee7098e214e94f8871026cc12029d83
2026-04-23 17:18:29 +08:00
YangJunzhou-01 fc6d722f05 fix(im): unify messages-search pagination int flags (#446)
Unify lark-cli im +messages-search pagination flags to use int semantics consistently.

Previously, page-limit was registered as an int flag while page-size was still handled as a string flag and parsed manually. This led to inconsistent runtime behavior inside the same shortcut and allowed test helpers to drift from the real CLI flag registration.

Change-Id: Ic4876f4ca7f410a8fe3234e08e41b54ce26990d9
2026-04-23 17:17:02 +08:00
max c7ced37959 feat: unify minute artifacts output to ./minutes/{minute_token}/ (#604)
* feat: unify minute artifacts output to ./minutes/{minute_token}/

* fix: tighten path validation and batch-mode --output rejection

* style: translate comments to english and trim historical context

* style: translate leftover chinese comments in vc_notes

* refactor: address review findings across validate ordering, error types, JSON, tests

* fix: sanitize server-provided filename to prevent escape from artifact dir

* style: tighten flag help text for minutes/vc output flags

* docs: update minutes/vc skill docs for unified artifact layout
2026-04-23 16:37:33 +08:00
liujinkun2025 81d22c6f34 feat(wiki): add +delete-space shortcut with async task polling (#610)
Add lark-cli wiki +delete-space to delete a knowledge space via
DELETE /open-apis/wiki/v2/spaces/:space_id. When the API returns an
async task_id, the shortcut polls /open-apis/wiki/v2/tasks/:task_id
with task_type=delete_space for a bounded window and emits a
next_command pointing to drive +task_result on timeout. A new
wiki_delete_space scenario is added to drive +task_result for resuming
timed-out deletes.

Change-Id: I75da52b617c206fb778a493ffaa200adf7920a27
2026-04-23 11:35:56 +08:00
zkh-bytedance 6b7263a53b feat(whiteboard): Pin whiteboard-cli to ^0.2.9 (#617) 2026-04-23 11:02:45 +08:00
河伯 bc6590abef feat(doc): add --from-clipboard flag to docs +media-insert (#508)
* feat(doc): add --from-clipboard flag to docs +media-insert

Allow users to upload the current clipboard image directly to a Lark
document without saving to a local file first.

- New --from-clipboard bool flag (mutually exclusive with --file)
- shortcuts/doc/clipboard.go: readClipboardToTempFile() with per-OS impl
    macOS   — osascript (built-in, no extra deps)
    Windows — PowerShell + System.Windows.Forms (built-in)
    Linux   — tries xclip / wl-paste / xsel in order; clear install hint
              on failure
- No new Go dependencies, no Cgo
- Temp file is created before upload and removed via defer cleanup()
- --file changed from Required:true to optional; Validate enforces
  exactly-one of --file / --from-clipboard

* fix(doc): fix clipboard image read on macOS for screenshots and browser-copied images

- Add TIFF fallback (macOS screenshots default to TIFF, not PNG)
- Add HTML base64 fallback (images copied from Feishu/browser embed data URI)
- Use current directory for temp file so FileIO path validation passes

* fix(doc): scan HTML/RTF/text clipboard formats for base64 image data URIs

Extend attempt-3 fallback to iterate all text-based clipboard formats
(HTML, RTF, UTF-8, plain text) rather than only HTML.  Any format that
contains a "data:<mime>;base64,<data>" pattern is accepted, covering
images copied from Feishu, Chrome, Safari, and other apps that embed
base64 in non-HTML clipboard slots.  Also handle URL-safe base64.

* test(doc): add unit tests for clipboard helpers to meet 60% coverage threshold

Cover decodeHex, hexVal, decodeOsascriptData, reBase64DataURI, and
extractBase64ImageFromClipboard (via fake osascript on PATH).
Package coverage: 57% → 61.2%.

* fix(doc): address CodeRabbit review comments on clipboard feature

- Extend reBase64DataURI regex to cover URL-safe base64 chars (-_) so
  URL-safe payloads are matched before decoding is attempted
- Fix readClipboardLinux to continue to next tool when a found tool
  returns empty output instead of failing immediately
- Guard fake-osascript test with runtime.GOOS == "darwin" skip
- Use os.PathListSeparator instead of hardcoded ":" in test PATH setup

* fix(doc): replace os.* temp-file clipboard path with in-memory streaming

Fixes forbidigo lint violations in shortcuts/doc: os.CreateTemp, os.Remove,
os.Stat, os.WriteFile are banned in shortcuts/; replaced with vfs.* equivalents
for sips TIFF→PNG conversion, and eliminated temp files entirely elsewhere by
having platform clipboard readers return []byte directly.

- readClipboardDarwin: osascript outputs hex literals decoded in Go (no file I/O)
- readClipboardWindows: PowerShell outputs base64 to stdout, decoded in Go
- readClipboardLinux: tool stdout bytes returned directly
- convertTIFFToPNGViaSips: still needs temp files — uses vfs.CreateTemp/Remove
- DriveMediaUploadAllConfig/DriveMediaMultipartUploadConfig: add Content io.Reader
  field so in-memory clipboard bytes skip FileIO.Open() path
- Fix ineffassign in clipboard_test.go (scriptBody double-assignment)
- Update TestReadClipboardLinux_NoToolsReturnsError for new signature

* fix(doc): address CodeRabbit review comments on Linux clipboard path

- Update --from-clipboard flag description to list xclip, xsel and wl-paste
- Preserve last backend-specific error in readClipboardLinux so users see
  a meaningful message when a tool is found but fails
- Validate PNG magic bytes for xsel output (xsel cannot negotiate MIME types)
- Add URL-safe base64 regression test for reBase64DataURI

* fix(doc): strip whitespace from base64 payload before decoding clipboard data URI

HTML and RTF clipboard content often line-wraps base64 at 76 characters.
FindSubmatch returns the raw wrapped token so direct decode would fail.
Normalize whitespace with strings.Fields before passing to base64.Decode.

* fix(doc): drop TIFF fallback and internal/vfs import on macOS clipboard

depguard rule shortcuts-no-vfs forbids shortcuts/ from importing
internal/vfs directly. The only caller was the sips TIFF→PNG
conversion, which was already a fragile best-effort fallback that
required temp files.

Remove the TIFF fallback entirely; the remaining two attempts cover
the real-world cases:
  1. osascript → PNG hex literal — native screenshots and most apps
  2. scan text clipboard formats for base64 data URI — Feishu/browsers

* test(doc): cover readClipboardLinux xsel PNG validation and dispatcher path

Added tests:
- TestReadClipboardLinux_XselRejectsNonPNG: fake xsel that returns plain
  text is rejected by the PNG-magic check, preventing text from being
  uploaded as an "image".
- TestHasPNGMagic: table-driven coverage of the PNG signature check.
- TestReadClipboardImageBytes_UnsupportedPlatform: exercises the shared
  dispatcher post-processing and asserts the (nil, nil) invariant.

Raises clipboard.go diff coverage and brings the package from 61.6% to
63.8% overall.

* test: cover in-memory Content upload paths for clipboard feature

Adds unit tests for the new Content io.Reader branches introduced by
the clipboard feature:

- UploadDriveMediaAll with in-memory Content (drive_media_upload.go 87.5%)
- UploadDriveMediaMultipart with in-memory Content (84.6%)
- uploadDocMediaFile single-part and multipart with clipboard bytes
  (doc_media_upload.go 0% -> 88.9%)

Adds TestNewRuntimeContextForAPI helper that wires Factory, context,
and bot identity so package tests can invoke DoAPI without mounting
the full cobra command tree.

* test: cover clipboard Validate/DryRun branches and testing helper

Adds unit tests for the clipboard-related Validate/DryRun paths that
Codecov patch-coverage was flagging as uncovered:

- Validate error when neither --file nor --from-clipboard is supplied
- Validate error when both are supplied (mutual exclusion)
- DryRun output contains <clipboard image> placeholder
- Self-test for TestNewRuntimeContextForAPI so shortcuts/common
  sees coverage for the new helper (not just shortcuts/doc)

* test: cover Execute clipboard branch via injectable readClipboardImage

Makes readClipboardImageBytes swappable in tests by routing the call
through a package-level variable readClipboardImage. Tests inject a
synthetic PNG payload so the full Execute clipboard flow
(resolve → create block → upload in-memory bytes → bind) runs under
unit test without a real pasteboard.

Covers:
- TestDocMediaInsertExecuteFromClipboard: end-to-end happy path
- TestDocMediaInsertExecuteClipboardReadError: early-return on
  readClipboardImage() failure

* ci: re-trigger pull_request workflow for PR #508

Previous push to 9dedb7a did not trigger the main CI workflow via
the pull_request event (only PR Labels ran). The workflow_dispatch
run I triggered manually lacks PR-scoped secrets so security and
e2e-live failed. An empty commit replays the pull_request event so
the full matrix (deadcode, license-header, security, e2e-live) runs
with proper context.

* test(doc): guard info.Size() behind err check to prevent nil-deref

CodeRabbit flagged that 't.Fatalf("... size=%d err=%v", info.Size(), err)'
evaluates info.Size() even when os.Stat returned (nil, err), which nil-derefs.
Split the check into two stages so the error-path t.Fatalf does not touch
info.

* fix(doc): address fangshuyu-768 review on clipboard PR

Seven code changes driven by review feedback:

1. clipboard.go: stop using CombinedOutput() on osascript / powershell.
   Stdout is decoded, stderr is captured separately via cmd.Stderr and
   surfaced in the terminal error message, so locale warnings or
   AppleEvent permission prompts no longer pollute the hex/base64
   payload or mask the real failure.

2. clipboard.go: validate decoded base64 data URI bytes against known
   image magic headers (PNG/JPEG/GIF/WebP/BMP). A text clipboard that
   happens to contain a literal 'data:image/...;base64,...' fragment
   (documentation, tutorials, pasted HTML source) no longer silently
   becomes an image upload.

3. clipboard.go: simplify the Linux 'no tool found' install hint to a
   distro-agnostic phrasing instead of apt/yum only.

4. clipboard_test.go: delete the stale TestReadClipboardToTempFile_*
   tests. They referenced a readClipboardToTempFile function that no
   longer exists and only exercised os.CreateTemp/os.Remove. Replace
   with TestReadClipboardImageBytes_EmptyResultReturnsError which
   actually locks in the 'empty clipboard' → error contract of the
   current API (Linux-only since mac/Windows need a real pasteboard).

5. doc_media_upload.go: introduce UploadDocMediaFileConfig struct so
   uploadDocMediaFile takes a named config instead of 8 positional
   params. Drops the //nolint:lll the old call site had to carry.

6. doc_media_insert.go: convert the clipboard upload call to the new
   config struct and only set Config.Content when the clipboard branch
   actually produced bytes — this also fixes a latent typed-nil bug
   where a nil *bytes.Reader was being passed through an io.Reader
   parameter, which tripped the 'if cfg.Content != nil' check in
   UploadDriveMediaAll and crashed --file uploads.

7. shortcuts/common/testing.go: TestNewRuntimeContextForAPI now takes
   the identity as an explicit core.Identity parameter instead of
   hardcoding core.AsBot, and its self-test covers both AsBot and
   AsUser. Existing call sites pass core.AsBot explicitly.

Also annotates DryRun output with an 'upload_size_note' when
--from-clipboard is set, since DryRun never reads the pasteboard and
can't predict whether the payload will take the single-part or
multipart path.

* fix(doc): capture line-wrapped base64 in clipboard data URI regex (#586)

HTML and RTF clipboard content commonly folds base64 payloads at
76 chars (standard MIME folding). The previous character class
[A-Za-z0-9+/\-_]+=* stopped at the first \n, so the downstream
strings.Fields normalisation was a no-op (nothing to strip) and
extractBase64ImageFromClipboard silently uploaded a truncated
payload whose 8-byte prefix happened to pass hasKnownImageMagic.

Extend the class to include \s so the Fields strip actually has
whitespace to remove before base64 decoding. Terminators (", <,
), ;) remain outside the class so the match still ends at the
URI boundary.

Add TestReBase64DataURI_LineWrapped covering \n, \r\n, and \t
folds, full round-trip byte-equality, and the terminator-boundary
invariant so any future regression trips a failing test.

* docs(skill): add clipboard-empty fallback guidance for +media-insert

When --from-clipboard returns 'no image data' (empty clipboard, non-image
content, or Linux without xclip/wl-paste/xsel), the agent must NOT silently
swallow the error. It should tell the user the clipboard had no image, ask
for a local file path, then retry the same insert command with --file.

Lists three anti-patterns (silent success, guessing a file path, pre-emptive
save-then-file workaround) that agents have been tempted into.

* docs(skill): user-stated source trumps clipboard/file heuristic

The heuristic table (prefer --from-clipboard when image is on the
clipboard) is a fallback for when the user is vague. If the user
explicitly says 'use the screenshot I just copied' → clipboard; if
they give a path → --file. Agent must not silently swap sources even
when the other looks 'better'.

---------

Co-authored-by: fangshuyu-768 <shuyufang768@outlook.com>
2026-04-22 22:05:33 +08:00
liujinkun2025 295f1d513e feat: support .base import and export for bitable (#599)
Allow drive +export to request bitable snapshots with --file-extension base and write them with a .base suffix.

Allow drive +import to accept .base files for bitable only, enforce the 20 MB size limit, and document the new examples and constraints.

Add unit tests for validation and size-limit coverage.

Change-Id: Ia13f5013913812df5fc600c43f90918de4ca6b39
2026-04-22 22:01:08 +08:00
sammi-bytedance e6f3fa2575 fix(im): fix markdown URL rendering issues in post content (#206)
Preserve fenced code blocks and balanced-parenthesis URLs when converting markdown to post elements. Add regression tests covering code-block URLs and wiki-style links.

Change-Id: I709a3daf3635402848c96b5122edfc67979ed1a4
2026-04-22 20:46:28 +08:00
liangshuo-1 776ee686ff chore: release v1.0.17 (#614)
Change-Id: I12f59a72996c9d21dacd5478190a85af765bb1a4
v1.0.17
2026-04-22 20:17:43 +08:00
chenxingtong-bytedance 4da6d610e2 feat(im): use Content-Disposition filename when downloading message resources (#536)
When downloading message resources, the saved filename was always derived from
file_key (e.g. file_v2_abc123.xlsx), ignoring the original filename the
sender uploaded. This PR resolves filenames from the Content-Disposition
response header first, falling back to Content-Type-based extension inference
only when the header is absent.

Change-Id: I68b48cf428aa8aded4ad9d55fa042f9d68263c3a
2026-04-22 19:52:27 +08:00
zl-bytedance 3f4352d50c feat: add image support to whiteboard-cli skill (#553)
* feat: add image support to whiteboard-cli skill

- Add references/image.md with image processing workflow
- Update content.md with strict image trigger condition
- Update schema.md with Image node type definition
- Update layout.md with image card layout rules
- Add scenes/photo-showcase.md for image showcase layouts
- Strict trigger: only when user explicitly requests images/配图/插图

* docs: sanitize image.md examples - remove real token, use placeholder URLs, cross-platform file check
2026-04-22 18:54:36 +08:00
wittam-01 543a8365d6 docs: clarify that lark-drive comment listing defaults to unresolved comments only (#609)
Change-Id: Ie4200fe14f1e3c4735c1fcc4aba4a3f9a4900e22
2026-04-22 17:37:23 +08:00
fangshuyu-768 0192cee859 docs(lark-doc): fix --markdown examples that teach literal \n (#602)
Skill examples taught the pattern --markdown "## A\n\n- x\n- y",
which in bash double quotes is a literal backslash + n, not a
newline. lark-cli forwards the value byte-for-byte to MCP, so
the resulting Feishu doc renders "\n\n" as visible text. Agents
and users copy-pasting the examples reliably produced broken
docs.

Documentation-only fix (issue #580 Option 1, non-breaking):

- Replace 9 "...\n..." examples with multi-line quoted strings,
  plus 1 single-quoted example that had the same bug inside
  Markdown-block content
- Add a one-sentence warning callout at the top of each file
- Add a stdin/heredoc example in lark-doc-create.md for longer
  content
- Leave existing $'...' ANSI-C examples untouched — those
  already produce real newlines

No CLI behavior change. Byte-for-byte forwarding is standard
shell semantics; auto-interpreting \n (Option 2) would be a
breaking change and is intentionally not pursued.

Fixes #580
2026-04-22 16:50:24 +08:00
sang-neo03 18e227f281 feat(cmdutil): add X-Cli-Build header for CLI build classification (#596)
* feat(cmdutil): add X-Cli-Build header for CLI build classification

  Adds X-Cli-Build (official / extended / unknown) so the gateway can distinguish official CLI from ISV-repackaged builds.

* test(cmdutil): lift coverage on build-kind classification

Extract classifyBuild as a pure helper so every branch (unknown / extended
main-path / extended credential / extended transport / extended fileio /
official) is reachable without mutating process-wide provider registries.

Also cover: isBuiltinProvider non-pointer values, BuildHeaderTransport
nil-Base fallback path, and fix the Name-spoof test so the test double
returns a value that actually mimics an ISV provider.

Coverage on PR-changed functions:
- classifyBuild: 100% (new)
- computeBuildKind: 61.5% -> 93.3%
- BuildHeaderTransport.RoundTrip: 80% -> 100%
2026-04-22 16:30:32 +08:00
caojie0621 7e9beec422 feat(drive): add +apply-permission to request doc access (#588)
Wrap the POST /drive/v1/permissions/:token/members/apply endpoint as a
user-only shortcut. --token accepts either a bare token or a document
URL, with type auto-inferred from the URL path (/docx/, /sheets/,
/base/, /bitable/, /file/, /wiki/, /doc/, /mindnote/, /minutes/,
/slides/); an explicit --type always wins. --perm is limited to view or
edit; full_access is rejected client-side to match the spec.

Classifier gains two domain-specific hints for the endpoint's newly
documented error codes: 1063006 (per-user-per-document quota of 5/day
reached) and 1063007 (document does not accept apply requests — covers
disallow-external-apply, already-has-access, and unsupported-type).

test(drive): add dry-run E2E for +apply-permission

Invoke the real CLI binary via clie2e.RunCmd under --dry-run and
parse the rendered request JSON with gjson to lock in method, URL
path (including the token segment), type query parameter (auto-inferred
for docx / sheet / slides URLs, taken from explicit --type for bare
tokens), perm body field, and remark presence/omission. A separate
test asserts --perm full_access is rejected by the enum validator
before reaching the server. Fake LARKSUITE_CLI_APP_ID / APP_SECRET /
BRAND are enough because dry-run short-circuits before any API call.

Update drive coverage.md to add a row and refresh metrics.

test(drive): isolate E2E dry-run subprocess from local CLI config

Set LARKSUITE_CLI_CONFIG_DIR to t.TempDir() in both +apply-permission
dry-run tests so the subprocess can't read a developer's real
credentials/profile instead of the fake env vars the tests inject.

test(drive): add E2E case that exercises URL inference override

Previous "bare token with explicit type wins over inference" row used a
bare token, which has no URL-derived type to override. Replace it with
a /docx/ URL + --type wiki combo that actually forces the explicit flag
to win over URL inference, and add a separate bare-token row to keep
the simpler path covered. Refresh coverage.md wording to match.
2026-04-22 16:28:48 +08:00
chanthuang 462d38e8f7 docs(mail): remove get_signatures from skill reference, exposed via +signature instead (#545)
Change-Id: I3463cbd08d595c1cb9cda4fadc6e2a5ad1c62189
2026-04-22 16:08:56 +08:00
kongenpei e4d263948c fix(base): add default-table follow-up hint to base-create (#600)
* fix(base): add default-table follow-up hint to base-create

* fix(base): route base-create hint to stderr

* fix(base): prefix base-create stderr tip

---------

Co-authored-by: kongenpei <kongenpei@users.noreply.github.com>
2026-04-22 14:53:58 +08:00
tuxedomm 11191df703 fix: skip flag-completion registration outside completion path (#598)
* fix: skip flag-completion registration outside completion path

Cobra keeps completion callbacks in a package-global map keyed by
*pflag.Flag with no removal path, so registrations made during Build()
outlive the command itself. Route all seven call sites through
cmdutil.RegisterFlagCompletion and enable registration only when the
invocation actually serves a __complete request.

Measured over 30 dropped Builds: ~202 KB / 2180 retained objects per
Build before, ~0 after.

Change-Id: I734d598a4c91a92c33b02e0f292f640cc0e224c6
2026-04-22 11:55:11 +08:00
yballul-bytedance e23b3a8dc6 fix: add record-share-link-create in SKILL.md (#597)
Change-Id: Ie8dc96521ee692804b734b030f7c143171193eb9
2026-04-22 11:54:01 +08:00
yballul-bytedance f3699298aa feat: cli 支持记录分享 no-meego (#466)
Change-Id: Ie78da99096cc1fc8a4671d8178176f4c587466ba
2026-04-22 10:31:37 +08:00
chanthuang 018eeb6414 fix(mail): remove leftover conflict marker in skill docs (#594)
The <<<<<<< HEAD marker was accidentally left in mail.md and SKILL.md
by commit cb301a3 (draft preview URL). Remove it.

Change-Id: I6e1d5c0c66761302a3c4ee1421a16961b666bd80
2026-04-21 21:58:01 +08:00