Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var BaseAdvpermDisable = common.Shortcut{ Service: "base", Command: "+advperm-disable", Description: "Disable advanced permissions for a Base", Risk: "high-risk-write", Scopes: []string{"base:app:update"}, AuthTypes: []string{"user", "bot"}, Flags: []common.Flag{ {Name: "base-token", Desc: "base token", Required: true}, }, Tips: []string{ baseHighRiskYesTip, "Disabling advanced permissions invalidates existing custom roles; confirm the target Base before passing --yes.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { if strings.TrimSpace(runtime.Str("base-token")) == "" { return baseFlagErrorf("--base-token must not be blank") } return nil }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). PUT("/open-apis/base/v3/bases/:base_token/advperm/enable?enable=false"). Set("base_token", runtime.Str("base-token")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") queryParams := make(larkcore.QueryParams) queryParams.Set("enable", "false") apiResp, err := runtime.DoAPI(&larkcore.ApiReq{ HttpMethod: http.MethodPut, ApiPath: fmt.Sprintf("/open-apis/base/v3/bases/%s/advperm/enable", validate.EncodePathSegment(baseToken)), QueryParams: queryParams, }) if err != nil { return err } return handleRoleAPIResponse(runtime, apiResp, "disable advanced permissions failed") }, }
View Source
var BaseAdvpermEnable = common.Shortcut{ Service: "base", Command: "+advperm-enable", Description: "Enable advanced permissions for a Base", Risk: "write", Scopes: []string{"base:app:update"}, AuthTypes: []string{"user", "bot"}, Flags: []common.Flag{ {Name: "base-token", Desc: "base token", Required: true}, }, Tips: []string{ "Caller must be a Base admin; enable advanced permissions before creating or updating roles.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { if strings.TrimSpace(runtime.Str("base-token")) == "" { return baseFlagErrorf("--base-token must not be blank") } return nil }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). PUT("/open-apis/base/v3/bases/:base_token/advperm/enable?enable=true"). Set("base_token", runtime.Str("base-token")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") queryParams := make(larkcore.QueryParams) queryParams.Set("enable", "true") apiResp, err := runtime.DoAPI(&larkcore.ApiReq{ HttpMethod: http.MethodPut, ApiPath: fmt.Sprintf("/open-apis/base/v3/bases/%s/advperm/enable", validate.EncodePathSegment(baseToken)), QueryParams: queryParams, }) if err != nil { return err } return handleRoleAPIResponse(runtime, apiResp, "enable advanced permissions failed") }, }
View Source
var BaseBaseBlockCreate = common.Shortcut{ Service: "base", Command: "+base-block-create", Description: "Create a block", Risk: "write", Scopes: []string{"base:block:create"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), {Name: "type", Desc: "resource type", Required: true, Enum: baseBlockTypeEnums}, {Name: "name", Desc: "block name", Required: true}, {Name: "parent-id", Desc: "folder block id; when omitted, create at root"}, }, Tips: []string{ "Example: lark-cli base +base-block-create --base-token <base_token> --type folder --name \"Project Docs\"", "Example: lark-cli base +base-block-create --base-token <base_token> --type table --name \"Tasks\"", "Example: lark-cli base +base-block-create --base-token <base_token> --type docx --name \"Spec\" --parent-id <folder_block_id>", "Example: lark-cli base +base-block-create --base-token <base_token> --type dashboard --name \"Metrics\"", "Example: lark-cli base +base-block-create --base-token <base_token> --type workflow --name \"Approval Flow\"", "Creates a folder, table, docx, dashboard, or workflow entry.", "Do not pass null for --parent-id. Omit it to create at the root level.", "Created resources still use their own commands for content operations, such as table/field/record/docx/dashboard/workflow commands.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateBaseBlockCreate(runtime) }, DryRun: dryRunBaseBlockCreate, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeBaseBlockCreate(runtime) }, }
View Source
var BaseBaseBlockDelete = common.Shortcut{ Service: "base", Command: "+base-block-delete", Description: "Delete a block", Risk: "high-risk-write", Scopes: []string{"base:block:delete"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), baseBlockIDFlag(true), }, Tips: []string{ "Example: lark-cli base +base-block-delete --base-token <base_token> --block-id <block_id> --yes", "Deletes the block identified by --block-id.", "Recursive folder deletion is not supported. If a folder is not empty, move or delete its children first.", "Different block types may have independent backing resources; deletion follows backend semantics.", "Use +base-block-list first when you need to confirm the target block id.", "If the user already explicitly confirmed this exact delete target, pass --yes without asking again.", }, DryRun: dryRunBaseBlockDelete, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeBaseBlockDelete(runtime) }, }
View Source
var BaseBaseBlockList = common.Shortcut{ Service: "base", Command: "+base-block-list", Description: "List blocks in a base", Risk: "read", Scopes: []string{"base:block:read"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), {Name: "type", Desc: "filter by resource type", Enum: baseBlockTypeEnums}, {Name: "parent-id", Desc: "folder block id; when omitted, list all blocks"}, }, Tips: []string{ "Example: lark-cli base +base-block-list --base-token <base_token>", "Example: lark-cli base +base-block-list --base-token <base_token> --type table", "Example: lark-cli base +base-block-list --base-token <base_token> --parent-id <folder_block_id>", `JQ crop: lark-cli base +base-block-list --base-token <base_token> | jq '.blocks[] | {type, name, block_id: .id, parent_id}'`, `JQ crop docx: lark-cli base +base-block-list --base-token <base_token> --type docx | jq '.blocks[] | {name, docx_token}'`, "Blocks are resources managed directly by the base, such as folder, table, docx, dashboard, and workflow.", "For table, dashboard, and workflow blocks, returned id is the table-id, dashboard-id, or workflow-id used by the corresponding commands.", "For docx blocks, use the returned docx_token with docx commands.", "For folder blocks, pass the returned id as --parent-id when creating, listing, or moving blocks inside that folder.", "This command returns the full backend list. It intentionally does not expose limit or offset.", "Pass --type to list only one resource type.", "Pass --parent-id to list only direct children of a folder.", "Dashboard blocks are chart/widget blocks inside a dashboard; use +dashboard-block-* for those.", }, DryRun: dryRunBaseBlockList, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeBaseBlockList(runtime) }, }
View Source
var BaseBaseBlockMove = common.Shortcut{ Service: "base", Command: "+base-block-move", Description: "Move a block", Risk: "write", Scopes: []string{"base:block:update"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), baseBlockIDFlag(true), {Name: "parent-id", Desc: "target folder block id; when omitted, move to root"}, {Name: "before-id", Desc: "sibling block id; move the block before this sibling in the target folder/root order"}, {Name: "after-id", Desc: "sibling block id; move the block after this sibling in the target folder/root order"}, }, Tips: []string{ "Example: lark-cli base +base-block-move --base-token <base_token> --block-id <block_id> --parent-id <folder_block_id>", "Example: lark-cli base +base-block-move --base-token <base_token> --block-id <block_id> --after-id <sibling_block_id>", "Example: lark-cli base +base-block-move --base-token <base_token> --block-id <block_id> --before-id <sibling_block_id>", "Example: lark-cli base +base-block-move --base-token <base_token> --block-id <block_id>", "Omit --parent-id to move the block to root; do not pass null.", "--before-id and --after-id are mutually exclusive.", "When moving a folder, its children remain under that folder.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateBaseBlockMove(runtime) }, DryRun: dryRunBaseBlockMove, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeBaseBlockMove(runtime) }, }
View Source
var BaseBaseBlockRename = common.Shortcut{ Service: "base", Command: "+base-block-rename", Description: "Rename a block", Risk: "write", Scopes: []string{"base:block:update"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), baseBlockIDFlag(true), {Name: "name", Desc: "new unique block name; must not duplicate another block name in this base", Required: true}, }, Tips: []string{ "Example: lark-cli base +base-block-rename --base-token <base_token> --block-id <block_id> --name \"New name\"", "Renames the block identified by --block-id.", "Block names must be unique in the base; use +base-block-list first when you need to check existing names.", "Use +base-block-list first when you need to resolve the target block id from a visible name.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateBaseBlockRename(runtime) }, DryRun: dryRunBaseBlockRename, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeBaseBlockRename(runtime) }, }
View Source
var BaseBaseCopy = common.Shortcut{ Service: "base", Command: "+base-copy", Description: "Copy a base resource", Risk: "write", UserScopes: []string{"base:app:copy"}, BotScopes: []string{"base:app:copy", "docs:permission.member:create"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), {Name: "name", Desc: "new base name"}, {Name: "folder-token", Desc: "folder token for destination"}, {Name: "without-content", Type: "bool", Desc: "copy structure only"}, {Name: "time-zone", Desc: "time zone, e.g. Asia/Shanghai"}, }, Tips: []string{ `Example: lark-cli base +base-copy --base-token <base_token> --name "Copy of Project Tracker"`, "Use --without-content when the user wants only structure.", "If copied as bot, output may include permission_grant; report it so the user knows whether they can open the new Base.", }, DryRun: dryRunBaseCopy, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeBaseCopy(runtime) }, }
View Source
var BaseBaseCreate = common.Shortcut{ Service: "base", Command: "+base-create", Description: "Create a new base resource", Risk: "write", UserScopes: []string{"base:app:create"}, BotScopes: []string{"base:app:create", "docs:permission.member:create"}, AuthTypes: authTypes(), Flags: []common.Flag{ {Name: "name", Desc: "base name", Required: true}, {Name: "folder-token", Desc: "folder token for destination"}, {Name: "time-zone", Desc: "time zone, e.g. Asia/Shanghai"}, }, Tips: []string{ `Example: lark-cli base +base-create --name "Project Tracker" --time-zone Asia/Shanghai`, "If created as bot, output may include permission_grant; report it so the user knows whether they can open the new Base.", }, DryRun: dryRunBaseCreate, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeBaseCreate(runtime) }, }
View Source
var BaseBaseGet = common.Shortcut{ Service: "base", Command: "+base-get", Description: "Get a base resource", Risk: "read", Scopes: []string{"base:app:read"}, AuthTypes: authTypes(), Flags: []common.Flag{baseTokenFlag(true)}, Tips: []string{ "Use a real Base token; workspace tokens and wiki tokens are not accepted by this command.", }, DryRun: dryRunBaseGet, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeBaseGet(runtime) }, }
View Source
var BaseDashboardArrange = common.Shortcut{ Service: "base", Command: "+dashboard-arrange", Description: "Auto-arrange dashboard blocks layout (server-side smart layout)", Risk: "write", Scopes: []string{"base:dashboard:update"}, AuthTypes: authTypes(), HasFormat: true, Flags: []common.Flag{ baseTokenFlag(true), dashboardIDFlag(true), {Name: "user-id-type", Desc: "user ID type: open_id / union_id / user_id"}, }, Tips: []string{ "Server-side smart layout is not deterministic or position-specific; use only when the user asks to arrange or beautify a dashboard.", }, DryRun: dryRunDashboardArrange, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeDashboardArrange(runtime) }, }
View Source
var BaseDashboardBlockCreate = common.Shortcut{ Service: "base", Command: "+dashboard-block-create", Description: "Create a block in a dashboard", Risk: "write", Scopes: []string{"base:dashboard:create"}, AuthTypes: authTypes(), HasFormat: true, Flags: []common.Flag{ baseTokenFlag(true), dashboardIDFlag(true), {Name: "name", Desc: "block name", Required: true}, {Name: "type", Desc: "block type: column(柱状图)|bar(条形图)|line(折线图)|pie(饼图)|ring(环形图)|area(面积图)|combo(组合图)|scatter(散点图)|funnel(漏斗图)|wordCloud(词云)|radar(雷达图)|statistics(指标卡)|text(文本). Read dashboard-block-data-config.md before creating.", Required: true}, {Name: "data-config", Desc: "data_config JSON object; read dashboard-block-data-config.md for the SSOT"}, {Name: "user-id-type", Desc: "user ID type for user fields in filters: open_id / union_id / user_id"}, {Name: "no-validate", Type: "bool", Desc: "skip local data_config validation"}, }, Tips: []string{ `lark-cli base +dashboard-block-create --base-token <base_token> --dashboard-id <dashboard_id> --name "Order Count" --type statistics --data-config '{"table_name":"Orders","count_all":true}'`, `lark-cli base +dashboard-block-create --base-token <base_token> --dashboard-id <dashboard_id> --name "Dashboard Note" --type text --data-config '{"text":"# Sales Dashboard"}'`, "Before creating data-backed blocks, use +table-list and +field-list to confirm real table and field names.", "data_config uses table and field names, not table_id or field_id.", "Read dashboard-block-data-config.md as the SSOT for chart templates, filters, metric rules, and type-specific fields; do not invent data_config from natural language.", "Record the returned block_id; block update/delete/get-data commands need it.", "Create dashboard blocks sequentially; do not parallelize multiple block creates for the same dashboard.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { pc := newParseCtx(runtime) if runtime.Bool("no-validate") { return nil } raw := runtime.Str("data-config") if strings.TrimSpace(raw) == "" { if strings.ToLower(runtime.Str("type")) == "text" { return errs.NewValidationError(errs.SubtypeInvalidArgument, "text 类型组件必须提供 data-config,包含必填字段 text").WithParam("--data-config") } return nil } cfg, err := parseJSONObject(pc, raw, "data-config") if err != nil { return err } norm := normalizeDataConfig(cfg) if errs := validateBlockDataConfig(runtime.Str("type"), norm); len(errs) > 0 { return formatDataConfigErrors(errs) } b, _ := json.Marshal(norm) _ = runtime.Cmd.Flags().Set("data-config", string(b)) return nil }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { pc := newParseCtx(runtime) body := map[string]interface{}{} if name := runtime.Str("name"); name != "" { body["name"] = name } if t := runtime.Str("type"); t != "" { body["type"] = t } if raw := runtime.Str("data-config"); raw != "" { if parsed, err := parseJSONObject(pc, raw, "data-config"); err == nil { body["data_config"] = parsed } } params := map[string]interface{}{} if uid := runtime.Str("user-id-type"); uid != "" { params["user_id_type"] = uid } return common.NewDryRunAPI(). POST("/open-apis/base/v3/bases/:base_token/dashboards/:dashboard_id/blocks"). Params(params). Body(body). Set("base_token", runtime.Str("base-token")). Set("dashboard_id", runtime.Str("dashboard-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeDashboardBlockCreate(runtime) }, }
View Source
var BaseDashboardBlockDelete = common.Shortcut{ Service: "base", Command: "+dashboard-block-delete", Description: "Delete a dashboard block", Risk: "high-risk-write", Scopes: []string{"base:dashboard:delete"}, AuthTypes: authTypes(), HasFormat: true, Flags: []common.Flag{ baseTokenFlag(true), dashboardIDFlag(true), blockIDFlag(true), }, Tips: []string{ "lark-cli base +dashboard-block-delete --base-token <base_token> --dashboard-id <dashboard_id> --block-id <block_id> --yes", baseHighRiskYesTip, }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). DELETE("/open-apis/base/v3/bases/:base_token/dashboards/:dashboard_id/blocks/:block_id"). Set("base_token", runtime.Str("base-token")). Set("dashboard_id", runtime.Str("dashboard-id")). Set("block_id", runtime.Str("block-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeDashboardBlockDelete(runtime) }, }
View Source
var BaseDashboardBlockGet = common.Shortcut{ Service: "base", Command: "+dashboard-block-get", Description: "Get a dashboard block by ID", Risk: "read", Scopes: []string{"base:dashboard:read"}, AuthTypes: authTypes(), HasFormat: true, Flags: []common.Flag{ baseTokenFlag(true), dashboardIDFlag(true), blockIDFlag(true), {Name: "user-id-type", Desc: "user ID type: open_id / union_id / user_id"}, }, Tips: []string{ "lark-cli base +dashboard-block-get --base-token <base_token> --dashboard-id <dashboard_id> --block-id <block_id>", "Use this command for block metadata such as name, type, layout, and data_config.", "Use +dashboard-block-get-data when you need the computed chart result instead of metadata.", }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { params := map[string]interface{}{} if uid := strings.TrimSpace(runtime.Str("user-id-type")); uid != "" { params["user_id_type"] = uid } return common.NewDryRunAPI(). GET("/open-apis/base/v3/bases/:base_token/dashboards/:dashboard_id/blocks/:block_id"). Params(params). Set("base_token", runtime.Str("base-token")). Set("dashboard_id", runtime.Str("dashboard-id")). Set("block_id", runtime.Str("block-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeDashboardBlockGet(runtime) }, }
View Source
var BaseDashboardBlockGetData = common.Shortcut{ Service: "base", Command: "+dashboard-block-get-data", Description: "Get computed data for a dashboard chart block", Risk: "read", Scopes: []string{"base:dashboard:read"}, AuthTypes: authTypes(), HasFormat: true, Flags: []common.Flag{ baseTokenFlag(true), blockIDFlag(true), }, Tips: []string{ "lark-cli base +dashboard-block-get-data --base-token <base_token> --block-id <block_id>", "This command does not need --dashboard-id.", "Use +dashboard-block-get first when you need block metadata like name, type, or data_config.", "This command returns computed chart protocol JSON directly, not wrapped block metadata.", "Text blocks do not have computed chart data; this shortcut is for chart/statistics blocks.", }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return dryRunDashboardBlockGetData(ctx, runtime) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeDashboardBlockGetData(runtime) }, }
View Source
var BaseDashboardBlockList = common.Shortcut{ Service: "base", Command: "+dashboard-block-list", Description: "List blocks in a dashboard", Risk: "read", Scopes: []string{"base:dashboard:read"}, AuthTypes: authTypes(), HasFormat: true, Flags: []common.Flag{ baseTokenFlag(true), dashboardIDFlag(true), {Name: "page-size", Desc: "page size, default 20, max 100"}, {Name: "page-token", Desc: "pagination token"}, }, Tips: []string{ "lark-cli base +dashboard-block-list --base-token <base_token> --dashboard-id <dashboard_id>", "Use returned block_id and type values for +dashboard-block-get/update/delete/get-data.", }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { params := map[string]interface{}{} if ps := strings.TrimSpace(runtime.Str("page-size")); ps != "" { params["page_size"] = ps } if pt := strings.TrimSpace(runtime.Str("page-token")); pt != "" { params["page_token"] = pt } return common.NewDryRunAPI(). GET("/open-apis/base/v3/bases/:base_token/dashboards/:dashboard_id/blocks"). Params(params). Set("base_token", runtime.Str("base-token")). Set("dashboard_id", runtime.Str("dashboard-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeDashboardBlockList(runtime) }, }
View Source
var BaseDashboardBlockUpdate = common.Shortcut{ Service: "base", Command: "+dashboard-block-update", Description: "Update a dashboard block", Risk: "write", Scopes: []string{"base:dashboard:update"}, AuthTypes: authTypes(), HasFormat: true, Flags: []common.Flag{ baseTokenFlag(true), dashboardIDFlag(true), blockIDFlag(true), {Name: "name", Desc: "new block name"}, {Name: "data-config", Desc: "data_config JSON object; read dashboard-block-data-config.md for the SSOT"}, {Name: "user-id-type", Desc: "user ID type for user fields in filters: open_id / union_id / user_id"}, {Name: "no-validate", Type: "bool", Desc: "skip local data_config validation"}, }, Tips: []string{ `lark-cli base +dashboard-block-update --base-token <base_token> --dashboard-id <dashboard_id> --block-id <block_id> --name "Total Sales"`, `lark-cli base +dashboard-block-update --base-token <base_token> --dashboard-id <dashboard_id> --block-id <block_id> --data-config '{"series":[{"field_name":"Amount","rollup":"SUM"}]}'`, "Read dashboard-block-data-config.md as the SSOT for data_config templates, filters, metric rules, and type-specific fields; do not invent data_config from natural language.", "Use +dashboard-block-get first to inspect the current data_config before replacing nested values.", "Block type cannot be changed; delete and recreate the block to change chart type.", "data_config update merges top-level keys, but each provided key is replaced as a whole.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { pc := newParseCtx(runtime) if runtime.Bool("no-validate") { return nil } raw := runtime.Str("data-config") if strings.TrimSpace(raw) == "" { return nil } cfg, err := parseJSONObject(pc, raw, "data-config") if err != nil { return err } norm := normalizeDataConfig(cfg) b, _ := json.Marshal(norm) _ = runtime.Cmd.Flags().Set("data-config", string(b)) return nil }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { pc := newParseCtx(runtime) body := map[string]interface{}{} if name := runtime.Str("name"); name != "" { body["name"] = name } if raw := runtime.Str("data-config"); raw != "" { if parsed, err := parseJSONObject(pc, raw, "data-config"); err == nil { body["data_config"] = parsed } } params := map[string]interface{}{} if uid := runtime.Str("user-id-type"); uid != "" { params["user_id_type"] = uid } return common.NewDryRunAPI(). PATCH("/open-apis/base/v3/bases/:base_token/dashboards/:dashboard_id/blocks/:block_id"). Params(params). Body(body). Set("base_token", runtime.Str("base-token")). Set("dashboard_id", runtime.Str("dashboard-id")). Set("block_id", runtime.Str("block-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeDashboardBlockUpdate(runtime) }, }
View Source
var BaseDashboardCreate = common.Shortcut{ Service: "base", Command: "+dashboard-create", Description: "Create a dashboard in a base", Risk: "write", Scopes: []string{"base:dashboard:create"}, AuthTypes: authTypes(), HasFormat: true, Flags: []common.Flag{ baseTokenFlag(true), {Name: "name", Desc: "dashboard name", Required: true}, {Name: "theme-style", Desc: "theme style, defaults to platform default when omitted"}, }, Tips: []string{ "Record the returned dashboard_id; dashboard block create/get/update/delete/arrange commands need it.", }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { body := map[string]interface{}{} if name := runtime.Str("name"); name != "" { body["name"] = name } if themeStyle := runtime.Str("theme-style"); themeStyle != "" { body["theme"] = map[string]interface{}{"theme_style": themeStyle} } return common.NewDryRunAPI(). POST("/open-apis/base/v3/bases/:base_token/dashboards"). Body(body). Set("base_token", runtime.Str("base-token")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeDashboardCreate(runtime) }, }
View Source
var BaseDashboardDelete = common.Shortcut{ Service: "base", Command: "+dashboard-delete", Description: "Delete a dashboard", Risk: "high-risk-write", Scopes: []string{"base:dashboard:delete"}, AuthTypes: authTypes(), HasFormat: true, Flags: []common.Flag{ baseTokenFlag(true), dashboardIDFlag(true), }, Tips: []string{ "lark-cli base +dashboard-delete --base-token <base_token> --dashboard-id <dashboard_id> --yes", "Deleting a dashboard also deletes its blocks and cannot be recovered.", baseHighRiskYesTip, }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). DELETE("/open-apis/base/v3/bases/:base_token/dashboards/:dashboard_id"). Set("base_token", runtime.Str("base-token")). Set("dashboard_id", runtime.Str("dashboard-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeDashboardDelete(runtime) }, }
View Source
var BaseDashboardGet = common.Shortcut{ Service: "base", Command: "+dashboard-get", Description: "Get a dashboard by ID", Risk: "read", Scopes: []string{"base:dashboard:read"}, AuthTypes: authTypes(), HasFormat: true, Flags: []common.Flag{ baseTokenFlag(true), dashboardIDFlag(true), }, Tips: []string{ "Use +dashboard-block-list or +dashboard-block-get when you need block-level details.", }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). GET("/open-apis/base/v3/bases/:base_token/dashboards/:dashboard_id"). Set("base_token", runtime.Str("base-token")). Set("dashboard_id", runtime.Str("dashboard-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeDashboardGet(runtime) }, }
View Source
var BaseDashboardList = common.Shortcut{ Service: "base", Command: "+dashboard-list", Description: "List dashboards in a base", Risk: "read", Scopes: []string{"base:dashboard:read"}, AuthTypes: authTypes(), HasFormat: true, Flags: []common.Flag{ baseTokenFlag(true), {Name: "page-size", Desc: "page size, max 100"}, {Name: "page-token", Desc: "pagination token"}, }, Tips: []string{ "Use returned dashboard_id values for +dashboard-get, +dashboard-block-list, and +dashboard-block-create.", }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { params := map[string]interface{}{} if ps := strings.TrimSpace(runtime.Str("page-size")); ps != "" { params["page_size"] = ps } if pt := strings.TrimSpace(runtime.Str("page-token")); pt != "" { params["page_token"] = pt } return common.NewDryRunAPI(). GET("/open-apis/base/v3/bases/:base_token/dashboards"). Params(params). Set("base_token", runtime.Str("base-token")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeDashboardList(runtime) }, }
View Source
var BaseDashboardUpdate = common.Shortcut{ Service: "base", Command: "+dashboard-update", Description: "Update a dashboard", Risk: "write", Scopes: []string{"base:dashboard:update"}, AuthTypes: authTypes(), HasFormat: true, Flags: []common.Flag{ baseTokenFlag(true), dashboardIDFlag(true), {Name: "name", Desc: "new dashboard name"}, {Name: "theme-style", Desc: "theme style, leave empty to keep current theme"}, }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { body := map[string]interface{}{} if name := runtime.Str("name"); name != "" { body["name"] = name } if themeStyle := runtime.Str("theme-style"); themeStyle != "" { body["theme"] = map[string]interface{}{"theme_style": themeStyle} } return common.NewDryRunAPI(). PATCH("/open-apis/base/v3/bases/:base_token/dashboards/:dashboard_id"). Body(body). Set("base_token", runtime.Str("base-token")). Set("dashboard_id", runtime.Str("dashboard-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeDashboardUpdate(runtime) }, }
View Source
var BaseDataQuery = common.Shortcut{ Service: "base", Command: "+data-query", Description: "Query and analyze Base data with JSON DSL (aggregation, filter, sort)", Risk: "read", Scopes: []string{"base:table:read"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), {Name: "dsl", Desc: "query JSON DSL; read lark-base-data-query-guide.md first, then lark-base-data-query.md for the full DSL SSOT", Required: true}, }, Tips: []string{ "Use +data-query for server-side aggregation, grouping, filtering, sorting, and Top N queries.", "Read lark-base-data-query-guide.md for common fewshots; use lark-base-data-query.md only when the full DSL reference is needed.", "`dimensions` and `measures` cannot both be empty.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { var dsl map[string]interface{} dec := json.NewDecoder(bytes.NewReader([]byte(runtime.Str("dsl")))) dec.UseNumber() if err := dec.Decode(&dsl); err != nil { return baseFlagErrorf("--dsl invalid JSON: %v", err) } _, hasDim := dsl["dimensions"] _, hasMeas := dsl["measures"] if !hasDim && !hasMeas { return baseFlagErrorf("--dsl must contain at least one of 'dimensions' or 'measures'") } return nil }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { var dsl map[string]interface{} dec := json.NewDecoder(bytes.NewReader([]byte(runtime.Str("dsl")))) dec.UseNumber() dec.Decode(&dsl) return common.NewDryRunAPI(). POST("/open-apis/base/v3/bases/:base_token/data/query"). Body(dsl). Set("base_token", runtime.Str("base-token")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") var dsl map[string]interface{} dec := json.NewDecoder(bytes.NewReader([]byte(runtime.Str("dsl")))) dec.UseNumber() dec.Decode(&dsl) data, err := baseV3Call(runtime, "POST", baseV3Path("bases", baseToken, "data/query"), nil, dsl) if err != nil { return err } runtime.Out(data, nil) return nil }, }
View Source
var BaseFieldCreate = common.Shortcut{ Service: "base", Command: "+field-create", Description: "Create a field", Risk: "write", Scopes: []string{"base:field:create"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), {Name: "json", Desc: "field property JSON object", Required: true}, {Name: "i-have-read-guide", Type: "bool", Desc: "set only after you have read the formula/lookup guide for those field types", Hidden: true}, }, Tips: []string{ `Example text: lark-cli base +field-create --base-token <base_token> --table-id <table_id> --json '{"name":"Status","type":"text"}'`, `Example select: lark-cli base +field-create --base-token <base_token> --table-id <table_id> --json '{"name":"Status","type":"select","multiple":false,"options":[{"name":"Todo"},{"name":"Done"}]}'`, "Agent hint: use the lark-base skill's field-create guide for usage and limits.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateFieldCreate(runtime) }, DryRun: dryRunFieldCreate, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeFieldCreate(runtime) }, }
View Source
var BaseFieldDelete = common.Shortcut{ Service: "base", Command: "+field-delete", Description: "Delete a field by ID or name", Risk: "high-risk-write", Scopes: []string{"base:field:delete"}, AuthTypes: authTypes(), Flags: []common.Flag{baseTokenFlag(true), tableRefFlag(true), fieldRefFlag(true)}, Tips: []string{ baseHighRiskYesTip, `Example: lark-cli base +field-delete --base-token <base_token> --table-id <table_id> --field-id "Status" --yes`, }, DryRun: dryRunFieldDelete, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeFieldDelete(runtime) }, }
View Source
var BaseFieldGet = common.Shortcut{ Service: "base", Command: "+field-get", Description: "Get a field by ID or name", Risk: "read", Scopes: []string{"base:field:read"}, AuthTypes: authTypes(), Flags: []common.Flag{baseTokenFlag(true), tableRefFlag(true), fieldRefFlag(true)}, Tips: []string{ `Example: lark-cli base +field-get --base-token <base_token> --table-id <table_id> --field-id "Status"`, "field-id accepts a field ID (fld...) or the field name from the current table.", "Returns full field configuration; use it as the baseline before +field-update.", }, DryRun: dryRunFieldGet, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeFieldGet(runtime) }, }
View Source
var BaseFieldList = common.Shortcut{ Service: "base", Command: "+field-list", Description: "List fields in a table", Risk: "read", Scopes: []string{"base:field:read"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), {Name: "offset", Type: "int", Default: "0", Desc: "pagination offset"}, {Name: "limit", Type: "int", Default: "100", Desc: "pagination size, range 1-200"}, }, DryRun: dryRunFieldList, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeFieldList(runtime) }, }
View Source
var BaseFieldSearchOptions = common.Shortcut{ Service: "base", Command: "+field-search-options", Description: "Search select options of a field", Risk: "read", Scopes: []string{"base:field:read"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), fieldRefFlag(true), {Name: "keyword", Desc: "keyword for option query"}, {Name: "offset", Type: "int", Default: "0", Desc: "pagination offset"}, {Name: "limit", Type: "int", Default: "30", Desc: "pagination size, default 30"}, }, Tips: []string{ `Example: lark-cli base +field-search-options --base-token <base_token> --table-id <table_id> --field-id "Status" --keyword "Do"`, "Use only for fields with options, such as select or multi-select fields.", }, DryRun: dryRunFieldSearchOptions, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeFieldSearchOptions(runtime) }, }
View Source
var BaseFieldUpdate = common.Shortcut{ Service: "base", Command: "+field-update", Description: "Update a field by ID or name", Risk: "high-risk-write", Scopes: []string{"base:field:update"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), fieldRefFlag(true), {Name: "json", Desc: "complete field definition JSON object; update uses full PUT semantics, not a patch", Required: true}, {Name: "i-have-read-guide", Type: "bool", Desc: "acknowledge reading formula/lookup guide before creating or updating those field types", Hidden: true}, }, Tips: []string{ baseHighRiskYesTip, `Example text: lark-cli base +field-update --base-token <base_token> --table-id <table_id> --field-id "Status" --json '{"name":"Status","type":"text"}' --yes`, `Example select: lark-cli base +field-update --base-token <base_token> --table-id <table_id> --field-id "Status" --json '{"name":"Status","type":"select","multiple":false,"options":[{"name":"Todo"},{"name":"Done"}]}' --yes`, "Update uses full field-definition PUT semantics. Read the current field first with +field-get, then send the target state.", "Type conversion is allowlist-based: only use CLI for safe conversions; otherwise migrate through a new field, or ask the user to finish high-risk conversions in the web UI.", "Formula and lookup updates require reading the corresponding guide first.", "Agent hint: use the lark-base skill's field-update guide for JSON shape, type-conversion rules, and limits.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateFieldUpdate(runtime) }, DryRun: dryRunFieldUpdate, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeFieldUpdate(runtime) }, }
View Source
var BaseFormCreate = common.Shortcut{ Service: "base", Command: "+form-create", Description: "Create a form in a Base table", Risk: "write", Scopes: []string{"base:form:create"}, AuthTypes: []string{"user", "bot"}, HasFormat: true, Flags: []common.Flag{ {Name: "base-token", Desc: "Base token (base_token)", Required: true}, {Name: "table-id", Desc: "table ID", Required: true}, {Name: "name", Desc: "form name", Required: true}, {Name: "description", Desc: `form description (plain text or markdown link like [text](https://example.com))`}, }, Tips: []string{ "Record the returned form_id; form question create/list/update/delete commands need it.", }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). POST("/open-apis/base/v3/bases/:base_token/tables/:table_id/forms"). Set("base_token", runtime.Str("base-token")). Set("table_id", runtime.Str("table-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") tableId := runtime.Str("table-id") name := runtime.Str("name") description := runtime.Str("description") body := map[string]interface{}{"name": name} if description != "" { body["description"] = description } data, err := baseV3Call(runtime, "POST", baseV3Path("bases", baseToken, "tables", tableId, "forms"), nil, body) if err != nil { return err } runtime.OutFormat(data, nil, func(w io.Writer) { output.PrintTable(w, []map[string]interface{}{ { "id": data["id"], "name": data["name"], "description": data["description"], }, }) }) return nil }, }
View Source
var BaseFormDelete = common.Shortcut{ Service: "base", Command: "+form-delete", Description: "Delete a form in a Base table", Risk: "high-risk-write", Scopes: []string{"base:form:delete"}, AuthTypes: []string{"user", "bot"}, HasFormat: true, Flags: []common.Flag{ baseTokenFlag(true), {Name: "table-id", Desc: "table ID", Required: true}, {Name: "form-id", Desc: "form ID", Required: true}, }, Tips: []string{ "Use +form-list or +form-get first when the form target is ambiguous.", baseHighRiskYesTip, }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). DELETE("/open-apis/base/v3/bases/:base_token/tables/:table_id/forms/:form_id"). Set("base_token", runtime.Str("base-token")). Set("table_id", runtime.Str("table-id")). Set("form_id", runtime.Str("form-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") tableId := runtime.Str("table-id") formId := runtime.Str("form-id") _, err := baseV3Call(runtime, "DELETE", baseV3Path("bases", baseToken, "tables", tableId, "forms", formId), nil, nil) if err != nil { return err } runtime.Out(map[string]interface{}{"deleted": true, "form_id": formId}, nil) return nil }, }
View Source
var BaseFormDetail = common.Shortcut{ Service: "base", Command: "+form-detail", Description: "Get form detail by share token", Risk: "read", Scopes: []string{"base:form:read"}, AuthTypes: []string{"user", "bot"}, HasFormat: true, Flags: []common.Flag{ {Name: "share-token", Desc: "Form share token (share_token)", Required: true}, }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). POST("/open-apis/base/v3/bases/tables/forms/detail"). Body(map[string]interface{}{ "share_token": runtime.Str("share-token"), }) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { body := map[string]interface{}{ "share_token": runtime.Str("share-token"), } data, err := baseV3Call(runtime, "POST", baseV3Path("bases", "tables", "forms", "detail"), nil, body) if err != nil { return err } runtime.Out(data, nil) return nil }, }
View Source
var BaseFormGet = common.Shortcut{ Service: "base", Command: "+form-get", Description: "Get a form in a Base table", Risk: "read", Scopes: []string{"base:form:read"}, AuthTypes: []string{"user", "bot"}, HasFormat: true, Flags: []common.Flag{ baseTokenFlag(true), {Name: "table-id", Desc: "table ID", Required: true}, {Name: "form-id", Desc: "form ID", Required: true}, }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). GET("/open-apis/base/v3/bases/:base_token/tables/:table_id/forms/:form_id"). Set("base_token", runtime.Str("base-token")). Set("table_id", runtime.Str("table-id")). Set("form_id", runtime.Str("form-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") tableId := runtime.Str("table-id") formId := runtime.Str("form-id") data, err := baseV3Call(runtime, "GET", baseV3Path("bases", baseToken, "tables", tableId, "forms", formId), nil, nil) if err != nil { return err } runtime.OutFormat(data, nil, func(w io.Writer) { output.PrintTable(w, []map[string]interface{}{ { "id": data["id"], "name": data["name"], "description": data["description"], }, }) }) return nil }, }
View Source
var BaseFormQuestionsCreate = common.Shortcut{ Service: "base", Command: "+form-questions-create", Description: "Create questions for a form in a Base table", Risk: "write", Scopes: []string{"base:form:update"}, AuthTypes: []string{"user", "bot"}, HasFormat: true, Flags: []common.Flag{ {Name: "base-token", Desc: "Base token (base_token)", Required: true}, {Name: "table-id", Desc: "table ID", Required: true}, {Name: "form-id", Desc: "form ID", Required: true}, {Name: "questions", Desc: `questions JSON array, max 10 items. Each item requires "title"(field title) and "type"(text/number/select/datetime/user/attachment/location). Optional fields: "description"(plain text or markdown link like [text](https://example.com)),"required","option_display_mode"(0=dropdown/1=vertical/2=horizontal,select only),"multiple"(bool,select/user),"options"([{"name":"opt","hue":"Blue"}],select only),"style"({"type":"plain/phone/url/email/barcode/rating","precision":2,"format":"yyyy/MM/dd","icon":"star","min":1,"max":5}). E.g. '[{"type":"text","title":"Your name","required":true}]'`, Required: true}, }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). POST("/open-apis/base/v3/bases/:base_token/tables/:table_id/forms/:form_id/questions"). Set("base_token", runtime.Str("base-token")). Set("table_id", runtime.Str("table-id")). Set("form_id", runtime.Str("form-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") tableId := runtime.Str("table-id") formId := runtime.Str("form-id") questionsJSON := runtime.Str("questions") var questions []interface{} if err := json.Unmarshal([]byte(questionsJSON), &questions); err != nil { return baseValidationErrorf("--questions must be a valid JSON array: %s", err) } data, err := baseV3Call(runtime, "POST", baseV3Path("bases", baseToken, "tables", tableId, "forms", formId, "questions"), nil, map[string]interface{}{"questions": questions}) if err != nil { return err } items, _ := data["questions"].([]interface{}) outData := map[string]interface{}{"questions": items} runtime.OutFormat(outData, nil, func(w io.Writer) { var rows []map[string]interface{} for _, item := range items { m, _ := item.(map[string]interface{}) rows = append(rows, map[string]interface{}{ "id": m["id"], "title": m["title"], "required": m["required"], }) } output.PrintTable(w, rows) fmt.Fprintf(w, "\n%d question(s) created\n", len(items)) }) return nil }, }
View Source
var BaseFormQuestionsDelete = common.Shortcut{ Service: "base", Command: "+form-questions-delete", Description: "Delete questions from a form in a Base table", Risk: "high-risk-write", Scopes: []string{"base:form:update"}, AuthTypes: []string{"user", "bot"}, HasFormat: true, Flags: []common.Flag{ {Name: "base-token", Desc: "Base token (base_token)", Required: true}, {Name: "table-id", Desc: "table ID", Required: true}, {Name: "form-id", Desc: "form ID", Required: true}, {Name: "question-ids", Desc: `JSON array of question IDs to delete, max 10 items, e.g. '["q_001","q_002"]'`, Required: true}, }, Tips: []string{ baseHighRiskYesTip, }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). DELETE("/open-apis/base/v3/bases/:base_token/tables/:table_id/forms/:form_id/questions"). Set("base_token", runtime.Str("base-token")). Set("table_id", runtime.Str("table-id")). Set("form_id", runtime.Str("form-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") tableId := runtime.Str("table-id") formId := runtime.Str("form-id") questionIdsJSON := runtime.Str("question-ids") var questionIds []string if err := json.Unmarshal([]byte(questionIdsJSON), &questionIds); err != nil { return baseValidationErrorf("--question-ids must be a valid JSON array of strings: %s", err) } _, err := baseV3Call(runtime, "DELETE", baseV3Path("bases", baseToken, "tables", tableId, "forms", formId, "questions"), nil, map[string]interface{}{"question_ids": questionIds}) if err != nil { return err } runtime.Out(map[string]interface{}{ "deleted": true, "question_ids": questionIds, }, nil) return nil }, }
View Source
var BaseFormQuestionsList = common.Shortcut{ Service: "base", Command: "+form-questions-list", Description: "List questions of a form in a Base table", Risk: "read", Scopes: []string{"base:form:read"}, AuthTypes: []string{"user", "bot"}, HasFormat: true, Flags: []common.Flag{ baseTokenFlag(true), {Name: "table-id", Desc: "table ID", Required: true}, {Name: "form-id", Desc: "form ID", Required: true}, }, Tips: []string{ "Use returned question id values for +form-questions-update and +form-questions-delete.", }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). GET("/open-apis/base/v3/bases/:base_token/tables/:table_id/forms/:form_id/questions"). Set("base_token", runtime.Str("base-token")). Set("table_id", runtime.Str("table-id")). Set("form_id", runtime.Str("form-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") tableId := runtime.Str("table-id") formId := runtime.Str("form-id") data, err := baseV3Call(runtime, "GET", baseV3Path("bases", baseToken, "tables", tableId, "forms", formId, "questions"), nil, nil) if err != nil { return err } items, _ := data["questions"].([]interface{}) outData := map[string]interface{}{ "questions": items, "total": data["total"], } runtime.OutFormat(outData, nil, func(w io.Writer) { if len(items) == 0 { fmt.Fprintln(w, "No questions found.") return } var rows []map[string]interface{} for _, item := range items { m, _ := item.(map[string]interface{}) rows = append(rows, map[string]interface{}{ "id": m["id"], "title": m["title"], "description": m["description"], "required": m["required"], }) } output.PrintTable(w, rows) fmt.Fprintf(w, "\n%v question(s) total\n", data["total"]) }) return nil }, }
View Source
var BaseFormQuestionsUpdate = common.Shortcut{ Service: "base", Command: "+form-questions-update", Description: "Update questions of a form in a Base table", Risk: "write", Scopes: []string{"base:form:update"}, AuthTypes: []string{"user", "bot"}, HasFormat: true, Flags: []common.Flag{ {Name: "base-token", Desc: "Base token (base_token)", Required: true}, {Name: "table-id", Desc: "table ID", Required: true}, {Name: "form-id", Desc: "form ID", Required: true}, {Name: "questions", Desc: `questions JSON array, max 10 items, each item must include "id". Supported fields: "id"(required),"title","description"(plain text or markdown link like [text](https://example.com)),"required","option_display_mode"(0=dropdown,1=vertical,2=horizontal,select only). E.g. '[{"id":"q_001","title":"Updated?","required":true}]'`, Required: true}, }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). PATCH("/open-apis/base/v3/bases/:base_token/tables/:table_id/forms/:form_id/questions"). Set("base_token", runtime.Str("base-token")). Set("table_id", runtime.Str("table-id")). Set("form_id", runtime.Str("form-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") tableId := runtime.Str("table-id") formId := runtime.Str("form-id") questionsJSON := runtime.Str("questions") var questions []interface{} if err := json.Unmarshal([]byte(questionsJSON), &questions); err != nil { return baseValidationErrorf("--questions must be a valid JSON array: %s", err) } data, err := baseV3Call(runtime, "PATCH", baseV3Path("bases", baseToken, "tables", tableId, "forms", formId, "questions"), nil, map[string]interface{}{"questions": questions}) if err != nil { return err } items, _ := data["items"].([]interface{}) if len(items) == 0 { items, _ = data["questions"].([]interface{}) } outData := map[string]interface{}{"questions": items} runtime.OutFormat(outData, nil, func(w io.Writer) { var rows []map[string]interface{} for _, item := range items { m, _ := item.(map[string]interface{}) rows = append(rows, map[string]interface{}{ "id": m["id"], "title": m["title"], "required": m["required"], }) } output.PrintTable(w, rows) fmt.Fprintf(w, "\n%d question(s) updated\n", len(items)) }) return nil }, }
View Source
var BaseFormSubmit = common.Shortcut{ Service: "base", Command: "+form-submit", Description: "Submit a form (fill and submit form data)", Risk: "write", Scopes: []string{"base:form:update", "docs:document.media:upload"}, AuthTypes: authTypes(), HasFormat: true, Flags: []common.Flag{ {Name: "share-token", Desc: "Form share token (required), extracted from the form share link", Required: true}, {Name: "base-token", Desc: "Base token (required when --json contains attachments, used for uploading attachments to Base Drive Media)"}, {Name: "json", Desc: `JSON object containing "fields" (field values) and "attachments" (attachment file paths). Example: '{"fields":{"Rating":5,"Review":"Good"},"attachments":{"Attachment":["./a.pdf","./b.png"]}}'`, Required: true}, }, Tips: []string{ `Example (no attachments): --share-token shrXXXX --json '{"fields":{"Service Rating":5,"Review":"Good service"}}'`, `Example (with attachments): --share-token shrXXXX --base-token basXXX --json '{"fields":{"Service Rating":5},"attachments":{"Attachment":["./report.pdf"]}}'`, `Cell values in "fields" follow lark-base-cell-value.md conventions; "attachments" maps field names to local file path arrays — the CLI uploads them in parallel and merges them into the submission.`, }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateFormSubmit(runtime) }, DryRun: dryRunFormSubmit, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeFormSubmit(runtime) }, }
View Source
var BaseFormUpdate = common.Shortcut{ Service: "base", Command: "+form-update", Description: "Update a form in a Base table", Risk: "write", Scopes: []string{"base:form:update"}, AuthTypes: []string{"user", "bot"}, HasFormat: true, Flags: []common.Flag{ {Name: "base-token", Desc: "Base token (base_token)", Required: true}, {Name: "table-id", Desc: "table ID", Required: true}, {Name: "form-id", Desc: "form ID", Required: true}, {Name: "name", Desc: "new form name"}, {Name: "description", Desc: "new form description (plain text or markdown link like [text](https://example.com))"}, }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). PATCH("/open-apis/base/v3/bases/:base_token/tables/:table_id/forms/:form_id"). Set("base_token", runtime.Str("base-token")). Set("table_id", runtime.Str("table-id")). Set("form_id", runtime.Str("form-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") tableId := runtime.Str("table-id") formId := runtime.Str("form-id") name := runtime.Str("name") description := runtime.Str("description") body := map[string]interface{}{} if name != "" { body["name"] = name } if description != "" { body["description"] = description } data, err := baseV3Call(runtime, "PATCH", baseV3Path("bases", baseToken, "tables", tableId, "forms", formId), nil, body) if err != nil { return err } runtime.OutFormat(data, nil, func(w io.Writer) { output.PrintTable(w, []map[string]interface{}{ { "id": data["id"], "name": data["name"], "description": data["description"], }, }) }) return nil }, }
View Source
var BaseFormsList = common.Shortcut{ Service: "base", Command: "+form-list", Description: "List all forms in a Base table (auto-paginated)", Risk: "read", Scopes: []string{"base:form:read"}, AuthTypes: []string{"user", "bot"}, HasFormat: true, Flags: []common.Flag{ {Name: "base-token", Desc: "Base token (base_token)", Required: true}, {Name: "table-id", Desc: "table ID", Required: true}, {Name: "page-size", Type: "int", Default: "100", Desc: "page size per request, max 100"}, }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). GET("/open-apis/base/v3/bases/:base_token/tables/:table_id/forms"). Set("base_token", runtime.Str("base-token")). Set("table_id", runtime.Str("table-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") tableId := runtime.Str("table-id") var allForms []interface{} pageToken := "" for { params := map[string]interface{}{ "page_size": runtime.Int("page-size"), } if pageToken != "" { params["page_token"] = pageToken } data, err := baseV3Call(runtime, "GET", baseV3Path("bases", baseToken, "tables", tableId, "forms"), params, nil) if err != nil { return err } forms, _ := data["forms"].([]interface{}) allForms = append(allForms, forms...) hasMore, _ := data["has_more"].(bool) if !hasMore { break } nextToken, _ := data["page_token"].(string) if nextToken == "" { break } pageToken = nextToken } outData := map[string]interface{}{ "forms": allForms, "total": len(allForms), } runtime.OutFormat(outData, nil, func(w io.Writer) { if len(allForms) == 0 { fmt.Fprintln(w, "No forms found.") return } var rows []map[string]interface{} for _, item := range allForms { m, _ := item.(map[string]interface{}) rows = append(rows, map[string]interface{}{ "id": m["id"], "name": m["name"], "description": m["description"], }) } output.PrintTable(w, rows) fmt.Fprintf(w, "\n%d form(s) total\n", len(allForms)) }) return nil }, }
View Source
var BaseRecordBatchCreate = common.Shortcut{ Service: "base", Command: "+record-batch-create", Description: "Batch create records", Risk: "write", Scopes: []string{"base:record:create"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), {Name: "json", Desc: `batch create JSON object, e.g. {"fields":["Name","Status"],"rows":[["Task A","Todo"],["Task B",null]]}; rows follow fields order`, Required: true}, }, Tips: append([]string{ "Happy path fields: fields is the column order; rows is an array of row arrays; each row must match fields order and may use null for empty cells.", "Before writing, use +field-list to confirm real writable fields; do not write system fields, formula, lookup, or attachment fields as normal CellValue.", "Batch create supports max 200 rows per call.", "Use the record-batch-create guide for command limits and edge cases.", }, recordCellValueHappyPathTips...), Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateRecordJSON(runtime) }, DryRun: dryRunRecordBatchCreate, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeRecordBatchCreate(runtime) }, }
View Source
var BaseRecordBatchUpdate = common.Shortcut{ Service: "base", Command: "+record-batch-update", Description: "Batch update records", Risk: "write", Scopes: []string{"base:record:update"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), {Name: "json", Desc: `batch update JSON object, e.g. {"record_id_list":["rec_xxx"],"patch":{"Status":"Done"}}; same patch applies to all records`, Required: true}, }, Tips: append([]string{ "Happy path fields: record_id_list is the target record IDs; patch is a field map applied unchanged to every target record.", "Do not use +record-batch-update for per-row different values; call +record-upsert per record or use another supported flow.", "Before writing, use +field-list to confirm real writable fields; do not write system fields, formula, lookup, or attachment fields as normal CellValue.", "Batch update supports max 200 records per call; use the record-batch-update guide for command limits and edge cases.", }, recordCellValueHappyPathTips...), Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateRecordJSON(runtime) }, DryRun: dryRunRecordBatchUpdate, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeRecordBatchUpdate(runtime) }, }
View Source
var BaseRecordDelete = common.Shortcut{ Service: "base", Command: "+record-delete", Description: "Delete one or more records by ID", Risk: "high-risk-write", Scopes: []string{"base:record:delete"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), {Name: "record-id", Type: "string_array", Desc: "record ID (repeatable)"}, {Name: "json", Desc: `JSON object with record_id_list, e.g. {"record_id_list":["rec_xxx"]}`}, }, Tips: []string{ baseHighRiskYesTip, `Example: lark-cli base +record-delete --base-token <base_token> --table-id <table_id> --record-id <record_id_1> --record-id <record_id_2> --yes`, }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateRecordSelection(runtime) }, DryRun: dryRunRecordDelete, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeRecordDelete(runtime) }, }
View Source
var BaseRecordDownloadAttachment = common.Shortcut{ Service: "base", Command: "+record-download-attachment", Description: "Download Base record attachments by record-id, optionally filtering by file-token", Risk: "read", Scopes: []string{"base:record:read", "docs:document.media:download"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), recordRefFlag(true), {Name: "file-token", Type: "string_array", Desc: "attachment file_token returned by Base; repeat to download selected files; omit to download all attachments in the record", Required: false}, {Name: "output", Desc: "local save path; with exactly one file token this may be a file path; with multiple or omitted file tokens this must be an existing directory", Required: true}, {Name: "overwrite", Type: "bool", Desc: "overwrite existing output file"}, }, Tips: []string{ `Example: lark-cli base +record-download-attachment --base-token <base_token> --table-id <table_id> --record-id <record_id> --file-token <file_token> --output ./downloads/`, `Omit --file-token to download every attachment in the record.`, `Base attachments should be downloaded with this command; other download commands may fail for Base attachment files.`, `With one --file-token, --output may be a file path or directory; with multiple or omitted --file-token values, --output must be an existing directory.`, }, DryRun: dryRunRecordDownloadAttachment, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateRecordDownloadAttachment(runtime) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeRecordDownloadAttachment(ctx, runtime) }, }
View Source
var BaseRecordGet = common.Shortcut{ Service: "base", Command: "+record-get", Description: "Get one or more records by ID", Risk: "read", Scopes: []string{"base:record:read"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), {Name: "record-id", Type: "string_array", Desc: "record ID (repeatable)"}, {Name: "field-id", Type: "string_array", Desc: "field ID or name to project; repeat to keep only needed columns"}, {Name: "json", Desc: `JSON object with record_id_list, e.g. {"record_id_list":["rec_xxx"]}`}, recordReadFormatFlag(), }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { if err := validateRecordReadFormat(runtime); err != nil { return err } return validateRecordSelection(runtime) }, Tips: []string{ "Example: lark-cli base +record-get --base-token <base_token> --table-id <table_id> --record-id <record_id>", "Example with projection: lark-cli base +record-get --base-token <base_token> --table-id <table_id> --record-id rec_001 --record-id rec_002 --field-id Name --field-id Status", "Default output is markdown; pass --format json to get the raw JSON envelope.", "Use --field-id as a projection boundary to avoid loading large cell values into context when they are not needed.", "Use +record-get when record_id is already known; otherwise use +record-search or +record-list.", "Agent hint: follow the lark-base record read SOP for record read routing.", }, DryRun: dryRunRecordGet, PostMount: func(cmd *cobra.Command) { preserveFlagOrder(cmd) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeRecordGet(runtime) }, }
View Source
var BaseRecordHistoryList = common.Shortcut{ Service: "base", Command: "+record-history-list", Description: "List record change history", Risk: "read", Scopes: []string{"base:history:read"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), recordRefFlag(true), {Name: "max-version", Type: "int", Desc: "max version for next page"}, {Name: "page-size", Type: "int", Default: "30", Desc: "pagination size, max 50"}, }, Tips: []string{ `Example: lark-cli base +record-history-list --base-token <base_token> --table-id <table_id> --record-id <record_id>`, "This reads one record's history only; it is not a table-wide audit scan.", }, DryRun: dryRunRecordHistoryList, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { params := map[string]interface{}{ "table_id": baseTableID(runtime), "record_id": runtime.Str("record-id"), "page_size": runtime.Int("page-size"), } if value := runtime.Int("max-version"); value > 0 { params["max_version"] = value } data, err := baseV3Call(runtime, "GET", baseV3Path("bases", runtime.Str("base-token"), "record_history"), params, nil) if err != nil { return err } runtime.Out(data, nil) return nil }, }
View Source
var BaseRecordList = common.Shortcut{ Service: "base", Command: "+record-list", Description: "List records in a table", Risk: "read", Scopes: []string{"base:record:read"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), recordListFieldRefFlag(), recordListViewRefFlag(), recordFilterFlag(), recordSortFlag(), {Name: "offset", Type: "int", Default: "0", Desc: "pagination offset"}, {Name: "limit", Type: "int", Default: "100", Desc: "pagination size, range 1-200"}, recordReadFormatFlag(), }, Tips: []string{ "Example: lark-cli base +record-list --base-token <base_token> --table-id <table_id> --limit 50", "Example with projection: lark-cli base +record-list --base-token <base_token> --table-id <table_id> --field-id Name --field-id Status --limit 50", `Text equality filter: --filter-json '{"logic":"and","conditions":[["Title","==","Launch plan"]]}'`, `Text contains/like filter: --filter-json '{"logic":"and","conditions":[["Title","intersects","urgent"]]}'`, `Number equality filter: --filter-json '{"logic":"and","conditions":[["Score","==",95]]}'`, `Date equality filter: --filter-json '{"logic":"and","conditions":[["Due Date","==","ExactDate(2026-06-02)"]]}'`, `Option intersection filter: --filter-json '{"logic":"and","conditions":[["Tags","intersects",["P0","Blocked"]]]}'`, `Sort priority follows --sort-json array order: --sort-json '[{"field":"Updated","desc":true},{"field":"Title","desc":false}]'`, formatRecordQueryPriorityTip(), "Default output is markdown; pass --format json to get the raw JSON envelope.", "Use --field-id repeatedly to keep output small and aligned with the task.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { if err := validateRecordReadFormat(runtime); err != nil { return err } return validateRecordQueryOptions(runtime) }, DryRun: dryRunRecordList, PostMount: func(cmd *cobra.Command) { preserveFlagOrder(cmd) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeRecordList(runtime) }, }
View Source
var BaseRecordRemoveAttachment = common.Shortcut{ Service: "base", Command: "+record-remove-attachment", Description: "Remove one or more file_token values from a Base record attachment cell", Risk: "high-risk-write", Scopes: []string{"base:record:update", "base:field:read"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), recordRefFlag(true), fieldRefFlag(true), {Name: "file-token", Type: "string_array", Desc: "attachment file_token to remove from the target cell; repeat to remove multiple attachments; max 50 tokens", Required: true}, }, Tips: []string{ baseHighRiskYesTip, `Example: lark-cli base +record-remove-attachment --base-token <base_token> --table-id <table_id> --record-id <record_id> --field-id <attachment_field_id> --file-token <file_token> --yes`, `Repeat --file-token to remove multiple attachments from the same cell in one call.`, `This is a high-risk write command and requires --yes.`, }, DryRun: dryRunRecordRemoveAttachment, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateRecordRemoveAttachment(runtime) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeRecordRemoveAttachment(runtime) }, }
View Source
var BaseRecordSearch = common.Shortcut{ Service: "base", Command: "+record-search", Description: "Search records in a table", Risk: "read", Scopes: []string{"base:record:read"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), {Name: "json", Desc: `record search JSON object for the full request body, e.g. {"keyword":"Alice","search_fields":["Name"],"select_fields":["Name","Status"],"filter":{"logic":"and","conditions":[]},"sort":[{"field":"Updated","desc":true}],"limit":50}; escape hatch for advanced cases`}, {Name: "keyword", Desc: "keyword for record search; required unless --json is used"}, {Name: "search-field", Type: "string_array", Desc: "field ID or name to search; repeat for multiple fields; required unless --json is used"}, recordListFieldRefFlag(), recordListViewRefFlag(), recordFilterFlag(), recordSortFlag(), {Name: "offset", Type: "int", Default: "0", Desc: "pagination offset"}, {Name: "limit", Type: "int", Default: "10", Desc: "pagination size, range 1-200"}, recordReadFormatFlag(), }, Tips: []string{ `Happy path fields: keyword (string), search_fields (1-20 field names/ids), select_fields (optional projection, <=50), view_id (optional), offset (default 0), limit (default 10, range 1-200).`, "JSON constraints: keyword length >=1; search_fields length 1-20; select_fields length <=50; offset >=0 defaults to 0; limit range 1-200 defaults to 10.", "view_id scopes search to records in that view; when select_fields is omitted, returned fields follow that view's visible fields.", `Example: lark-cli base +record-search --base-token <base_token> --table-id <table_id> --keyword Alice --search-field Name --field-id Name --field-id Status --limit 20`, `Example with filter/sort JSON: lark-cli base +record-search --base-token <base_token> --table-id <table_id> --keyword Alice --search-field Name --filter-json @filter.json --sort-json '[{"field":"Updated","desc":true}]'`, `Text equality filter: --filter-json '{"logic":"and","conditions":[["Title","==","Launch plan"]]}'`, `Text contains/like filter: --filter-json '{"logic":"and","conditions":[["Title","intersects","urgent"]]}'`, `Option intersection filter: --filter-json '{"logic":"and","conditions":[["Tags","intersects",["P0","Blocked"]]]}'`, `Sort priority follows --sort-json array order.`, formatRecordQueryPriorityTip(), "Use +record-search for keyword matching; use --filter-json for structured conditions and --sort-json for result ordering.", "Use --json only when you need to pass the full search body directly.", "Default output is markdown; pass --format json to get the raw JSON envelope.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateRecordSearchFlags(runtime) }, DryRun: dryRunRecordSearch, PostMount: func(cmd *cobra.Command) { preserveFlagOrder(cmd) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeRecordSearch(runtime) }, }
View Source
Service: "base", Command: "+record-share-link-create", Description: "Generate share links for one or more records (max 100 per request)", Risk: "read", Scopes: []string{"base:record:read"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), {Name: "record-ids", Type: "string_slice", Desc: "record IDs to generate share links for (comma-separated or repeatable, max 100)", Required: true}, }, Tips: []string{ `Example: lark-cli base +record-share-link-create --base-token <base_token> --table-id <table_id> --record-ids <record_id>`, "Max 100 record IDs per call; duplicate IDs are ignored.", "Output record_share_links maps record_id to URL; records without permission or missing records may be absent.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateRecordShareBatch(runtime) }, DryRun: dryRunRecordShareBatch, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeRecordShareBatch(runtime) }, }
View Source
var BaseRecordUploadAttachment = common.Shortcut{ Service: "base", Command: "+record-upload-attachment", Description: "Upload one or more local files and append the returned file_token values to a Base attachment cell", Risk: "write", Scopes: []string{"base:record:update", "base:field:read", "docs:document.media:upload"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), recordRefFlag(true), fieldRefFlag(true), {Name: "file", Type: "string_array", Desc: "local file path; repeat to append multiple attachments in one cell; max 50 files, max 2GB each; files > 20MB use multipart upload automatically", Required: true}, {Name: "name", Desc: "deprecated; attachment names are derived from local file basenames", Hidden: true}, }, Tips: []string{ `Example: lark-cli base +record-upload-attachment --base-token <base_token> --table-id <table_id> --record-id <record_id> --field-id <attachment_field_id> --file ./report.pdf`, `Repeat --file to append multiple attachments: --file ./report.pdf --file ./screenshot.png`, `Reuse returned file_token values for download/remove`, }, DryRun: dryRunRecordUploadAttachment, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateRecordUploadAttachment(runtime) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeRecordUploadAttachment(runtime) }, }
View Source
var BaseRecordUpsert = common.Shortcut{ Service: "base", Command: "+record-upsert", Description: "Create or update a record", Risk: "write", Scopes: []string{"base:record:create", "base:record:update"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), recordRefFlag(false), {Name: "json", Desc: `record field map JSON object, e.g. {"Name":"Alice","Status":"Todo"}; do not wrap in fields`, Required: true}, }, Tips: append([]string{ "Happy path JSON is a top-level field map: each key is a real field name or field ID, each value is that field's CellValue.", "Without --record-id this creates a record; with --record-id this updates that record. It does not auto-upsert by business key.", "Before writing, use +field-list to confirm real writable fields; do not write system fields, formula, lookup, or attachment fields as normal CellValue.", "Use the record-upsert guide for command limits and edge cases.", }, recordCellValueHappyPathTips...), Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateRecordJSON(runtime) }, DryRun: dryRunRecordUpsert, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeRecordUpsert(runtime) }, }
View Source
var BaseRoleCreate = common.Shortcut{ Service: "base", Command: "+role-create", Description: "Create a custom role in a Base", Risk: "write", Scopes: []string{"base:role:create"}, AuthTypes: []string{"user", "bot"}, Flags: []common.Flag{ {Name: "base-token", Desc: "base token", Required: true}, {Name: "json", Desc: "role config JSON; read lark-base-role-guide.md and role-config.md before constructing permissions", Required: true}, }, Tips: []string{ "Requires advanced permissions to be enabled and the caller to be a Base admin.", "Use lark-base-role-guide.md as the entry guide and role-config.md as the role permission JSON SSOT.", "Create supports custom_role only.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { if strings.TrimSpace(runtime.Str("base-token")) == "" { return baseFlagErrorf("--base-token must not be blank") } var body map[string]any if err := json.Unmarshal([]byte(runtime.Str("json")), &body); err != nil { return baseFlagErrorf("--json must be valid JSON: %v", err) } return nil }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { var body map[string]any json.Unmarshal([]byte(runtime.Str("json")), &body) return common.NewDryRunAPI(). POST("/open-apis/base/v3/bases/:base_token/roles"). Body(body). Set("base_token", runtime.Str("base-token")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") var body map[string]any json.Unmarshal([]byte(runtime.Str("json")), &body) apiResp, err := runtime.DoAPI(&larkcore.ApiReq{ HttpMethod: http.MethodPost, ApiPath: fmt.Sprintf("/open-apis/base/v3/bases/%s/roles", validate.EncodePathSegment(baseToken)), Body: body, }) if err != nil { return err } return handleRoleAPIResponse(runtime, apiResp, "create role failed") }, }
View Source
var BaseRoleDelete = common.Shortcut{ Service: "base", Command: "+role-delete", Description: "Delete a custom role (system roles cannot be deleted)", Risk: "high-risk-write", Scopes: []string{"base:role:delete"}, AuthTypes: []string{"user", "bot"}, Flags: []common.Flag{ {Name: "base-token", Desc: "base token", Required: true}, {Name: "role-id", Desc: "role ID (e.g. rolxxxxxx4)", Required: true}, }, Tips: []string{ baseHighRiskYesTip, "Requires advanced permissions to be enabled and the caller to be a Base admin.", "Only custom roles can be deleted; system roles cannot be deleted.", "Use +role-get first if the role target is ambiguous, then pass --yes to confirm deletion.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { if strings.TrimSpace(runtime.Str("base-token")) == "" { return baseFlagErrorf("--base-token must not be blank") } if strings.TrimSpace(runtime.Str("role-id")) == "" { return baseFlagErrorf("--role-id must not be blank") } return nil }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). DELETE("/open-apis/base/v3/bases/:base_token/roles/:role_id"). Set("base_token", runtime.Str("base-token")). Set("role_id", runtime.Str("role-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") roleId := runtime.Str("role-id") apiResp, err := runtime.DoAPI(&larkcore.ApiReq{ HttpMethod: http.MethodDelete, ApiPath: fmt.Sprintf("/open-apis/base/v3/bases/%s/roles/%s", validate.EncodePathSegment(baseToken), validate.EncodePathSegment(roleId)), Body: map[string]any{}, }) if err != nil { return err } return handleRoleAPIResponse(runtime, apiResp, "delete role failed") }, }
View Source
var BaseRoleGet = common.Shortcut{ Service: "base", Command: "+role-get", Description: "Get full config of a role", Risk: "read", Scopes: []string{"base:role:read"}, AuthTypes: []string{"user", "bot"}, HasFormat: true, Flags: []common.Flag{ {Name: "base-token", Desc: "base token", Required: true}, {Name: "role-id", Desc: "role ID (e.g. rolxxxxxx4)", Required: true}, }, Tips: []string{ "Requires advanced permissions to be enabled and the caller to be a Base admin.", "Use before +role-update to inspect the current full permission config.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { if strings.TrimSpace(runtime.Str("base-token")) == "" { return baseFlagErrorf("--base-token must not be blank") } if strings.TrimSpace(runtime.Str("role-id")) == "" { return baseFlagErrorf("--role-id must not be blank") } return nil }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). GET("/open-apis/base/v3/bases/:base_token/roles/:role_id"). Set("base_token", runtime.Str("base-token")). Set("role_id", runtime.Str("role-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") roleId := runtime.Str("role-id") apiResp, err := runtime.DoAPI(&larkcore.ApiReq{ HttpMethod: http.MethodGet, ApiPath: fmt.Sprintf("/open-apis/base/v3/bases/%s/roles/%s", validate.EncodePathSegment(baseToken), validate.EncodePathSegment(roleId)), }) if err != nil { return err } return handleRoleAPIResponse(runtime, apiResp, "get role failed") }, }
View Source
var BaseRoleList = common.Shortcut{ Service: "base", Command: "+role-list", Description: "List all roles in a Base", Risk: "read", Scopes: []string{"base:role:read"}, AuthTypes: []string{"user", "bot"}, HasFormat: true, Flags: []common.Flag{ {Name: "base-token", Desc: "base token", Required: true}, }, Tips: []string{ "Requires advanced permissions to be enabled and the caller to be a Base admin.", "Returns role summaries; use +role-get for the full permission config.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { if strings.TrimSpace(runtime.Str("base-token")) == "" { return baseFlagErrorf("--base-token must not be blank") } return nil }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). GET("/open-apis/base/v3/bases/:base_token/roles"). Set("base_token", runtime.Str("base-token")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") apiResp, err := runtime.DoAPI(&larkcore.ApiReq{ HttpMethod: http.MethodGet, ApiPath: fmt.Sprintf("/open-apis/base/v3/bases/%s/roles", validate.EncodePathSegment(baseToken)), }) if err != nil { return err } return handleRoleAPIResponse(runtime, apiResp, "list roles failed") }, }
View Source
var BaseRoleUpdate = common.Shortcut{ Service: "base", Command: "+role-update", Description: "Update a role config (delta merge, only changed fields needed)", Risk: "high-risk-write", Scopes: []string{"base:role:update"}, AuthTypes: []string{"user", "bot"}, Flags: []common.Flag{ {Name: "base-token", Desc: "base token", Required: true}, {Name: "role-id", Desc: "role ID (e.g. rolxxxxxx4)", Required: true}, {Name: "json", Desc: "delta role config JSON; read lark-base-role-guide.md and role-config.md before changing permissions", Required: true}, }, Tips: []string{ baseHighRiskYesTip, "Requires advanced permissions to be enabled and the caller to be a Base admin.", "Update is a delta merge: only changed fields are updated, others remain unchanged.", "Use lark-base-role-guide.md as the entry guide and role-config.md as the role permission JSON SSOT.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { if strings.TrimSpace(runtime.Str("base-token")) == "" { return baseFlagErrorf("--base-token must not be blank") } if strings.TrimSpace(runtime.Str("role-id")) == "" { return baseFlagErrorf("--role-id must not be blank") } var body map[string]any if err := json.Unmarshal([]byte(runtime.Str("json")), &body); err != nil { return baseFlagErrorf("--json must be valid JSON: %v", err) } return nil }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { var body map[string]any json.Unmarshal([]byte(runtime.Str("json")), &body) return common.NewDryRunAPI(). Desc("Delta merge: only changed fields are updated, others remain unchanged"). PUT("/open-apis/base/v3/bases/:base_token/roles/:role_id"). Body(body). Set("base_token", runtime.Str("base-token")). Set("role_id", runtime.Str("role-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { baseToken := runtime.Str("base-token") roleId := runtime.Str("role-id") var body map[string]any json.Unmarshal([]byte(runtime.Str("json")), &body) apiResp, err := runtime.DoAPI(&larkcore.ApiReq{ HttpMethod: http.MethodPut, ApiPath: fmt.Sprintf("/open-apis/base/v3/bases/%s/roles/%s", validate.EncodePathSegment(baseToken), validate.EncodePathSegment(roleId)), Body: body, }) if err != nil { return err } return handleRoleAPIResponse(runtime, apiResp, "update role failed") }, }
View Source
var BaseTableCreate = common.Shortcut{ Service: "base", Command: "+table-create", Description: "Create a table and optional fields/views", Risk: "write", Scopes: []string{"base:table:create", "base:field:read", "base:field:create", "base:field:update", "base:view:write_only"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), {Name: "name", Desc: "table name", Required: true}, {Name: "view", Desc: "view JSON object/array for create"}, {Name: "fields", Desc: `field JSON array for create, e.g. [{"name":"Title","type":"text"},{"name":"Status","type":"select","options":[{"name":"Todo"},{"name":"Done"}]}]`}, }, Tips: []string{ "Before using --fields, read lark-base-field-json.md or rely on the same field JSON shape used by +field-create; do not invent field properties.", "The first --fields item replaces the default field.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateTableCreate(runtime) }, DryRun: dryRunTableCreate, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeTableCreate(runtime) }, }
View Source
var BaseTableDelete = common.Shortcut{ Service: "base", Command: "+table-delete", Description: "Delete a table by ID or name", Risk: "high-risk-write", Scopes: []string{"base:table:delete"}, AuthTypes: authTypes(), Flags: []common.Flag{baseTokenFlag(true), tableRefFlag(true)}, Tips: []string{ `Example: lark-cli base +table-delete --base-token <base_token> --table-id "Old Tasks" --yes`, "table-id accepts a table ID (tbl...) or the table name in the current Base.", baseHighRiskYesTip, }, DryRun: dryRunTableDelete, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeTableDelete(runtime) }, }
View Source
var BaseTableGet = common.Shortcut{ Service: "base", Command: "+table-get", Description: "Get a table by ID or name", Risk: "read", Scopes: []string{"base:table:read", "base:field:read", "base:view:read"}, AuthTypes: authTypes(), Flags: []common.Flag{baseTokenFlag(true), tableRefFlag(true)}, Tips: []string{ `Example: lark-cli base +table-get --base-token <base_token> --table-id "Tasks"`, "table-id accepts a table ID (tbl...) or the table name in the current Base.", }, DryRun: dryRunTableGet, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeTableGet(runtime) }, }
View Source
var BaseTableList = common.Shortcut{ Service: "base", Command: "+table-list", Description: "List tables in a base", Risk: "read", Scopes: []string{"base:table:read"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), {Name: "offset", Type: "int", Default: "0", Desc: "pagination offset"}, {Name: "limit", Type: "int", Default: "50", Desc: "pagination size, range 1-100"}, }, DryRun: dryRunTableList, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeTableList(runtime) }, }
View Source
var BaseTableUpdate = common.Shortcut{ Service: "base", Command: "+table-update", Description: "Rename a table by ID or name", Risk: "write", Scopes: []string{"base:table:update"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), {Name: "name", Desc: "new table name", Required: true}, }, DryRun: dryRunTableUpdate, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeTableUpdate(runtime) }, }
View Source
var BaseViewCreate = common.Shortcut{ Service: "base", Command: "+view-create", Description: "Create one or more views", Risk: "write", Scopes: []string{"base:view:write_only"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), {Name: "json", Desc: "view JSON object/array; type defaults to grid; type range: grid, kanban, gallery, calendar, gantt", Required: true}, }, Tips: []string{ `Example: lark-cli base +view-create --base-token <base_token> --table-id <table_id> --json '{"name":"Main","type":"grid"}'`, `Minimal: --json '{"name":"Main"}' creates a grid view.`, "Do not pass form as a view type; form views are managed through form commands.", `Use +view-set-visible-fields after creation when the user needs a specific field order or visibility.`, }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateViewCreate(runtime) }, DryRun: dryRunViewCreate, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewCreate(runtime) }, }
View Source
var BaseViewDelete = common.Shortcut{ Service: "base", Command: "+view-delete", Description: "Delete a view by ID or name", Risk: "high-risk-write", Scopes: []string{"base:view:write_only"}, AuthTypes: authTypes(), Flags: []common.Flag{baseTokenFlag(true), tableRefFlag(true), viewRefFlag(true)}, Tips: []string{ baseHighRiskYesTip, `Example: lark-cli base +view-delete --base-token <base_token> --table-id <table_id> --view-id "Old View" --yes`, }, DryRun: dryRunViewDelete, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewDelete(runtime) }, }
View Source
var BaseViewGet = common.Shortcut{ Service: "base", Command: "+view-get", Description: "Get a view by ID or name", Risk: "read", Scopes: []string{"base:view:read"}, AuthTypes: authTypes(), Flags: []common.Flag{baseTokenFlag(true), tableRefFlag(true), viewRefFlag(true)}, DryRun: dryRunViewGet, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewGet(runtime) }, }
View Source
var BaseViewGetCard = common.Shortcut{ Service: "base", Command: "+view-get-card", Description: "Get view card configuration", Risk: "read", Scopes: []string{"base:view:read"}, AuthTypes: authTypes(), Flags: []common.Flag{baseTokenFlag(true), tableRefFlag(true), viewRefFlag(true)}, DryRun: dryRunViewGetCard, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewGetProperty(runtime, "card", "card") }, }
View Source
var BaseViewGetFilter = common.Shortcut{ Service: "base", Command: "+view-get-filter", Description: "Get view filter configuration", Risk: "read", Scopes: []string{"base:view:read"}, AuthTypes: authTypes(), Flags: []common.Flag{baseTokenFlag(true), tableRefFlag(true), viewRefFlag(true)}, DryRun: dryRunViewGetFilter, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewGetProperty(runtime, "filter", "filter") }, }
View Source
var BaseViewGetGroup = common.Shortcut{ Service: "base", Command: "+view-get-group", Description: "Get view group configuration", Risk: "read", Scopes: []string{"base:view:read"}, AuthTypes: authTypes(), Flags: []common.Flag{baseTokenFlag(true), tableRefFlag(true), viewRefFlag(true)}, DryRun: dryRunViewGetGroup, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewGetProperty(runtime, "group", "group") }, }
View Source
var BaseViewGetSort = common.Shortcut{ Service: "base", Command: "+view-get-sort", Description: "Get view sort configuration", Risk: "read", Scopes: []string{"base:view:read"}, AuthTypes: authTypes(), Flags: []common.Flag{baseTokenFlag(true), tableRefFlag(true), viewRefFlag(true)}, DryRun: dryRunViewGetSort, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewGetProperty(runtime, "sort", "sort") }, }
View Source
var BaseViewGetTimebar = common.Shortcut{ Service: "base", Command: "+view-get-timebar", Description: "Get view timebar configuration", Risk: "read", Scopes: []string{"base:view:read"}, AuthTypes: authTypes(), Flags: []common.Flag{baseTokenFlag(true), tableRefFlag(true), viewRefFlag(true)}, DryRun: dryRunViewGetTimebar, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewGetProperty(runtime, "timebar", "timebar") }, }
View Source
var BaseViewGetVisibleFields = common.Shortcut{ Service: "base", Command: "+view-get-visible-fields", Description: "Get view visible fields configuration", Risk: "read", Scopes: []string{"base:view:read"}, AuthTypes: authTypes(), Flags: []common.Flag{baseTokenFlag(true), tableRefFlag(true), viewRefFlag(true)}, DryRun: dryRunViewGetVisibleFields, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewGetProperty(runtime, "visible_fields", "visible_fields") }, }
View Source
var BaseViewList = common.Shortcut{ Service: "base", Command: "+view-list", Description: "List views in a table", Risk: "read", Scopes: []string{"base:view:read"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), {Name: "offset", Type: "int", Default: "0", Desc: "pagination offset"}, {Name: "limit", Type: "int", Default: "100", Desc: "pagination size, range 1-200"}, }, DryRun: dryRunViewList, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewList(runtime) }, }
View Source
var BaseViewRename = common.Shortcut{ Service: "base", Command: "+view-rename", Description: "Rename a view by ID or name", Risk: "write", Scopes: []string{"base:view:write_only"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), viewRefFlag(true), {Name: "name", Desc: "new view name", Required: true}, }, DryRun: dryRunViewRename, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewRename(runtime) }, }
View Source
var BaseViewSetCard = common.Shortcut{ Service: "base", Command: "+view-set-card", Description: "Set view card configuration", Risk: "write", Scopes: []string{"base:view:write_only"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), viewRefFlag(true), {Name: "json", Desc: `card JSON object, e.g. {"cover_field":"Cover"} or {"cover_field":null} to clear`, Required: true}, }, Tips: []string{ "Supported view types: gallery, kanban.", "cover_field should be an attachment field id/name, or null to clear.", "Use +view-get-card first when updating an existing card view configuration.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateViewJSONObject(runtime) }, DryRun: dryRunViewSetCard, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewSetJSONObject(runtime, "card", "card") }, }
View Source
var BaseViewSetFilter = common.Shortcut{ Service: "base", Command: "+view-set-filter", Description: "Set view filter configuration", Risk: "write", Scopes: []string{"base:view:write_only"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), viewRefFlag(true), {Name: "json", Desc: `filter JSON object, e.g. {"logic":"and","conditions":[["Status","==","Todo"]]}`, Required: true}, }, Tips: []string{ "Agent hint: use the lark-base skill's view-set-filter guide for usage and limits.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateViewJSONObject(runtime) }, DryRun: dryRunViewSetFilter, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewSetJSONObject(runtime, "filter", "filter") }, }
View Source
var BaseViewSetGroup = common.Shortcut{ Service: "base", Command: "+view-set-group", Description: "Set view group configuration", Risk: "write", Scopes: []string{"base:view:write_only"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), viewRefFlag(true), {Name: "json", Desc: `group JSON object with group_config array, e.g. {"group_config":[{"field":"Status","desc":false}]}; use {"group_config":[]} to clear`, Required: true}, }, Tips: []string{ "Supported view types: grid, kanban, gantt.", "Use a JSON object, not a bare array; grouping fields must be supported by the current view.", "group_config supports max 3 group items.", "Use +view-get-group first when modifying an existing grouping configuration.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateViewJSONObject(runtime) }, DryRun: dryRunViewSetGroup, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewSetWrapped(runtime, "group", "group_config", "group") }, }
View Source
var BaseViewSetSort = common.Shortcut{ Service: "base", Command: "+view-set-sort", Description: "Set view sort configuration", Risk: "write", Scopes: []string{"base:view:write_only"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), viewRefFlag(true), {Name: "json", Desc: `sort_config JSON object, e.g. {"sort_config":[{"field":"Priority","desc":true}]}; use {"sort_config":[]} to clear; max 10 items`, Required: true}, }, Tips: []string{ "Supported view types: grid, kanban, gallery, gantt.", "Use a JSON object, not a bare array; sorting fields must be supported by the current view.", "sort_config supports max 10 sort items.", "Use +view-get-sort first when modifying an existing sort configuration.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateViewJSONObject(runtime) }, DryRun: dryRunViewSetSort, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewSetWrapped(runtime, "sort", "sort_config", "sort") }, }
View Source
var BaseViewSetTimebar = common.Shortcut{ Service: "base", Command: "+view-set-timebar", Description: "Set view timebar configuration", Risk: "write", Scopes: []string{"base:view:write_only"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), viewRefFlag(true), {Name: "json", Desc: `timebar JSON object with start_time, end_time, title, e.g. {"start_time":"Start Date","end_time":"End Date","title":"Name"}`, Required: true}, }, Tips: []string{ "Supported view types: calendar, gantt.", "start_time, end_time, and title are required; use date/time fields for start_time and end_time.", "Use +view-get-timebar first when modifying an existing timebar configuration.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateViewJSONObject(runtime) }, DryRun: dryRunViewSetTimebar, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewSetJSONObject(runtime, "timebar", "timebar") }, }
View Source
var BaseViewSetVisibleFields = common.Shortcut{ Service: "base", Command: "+view-set-visible-fields", Description: "Set view visible fields", Risk: "write", Scopes: []string{"base:view:write_only"}, AuthTypes: authTypes(), Flags: []common.Flag{ baseTokenFlag(true), tableRefFlag(true), viewRefFlag(true), {Name: "json", Desc: `visible fields JSON object, e.g. {"visible_fields":["Name","Status"]}`, Required: true}, }, Tips: []string{ "Supported view types: grid, kanban, gallery, calendar, gantt.", "Use a JSON object, not a bare array; primary field may be forced to the first position by the API.", "visible_fields controls both visibility and order; include every field that should remain visible.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { return validateViewJSONObject(runtime) }, DryRun: dryRunViewSetVisibleFields, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { return executeViewSetVisibleFields(runtime) }, }
View Source
var BaseWorkflowCreate = common.Shortcut{ Service: "base", Command: "+workflow-create", Description: "Create a new workflow in a base", Risk: "write", Scopes: []string{"base:workflow:create"}, AuthTypes: []string{"user", "bot"}, Flags: []common.Flag{ {Name: "base-token", Desc: "base token", Required: true}, {Name: "json", Desc: "workflow body JSON; read lark-base-workflow-guide.md and lark-base-workflow-schema.md before constructing steps", Required: true}, }, Tips: []string{ "lark-cli base +workflow-create --base-token <base_token> --json @workflow.json", "client_token is required and should be unique per create request.", "New workflows are created disabled; call +workflow-enable after creation when the user wants it active.", "Before constructing steps, use +table-list and +field-list to confirm real table and field names.", "Step ids must be unique, and every next/children link must reference an existing step id.", "Use lark-base-workflow-guide.md as the entry guide and lark-base-workflow-schema.md as the steps JSON SSOT; do not invent steps[].type/data/next/children from natural language.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { if strings.TrimSpace(runtime.Str("base-token")) == "" { return baseFlagErrorf("--base-token must not be blank") } pc := newParseCtx(runtime) raw, err := loadJSONInput(pc, runtime.Str("json"), "json") if err != nil { return err } if _, err := parseJSONObject(pc, raw, "json"); err != nil { return err } return nil }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { pc := newParseCtx(runtime) var body map[string]interface{} if raw, err := loadJSONInput(pc, runtime.Str("json"), "json"); err == nil { body, _ = parseJSONObject(pc, raw, "json") } return common.NewDryRunAPI(). POST("/open-apis/base/v3/bases/:base_token/workflows"). Body(body). Set("base_token", runtime.Str("base-token")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { pc := newParseCtx(runtime) raw, err := loadJSONInput(pc, runtime.Str("json"), "json") if err != nil { return err } body, err := parseJSONObject(pc, raw, "json") if err != nil { return err } data, err := baseV3Call(runtime, "POST", baseV3Path("bases", runtime.Str("base-token"), "workflows"), nil, body, ) if err != nil { return err } runtime.Out(data, nil) return nil }, }
View Source
var BaseWorkflowDisable = common.Shortcut{ Service: "base", Command: "+workflow-disable", Description: "Disable a workflow in a base", Risk: "write", Scopes: []string{"base:workflow:update"}, AuthTypes: []string{"user", "bot"}, Flags: []common.Flag{ {Name: "base-token", Desc: "base token", Required: true}, {Name: "workflow-id", Desc: "workflow ID (wkf... prefix)", Required: true}, }, Tips: []string{ "workflow-id must start with wkf; do not pass a tbl table ID from the same URL.", "Disable only changes workflow state; it does not delete the workflow or its steps.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { if strings.TrimSpace(runtime.Str("base-token")) == "" { return baseFlagErrorf("--base-token must not be blank") } if strings.TrimSpace(runtime.Str("workflow-id")) == "" { return baseFlagErrorf("--workflow-id must not be blank") } return nil }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). PATCH("/open-apis/base/v3/bases/:base_token/workflows/:workflow_id/disable"). Set("base_token", runtime.Str("base-token")). Set("workflow_id", runtime.Str("workflow-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { data, err := baseV3Call(runtime, "PATCH", baseV3Path("bases", runtime.Str("base-token"), "workflows", runtime.Str("workflow-id"), "disable"), nil, map[string]interface{}{}, ) if err != nil { return err } runtime.Out(data, nil) return nil }, }
View Source
var BaseWorkflowEnable = common.Shortcut{ Service: "base", Command: "+workflow-enable", Description: "Enable a workflow in a base", Risk: "write", Scopes: []string{"base:workflow:update"}, AuthTypes: []string{"user", "bot"}, Flags: []common.Flag{ {Name: "base-token", Desc: "base token", Required: true}, {Name: "workflow-id", Desc: "workflow ID (wkf... prefix)", Required: true}, }, Tips: []string{ "workflow-id must start with wkf; do not pass a tbl table ID from the same URL.", "Enable only changes workflow state; it does not modify steps.", "New workflows are created disabled; enable after creation only when the user wants it active.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { if strings.TrimSpace(runtime.Str("base-token")) == "" { return baseFlagErrorf("--base-token must not be blank") } if strings.TrimSpace(runtime.Str("workflow-id")) == "" { return baseFlagErrorf("--workflow-id must not be blank") } return nil }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { return common.NewDryRunAPI(). PATCH("/open-apis/base/v3/bases/:base_token/workflows/:workflow_id/enable"). Set("base_token", runtime.Str("base-token")). Set("workflow_id", runtime.Str("workflow-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { data, err := baseV3Call(runtime, "PATCH", baseV3Path("bases", runtime.Str("base-token"), "workflows", runtime.Str("workflow-id"), "enable"), nil, map[string]interface{}{}, ) if err != nil { return err } runtime.Out(data, nil) return nil }, }
View Source
var BaseWorkflowGet = common.Shortcut{ Service: "base", Command: "+workflow-get", Description: "Get a single workflow definition (including steps) from a base", Risk: "read", Scopes: []string{"base:workflow:read"}, AuthTypes: []string{"user", "bot"}, Flags: []common.Flag{ {Name: "base-token", Desc: "base token", Required: true}, {Name: "workflow-id", Desc: "workflow ID (wkf... prefix)", Required: true}, {Name: "user-id-type", Desc: "user ID type for creator/updater fields, default open_id", Enum: []string{"open_id", "union_id", "user_id"}}, }, Tips: []string{ "workflow-id must start with wkf; use +workflow-list if the ID is unknown.", "steps may be an empty array; that is valid for an unconfigured workflow.", "Use +workflow-get before +workflow-update, then edit the returned definition and keep fields you do not intend to change.", "Read lark-base-workflow-schema.md when interpreting or reusing returned steps.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { if strings.TrimSpace(runtime.Str("base-token")) == "" { return baseFlagErrorf("--base-token must not be blank") } if strings.TrimSpace(runtime.Str("workflow-id")) == "" { return baseFlagErrorf("--workflow-id must not be blank") } return nil }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { api := common.NewDryRunAPI(). GET("/open-apis/base/v3/bases/:base_token/workflows/:workflow_id"). Set("base_token", runtime.Str("base-token")). Set("workflow_id", runtime.Str("workflow-id")) if t := runtime.Str("user-id-type"); t != "" { api = api.Params(map[string]interface{}{"user_id_type": t}) } return api }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { var params map[string]interface{} if t := runtime.Str("user-id-type"); t != "" { params = map[string]interface{}{"user_id_type": t} } data, err := baseV3Call(runtime, "GET", baseV3Path("bases", runtime.Str("base-token"), "workflows", runtime.Str("workflow-id")), params, nil, ) if err != nil { return err } runtime.Out(data, nil) return nil }, }
View Source
var BaseWorkflowList = common.Shortcut{ Service: "base", Command: "+workflow-list", Description: "List all workflows in a base (auto-paginated)", Risk: "read", Scopes: []string{"base:workflow:read"}, AuthTypes: []string{"user", "bot"}, Flags: []common.Flag{ {Name: "base-token", Desc: "base token", Required: true}, {Name: "status", Desc: "filter by status", Enum: []string{"enabled", "disabled"}}, {Name: "page-size", Type: "int", Default: "100", Desc: "page size per request, max 100"}, }, Tips: []string{ "Returns workflow_id values with wkf prefix; pass those IDs to +workflow-get/enable/disable/update.", "This shortcut auto-paginates and returns all matched workflows.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { if strings.TrimSpace(runtime.Str("base-token")) == "" { return baseFlagErrorf("--base-token must not be blank") } return nil }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { body := map[string]interface{}{ "page_size": runtime.Int("page-size"), } if s := runtime.Str("status"); s != "" { body["status"] = s } return common.NewDryRunAPI(). POST("/open-apis/base/v3/bases/:base_token/workflows/list"). Body(body). Set("base_token", runtime.Str("base-token")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { var allItems []interface{} pageToken := "" for { body := map[string]interface{}{ "page_size": runtime.Int("page-size"), } if pageToken != "" { body["page_token"] = pageToken } if s := runtime.Str("status"); s != "" { body["status"] = s } data, err := baseV3Call(runtime, "POST", baseV3Path("bases", runtime.Str("base-token"), "workflows", "list"), nil, body, ) if err != nil { return err } items, _ := data["items"].([]interface{}) allItems = append(allItems, items...) hasMore, _ := data["has_more"].(bool) if !hasMore { break } nextToken, _ := data["page_token"].(string) if nextToken == "" { break } pageToken = nextToken } runtime.Out(map[string]interface{}{ "items": allItems, "total": len(allItems), }, nil) return nil }, }
View Source
var BaseWorkflowUpdate = common.Shortcut{ Service: "base", Command: "+workflow-update", Description: "Replace a workflow's full definition (title and/or steps) in a base", Risk: "write", Scopes: []string{"base:workflow:update"}, AuthTypes: []string{"user", "bot"}, Flags: []common.Flag{ {Name: "base-token", Desc: "base token", Required: true}, {Name: "workflow-id", Desc: "workflow ID (wkf... prefix)", Required: true}, {Name: "json", Desc: "workflow body JSON; read lark-base-workflow-guide.md and lark-base-workflow-schema.md before replacing steps", Required: true}, }, Tips: []string{ "lark-cli base +workflow-update --base-token <base_token> --workflow-id <workflow_id> --json @workflow.json", "PUT uses full replacement semantics; omitting steps clears the existing workflow steps.", "Use +workflow-get first, then edit the returned definition and keep title/status/steps fields you do not intend to change.", "workflow-id must start with wkf; do not pass a tbl table ID.", "Step ids must be unique, and every next/children link must reference an existing step id.", "Updating does not enable or disable a workflow; call +workflow-enable or +workflow-disable separately.", "Use lark-base-workflow-guide.md as the entry guide and lark-base-workflow-schema.md as the steps JSON SSOT; do not invent steps[].type/data/next/children from natural language.", }, Validate: func(ctx context.Context, runtime *common.RuntimeContext) error { if strings.TrimSpace(runtime.Str("base-token")) == "" { return baseFlagErrorf("--base-token must not be blank") } if strings.TrimSpace(runtime.Str("workflow-id")) == "" { return baseFlagErrorf("--workflow-id must not be blank") } pc := newParseCtx(runtime) if _, err := parseJSONObject(pc, runtime.Str("json"), "json"); err != nil { return err } return nil }, DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI { pc := newParseCtx(runtime) var body map[string]interface{} body, _ = parseJSONObject(pc, runtime.Str("json"), "json") return common.NewDryRunAPI(). PUT("/open-apis/base/v3/bases/:base_token/workflows/:workflow_id"). Body(body). Set("base_token", runtime.Str("base-token")). Set("workflow_id", runtime.Str("workflow-id")) }, Execute: func(ctx context.Context, runtime *common.RuntimeContext) error { pc := newParseCtx(runtime) body, err := parseJSONObject(pc, runtime.Str("json"), "json") if err != nil { return err } data, err := baseV3Call(runtime, "PUT", baseV3Path("bases", runtime.Str("base-token"), "workflows", runtime.Str("workflow-id")), nil, body, ) if err != nil { return err } runtime.Out(data, nil) return nil }, }
Functions ¶
Types ¶
This section is empty.
Source Files
¶
- base_advperm_disable.go
- base_advperm_enable.go
- base_block_create.go
- base_block_delete.go
- base_block_list.go
- base_block_move.go
- base_block_ops.go
- base_block_rename.go
- base_command_common.go
- base_copy.go
- base_create.go
- base_data_query.go
- base_errors.go
- base_form_create.go
- base_form_delete.go
- base_form_detail.go
- base_form_get.go
- base_form_list.go
- base_form_questions_create.go
- base_form_questions_delete.go
- base_form_questions_list.go
- base_form_questions_update.go
- base_form_submit.go
- base_form_update.go
- base_get.go
- base_ops.go
- base_role_common.go
- base_role_create.go
- base_role_delete.go
- base_role_get.go
- base_role_list.go
- base_role_update.go
- base_shortcut_helpers.go
- dashboard_arrange.go
- dashboard_block_create.go
- dashboard_block_delete.go
- dashboard_block_get.go
- dashboard_block_get_data.go
- dashboard_block_list.go
- dashboard_block_update.go
- dashboard_create.go
- dashboard_delete.go
- dashboard_get.go
- dashboard_list.go
- dashboard_ops.go
- dashboard_update.go
- field_create.go
- field_delete.go
- field_get.go
- field_list.go
- field_ops.go
- field_search_options.go
- field_update.go
- help.go
- helpers.go
- high_risk.go
- record_batch_create.go
- record_batch_update.go
- record_delete.go
- record_get.go
- record_history_list.go
- record_list.go
- record_markdown.go
- record_ops.go
- record_query.go
- record_search.go
- record_share_link_create.go
- record_upload_attachment.go
- record_upsert.go
- shortcuts.go
- table_create.go
- table_delete.go
- table_get.go
- table_list.go
- table_ops.go
- table_update.go
- view_create.go
- view_delete.go
- view_get.go
- view_get_card.go
- view_get_filter.go
- view_get_group.go
- view_get_sort.go
- view_get_timebar.go
- view_get_visible_fields.go
- view_list.go
- view_ops.go
- view_rename.go
- view_set_card.go
- view_set_filter.go
- view_set_group.go
- view_set_sort.go
- view_set_timebar.go
- view_set_visible_fields.go
- workflow_create.go
- workflow_disable.go
- workflow_enable.go
- workflow_get.go
- workflow_list.go
- workflow_update.go
Click to show internal directories.
Click to hide internal directories.