feat(schema): output json spec envelope for all API commands#1048
Conversation
Rewrites cmd/schema/schema.go so the default --format json branch emits MCP-spec envelopes via schema.AssembleAll/AssembleService/AssembleEnvelope. The legacy --format pretty branch is preserved verbatim and still uses printServices / printResourceList / printMethodDetail. Args max raised from 1 to 8 so the path can be supplied either as a single dotted argument (im.reactions.list) or as space-separated segments (im reactions list); both forms route through schema.ParsePath and produce byte-identical output. The completeSchemaPath function is extended to drive tab-completion for both forms: legacy dotted prefix when len(args) == 0, and per-segment resource/method completion when args already contains earlier segments. BREAKING CHANGE: default JSON output shape changes from the raw meta_data structure to an MCP envelope array/object. Existing scripts parsing the old shape must either pin --format pretty or migrate to the new envelope fields (name, description, inputSchema, outputSchema, _meta).
Replaces TestSchemaCmd_NoArgs with two variants reflecting the new default shape: TestSchemaCmd_NoArgs_Pretty asserts the legacy "Available services" text appears only under --format pretty, and TestSchemaCmd_NoArgs_JSON_IsArray asserts the default JSON output parses as an envelope array with at least 180 entries. Adds six new tests: - TestSchemaCmd_JSONIsEnvelope: single-method output has name / description / inputSchema / outputSchema / _meta keys and envelope_version "1.0". - TestSchemaCmd_SpaceSeparatedPath_EqualsDotted: dotted and space forms produce identical output bytes for the same command path. - TestSchemaCmd_ServiceListIsArray: schema <service> returns a JSON array whose every entry's name starts with "<service> ". - TestSchemaCmd_HighRiskYesInjection: high-risk-write commands inject inputSchema.properties.yes. - TestSchemaCmd_NoYesForReadRisk: read-risk commands do not inject yes. - TestSchemaCmd_PrettyUnchanged_KeyTextPresent: --format pretty still surfaces the legacy section markers (Parameters:, Response:, Identity:, Scopes:, CLI:).
Nested resources whose meta_data key contains a dot (e.g. chat.members,
user_mailbox.templates) were previously split on '.' and rejoined with
spaces, producing envelope names like 'im chat members bots'. AI
consumers doing name.split(' ') and feeding the result back as argv
got 'lark-cli im chat members bots' which the CLI rejects — the actual
invocation form is 'lark-cli im chat.members bots'.
Pass the dotted resource key as a single argv segment so the envelope
name 'im chat.members bots' round-trips through name.split(' ') back
to the CLI. Mirror the same convention in the golden harness so its
single-method assembly matches the live AssembleService walk.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR introduces a complete MCP schema envelope system: ordered JSON-Schema type contracts (Envelope, InputSchema, OutputSchema, Property, Meta) with key-order-preserving OrderedProps marshaling; a deterministic assembler that parses embedded metadata, converts field specs to schema properties with enum coercion and type normalization, builds ordered input/output schemas with XIn markers and required lists, composes _meta with scope/token/risk translation, and aggregates envelopes by service and globally; comprehensive L1/L2/L3 linting validation of structure, type consistency, and cross-field dependencies; CLI refactoring to support multi-argument paths with ParsePath normalization and new JSON/pretty dispatch modes; and extensive test coverage including golden snapshot fixtures. ChangesSchema Envelope Assembly and CLI
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🚀 PR Preview Install Guide🧰 CLI updatenpm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@35453691cf823bb9cf15f21fa78c0689a5922e27🧩 Skill updatenpx skills add larksuite/cli#feat/ai-friendly-schema -y -g |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cmd/schema/schema_test.go (1)
16-18:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winSet isolated config dir in tests that use
cmdutil.TestFactory.Please set
LARKSUITE_CLI_CONFIG_DIRtot.TempDir()in these tests (or via a shared helper) to prevent cross-test config-state coupling.As per coding guidelines
**/*_test.go:Use t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir()) to isolate config state in tests.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmd/schema/schema_test.go` around lines 16 - 18, TestSchemaCmd_FlagParsing uses cmdutil.TestFactory and must isolate CLI config state; before calling cmdutil.TestFactory in TestSchemaCmd_FlagParsing, call t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir()) (or add a shared helper that sets this env var) so each test gets its own config directory and avoids cross-test coupling.
🧹 Nitpick comments (1)
internal/schema/testdata/golden/wiki.spaces.create.json (1)
4-35: 💤 Low valueConsider adding explicit
"required"field for consistency.The
inputSchemaomits the"required"field entirely, while all other golden fixtures include an explicit"required"array (even when empty or with just required params). For deterministic serialization and structural consistency across the 193 API method envelopes, consider always emitting"required": []when no fields are required.Proposed addition for consistency
"inputSchema": { "type": "object", + "required": [], "properties": {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/schema/testdata/golden/wiki.spaces.create.json` around lines 4 - 35, The inputSchema for this golden fixture is missing an explicit "required" array which other fixtures include; update the inputSchema object (the one containing "properties" with keys name, description, open_sharing, yes) to include a "required" field—use "required": [] if no properties are mandatory (or list the required property names if some must be required) so serialization is deterministic and consistent across fixtures.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cmd/schema/schema.go`:
- Around line 596-607: The code currently accepts remaining[0] as the method
name and silently ignores remaining[1:], causing invalid paths to be accepted;
update the handler that reads remaining and methodName (and the analogous block
that resolves operations) to explicitly reject extra trailing segments: if
len(remaining) != 1 (or if len(remaining) > 1) return
output.ErrWithHint(output.ExitValidation, "validation", fmt.Sprintf("Invalid
path: extra trailing path segments on %s.%s", serviceName, resName),
fmt.Sprintf("Got: %v", remaining[1:])), so callers of methods,
resource["methods"], methodName and the other resolution block fail fast instead
of silently resolving to a different method.
In `@internal/registry/loader.go`:
- Around line 28-30: The EmbeddedMetaJSON function (and the other embedded
getter functions referenced around lines 75-77) currently returns the
package-level byte slice directly, allowing callers to mutate shared state;
change each getter (e.g., EmbeddedMetaJSON) to return a defensive copy of the
underlying slice by allocating a new []byte and copying the contents (for
example via append([]byte(nil), embeddedMetaJSON...) or make + copy) so callers
cannot modify the original package-level slice.
In `@internal/schema/assembler_test.go`:
- Around line 549-550: Before calling registry.LoadFromMeta in the tests that
call AssembleService (e.g., the test cases invoking registry.LoadFromMeta("im")
and AssembleService("im", spec, nil)), isolate registry-backed state by setting
the config dir to a temp directory using t.Setenv("LARKSUITE_CLI_CONFIG_DIR",
t.TempDir()) at the start of each test; apply this change to the occurrences
around the registry.LoadFromMeta calls (the blocks that start with spec :=
registry.LoadFromMeta("im") / envs := AssembleService(...)) including the other
noted occurrences in the file so host config/cache cannot leak into test
results.
In `@internal/schema/lint.go`:
- Around line 153-155: The current check only recurses into array item schemas
when p.Items.Properties exists, so primitive or invalid item schemas
(p.Items.type, etc.) are not linted; update the logic in validatePropertyTypes
to always validate the p.Items schema node when p.Items != nil — if
p.Items.Properties is present recurse with
validatePropertyTypes(p.Items.Properties, false, errs), otherwise run the
schema-level validation on p.Items (the same validations used for non-array
property schemas) and append errors to errs so invalid primitive item schemas
are caught.
In `@internal/schema/testdata/golden/calendar.calendars.list.json`:
- Around line 7-14: The "page_size" schema defines type "integer" but sets
"default" as the string "500"; update the default to an integer (500) to match
the declared type for the page_size property in the JSON schema (look for the
"page_size" object and its "default" field) so the default value's type aligns
with "type": "integer".
In
`@internal/schema/testdata/golden/mail.user_mailbox.template.attachments.download_url.json`:
- Around line 24-28: The "attachment_ids" schema entry uses an invalid JSON
Schema type "list"; update the "attachment_ids" object so its "type" is "array"
(replace "list" with "array") and, if missing, add an "items" definition (e.g.,
{"type":"string"} or the appropriate item schema) to match other golden files
and restore JSON Schema validation for the property.
In `@internal/schema/testdata/golden/mail.user_mailbox.templates.create.json`:
- Around line 291-292: The create operation currently has "danger": true but an
incorrect "risk": "read"; update the risk value for the create with scope
"mail:user_mailbox.message:modify" (and any other create entries marked
danger:true) to an appropriate write-level risk such as "write" or
"high-risk-write" so it matches the modify/create semantics and danger flag;
locate the JSON entry containing "danger": true and "risk": "read" associated
with the mail:user_mailbox.message:modify create operation and change "risk" to
"write" (or "high-risk-write" if applicable).
In `@internal/schema/types.go`:
- Around line 85-88: The MarshalJSON method on OrderedProps currently returns
"{}" when o.Order is empty, which drops any entries present in o.Map; change
MarshalJSON (for receiver OrderedProps) so that when o is nil return "{}", but
if o.Order is empty and o.Map is non-nil/non-empty it marshals the entries from
o.Map (instead of returning "{}"), otherwise preserve existing behavior that
emits fields in o.Order; reference OrderedProps.MarshalJSON, the Order slice,
and the Map field when implementing the fix.
---
Outside diff comments:
In `@cmd/schema/schema_test.go`:
- Around line 16-18: TestSchemaCmd_FlagParsing uses cmdutil.TestFactory and must
isolate CLI config state; before calling cmdutil.TestFactory in
TestSchemaCmd_FlagParsing, call t.Setenv("LARKSUITE_CLI_CONFIG_DIR",
t.TempDir()) (or add a shared helper that sets this env var) so each test gets
its own config directory and avoids cross-test coupling.
---
Nitpick comments:
In `@internal/schema/testdata/golden/wiki.spaces.create.json`:
- Around line 4-35: The inputSchema for this golden fixture is missing an
explicit "required" array which other fixtures include; update the inputSchema
object (the one containing "properties" with keys name, description,
open_sharing, yes) to include a "required" field—use "required": [] if no
properties are mandatory (or list the required property names if some must be
required) so serialization is deterministic and consistent across fixtures.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 68123346-b43c-48f9-831e-92fc4c6cee2c
📒 Files selected for processing (33)
cmd/schema/schema.gocmd/schema/schema_test.gointernal/registry/loader.gointernal/schema/annotations/.gitkeepinternal/schema/assembler.gointernal/schema/assembler_test.gointernal/schema/golden_test.gointernal/schema/lint.gointernal/schema/lint_test.gointernal/schema/path.gointernal/schema/path_test.gointernal/schema/testdata/golden/approval.instances.cancel.jsoninternal/schema/testdata/golden/approval.instances.get.jsoninternal/schema/testdata/golden/calendar.calendars.list.jsoninternal/schema/testdata/golden/calendar.events.create.jsoninternal/schema/testdata/golden/drive.files.copy.jsoninternal/schema/testdata/golden/im.chats.create.jsoninternal/schema/testdata/golden/im.images.create.jsoninternal/schema/testdata/golden/im.messages.delete.jsoninternal/schema/testdata/golden/im.pins.delete.jsoninternal/schema/testdata/golden/im.reactions.create.jsoninternal/schema/testdata/golden/im.reactions.list.jsoninternal/schema/testdata/golden/mail.user_mailbox.folders.delete.jsoninternal/schema/testdata/golden/mail.user_mailbox.messages.get.jsoninternal/schema/testdata/golden/mail.user_mailbox.template.attachments.download_url.jsoninternal/schema/testdata/golden/mail.user_mailbox.templates.create.jsoninternal/schema/testdata/golden/okr.objectives.delete.jsoninternal/schema/testdata/golden/sheets.spreadsheet.sheet.filters.create.jsoninternal/schema/testdata/golden/slides.xml_presentation.slide.replace.jsoninternal/schema/testdata/golden/task.tasks.delete.jsoninternal/schema/testdata/golden/wiki.spaces.create.jsoninternal/schema/types.gointernal/schema/types_test.go
- coerce enum literals to typed JSON values (integer to int64,
number to float64, boolean to bool) so type:"integer" fields no
longer emit string enums; sort numeric/boolean enums while
preserving meta_data order for string enums that carry semantic
priority
- translate non-standard meta_data type:"list" to JSON Schema
type:"array" with items:{} fallback when element shape is absent
(covers the two mail attachment_ids fields)
- render inputSchema.required even when empty so consumers see a
stable envelope shape ("[]" means no required fields, not "field
is missing")
- reject trailing path segments in both JSON and pretty modes so
schema im.messages.delete.foo errors instead of silently
returning the delete method
- drop dead "list type" entry from lint_test isKnownDataInconsistency
whitelist now that list values are translated upstream
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
internal/schema/testdata/golden/mail.user_mailbox.templates.create.json (1)
291-292:⚠️ Potential issue | 🟠 Major | ⚡ Quick winUse write-level risk for this dangerous create operation.
danger: truewith modify scope on a create endpoint should not be classified as"read"; this under-classifies operation safety.🔧 Suggested fix
"danger": true, - "risk": "read", + "risk": "write",🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/schema/testdata/golden/mail.user_mailbox.templates.create.json` around lines 291 - 292, The create template currently marks a dangerous create operation with "danger": true but incorrectly sets "risk": "read"; update the JSON in mail.user_mailbox.templates.create (keys "danger" and "risk") to use a write-level risk (change "risk" from "read" to "write") so the create endpoint is classified correctly as a modifying operation.internal/schema/testdata/golden/calendar.calendars.list.json (1)
8-12:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winMatch
defaulttype with declared integer schema type.
page_sizeis declared as"type": "integer"but uses a string default"500".🔧 Suggested fix
"page_size": { "type": "integer", - "default": "500", + "default": 500,🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/schema/testdata/golden/calendar.calendars.list.json` around lines 8 - 12, The JSON schema property "page_size" declares "type": "integer" but its "default" is the string "500"; change the default value for the page_size property to an integer (500) so the default type matches the declared schema type (look for the page_size property in the calendar.calendars.list JSON schema and replace the quoted "500" with the numeric 500).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/schema/assembler.go`:
- Around line 414-430: The code currently always calls sortEnum after building
p.Enum from optsRaw, which alphabetizes string enums; change the logic in the
branch that builds p.Enum (using optsRaw, om, raw, coerceEnumValue) to preserve
the source order for string enums by only invoking sortEnum(p.Type, p.Enum) when
p.Type is numeric or boolean (i.e., when p.Type != "string"), leaving p.Enum in
the appended order for string types; ensure you still dedupe using seen and keep
using coerceEnumValue and p.Enum append as before, and update
TestConvertProperty_OptionsToEnum expectations to no longer assume alphabetical
ordering for string enums.
---
Duplicate comments:
In `@internal/schema/testdata/golden/calendar.calendars.list.json`:
- Around line 8-12: The JSON schema property "page_size" declares "type":
"integer" but its "default" is the string "500"; change the default value for
the page_size property to an integer (500) so the default type matches the
declared schema type (look for the page_size property in the
calendar.calendars.list JSON schema and replace the quoted "500" with the
numeric 500).
In `@internal/schema/testdata/golden/mail.user_mailbox.templates.create.json`:
- Around line 291-292: The create template currently marks a dangerous create
operation with "danger": true but incorrectly sets "risk": "read"; update the
JSON in mail.user_mailbox.templates.create (keys "danger" and "risk") to use a
write-level risk (change "risk" from "read" to "write") so the create endpoint
is classified correctly as a modifying operation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ad7072a4-90d0-410b-8edb-16a74e2d39f1
📒 Files selected for processing (11)
cmd/schema/schema.gointernal/schema/assembler.gointernal/schema/assembler_test.gointernal/schema/lint_test.gointernal/schema/testdata/golden/calendar.calendars.list.jsoninternal/schema/testdata/golden/im.chats.create.jsoninternal/schema/testdata/golden/mail.user_mailbox.messages.get.jsoninternal/schema/testdata/golden/mail.user_mailbox.template.attachments.download_url.jsoninternal/schema/testdata/golden/mail.user_mailbox.templates.create.jsoninternal/schema/testdata/golden/wiki.spaces.create.jsoninternal/schema/types.go
💤 Files with no reviewable changes (1)
- internal/schema/lint_test.go
CI fix
- Replace hard-coded absolute key-order assertions in TestKeyOrderIndex_*
and TestBuildInputSchema_* with set-membership and propagation invariants;
the upstream meta_data API does not guarantee stable JSON key order across
fetches, so the old tests were flaky on CI by design.
- Skip byte-level TestGoldenEnvelopes when CI=true; golden snapshots are a
manual refresh artefact tied to a specific meta_data fetch, not a CI gate.
- Add TestMain to isolate registry-backed tests from any host ~/.lark-cli
cache (LARKSUITE_CLI_CONFIG_DIR + LARKSUITE_CLI_REMOTE_META=off) so the
suite gives the same answer on every machine.
CodeRabbit review actionables
- EmbeddedServiceNames returns a defensive copy so callers cannot mutate
the package-level slice and affect subsequent assembly determinism.
- coerceEnumValue is now also applied to default literals: integer fields
no longer ship default: "500" — they ship default: 500 (same idea as the
earlier enum coercion fix).
- options-branch string enums preserve meta_data source order, matching the
enum-branch policy; only numeric/boolean enums get sorted.
- validatePropertyTypes now validates the array element schema itself
(type, nested items), not only items.properties — previously a primitive
element with an invalid type (e.g. items.type="list") slipped past lint.
- OrderedProps.MarshalJSON falls back to alphabetical key order when Map
has entries but Order is empty, instead of silently emitting {}.
Tests pass locally and with CI=true env (simulating GitHub Actions).
Re-generated with UPDATE_GOLDEN=1 against the current meta_data.json
snapshot. The bulk of the diff is upstream noise (description wording,
enum entries, field order) which the CI snapshot diff can no longer
reasonably gate (see previous commit). Side-effects of the code fixes
in the parent commit are also captured:
- integer-typed defaults now emit numeric literals (e.g. page_size
default 500, not "500") thanks to coerceEnumValue
- mail.user_mailbox.templates.create _meta.risk corrects to "write"
(assembler already emitted "write"; the old golden was stale)
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1048 +/- ##
==========================================
+ Coverage 67.92% 68.22% +0.29%
==========================================
Files 601 617 +16
Lines 55766 57192 +1426
==========================================
+ Hits 37880 39017 +1137
- Misses 14751 14945 +194
- Partials 3135 3230 +95 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/schema/testdata/golden/im.reactions.list.json (1)
30-34:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
page_size.defaulttype mismatches declared schema type.
page_sizeis declared asinteger, butdefaultis""(string). This makes the contract internally inconsistent.Suggested fix
"page_size": { "type": "integer", "description": "分页大小,用于限制一次请求返回的数据条目数。;;**默认值**:20", - "default": "", + "default": 20, "example": "10", "maximum": 50, "x-in": "query" },🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/schema/testdata/golden/im.reactions.list.json` around lines 30 - 34, The schema for the "page_size" property has a default value of "" (string) but its type is integer; update the "page_size" property's "default" to an integer (e.g., 20 to match the description) so the "page_size" entry's "type", "default", and description remain consistent; locate the "page_size" object in the JSON and replace the empty-string default with a numeric value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/schema/assembler_test.go`:
- Around line 20-27: TestMain currently defers cleanup which never runs because
os.Exit skips defers and also silently continues on MkdirTemp error; change it
to fail-fast on MkdirTemp error (return non-zero exit immediately) and ensure
cleanup always runs by storing the result of m.Run in a variable, calling
os.RemoveAll(dir) after the run, then calling os.Exit(code). Only call
os.Setenv("LARKSUITE_CLI_CONFIG_DIR", dir) and the other env setup after
MkdirTemp succeeds; reference the TestMain function, MkdirTemp, os.Setenv,
os.RemoveAll, m.Run, and os.Exit when making the change.
---
Outside diff comments:
In `@internal/schema/testdata/golden/im.reactions.list.json`:
- Around line 30-34: The schema for the "page_size" property has a default value
of "" (string) but its type is integer; update the "page_size" property's
"default" to an integer (e.g., 20 to match the description) so the "page_size"
entry's "type", "default", and description remain consistent; locate the
"page_size" object in the JSON and replace the empty-string default with a
numeric value.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 284a855d-b800-42a3-b879-acf198593e58
📒 Files selected for processing (19)
internal/registry/loader.gointernal/schema/assembler.gointernal/schema/assembler_test.gointernal/schema/golden_test.gointernal/schema/lint.gointernal/schema/testdata/golden/approval.instances.get.jsoninternal/schema/testdata/golden/calendar.calendars.list.jsoninternal/schema/testdata/golden/calendar.events.create.jsoninternal/schema/testdata/golden/drive.files.copy.jsoninternal/schema/testdata/golden/im.chats.create.jsoninternal/schema/testdata/golden/im.reactions.create.jsoninternal/schema/testdata/golden/im.reactions.list.jsoninternal/schema/testdata/golden/mail.user_mailbox.folders.delete.jsoninternal/schema/testdata/golden/mail.user_mailbox.messages.get.jsoninternal/schema/testdata/golden/mail.user_mailbox.templates.create.jsoninternal/schema/testdata/golden/sheets.spreadsheet.sheet.filters.create.jsoninternal/schema/testdata/golden/slides.xml_presentation.slide.replace.jsoninternal/schema/testdata/golden/wiki.spaces.create.jsoninternal/schema/types.go
✅ Files skipped from review due to trivial changes (4)
- internal/schema/testdata/golden/im.reactions.create.json
- internal/schema/testdata/golden/approval.instances.get.json
- internal/schema/testdata/golden/sheets.spreadsheet.sheet.filters.create.json
- internal/schema/testdata/golden/im.chats.create.json
- TestMain: cleanup now runs reliably. os.Exit skips deferred functions, so the previous defer os.RemoveAll(dir) never executed. Replace defer with explicit cleanup, and fail fast if MkdirTemp errors instead of silently running against the host cache (which defeats isolation). - convertProperty default coercion: when the literal cannot be coerced to the declared type (e.g. default:"" on integer field, used by meta_data to mean "no default"), omit the field entirely rather than emit a type-mismatched default. Removes a contract violation flagged on im.reactions.list.json#page_size.
Replace the loadAffordance stub (which always returned nil and read from an empty embedded annotations/ directory) with parseAffordance, which lifts the affordance block from method["affordance"]. The block is authored under larksuite-cli-registry's registry-config.yaml in the overrides: section and flows through gen-registry.py's deep_merge into the embedded meta_data.json. Simplify buildMeta signature: the service/resourcePath/method args existed only to feed the old dotted-path lookup. Refresh 9 golden envelopes for unrelated upstream meta_data.json drift.
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/schema/testdata/golden/calendar.events.create.json`:
- Around line 391-397: The "duration" schema entries (e.g., the duration
property inside the check-in timing configurations like
check_in_start_time.duration and check_in_end_time.duration) have example values
quoted as strings ("0") while their type is integer; update those example fields
to use an integer literal (0) instead of a quoted string for both occurrences so
the example matches the declared type and constraints.
- Around line 294-299: The "color" schema object has type "integer" but its
"example" is a quoted string ("-1"); change the example value to an unquoted
numeric literal -1 so it matches the integer type declaration (update the
"example" field inside the "color" object to -1).
- Around line 306-312: The "minutes" schema property currently sets "type":
"integer" but uses a quoted string for the example ("example": "5"); update the
example to an actual integer value so the example's JSON type matches the
declared type—locate the "minutes" object in calendar.events.create.json and
change the "example" entry from the string "5" to the numeric 5.
- Around line 48-52: The "need_notification" schema has a type boolean but its
example is the string "false"; update the example for need_notification to be a
boolean false (remove quotes) so it matches the declared "type": "boolean" and
consumers see the correct example value.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 656d8bbc-9289-44f3-9c17-e034c6ebcfe0
📒 Files selected for processing (11)
internal/schema/assembler.gointernal/schema/assembler_test.gointernal/schema/testdata/golden/approval.instances.get.jsoninternal/schema/testdata/golden/calendar.calendars.list.jsoninternal/schema/testdata/golden/calendar.events.create.jsoninternal/schema/testdata/golden/drive.files.copy.jsoninternal/schema/testdata/golden/im.chats.create.jsoninternal/schema/testdata/golden/im.reactions.list.jsoninternal/schema/testdata/golden/mail.user_mailbox.messages.get.jsoninternal/schema/testdata/golden/mail.user_mailbox.templates.create.jsoninternal/schema/testdata/golden/slides.xml_presentation.slide.replace.json
✅ Files skipped from review due to trivial changes (4)
- internal/schema/testdata/golden/drive.files.copy.json
- internal/schema/testdata/golden/approval.instances.get.json
- internal/schema/testdata/golden/im.chats.create.json
- internal/schema/testdata/golden/slides.xml_presentation.slide.replace.json
x-in (path/query/body) was an HTTP-shape leak in a CLI-facing tool spec. AI consumers call the CLI by name with named args — they never construct HTTP requests directly, so the path-vs-body-vs-query distinction is the CLI's internal concern, not part of the contract. Execution path (cmd/service/service.go) already reads location from meta_data.json directly, so removing x-in does not affect routing. Drop: - Property.XIn field - validXIn map and the two lint rules that depend on x-in (L1 "top-level missing x-in" and L2 "path field must be in required") - contains() helper, no longer referenced after the path-required rule went away Refresh 20 goldens for the now-absent x-in lines.
Replace the flat inputSchema with a 3-bucket nested structure that mirrors
the CLI's actual flag layout, so AI consumers can directly map envelope
fields to lark-cli invocation:
inputSchema:
properties:
params: { ...path + query fields } → CLI --params JSON
data: { ...body fields } → CLI --data JSON
flags: { yes: ... } → CLI --yes (only for high-risk-write)
Each sub-object only appears when the method has the corresponding source,
so read-only GETs have a single `params` block, body-only POSTs have a
single `data` block, etc.
The `flags` wrapper carries an explicit description marking it as a CLI
control bucket (not API fields), so AI does not confuse `yes` with a
backend parameter.
Lint:
- L2 walkForL2 helper recurses into params/data sub-objects so leaf
invariants (format:binary on non-string, min<max, required-in-properties)
still apply.
- L3 yes-presence check now navigates flags.properties.yes.
Refresh all 20 goldens for the new shape.
…params/data
The flags wrapper added one extra layer for a single field. Flatten so
inputSchema.properties has three siblings:
inputSchema:
properties:
params: { ...path + query } → CLI --params
data: { ...body } → CLI --data
yes: { boolean, default:false } → CLI --yes (only when risk == high-risk-write)
`yes` description strengthened to mark it as a CLI confirmation gate
(consumed by lark-cli, not sent to the backend), so AI can still
distinguish it from API fields without needing a wrapper.
Lint L3 yes-presence check goes back to top-level Properties.Map["yes"].
Refresh 20 goldens.
Splits file fields out of `data` into their own sibling, so the four
top-level slots in inputSchema map 1:1 to CLI flag dispatch:
inputSchema.properties:
params { path + query fields } → --params JSON
data { non-file body fields } → --data JSON
file { type:file body fields, format:binary } → --file <key>=<path>
yes boolean → --yes (only when risk == high-risk-write)
Each slot is conditional: only registered when the method actually has
fields for that source. This matches the CLI's own conditional flag
registration (cmd/service/service.go:170-195), so what AI sees in the
schema is exactly what flags exist for that method.
The file sub-object carries a description explaining its semantics so AI
knows to use --file for those fields rather than embedding the binary
in --data JSON.
Refresh im.images.create golden (the only file-upload method in the
golden set).
Add two negative test cases that stuff bad values inside the wrapped inputSchema sub-objects (rather than at top-level), to lock in walkForL2's recursive coverage: - format:binary on a non-string field nested under params - sub-object Required referencing a key not in its Properties Regression guard so future walkForL2 refactors do not silently lose recursion and let leaf-field violations slip past lint.
- coerce `example` literal to the declared JSON Schema type (rename coerceEnumValue -> coerceLiteral, drop on coerce failure to match the `default` policy). Without this, integer/boolean/number fields emitted string examples and failed strict validators. - aggregate child field `required:true` into the enclosing nested object's `required[]` (both object and array-items shapes). Previously only the top-level params/data sub-objects scanned `required`, so envelopes silently under-reported the real call contract. - check method existence before reporting trailing-segment failure in both JSON and pretty `schema` paths. A typo like `schema im messages typo extra` now reports "Unknown method: im.messages.typo" instead of the misleading "Method 'typo' exists but trailing segments ..." hint. - extract risk level constants (RiskRead / RiskWrite / RiskHighRiskWrite) in internal/cmdutil/risk.go; replace literal usages in schema, lint, and confirm helpers so the typo radius is one file. - reconcile AssembleEnvelope docstring with implementation reality (the package-level currentMethodOrder + assembleMu serialize concurrent callers; output is deterministic per inputs). - drop testdata/golden/ and golden_test harness. End-to-end envelope shape regression now relies on real CLI invocations and the existing property-level unit + lint coverage.
The list→array fallback only added items:{} when the source type was
"list", leaving ~64 natively-typed array fields (e.g.
approval.instances.cc.cc_user_ids) as {type:"array"} with no items.
These violated the L1 lint rule, but TestAllEnvelopesPass skipped the
"array missing items" error as a known data inconsistency, so the MCP
tool contract was not actually lint-clean.
Relax the fallback to cover every array lacking element shape regardless
of source type, and drop the lint-test skip so the gate is hard again.
…te#1048) * feat(schema): add envelope types and ordered properties container * feat(schema): build meta_data.json key-order index for property ordering * feat(schema): implement convertProperty with file/enum/range/nested handling * feat(schema): build inputSchema with x-in / file binary / yes injection * feat(schema): build outputSchema wrapping responseBody * feat(schema): build _meta with scopes/risk/access_tokens normalization * feat(schema): scaffold affordance overlay loader (PR-1 stub) * feat(schema): wire up AssembleEnvelope main entry point * feat(schema): parse dotted and space-separated path arguments * feat(schema): batch envelope assembly with optional method filter * feat(schema): implement L1-L3 envelope lint (structure/type/cross-field) * feat(schema): measure L4 coverage and gate all envelopes through L1-L3 * feat(schema): add golden test harness with UPDATE_GOLDEN refresh * test(schema): seed 20 golden envelopes covering edge cases * feat(schema): output MCP envelope as default JSON, preserve pretty mode Rewrites cmd/schema/schema.go so the default --format json branch emits MCP-spec envelopes via schema.AssembleAll/AssembleService/AssembleEnvelope. The legacy --format pretty branch is preserved verbatim and still uses printServices / printResourceList / printMethodDetail. Args max raised from 1 to 8 so the path can be supplied either as a single dotted argument (im.reactions.list) or as space-separated segments (im reactions list); both forms route through schema.ParsePath and produce byte-identical output. The completeSchemaPath function is extended to drive tab-completion for both forms: legacy dotted prefix when len(args) == 0, and per-segment resource/method completion when args already contains earlier segments. BREAKING CHANGE: default JSON output shape changes from the raw meta_data structure to an MCP envelope array/object. Existing scripts parsing the old shape must either pin --format pretty or migrate to the new envelope fields (name, description, inputSchema, outputSchema, _meta). * test(schema): cover envelope JSON output, space-form path, yes injection Replaces TestSchemaCmd_NoArgs with two variants reflecting the new default shape: TestSchemaCmd_NoArgs_Pretty asserts the legacy "Available services" text appears only under --format pretty, and TestSchemaCmd_NoArgs_JSON_IsArray asserts the default JSON output parses as an envelope array with at least 180 entries. Adds six new tests: - TestSchemaCmd_JSONIsEnvelope: single-method output has name / description / inputSchema / outputSchema / _meta keys and envelope_version "1.0". - TestSchemaCmd_SpaceSeparatedPath_EqualsDotted: dotted and space forms produce identical output bytes for the same command path. - TestSchemaCmd_ServiceListIsArray: schema <service> returns a JSON array whose every entry's name starts with "<service> ". - TestSchemaCmd_HighRiskYesInjection: high-risk-write commands inject inputSchema.properties.yes. - TestSchemaCmd_NoYesForReadRisk: read-risk commands do not inject yes. - TestSchemaCmd_PrettyUnchanged_KeyTextPresent: --format pretty still surfaces the legacy section markers (Parameters:, Response:, Identity:, Scopes:, CLI:). * feat(schema): assemble envelope from embedded data only for stability * chore(schema): lint cleanup * fix(schema): preserve dotted resource segments in envelope name Nested resources whose meta_data key contains a dot (e.g. chat.members, user_mailbox.templates) were previously split on '.' and rejoined with spaces, producing envelope names like 'im chat members bots'. AI consumers doing name.split(' ') and feeding the result back as argv got 'lark-cli im chat members bots' which the CLI rejects — the actual invocation form is 'lark-cli im chat.members bots'. Pass the dotted resource key as a single argv segment so the envelope name 'im chat.members bots' round-trips through name.split(' ') back to the CLI. Mirror the same convention in the golden harness so its single-method assembly matches the live AssembleService walk. * fix(schema): align MCP envelope output with JSON Schema 2020-12 contract - coerce enum literals to typed JSON values (integer to int64, number to float64, boolean to bool) so type:"integer" fields no longer emit string enums; sort numeric/boolean enums while preserving meta_data order for string enums that carry semantic priority - translate non-standard meta_data type:"list" to JSON Schema type:"array" with items:{} fallback when element shape is absent (covers the two mail attachment_ids fields) - render inputSchema.required even when empty so consumers see a stable envelope shape ("[]" means no required fields, not "field is missing") - reject trailing path segments in both JSON and pretty modes so schema im.messages.delete.foo errors instead of silently returning the delete method - drop dead "list type" entry from lint_test isKnownDataInconsistency whitelist now that list values are translated upstream * fix(schema): address CodeRabbit findings and stabilize CI tests CI fix - Replace hard-coded absolute key-order assertions in TestKeyOrderIndex_* and TestBuildInputSchema_* with set-membership and propagation invariants; the upstream meta_data API does not guarantee stable JSON key order across fetches, so the old tests were flaky on CI by design. - Skip byte-level TestGoldenEnvelopes when CI=true; golden snapshots are a manual refresh artefact tied to a specific meta_data fetch, not a CI gate. - Add TestMain to isolate registry-backed tests from any host ~/.lark-cli cache (LARKSUITE_CLI_CONFIG_DIR + LARKSUITE_CLI_REMOTE_META=off) so the suite gives the same answer on every machine. CodeRabbit review actionables - EmbeddedServiceNames returns a defensive copy so callers cannot mutate the package-level slice and affect subsequent assembly determinism. - coerceEnumValue is now also applied to default literals: integer fields no longer ship default: "500" — they ship default: 500 (same idea as the earlier enum coercion fix). - options-branch string enums preserve meta_data source order, matching the enum-branch policy; only numeric/boolean enums get sorted. - validatePropertyTypes now validates the array element schema itself (type, nested items), not only items.properties — previously a primitive element with an invalid type (e.g. items.type="list") slipped past lint. - OrderedProps.MarshalJSON falls back to alphabetical key order when Map has entries but Order is empty, instead of silently emitting {}. Tests pass locally and with CI=true env (simulating GitHub Actions). * chore(schema): refresh golden envelopes after meta_data drift Re-generated with UPDATE_GOLDEN=1 against the current meta_data.json snapshot. The bulk of the diff is upstream noise (description wording, enum entries, field order) which the CI snapshot diff can no longer reasonably gate (see previous commit). Side-effects of the code fixes in the parent commit are also captured: - integer-typed defaults now emit numeric literals (e.g. page_size default 500, not "500") thanks to coerceEnumValue - mail.user_mailbox.templates.create _meta.risk corrects to "write" (assembler already emitted "write"; the old golden was stale) * fix(schema): address CodeRabbit round-3 review findings - TestMain: cleanup now runs reliably. os.Exit skips deferred functions, so the previous defer os.RemoveAll(dir) never executed. Replace defer with explicit cleanup, and fail fast if MkdirTemp errors instead of silently running against the host cache (which defeats isolation). - convertProperty default coercion: when the literal cannot be coerced to the declared type (e.g. default:"" on integer field, used by meta_data to mean "no default"), omit the field entirely rather than emit a type-mismatched default. Removes a contract violation flagged on im.reactions.list.json#page_size. * feat(schema): wire affordance overlay into envelope _meta Replace the loadAffordance stub (which always returned nil and read from an empty embedded annotations/ directory) with parseAffordance, which lifts the affordance block from method["affordance"]. The block is authored under larksuite-cli-registry's registry-config.yaml in the overrides: section and flows through gen-registry.py's deep_merge into the embedded meta_data.json. Simplify buildMeta signature: the service/resourcePath/method args existed only to feed the old dotted-path lookup. Refresh 9 golden envelopes for unrelated upstream meta_data.json drift. * refactor(schema): drop x-in extension from inputSchema x-in (path/query/body) was an HTTP-shape leak in a CLI-facing tool spec. AI consumers call the CLI by name with named args — they never construct HTTP requests directly, so the path-vs-body-vs-query distinction is the CLI's internal concern, not part of the contract. Execution path (cmd/service/service.go) already reads location from meta_data.json directly, so removing x-in does not affect routing. Drop: - Property.XIn field - validXIn map and the two lint rules that depend on x-in (L1 "top-level missing x-in" and L2 "path field must be in required") - contains() helper, no longer referenced after the path-required rule went away Refresh 20 goldens for the now-absent x-in lines. * refactor(schema): wrap inputSchema into params/data/flags sub-objects Replace the flat inputSchema with a 3-bucket nested structure that mirrors the CLI's actual flag layout, so AI consumers can directly map envelope fields to lark-cli invocation: inputSchema: properties: params: { ...path + query fields } → CLI --params JSON data: { ...body fields } → CLI --data JSON flags: { yes: ... } → CLI --yes (only for high-risk-write) Each sub-object only appears when the method has the corresponding source, so read-only GETs have a single `params` block, body-only POSTs have a single `data` block, etc. The `flags` wrapper carries an explicit description marking it as a CLI control bucket (not API fields), so AI does not confuse `yes` with a backend parameter. Lint: - L2 walkForL2 helper recurses into params/data sub-objects so leaf invariants (format:binary on non-string, min<max, required-in-properties) still apply. - L3 yes-presence check now navigates flags.properties.yes. Refresh all 20 goldens for the new shape. * refactor(schema): drop flags wrapper, put yes at top level alongside params/data The flags wrapper added one extra layer for a single field. Flatten so inputSchema.properties has three siblings: inputSchema: properties: params: { ...path + query } → CLI --params data: { ...body } → CLI --data yes: { boolean, default:false } → CLI --yes (only when risk == high-risk-write) `yes` description strengthened to mark it as a CLI confirmation gate (consumed by lark-cli, not sent to the backend), so AI can still distinguish it from API fields without needing a wrapper. Lint L3 yes-presence check goes back to top-level Properties.Map["yes"]. Refresh 20 goldens. * feat(schema): add `file` top-level sub-object for binary upload fields Splits file fields out of `data` into their own sibling, so the four top-level slots in inputSchema map 1:1 to CLI flag dispatch: inputSchema.properties: params { path + query fields } → --params JSON data { non-file body fields } → --data JSON file { type:file body fields, format:binary } → --file <key>=<path> yes boolean → --yes (only when risk == high-risk-write) Each slot is conditional: only registered when the method actually has fields for that source. This matches the CLI's own conditional flag registration (cmd/service/service.go:170-195), so what AI sees in the schema is exactly what flags exist for that method. The file sub-object carries a description explaining its semantics so AI knows to use --file for those fields rather than embedding the binary in --data JSON. Refresh im.images.create golden (the only file-upload method in the golden set). * test(schema): cover L2 lint recursion into params/data sub-objects Add two negative test cases that stuff bad values inside the wrapped inputSchema sub-objects (rather than at top-level), to lock in walkForL2's recursive coverage: - format:binary on a non-string field nested under params - sub-object Required referencing a key not in its Properties Regression guard so future walkForL2 refactors do not silently lose recursion and let leaf-field violations slip past lint. * fix(schema): coerce example, aggregate nested required, fix path hint - coerce `example` literal to the declared JSON Schema type (rename coerceEnumValue -> coerceLiteral, drop on coerce failure to match the `default` policy). Without this, integer/boolean/number fields emitted string examples and failed strict validators. - aggregate child field `required:true` into the enclosing nested object's `required[]` (both object and array-items shapes). Previously only the top-level params/data sub-objects scanned `required`, so envelopes silently under-reported the real call contract. - check method existence before reporting trailing-segment failure in both JSON and pretty `schema` paths. A typo like `schema im messages typo extra` now reports "Unknown method: im.messages.typo" instead of the misleading "Method 'typo' exists but trailing segments ..." hint. - extract risk level constants (RiskRead / RiskWrite / RiskHighRiskWrite) in internal/cmdutil/risk.go; replace literal usages in schema, lint, and confirm helpers so the typo radius is one file. - reconcile AssembleEnvelope docstring with implementation reality (the package-level currentMethodOrder + assembleMu serialize concurrent callers; output is deterministic per inputs). - drop testdata/golden/ and golden_test harness. End-to-end envelope shape regression now relies on real CLI invocations and the existing property-level unit + lint coverage. * fix(schema): emit items:{} for all typeless arrays, restore lint gate The list→array fallback only added items:{} when the source type was "list", leaving ~64 natively-typed array fields (e.g. approval.instances.cc.cc_user_ids) as {type:"array"} with no items. These violated the L1 lint rule, but TestAllEnvelopesPass skipped the "array missing items" error as a known data inconsistency, so the MCP tool contract was not actually lint-clean. Relax the fallback to cover every array lacking element shape regardless of source type, and drop the lint-test skip so the gate is hard again.
Summary
Replace
lark-cli schema <path>default JSON output with json schemacompliant envelopes covering all 193 embedded API methods, so AI consumers can read the full call contract (parameters, types, conditional flags, scopes, risk, access tokens, doc URL) directly from one envelope without writing per-command Skill markdown. This is a BREAKING CHANGE to the JSON shape only;--format prettykeeps its legacy ANSI rendering and remains the developer-facing browsing view.Changes
internal/schema/package — stateless transformation frommeta_data.jsonto MCP envelope:Envelope/InputSchema/OutputSchema/Property(with order-preservingOrderedProps) /Meta/Affordancetypes intypes.go;AssembleEnvelope/AssembleService/AssembleAll/ParsePathentry points inassembler.goandpath.go; L1–L3 hard-fail lint + L4 coverage inlint.go; embed slotannotations/for future affordance overlays (PR-1 stub, no YAML).meta_data.jsononly, bypassingremote_meta.jsonoverlay — guarantees deterministic output across machines / brands. Newregistry.EmbeddedSpec/EmbeddedServiceNames/EmbeddedMetaJSONhelpers ininternal/registry/loader.go.cmd/schema/schema.goJSON branch rewired to envelope output; pretty branch (printServices/printResourceList/printMethodDetail) preserved verbatim and still walks merged registry data for runtime inspection. Cobra arg cap raised from 1 to 8;completeSchemaPathextended to handle both dotted (im.messages.reply) and space-separated (im messages reply) forms.namefield reflects the actual CLI argv form: nested resources keep their dotted segment (e.g."im chat.members bots"), soname.split(" ")is directly executable asargv.inputSchema.properties.yesinjected for high-risk-write methods (52 envelopes); file fields encoded astype: "string"+format: "binary"+x-in: "body"; path/query parameters taggedx-in: "path"|"query";_meta.access_tokenstranslatedtenant→botand sorted;_meta.required_scopesalways emitted ([]when empty);_meta.doc_urland_meta.affordanceomitempty.meta_data.jsondata-quality patterns (danger↔riskinconsistency, typeless arrays, non-standardtype: "list",min==max); 20 hand-picked golden fixtures ininternal/schema/testdata/golden/covering edge cases (file upload, high-risk-write, missingrisk,requiredScopes, nested response, bot-only / user-only access tokens, deep nesting, multi-segment resource paths).UPDATE_GOLDEN=1 go test ./internal/schema/...refreshes goldens after meta_data updates.cmd/schema/schema_test.go(envelope JSON shape, dotted-vs-spaced byte equality, bare/service list arrays,yesinjection presence/absence, pretty mode preservation);TestSchemaCmd_NoArgssplit into_Prettyand_JSON_IsArrayfor the new default output.Test Plan
make unit-testpassedgo test $(go list ./... | grep -Ev '/(tests_e2e|tests/cli_e2e)(/|$)') -short -count=1passedtests_e2e/schema/...19/19 subtests passed (8 test functions); other historical E2E packages report env-level failures unrelated to this PR (test appcli_aa9a9dde09781cb0lacks several scopes in the Lark developer console)namesegmentation, spec §5.3 lint known-list disclosure)golangci-lint --new-from-rev=origin/main0 issues;go mod tidyno difflark-cli schema im.images.create --format json | jq '{name, has_yes: (.inputSchema.properties.yes != null), risk: ._meta.risk}'—{"name":"im images create","has_yes":false,"risk":"write"}lark-cli schema im messages delete --format json | jq '._meta.risk, .inputSchema.properties.yes.type'—"high-risk-write"/"boolean"lark-cli schema im.chat.members.bots --format json | jq -r '.name'—im chat.members bots(matcheslark-cli im chat.members botsargv)lark-cli schema --format pretty | head— legacy ANSI service catalog preservedRelated Issues
N/A
Summary by CodeRabbit
Release Notes
New Features
--format jsonoption to schema command for structured query outputBug Fixes
Documentation