* fix(base): make record history queries explicit and readable
1. Require an explicit confirmed record ID and document deterministic record resolution
2. Add shared-format pretty history output and projection aliases without changing default JSON
3. Reject explicitly non-positive history cursors and cover request, help, formatting,
and dry-run behavior
```ai-signature
改动范围: 将 Codebase MR 1438 的最终十文件差异移植到 GitHub PR 2298,覆盖 record history 命令、record list 投影别名、Base 引导文档与对应单元及 dry-run 回归测试
思考过程: 以 GitHub 最新 main 为基线执行三方内容合并,保留 GitHub 独立演进;删除原 PR 针对 base_history_003 的 Skill 改动,并仅按 GitHub 当前分母重算 coverage 指标
改动原因: GitHub PR 原先承载的是已确认应撤回的单题文档方案,需要由已评审的 MR 1438 最终通用实现完整替换,同时避免复制 Codebase 的多轮提交与 revert 历史
Break Change: 行为 breaking | record history 要求显式确认的 record ID,且显式非正 --max-version 现在返回 typed validation error
```
Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
AI-SHA256: 5bf66267670f435c7d577d2444b61b209322eb5a73f15e47e671a5b8dd2603bf
* fix(base): validate history cursors and NDJSON dry runs
1. Reject missing or invalid next_max_version values before emitting pagination guidance
2. Use the execution page size in NDJSON dry runs and assert the requested output path
3. Cover valid and invalid history cursors and prove a 2000-row request is capped to a 500-row first
page
```ai-signature
改动范围: shortcuts/base/record_history_list.go、record_ops.go 及邻近单元和 dry-run E2E 测试,仅处理 PR 2298 中有效 CodeRabbit 评论,不新增 live E2E 或修改主 Skill
思考过程: 分页提示只接受解码后的正整数游标;NDJSON dry-run 复用执行阶段的五百行页大小,并以两千行请求验证真实截断而非相等值偶然通过,同时直接断言导出路径契约
改动原因: 原实现可能把不可用的服务端游标打印成命令,同时 dry-run 对 201 到 500 条请求报告的首屏大小与真实执行不一致,初版测试也未真正证明五百行上限或 search 输出路径
Break Change: 否
```
Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
AI-SHA256: a362c47d739d6de5676b87431fbc015d1eaa3d47d46d711e2535baa4dad7ffce
* docs(base): simplify record history prerequisites
1. Condense the record history prerequisites into generic record selection rules.
2. Remove the positive and negative examples from the reference.
```ai-signature
改动范围: 仅修改 skills/lark-base/references/lark-base-record-history-list.md,精简使用前置并删除正反例章节。
思考过程: 保留调用前确认同表 record_id、不得自行选择记录或扩展整表扫描的核心约束,移除具体链接、视图位置和命令示例以提升通用性。
改动原因: 用户要求使用前置更精简、表述更通用,并删除正反例;本次不涉及命令行为或测试。
Break Change: 否
```
Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
AI-SHA256: 7e69951d47c1535cd5fe0fa9ebd7018af2e17373e5851c229dac46d68eaefa84
* fix(base): align history guidance with affordance
* fix(base): keep history guidance in the existing reference
1. Remove the new Base affordance file and its Markdown-only tests
2. Keep selection and field quoting guidance in the existing record history reference
3. Restore the pre-existing command tips and retain only behavior-focused regressions
```ai-signature
改动范围: 删除新增 affordance/base.md 与对应 source/help 文案测试,调整 record-history 现有 reference、覆盖说明和原命令 Tips
思考过程: 用户要求不新增 Base affordance 文件且 Markdown 不需要专门测试,因此保留运行时代码测试,把跨命令选行和字段引号说明收敛到已有 reference
改动原因: 新增 affordance 与文案测试扩大了 PR 改动面,并重复承载已有 history reference 的 agent 工作流说明
Break Change: 否
```
Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
AI-SHA256: 4c7e3db10025f412d4b2cb4443d94724b5997b72b7e8f97fafdae2f08633b5a2
* docs(base): clarify record history target selection
1. Describe the record ID as uniquely resolving the user-selected target
2. Avoid implying that users must confirm an opaque internal record ID directly
```ai-signature
改动范围: 仅调整现有 lark-base record-history reference 的一处目标记录选择表述
思考过程: CLI 运行时只要求有效 record_id,agent 工作流要求用户确认目标而不是直接确认内部 ID,因此需要区分产品事实和操作约束
改动原因: 原表述可能被误解为 base-cli 能验证 record_id 的用户确认来源,与实际产品边界不一致
Break Change: 否
```
Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
AI-SHA256: bd6c9584cc38689e1c3d9f26514425e3e38ffe2f2cff7b2bb0c65ff316aaf8dc
* docs(base): preserve serial history queries
---------
Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
* feat(base): add BaseApp workspace, page and block shortcuts
Implement the CLI layer of the BaseApp CLI/OpenAPI protocol design: 17 new
shortcuts covering workspace entities, blank app creation, page CRUD and page
block CRUD, plus skill references and dry-run E2E for each.
The data_config validator moves to a neutral block_data_config.go with chart
logic unchanged; list and richText dispatch are new branches, so dashboard
behaviour is untouched. Command spaces stay separate — dashboard commands never
take --app-token and app block commands never take --dashboard-id. The one
exception is +app-block-get-data, which shares the dashboard endpoint, execute
and dry-run hooks and therefore takes --base-token instead of --app-token.
This phase ships no +app-block-delete and no page arrange command; both the
help text and the skill docs spell out that a block type cannot be changed
after creation.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(base): implement app mode shortcuts and list components
* feat: support deleting BaseApp via drive delete
* fix: 修复 workspace scope
* fix: correct BaseApp permission scopes
* feat: 新增 moveIn workspace 逻辑
* feat(base): support multi-datasource data_config for BaseApp charts
BaseApp page charts follow section 8 图表协议 of the App CLI RPC 协议,
which differs from dashboard charts by supporting multiple data sources:
base_token is a single top-level value shared by every source, while
table_name/series/count_all/group_by/filter move into each data_sources[]
element (plus top-level data_source_mode and sort). The per-source value
semantics are identical to dashboard charts, so each data_sources[] element
reuses normalizeDataConfig / validateChartDataConfig; the wrapper only adds
the top-level structure. Dashboard charts keep the flat shape; the list
protocol is untouched.
- block_data_config.go: add normalizeAppChartDataConfig /
validateAppChartDataConfig / validateAppBlockDataConfig
- app_block_create/update: route chart blocks to the multi-datasource
normalize/validate; refresh tips and examples
- reference doc: rewrite the chart section for the multi-datasource shape
- unit + e2e tests: migrate chart cases to data_sources; add a
multi-datasource combo case
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(base): map BaseApp richText block type to the wire type "text"
The rich-text widget's API type is "text" (App CLI RPC 协议 §10), but the
CLI exposes the friendlier "richText" alias and was sending it verbatim, so
the backend rejected +app-block-create --type richText with "type is
invalid". Map richText -> text when building the request body; the
user-facing --type richText is unchanged. Add TestAppRichTextTypeMapsToText.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(base): remove internal protocol doc link/reference from skills
The BaseApp skill references pointed at an internal Lark doc (deep link with
a private token) as the source of truth, which must not ship in this repo.
Drop the link and the doc name entirely from the reference markdown and from
code comments; describe behavior in neutral terms ("服务端协议 / 服务端返回和校验")
instead. No functional change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: create workspace for BaseApp when omitted
* fix(base): align BaseApp block protocol
* fix: 删掉废弃的 workspace-entity-remove
* fix(base): align app get reference response
* fix(base): align app shortcuts with API contract
* fix(base): refine app mode shortcut contracts
* fix: use entity_type for workspace entity filtering
* fix: return workspace URLs for base workspace ops
* fix(base): enforce unique app block names
* fix(base): use chart token for app block data
* 明确baseapp边界,不导向到dashboard-arrange
* docs(base): clarify app copy is unsupported
* docs(base): define unsupported app page operations
* fix(base): align app block text type with dashboard
AppMode 的文本组件此前对外叫 richText,发送时再映射成 wire 上的 text,
而读取方向没有反向映射:写进去用 richText、读回来是 text,同一个 CLI
表面自相矛盾,回填或幂等复建时会被枚举校验拒掉。
统一成 text,与 Dashboard 文本组件同名同义:
- appBlockTypes/isAppBlockType/textBlockTypes 去掉 richText
- 删除 appBlockBody 里的 richText → text 发送期映射
- help、枚举、示例、tips 与 baseapp block data_config reference 同步
- 新增回归测试,确保 richText 不再被接受也不再出现在枚举里
richText 不保留别名:+app-* 尚未随已发布版本对外,无存量调用方。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(base): resolve BaseApp URLs
Migrate the net changes from bitable/base_cli!1308 onto the current BaseApp development branch.
* fix(base): remove app block list type filter
* docs: preserve explicit intent when reusing BaseApp blocks
* fix(base): route +app-block-get-data to base_apps endpoint
Move the shortcut off the dashboard route and onto the dedicated
BaseApp block-data endpoint:
- URL: /open-apis/base/v3/base_apps/:app_token/blocks/:block_id/data
- base_token is passed as a required query parameter per the new IDL
- Refresh --block-id description and tips to list all producers of the
chart_token (create/list/get) and note the cht… prefix
- Update the dryrun test to expect the new URL
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix: clarify unsupported BaseApp copy paths
* fix: front-load BaseApp copy stop rule
* fix: surface unsupported PageGroup operations
* fix: preserve PageGroup support boundary
* docs(base): clarify unsupported app block handling
* docs(base): clarify how to read text block content
Text blocks have no /data endpoint; calling +app-block-get-data on
one returns a generic server 500. Point readers at +app-block-get,
whose data_config.text carries the Markdown source.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* docs: clarify immutable BaseApp block types
* docs(base): correct chart date filter format
* docs(base): explain inaccessible app pages
* docs: require workspace removal lookup
* fix(base): return workspace move-in result faithfully
* chore(base): adapt BaseApp changes to upstream main
* fix(base): align app mode changes with upstream scope
* fix(base): address app mode review feedback
* test(base): assert app data transport error contract
* fix(base): satisfy app mode merge requirements
* refactor(base): align app mode filenames
* docs: fix BaseApp rename guidance
* fix(base): remove unsupported workspace icon
* docs(base): clarify app mode concepts and config reuse
---------
Co-authored-by: weibiao.x <weibiao.x@bytedance.com>
Co-authored-by: zhangbinkai.zbk <zhangbinkai.zbk@bytedance.com>
Co-authored-by: yurunjie <yurunjie.xx@bytedance.com>
Co-authored-by: Codex <codex@example.com>
* feat(base): require --fields on +table-create
A table created without --fields gets the platform default schema. Those
default fields then sit in the table alongside every field the caller adds
afterwards, and no field command removes them all, so the only clean recovery
is to drop the table and start over.
Make --fields required so the schema is declared up front, the way
+base-create already recommends via --table-name + --fields.
- Mark --fields Required on +table-create, and reject blank / non-array /
empty-array values in Validate: cobra's MarkFlagRequired only checks that the
flag was set, so --fields "" and --fields "[]" would still reach the API with
no fields body and fall back to the default schema.
- Validate runs ahead of the dry-run branch, so --dry-run can no longer preview
an invocation the real call would reject.
- Update the lark-base skill, e2e coverage notes and the live e2e helper.
BREAKING CHANGE: `lark-cli base +table-create --base-token <t> --name <n>`
without --fields now fails with a validation error instead of creating a
default-schema table. Callers that relied on create-empty-then-add-fields must
pass the schema to --fields.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(base): pin typed metadata on the invalid-schema rejection
Address review feedback on the +table-create schema validation.
- The invalid-fields-JSON rejection now asserts category, subtype and param
through assertInvalidArgumentValidation, plus the preserved *json.SyntaxError
cause, instead of only asserting that some error came back.
- Document why the missing-flag test asserts cobra's text rather than errs
metadata, and pin that layer boundary: cobra's ValidateRequiredFlags emits a
plain error and the dispatcher types it later (cmd/root_test.go). The test now
fails if that boundary moves, so the weaker assertion cannot silently outlive
its reason.
- Reword the --fields tip and the lark-base skill note: both described the
fieldless path as if it were still reachable through +table-create. They now
say the command rejects omitted / blank / empty schemas up front, while
keeping why the schema must be declared here.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(base): enrich +table-create field example and drop redundant tips
The cobra Required declaration and flag Desc already advertise the
--fields requirement, so the tips paragraph restating it (and its
SKILL.md / coverage.md echoes) is dropped. The select-field example
now carries multiple/hue/lightness so agents copy a complete option
shape.
* chore: remove useless example
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(base): clarify form and file operation routing
* docs: clarify complete base role table rules
* docs: clarify base advanced permission status
* docs: clarify base form field lifecycle
* docs: guide base form question creation
* fix(base): address form dry-run review findings
* docs(base): add complete editable role example
* fix(base): validate form question create inputs
Form questions can now carry a visible_rule (display condition) so a question shows only when earlier questions match the rule. The rule shares the exact same structure as the view filter, so extract that structure into a single shared reference (lark-base-filter-condition.md) that both view-set-filter and visible_rule point to.
- create/update shortcuts: document visible_rule in --questions help and transcribe the questions body (including visible_rule) into dry-run output
- document that form question updates use full overwrite semantics and must preserve existing fields via read-modify-write
- skill refs: add visible_rule sections to form-questions create/update, note it is only needed when the user asks for a display condition, and clarify that the shared tuple filter protocol does not apply to data-query filters
- tests: pin flag help, verbatim visible_rule passthrough on create/update/list, and add dry-run E2E coverage
Co-authored-by: yballul-bytedance <273011618+yballul-bytedance@users.noreply.github.com>
Co-authored-by: TRAE CLI <noreply@bytedance.com>
Form submission writes and submits data through a public share link, an
irreversible action that should require explicit confirmation. Reclassify
the shortcut from write to high-risk-write so the runner's --yes gate fires
before execution, matching +form-delete and other high-risk base commands.
Update the lark-base skill docs (--yes on all examples, param table, tips)
and add tests pinning the confirmation gate (unit) and dry-run structure (e2e).
Co-authored-by: yballul-bytedance <273011618+yballul-bytedance@users.noreply.github.com>
* fix: standardize CLI shortcut text in English
- translate Docs create and update help descriptions
- remove localized permission annotations
- replace Chinese examples and fallback text
- use English labels for Docs IM Markdown resources
- update regression tests for English output
* test: strengthen English output contracts
* fix(base): improve dashboard shortcut guidance
* docs(base): refine dashboard funnel guidance
* docs(base): drop redundant block-get audit tip
The 'do not audit every block after creation' hint duplicates the
create-then-suppress-get guidance already in lark-base-dashboard.md,
so remove it from the +dashboard-block-get tips to keep them focused.
* test(base): drop stale block-get audit tip assertion
Commit 778da63a removed the 'do not audit every block' tip from the
+dashboard-block-get source as redundant but left the matching
assertion in TestBaseDashboardHelpGuidesAgents, breaking the unit
test. Remove the stale assertion to realign the test with the tips.
* docs(base): clarify when NOT to use helper table for dashboard blocks
* fix(base): defer record-list --json to framework shorthand (align with main)
* fix(base): reject non-string dashboard sort.order instead of silently defaulting to asc
* docs(base): fix reversed cumulative-funnel direction (suffix sum + assumptions)
* docs(base): scope dashboard-arrange to explicit request or fresh new dashboard
* test(base): pin missing sort.order behavior; clarify --no-validate is raw pass-through
* docs(base): show real CLI envelope {ok,identity,data} for get-data and data-query outputs
* fix: decouple --json shorthand registration from default format injection
* fix: fold --json shorthand into format flag before consumption
* fix: enable --json shorthand for mail +triage and mail +watch
* fix: enable --json shorthand for base +record-list
* docs: document --json shorthand for triage, watch and record-list
* docs: clarify record-list JSON output for script consumption
* docs: guide agents to JSON output for machine consumption scenarios
* test: make test comments self-contained
* test: assert typed error metadata in enum validation test
* docs: correct mail +watch --format default and enum in skill doc
* docs: keep --json shorthand undocumented as a silent fallback
* feat(base): add URL and title resolve shortcuts
* docs: clarify base coordinate resolution
* fix(base): address resolve shortcut ci
* fix(base): format resolved record share hint
* fix(base): simplify record share hint data
* fix(base): use field ids in resolved record data
* fix(base): guide record share resolve to update record
* fix(base): include record upsert example in resolve hint
* fix(base): reject add-record urls in resolver
* fix(base): validate title resolve query length
* fix(base): hide resolve alias flags from help
* fix(base): prefer title flag for title resolve
* docs(base): clarify token resolution wording
* refactor: retire legacy error envelopes and enforce typed contract
Consolidate all command error reporting onto the typed errs.* contract, remove
the legacy error surface that predated it, and tighten the lint guards so the
contract holds across the whole repository going forward.
Every failure now reaches stderr as one envelope shape: a category, an
optional subtype, a human- and agent-readable message, and a recovery hint,
with invalid parameters listed under `params`. The legacy ExitError envelope,
its constructors, and the boundary bridge that promoted untyped config and
authorization errors are deleted, leaving a single path from error to wire.
Predicate commands keep their silent-exit behavior through a dedicated signal
that carries only an exit code.
Infrastructure paths that still emitted ad-hoc envelopes — flag parsing,
unknown commands and subcommands, plugin and policy guards, confirmation
prompts, and auth/config failures — now classify into the same taxonomy.
Business, API, auth, and config exit codes are preserved; the one behavioral
change is that Cobra usage failures (missing required flag, unknown command,
bad arguments) now emit the typed validation envelope and exit 2, matching the
explicit flag and subcommand guards, instead of Cobra's plain-text exit 1.
Enforcement is repo-wide rather than per-path:
- The errscontract guards run by default everywhere instead of through a
migration allowlist, so legacy envelopes cannot be reintroduced anywhere.
- errorlint runs across the whole repository: every error wrap must use %w and
every comparison must use errors.Is/errors.As, so interior wraps stay legal
but can no longer break the chain the typed boundary relies on.
- The errs-no-bare-wrap guard is keyed by structural prefix instead of an
explicit per-domain allowlist, so new shortcut domains are covered without
editing a list. It runs where forbidigo is enabled (the shortcut domains and
the auth/config/service command groups); repo-wide chain integrity for the
remaining command paths is carried by errorlint above.
* test: align cli_e2e success assertions to the ok envelope
The api and service success path now emits the {"ok":true} envelope, so the
cli_e2e workflow assertions that still expected the old {"code":0} shape via
AssertStdoutStatus(t, 0) fail once they run with live credentials. Switch those
workflow assertions to AssertStdoutStatus(t, true); the fake-payload helper test
in core_test.go keeps its code-shape assertion.
* feat(base): add base block shortcuts
* fix(base): use block scopes for base block shortcuts
* fix(base): split base block shortcut scopes
* docs(base): consolidate base block help
* docs(base): simplify block help wording
* test(base): cover base block shortcut execution
* feat(base): filter base block list by type
* docs(base): clarify base block ids
* docs(base): simplify docx block help
* docs(base): refine base block agent help
Every failure on the authentication, authorization, and configuration
path now surfaces as a typed structured error instead of an ad-hoc
envelope. Users and scripts that consume CLI output get:
- a fixed nine-category taxonomy on the wire, each mapped to a
stable shell exit code (authentication/authorization/config = 3,
network = 4, internal = 5, policy = 6, confirmation = 10)
- identity-aware detail fields (missing_scopes, requested_scopes,
granted_scopes, console_url, log_id, retryable, hint) carried
uniformly on the envelope
- a single canonical policy envelope at exit 6; the legacy
auth_error carve-out is retired
- per-subtype canonical message + hint that preserves Lark's
diagnostic phrasing and routes recovery to the right actor:
app developer (app_scope_not_applied), user (missing_scope,
token_scope_insufficient, user_unauthorized), or tenant admin
(app_unavailable, app_disabled)
- wrong app credentials classify as config/invalid_client whether
surfaced by the Open API endpoint (99991543) or the tenant
access-token mint endpoint (10003 / 10014), instead of
collapsing to a transport error or api/unknown
- local shortcut scope preflight emits the same
authorization/missing_scope envelope (identity + deterministic
missing-scope set) used by the post-call permission path, so AI
consumers read the same structured shape from precheck and from
server-returned permission denial
- streaming download/upload failures keep the same network subtype
split (timeout / TLS / DNS / transport) as the non-stream path
instead of collapsing every cause to a generic transport failure
- console_url is carried only on the bot-perspective
app_scope_not_applied envelope (where the recovery action is
"developer applies the scope at the developer console"); the
user-perspective missing_scope envelope drops the field, since
the only actionable user recovery is `lark-cli auth login --scope`
and pointing an end user at a console they cannot modify is
misleading
- bind workflows (Hermes / OpenClaw / lark-channel) flatten dynamic
Type tags to wire 'config' with the original module name kept
as a metric label
All 10 typed errors are cause-bearing, nil-safe on .Error() and
.Unwrap(), and defensively clone slice setter inputs. Four lint
rules (CheckNilSafeError / CheckBuilderImmutable / CheckUnwrapSymmetry
/ CheckBuildAPIErrorArms) lock these invariants on migrated paths.
Introduce a typed error contract framework for lark-cli so in-process
Go callers can branch via errors.As(&errs.XxxError{}) and shell scripts,
AI agents, and protocol adapters can branch on stable JSON type/subtype
fields instead of regex-parsing free-form messages.
Adds:
- Canonical taxonomy under errs/ (9 categories + typed Error structs
embedding a shared Problem, RFC 7807-aligned)
- Centralized Lark code metadata + identity-aware BuildAPIError dispatch
- Typed JSON envelope writer alongside the legacy envelope writer
- MCP / OAuth (RFC 6750 Bearer) projection adapters
- Five CI lint guards preventing ad-hoc taxonomy drift
Backward compatibility: legacy *output.ExitError producers (ErrAPI,
ErrWithHint, Errorf, ErrBare) and business shortcuts that use them
continue to render the legacy envelope unchanged. SecurityPolicyError
wire format and exit code are preserved via a carve-out; taxonomy
migration is deferred to PR 2. Domain-specific business migration is
staged across PR 3+.
Framework-direct paths now return typed *errs.*Error: ErrAuth /
ErrValidation / ErrNetwork emit category literals on the wire
(authentication / validation / network), *core.ConfigError is promoted
at the cmd/root boundary with exit code aligned from 2 to 3, and Lark
API permission denials classified by BuildAPIError exit 3.
At the SDK boundary, WrapDoAPIError preserves any already-classified
error (legacy *output.ExitError or typed *errs.*) so output.ErrAuth
from missing credentials surfaces with the auth category and exit 3
intact instead of being downgraded to a network error. Policy responses
classified by BuildAPIError (codes 21000 / 21001) extract challenge_url
and the canonical hint from the response body, matching what the
auth transport already surfaces at the HTTP layer; non-https
challenge URLs are dropped.
First PR in the feat/error-contract-* series.
* feat(base): support batch record get and delete
* fix(base): address batch record PR feedback
* docs(base): refine record skill routing
* refactor(base): use batch record get and delete only
* refactor(base): share record selection normalization
* docs(base): clarify record get field projection help
* feat(base): add record read SOP guidance
1. Add a unified lark-base record read SOP for get/search/list routing, field projection, temporary view querying, pagination, matrix result binding, and link field reads.
2. Inline command-focused parameter guidance into +record-get, +record-search, and +record-list help, including examples, JSON shape, view scope, projection, and limit constraints.
3. Preserve base shortcut flag order in help output and add tests covering record read help guidance.
4. Remove the single-method record read skill references in favor of the unified SOP.
* test(base): remove stale record list fixture
* fix(base): scan record markdown output
* fix(base): fallback record markdown output
* fix(base): unify base token wording in shortcuts and skills
* 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.
* 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>
* 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>
- 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>