feat: declarative LeafSpec command framework + schema generation/consumption separation
== LeafSpec command framework (internal/helpers/leaf.go) ==
Declarative command construction: LeafSpec/LeafFlag/NewLeafCommand with
Call (pluggable dispatch), LeafInt, PostMount, Trim, Validate. Collapses
per-command hand-written required validation, alias/env fallback, value
transform, and toolArgs assembly into one declarative path.
== devapp migration (28/31 commands) ==
All MCP-direct devapp leaf commands migrated to LeafSpec. Factories
(devAppCall/devAppCallCursor/devAppMeta) fold 33 repeated closures.
fakeDevAppRunner asserts toolArgs for every migrated command. 4 complex
commands (delete/robot submit/result/config) kept hand-written.
== Schema generation/consumption separation ==
- gen.go: isolated //go:generate pragmas from business code.
- command_meta.go: ResolveMeta(cliPath) -> CommandMeta{Identity,Safety,Selection}.
- command_safety.go: SafetyForCLIPath + RenderSafetyAnnotation; safety metadata
flows from embedded catalog into --help output.
- calendar.go HelpFunc fix: delegates to root HelpFunc at help-time.
- schema_catalog_structure.go: closed catalog structure validation gate.
== Registry + catalog per-product sharding ==
schema_command_registry and schema_catalog split into per-product shards,
eliminating concurrent-PR merge conflicts on these files.
== MCP metadata refresh tool ==
cmd/fetch_mcp_metadata: iterates 26 MCP server endpoints, merges with previous
data for cross-server interface_ref. make fetch-mcp-metadata target.
== AGENTS.md ==
Documents the generation/consumption split.
Verified: make policy exit 0, drift zero, all tests pass.
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
// Copyright 2026 Alibaba Group
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// command_meta.go provides the unified metadata consumption API. All runtime
|
||||
// consumers (help, schema, agent selection, skill generation) call ResolveMeta
|
||||
// to get a CommandMeta struct — one function, one struct, no need to know which
|
||||
// of the 6 generation layers a field comes from.
|
||||
//
|
||||
// This is the "simple consumption" half of the generation/consumption split:
|
||||
// - Generation (gen.go + internal/generator/): 6 inputs → catalog snapshot.
|
||||
// - Consumption (this file): catalog snapshot → ResolveMeta → CommandMeta.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// CommandMeta is the complete runtime metadata view for a single command.
|
||||
// Consumers read this struct; they never touch the raw catalog maps.
|
||||
type CommandMeta struct {
|
||||
Identity CommandIdentity
|
||||
Safety CommandSafety
|
||||
Selection CommandSelection
|
||||
}
|
||||
|
||||
// CommandIdentity is the stable identity of a command.
|
||||
type CommandIdentity struct {
|
||||
CLIPath string // "dev app delete"
|
||||
Canonical string // "dev.delete_dev_app"
|
||||
Aliases []string // ["search", ...]
|
||||
ProductID string // "devapp"
|
||||
Title string // one-line description
|
||||
}
|
||||
|
||||
// CommandSelection is the agent-facing selection metadata.
|
||||
type CommandSelection struct {
|
||||
AgentSummary string
|
||||
UseWhen []string
|
||||
AvoidWhen []string
|
||||
Examples []string
|
||||
}
|
||||
|
||||
var (
|
||||
metaByCLIPathOnce sync.Once
|
||||
metaByCLIPath map[string]CommandMeta
|
||||
)
|
||||
|
||||
// initMetaByCLIPath builds the cli_path → CommandMeta lookup from the embedded
|
||||
// catalog. Runs once (sync.Once); the catalog is already decoded at package init.
|
||||
func initMetaByCLIPath() {
|
||||
metaByCLIPath = make(map[string]CommandMeta)
|
||||
loaded := embeddedSchemaCatalog()
|
||||
if loaded.Snapshot.Tools == nil {
|
||||
return
|
||||
}
|
||||
for _, tool := range loaded.Snapshot.Tools {
|
||||
cliPath := catalogStringVal(tool, "cli_path")
|
||||
if cliPath == "" {
|
||||
continue
|
||||
}
|
||||
meta := CommandMeta{
|
||||
Identity: CommandIdentity{
|
||||
CLIPath: cliPath,
|
||||
Canonical: catalogStringVal(tool, "canonical_path"),
|
||||
ProductID: catalogStringVal(tool, "product_id"),
|
||||
Title: catalogStringVal(tool, "title"),
|
||||
},
|
||||
Safety: CommandSafety{
|
||||
Effect: catalogStringVal(tool, "effect"),
|
||||
Risk: catalogStringVal(tool, "risk"),
|
||||
Confirmation: catalogStringVal(tool, "confirmation"),
|
||||
Idempotency: catalogStringVal(tool, "idempotency"),
|
||||
},
|
||||
Selection: CommandSelection{
|
||||
AgentSummary: catalogStringVal(tool, "agent_summary"),
|
||||
UseWhen: catalogStringSliceVal(tool, "use_when"),
|
||||
AvoidWhen: catalogStringSliceVal(tool, "avoid_when"),
|
||||
Examples: catalogStringSliceVal(tool, "examples"),
|
||||
},
|
||||
}
|
||||
metaByCLIPath[cliPath] = meta
|
||||
}
|
||||
}
|
||||
|
||||
// catalogStringSliceVal reads a []string field from a catalog tool map.
|
||||
func catalogStringSliceVal(tool map[string]any, key string) []string {
|
||||
raw, ok := tool[key].([]any)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
out := make([]string, 0, len(raw))
|
||||
for _, v := range raw {
|
||||
if s, ok := v.(string); ok {
|
||||
out = append(out, s)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// ResolveMeta returns the complete metadata for a command identified by its CLI
|
||||
// path (e.g. "dev app delete"). Returns ok=false for commands not in the
|
||||
// embedded catalog (utility commands, hidden commands, shortcuts).
|
||||
func ResolveMeta(cliPath string) (CommandMeta, bool) {
|
||||
metaByCLIPathOnce.Do(initMetaByCLIPath)
|
||||
m, ok := metaByCLIPath[strings.TrimSpace(cliPath)]
|
||||
return m, ok
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// Copyright 2026 Alibaba Group
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// CommandSafety holds the safety metadata for a CLI command, resolved at
|
||||
// runtime from the embedded schema catalog. This is a read-only view over the
|
||||
// catalog — NOT a second safety source. The catalog remains the single
|
||||
// authoritative reviewed source; this struct merely provides typed access for
|
||||
// consumers (help rendering, skill generation).
|
||||
type CommandSafety struct {
|
||||
Effect string // read / write / destructive
|
||||
Risk string // low / medium / high
|
||||
Confirmation string // not_required / user_required
|
||||
Idempotency string // idempotent / non_idempotent
|
||||
}
|
||||
|
||||
// ShouldRender returns true when the safety metadata warrants a visible
|
||||
// annotation in --help. Only commands that need confirmation or carry
|
||||
// above-low risk are annotated; read-only low-risk commands stay clean.
|
||||
func (s CommandSafety) ShouldRender() bool {
|
||||
return s.Confirmation == "user_required" ||
|
||||
(s.Risk != "" && s.Risk != "low")
|
||||
}
|
||||
|
||||
var (
|
||||
safetyByCLIPathOnce sync.Once
|
||||
safetyByCLIPath map[string]CommandSafety
|
||||
)
|
||||
|
||||
// initSafetyByCLIPath builds a cli_path → CommandSafety lookup from the
|
||||
// embedded catalog. Runs once (sync.Once); the catalog is already decoded at
|
||||
// package init, so this is a cheap map iteration.
|
||||
func initSafetyByCLIPath() {
|
||||
safetyByCLIPath = make(map[string]CommandSafety)
|
||||
loaded := embeddedSchemaCatalog()
|
||||
if loaded.Snapshot.Tools == nil {
|
||||
return
|
||||
}
|
||||
for _, tool := range loaded.Snapshot.Tools {
|
||||
cliPath := catalogStringVal(tool, "cli_path")
|
||||
if cliPath == "" {
|
||||
continue
|
||||
}
|
||||
safetyByCLIPath[cliPath] = CommandSafety{
|
||||
Effect: catalogStringVal(tool, "effect"),
|
||||
Risk: catalogStringVal(tool, "risk"),
|
||||
Confirmation: catalogStringVal(tool, "confirmation"),
|
||||
Idempotency: catalogStringVal(tool, "idempotency"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// catalogStringVal reads a string field from a catalog tool map[string]any.
|
||||
func catalogStringVal(tool map[string]any, key string) string {
|
||||
if v, ok := tool[key].(string); ok {
|
||||
return v
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// SafetyForCLIPath returns the safety metadata for a command identified by its
|
||||
// CLI path (e.g. "dev app delete"). Returns ok=false when the command is not
|
||||
// in the embedded catalog (utility commands, hidden commands, shortcuts).
|
||||
//
|
||||
// Deprecated: use ResolveMeta(cliPath).Safety for the complete metadata view.
|
||||
// Kept for backward compatibility with existing callers.
|
||||
func SafetyForCLIPath(cliPath string) (CommandSafety, bool) {
|
||||
meta, ok := ResolveMeta(cliPath)
|
||||
if !ok {
|
||||
return CommandSafety{}, false
|
||||
}
|
||||
return meta.Safety, true
|
||||
}
|
||||
|
||||
// RenderSafetyAnnotation writes a "Safety:" line to the command's stdout when
|
||||
// the command carries above-low risk or requires user confirmation. This is
|
||||
// the shared entry point for ALL help rendering paths (root HelpFunc, product
|
||||
// group custom HelpFuncs like calendar's). It avoids the timing issue where a
|
||||
// group captures origHelp before configureRootHelp sets the root's custom func.
|
||||
func RenderSafetyAnnotation(cmd *cobra.Command) {
|
||||
cliPath := strings.TrimSpace(strings.TrimPrefix(cmd.CommandPath(), cmd.Root().Name()+" "))
|
||||
safety, ok := SafetyForCLIPath(cliPath)
|
||||
if !ok || !safety.ShouldRender() {
|
||||
return
|
||||
}
|
||||
w := cmd.OutOrStdout()
|
||||
fmt.Fprintf(w, "\nSafety: effect=%s risk=%s confirmation=%s", safety.Effect, safety.Risk, safety.Confirmation)
|
||||
if safety.Idempotency != "" {
|
||||
fmt.Fprintf(w, " idempotency=%s", safety.Idempotency)
|
||||
}
|
||||
if safety.Confirmation == "user_required" {
|
||||
fmt.Fprint(w, " (需 --yes)")
|
||||
}
|
||||
fmt.Fprintln(w)
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright 2026 Alibaba Group
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSafetyForCLIPathKnownCommand(t *testing.T) {
|
||||
// dev app delete 是 destructive + high risk + user_required。
|
||||
s, ok := SafetyForCLIPath("dev app delete")
|
||||
if !ok {
|
||||
t.Fatal("SafetyForCLIPath(\"dev app delete\") returned ok=false; want true")
|
||||
}
|
||||
if s.Effect != "destructive" {
|
||||
t.Errorf("effect = %q, want destructive", s.Effect)
|
||||
}
|
||||
if s.Risk != "high" {
|
||||
t.Errorf("risk = %q, want high", s.Risk)
|
||||
}
|
||||
if s.Confirmation != "user_required" {
|
||||
t.Errorf("confirmation = %q, want user_required", s.Confirmation)
|
||||
}
|
||||
if !s.ShouldRender() {
|
||||
t.Error("ShouldRender() = false for destructive/high/user_required; want true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSafetyForCLIPathUnknownSkips(t *testing.T) {
|
||||
// 不存在的命令 → ok=false。
|
||||
_, ok := SafetyForCLIPath("nonexistent fake command")
|
||||
if ok {
|
||||
t.Fatal("SafetyForCLIPath for nonexistent command returned ok=true; want false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSafetyForCLIPathReadOnlyLowRiskSkips(t *testing.T) {
|
||||
// 找一个 read/low 风险命令,ShouldRender 应 false。
|
||||
// dev app list 是 read,默认 low risk。
|
||||
s, ok := SafetyForCLIPath("dev app list")
|
||||
if !ok {
|
||||
t.Skip("dev app list not in catalog; skipping")
|
||||
}
|
||||
if s.ShouldRender() {
|
||||
t.Errorf("ShouldRender() = true for effect=%s risk=%s; want false (read/low)", s.Effect, s.Risk)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSafetyForCLIPathTrimsWhitespace(t *testing.T) {
|
||||
// 带首尾空格的 cli_path 也能查到。
|
||||
s1, _ := SafetyForCLIPath("dev app delete")
|
||||
s2, ok2 := SafetyForCLIPath(" dev app delete ")
|
||||
if !ok2 {
|
||||
t.Fatal("trimmed lookup failed; whitespace not trimmed")
|
||||
}
|
||||
if s1 != s2 {
|
||||
t.Errorf("whitespace-trimmed result differs: %+v vs %+v", s1, s2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveMetaComplete(t *testing.T) {
|
||||
// dev app delete: destructive + high + user_required + 有 selection。
|
||||
m, ok := ResolveMeta("dev app delete")
|
||||
if !ok {
|
||||
t.Fatal("ResolveMeta(\"dev app delete\") returned ok=false")
|
||||
}
|
||||
if m.Identity.CLIPath != "dev app delete" {
|
||||
t.Errorf("CLIPath = %q", m.Identity.CLIPath)
|
||||
}
|
||||
if m.Safety.Effect != "destructive" {
|
||||
t.Errorf("Effect = %q, want destructive", m.Safety.Effect)
|
||||
}
|
||||
if len(m.Selection.UseWhen) == 0 && m.Selection.AgentSummary == "" {
|
||||
t.Error("Selection is empty; expected use_when or agent_summary")
|
||||
}
|
||||
t.Logf("dev app delete: canonical=%s safety=%+v selection(use_when=%d avoid_when=%d examples=%d)",
|
||||
m.Identity.Canonical, m.Safety, len(m.Selection.UseWhen), len(m.Selection.AvoidWhen), len(m.Selection.Examples))
|
||||
}
|
||||
|
||||
func TestResolveMetaUnknownSkips(t *testing.T) {
|
||||
_, ok := ResolveMeta("nonexistent fake command")
|
||||
if ok {
|
||||
t.Fatal("ResolveMeta for unknown command returned ok=true")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2026 Alibaba Group
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// gen.go is the single entry point for schema metadata generation. It isolates
|
||||
// all //go:generate pragmas from business code so that:
|
||||
// - schema_agent_metadata.go / schema_catalog.go contain only types + embed.
|
||||
// - Generation is a standalone process (make generate-schema triggers this).
|
||||
// - The 6-input → 1-output contract is documented in one place.
|
||||
//
|
||||
// Generation inputs (authored, reviewed):
|
||||
// 1. schema_command_registry/ identity (canonical/aliases/navigation)
|
||||
// 2. schema_hints/metadata/*.json safety (effect/risk/confirmation)
|
||||
// 3. schema_hints/selection/*.json selection (use_when/avoid_when)
|
||||
// 4. schema_mcp_metadata.json MCP server tool definitions
|
||||
// 5. schema_parameter_bindings.json parameter type/property mappings
|
||||
// 6. cobra command tree (Go runtime) flags/usage/required (reflected)
|
||||
//
|
||||
// Generation outputs (embedded at build):
|
||||
// - schema_agent_metadata/*.json per-product agent metadata
|
||||
// - schema_catalog/ per-product catalog shards
|
||||
|
||||
package cli
|
||||
|
||||
//go:generate go run ../generator/cmd_schema_agent_metadata -root ../.. -registry internal/cli/schema_command_registry -output-dir schema_agent_metadata -audit-output schema_agent_metadata_audit.json
|
||||
// Rebuild all dependencies so the Catalog compiler cannot reuse the cli
|
||||
// package cached by the preceding metadata generator with the old embedded
|
||||
// JSON files.
|
||||
//go:generate go run -a ../generator/cmd_schema_catalog -root ../.. -output schema_catalog
|
||||
@@ -22,12 +22,6 @@ import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
//go:generate go run ../generator/cmd_schema_agent_metadata -root ../.. -registry internal/cli/schema_command_registry.json -output-dir schema_agent_metadata -audit-output schema_agent_metadata_audit.json
|
||||
// Rebuild all dependencies so the Catalog compiler cannot reuse the cli
|
||||
// package cached by the preceding metadata generator with the old embedded
|
||||
// JSON files.
|
||||
//go:generate go run -a ../generator/cmd_schema_catalog -root ../.. -output schema_catalog.json
|
||||
|
||||
//go:embed schema_agent_metadata/*.json
|
||||
var embeddedAgentMetadataFS embed.FS
|
||||
|
||||
|
||||
@@ -15,10 +15,11 @@ package cli
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
_ "embed"
|
||||
"embed"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -29,8 +30,20 @@ import (
|
||||
|
||||
const SchemaCatalogSnapshotVersion = 1
|
||||
|
||||
//go:embed schema_catalog.json
|
||||
var embeddedSchemaCatalogJSON []byte
|
||||
// The release Catalog is committed as a per-product split so concurrent
|
||||
// feature PRs only rewrite the shard for the product they touch:
|
||||
//
|
||||
// schema_catalog/catalog.json global envelope + Catalog map
|
||||
// schema_catalog/tools/<product>.json that product's leaf ToolSpecs
|
||||
//
|
||||
// The loader reassembles the exact same SchemaCatalogSnapshot, so the
|
||||
// source_hash integrity check is identical to the single-file layout.
|
||||
//
|
||||
//go:embed schema_catalog/catalog.json
|
||||
var embeddedSchemaCatalogEnvelopeJSON []byte
|
||||
|
||||
//go:embed schema_catalog/tools
|
||||
var embeddedSchemaCatalogTools embed.FS
|
||||
|
||||
// SchemaCatalogSnapshot is the release-stable Agent contract. Catalog holds
|
||||
// the progressive product/tool index; Tools holds full leaf parameter schemas.
|
||||
@@ -68,11 +81,69 @@ var runtimeEmbeddedSchemaCatalogLazyLoadCount atomic.Uint64
|
||||
func embeddedSchemaCatalog() loadedSchemaCatalog {
|
||||
runtimeEmbeddedSchemaCatalogOnce.Do(func() {
|
||||
runtimeEmbeddedSchemaCatalogLazyLoadCount.Add(1)
|
||||
runtimeEmbeddedSchemaCatalog, runtimeEmbeddedSchemaCatalogErr = decodeSchemaCatalogSnapshot(embeddedSchemaCatalogJSON)
|
||||
runtimeEmbeddedSchemaCatalog, runtimeEmbeddedSchemaCatalogErr = assembleEmbeddedSchemaCatalog()
|
||||
})
|
||||
return runtimeEmbeddedSchemaCatalog
|
||||
}
|
||||
|
||||
// schemaCatalogEnvelope is the global half of the split release Catalog. It
|
||||
// mirrors the generator's envelope struct; the Catalog map and release hashes
|
||||
// do not partition by product and stay in one file.
|
||||
type schemaCatalogEnvelope struct {
|
||||
Version int `json:"version"`
|
||||
SurfaceHash string `json:"surface_hash,omitempty"`
|
||||
SourceHash string `json:"source_hash"`
|
||||
Catalog map[string]any `json:"catalog"`
|
||||
}
|
||||
|
||||
// schemaCatalogToolShard mirrors the per-product shard written by the
|
||||
// generator. Only the product and its leaf ToolSpecs are stored here.
|
||||
type schemaCatalogToolShard struct {
|
||||
Product string `json:"product"`
|
||||
Tools map[string]map[string]any `json:"tools"`
|
||||
}
|
||||
|
||||
// assembleEmbeddedSchemaCatalog reassembles the split release Catalog shards
|
||||
// into the same SchemaCatalogSnapshot the single-file layout produced, then
|
||||
// validates it through the production loader. source_hash still covers the
|
||||
// whole payload: if any shard is missing, stale, or tampered, the content hash
|
||||
// check in loadSchemaCatalogSnapshot fails exactly as before.
|
||||
func assembleEmbeddedSchemaCatalog() (loadedSchemaCatalog, error) {
|
||||
var envelope schemaCatalogEnvelope
|
||||
if err := decodeStrictSchemaJSON(embeddedSchemaCatalogEnvelopeJSON, &envelope); err != nil {
|
||||
return loadedSchemaCatalog{}, fmt.Errorf("decode embedded schema catalog.json: %w", err)
|
||||
}
|
||||
entries, err := embeddedSchemaCatalogTools.ReadDir("schema_catalog/tools")
|
||||
if err != nil {
|
||||
return loadedSchemaCatalog{}, fmt.Errorf("read embedded schema catalog tools directory: %w", err)
|
||||
}
|
||||
tools := make(map[string]map[string]any, len(entries)*8)
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".json") {
|
||||
continue
|
||||
}
|
||||
data, readErr := fs.ReadFile(embeddedSchemaCatalogTools, "schema_catalog/tools/"+entry.Name())
|
||||
if readErr != nil {
|
||||
return loadedSchemaCatalog{}, fmt.Errorf("read embedded schema catalog shard %s: %w", entry.Name(), readErr)
|
||||
}
|
||||
var shard schemaCatalogToolShard
|
||||
if err := decodeStrictSchemaJSON(data, &shard); err != nil {
|
||||
return loadedSchemaCatalog{}, fmt.Errorf("decode embedded schema catalog shard %s: %w", entry.Name(), err)
|
||||
}
|
||||
for canonical, spec := range shard.Tools {
|
||||
tools[canonical] = spec
|
||||
}
|
||||
}
|
||||
snapshot := SchemaCatalogSnapshot{
|
||||
Version: envelope.Version,
|
||||
SurfaceHash: envelope.SurfaceHash,
|
||||
SourceHash: envelope.SourceHash,
|
||||
Catalog: envelope.Catalog,
|
||||
Tools: tools,
|
||||
}
|
||||
return loadSchemaCatalogSnapshot(snapshot)
|
||||
}
|
||||
|
||||
func embeddedSchemaCatalogError() error {
|
||||
_ = embeddedSchemaCatalog()
|
||||
return runtimeEmbeddedSchemaCatalogErr
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,762 @@
|
||||
{
|
||||
"product": "devdoc",
|
||||
"tools": {
|
||||
"devdoc.search_open_platform_docs_rag": {
|
||||
"agent_metadata_source": "embedded-skill-metadata",
|
||||
"agent_source_refs": [
|
||||
"CommandRegistry:canonical_path=devdoc.search_open_platform_docs_rag",
|
||||
"Skill:skills/mono/references/products/devdoc.md",
|
||||
"cobra-help:dws devdoc article search",
|
||||
"dws-wukong-envelope@4574f7022c32:dws-wukong-discovery.devdoc.prod.json#devdoc.search_open_platform_docs",
|
||||
"internal/cli/schema_command_registry.json#devdoc.search_open_platform_docs_rag",
|
||||
"internal/cli/schema_hints/imported/wukong.json",
|
||||
"internal/cli/schema_hints/metadata/devdoc.json",
|
||||
"internal/cli/schema_hints/selection/devdoc.json",
|
||||
"internal/cli/schema_mcp_metadata.json#tools.devdoc.search_open_platform_docs_rag",
|
||||
"live-dws-schema:devdoc.search_open_platform_docs_rag",
|
||||
"skills/mono/references/products/devdoc.md",
|
||||
"skills/mono/references/products/simple.md",
|
||||
"structured-hint:internal/cli/schema_hints/imported/wukong.json#devdoc.search_open_platform_docs_rag",
|
||||
"structured-hint:internal/cli/schema_hints/selection-review.json#devdoc.search_open_platform_docs_rag"
|
||||
],
|
||||
"agent_summary": "搜索钉钉开放平台开发文档,返回资料与链接(不生成分析答案)",
|
||||
"agent_summary_source": "dws-agent-selection/devdoc",
|
||||
"availability": "available",
|
||||
"avoid_when": [
|
||||
"搜索用户业务文档用 drive/wiki/doc,不要用 devdoc",
|
||||
"要执行开放平台应用配置变更时用 dev"
|
||||
],
|
||||
"canonical_path": "devdoc.search_open_platform_docs_rag",
|
||||
"cli_name": "search",
|
||||
"cli_path": "devdoc article search",
|
||||
"confirmation": "not_required",
|
||||
"constraints": {
|
||||
"require_one_of": [
|
||||
[
|
||||
"query",
|
||||
"keyword"
|
||||
]
|
||||
]
|
||||
},
|
||||
"description": "按关键词搜索 open.dingtalk.com 文档,支持分页。默认表格输出,可用 -f json 获取完整响应。",
|
||||
"display": "开放平台文档搜索",
|
||||
"effect": "read",
|
||||
"effect_source": "command-verb",
|
||||
"examples": [
|
||||
"dws devdoc article search --query \"OAuth2 接入\" --format json",
|
||||
"dws devdoc article search --query \"errcode 40078\" --format json"
|
||||
],
|
||||
"field_provenance": {
|
||||
"agent_summary": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/selection/devdoc.json",
|
||||
"value": "搜索钉钉开放平台开发文档,返回资料与链接(不生成分析答案)"
|
||||
}
|
||||
],
|
||||
"precedence": "reviewed_explicit",
|
||||
"resolution": "highest_precedence",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"source": "internal/cli/schema_hints/selection/devdoc.json",
|
||||
"value": "搜索钉钉开放平台开发文档,返回资料与链接(不生成分析答案)"
|
||||
},
|
||||
"availability": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "Search text may be supplied as positional keyword or public --query; hidden --keyword remains a runtime compatibility alias and is intentionally not published as a parameter. The versioned binding owns query -\u003e keyword.",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/metadata/devdoc.json",
|
||||
"value": "available"
|
||||
},
|
||||
{
|
||||
"precedence": "mcp_fallback",
|
||||
"selected": false,
|
||||
"source": "internal/cli/schema_mcp_metadata.json#tools.devdoc.search_open_platform_docs_rag.interface_ref",
|
||||
"value": "available"
|
||||
}
|
||||
],
|
||||
"precedence": "reviewed_explicit",
|
||||
"resolution": "highest_precedence",
|
||||
"review_reason": "Search text may be supplied as positional keyword or public --query; hidden --keyword remains a runtime compatibility alias and is intentionally not published as a parameter. The versioned binding owns query -\u003e keyword.",
|
||||
"source": "internal/cli/schema_hints/metadata/devdoc.json",
|
||||
"value": "available"
|
||||
},
|
||||
"avoid_when": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/selection/devdoc.json",
|
||||
"value": [
|
||||
"搜索用户业务文档用 drive/wiki/doc,不要用 devdoc",
|
||||
"要执行开放平台应用配置变更时用 dev"
|
||||
]
|
||||
}
|
||||
],
|
||||
"precedence": "reviewed_explicit",
|
||||
"resolution": "highest_precedence",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"source": "internal/cli/schema_hints/selection/devdoc.json",
|
||||
"value": [
|
||||
"搜索用户业务文档用 drive/wiki/doc,不要用 devdoc",
|
||||
"要执行开放平台应用配置变更时用 dev"
|
||||
]
|
||||
},
|
||||
"canonical_path": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "command_registry",
|
||||
"selected": true,
|
||||
"source": "reviewed_command_registry",
|
||||
"source_ref": "devdoc article search",
|
||||
"value": "devdoc.search_open_platform_docs_rag"
|
||||
},
|
||||
{
|
||||
"precedence": "reviewed_manual",
|
||||
"review_reason": "Search text may be supplied as positional keyword or public --query; hidden --keyword remains a runtime compatibility alias and is intentionally not published as a parameter. The versioned binding owns query -\u003e keyword.",
|
||||
"selected": false,
|
||||
"source": "reviewed_manual_hint",
|
||||
"source_ref": "devdoc article search",
|
||||
"value": "devdoc.search_open_platform_docs_rag"
|
||||
}
|
||||
],
|
||||
"precedence": "command_registry",
|
||||
"resolution": "registry_identity",
|
||||
"source": "reviewed_command_registry",
|
||||
"source_ref": "devdoc article search",
|
||||
"value": "devdoc.search_open_platform_docs_rag"
|
||||
},
|
||||
"confirmation": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "Search text may be supplied as positional keyword or public --query; hidden --keyword remains a runtime compatibility alias and is intentionally not published as a parameter. The versioned binding owns query -\u003e keyword.",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/metadata/devdoc.json",
|
||||
"value": "not_required"
|
||||
},
|
||||
{
|
||||
"precedence": "inference_or_default",
|
||||
"selected": false,
|
||||
"source": "risk-default",
|
||||
"value": "not_required"
|
||||
}
|
||||
],
|
||||
"precedence": "reviewed_explicit",
|
||||
"resolution": "highest_precedence",
|
||||
"review_reason": "Search text may be supplied as positional keyword or public --query; hidden --keyword remains a runtime compatibility alias and is intentionally not published as a parameter. The versioned binding owns query -\u003e keyword.",
|
||||
"source": "internal/cli/schema_hints/metadata/devdoc.json",
|
||||
"value": "not_required"
|
||||
},
|
||||
"description": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "cobra_help",
|
||||
"selected": true,
|
||||
"source": "cobra_help",
|
||||
"value": "按关键词搜索 open.dingtalk.com 文档,支持分页。默认表格输出,可用 -f json 获取完整响应。"
|
||||
},
|
||||
{
|
||||
"precedence": "mcp_metadata",
|
||||
"selected": false,
|
||||
"source": "mcp_metadata",
|
||||
"value": "根据关键词搜索钉钉开放平台的开发文档,返回匹配的文档条目列表,包含标题、摘要、文档链接和相关标签。搜索结果按相关性排序。适用于开发者在集成或调试过程中快速查找 API 说明、接入指南、错误码解释等技术资料。"
|
||||
}
|
||||
],
|
||||
"precedence": "cobra_help",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "cobra_help",
|
||||
"value": "按关键词搜索 open.dingtalk.com 文档,支持分页。默认表格输出,可用 -f json 获取完整响应。"
|
||||
},
|
||||
"effect": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "inference_or_default",
|
||||
"selected": true,
|
||||
"source": "command-verb",
|
||||
"value": "read"
|
||||
}
|
||||
],
|
||||
"precedence": "inference_or_default",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "command-verb",
|
||||
"value": "read"
|
||||
},
|
||||
"examples": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/selection/devdoc.json",
|
||||
"value": [
|
||||
"dws devdoc article search --query \"OAuth2 接入\" --format json",
|
||||
"dws devdoc article search --query \"errcode 40078\" --format json"
|
||||
]
|
||||
}
|
||||
],
|
||||
"precedence": "reviewed_explicit",
|
||||
"resolution": "highest_precedence",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"source": "internal/cli/schema_hints/selection/devdoc.json",
|
||||
"value": [
|
||||
"dws devdoc article search --query \"OAuth2 接入\" --format json",
|
||||
"dws devdoc article search --query \"errcode 40078\" --format json"
|
||||
]
|
||||
},
|
||||
"idempotency": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "inference_or_default",
|
||||
"selected": true,
|
||||
"source": "effect-default",
|
||||
"value": "idempotent"
|
||||
}
|
||||
],
|
||||
"precedence": "inference_or_default",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "effect-default",
|
||||
"value": "idempotent"
|
||||
},
|
||||
"interface_mode": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "Search text may be supplied as positional keyword or public --query; hidden --keyword remains a runtime compatibility alias and is intentionally not published as a parameter. The versioned binding owns query -\u003e keyword.",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/metadata/devdoc.json",
|
||||
"value": "mcp"
|
||||
},
|
||||
{
|
||||
"precedence": "mcp_fallback",
|
||||
"selected": false,
|
||||
"source": "internal/cli/schema_mcp_metadata.json#tools.devdoc.search_open_platform_docs_rag.interface_ref",
|
||||
"value": "mcp"
|
||||
}
|
||||
],
|
||||
"precedence": "reviewed_explicit",
|
||||
"resolution": "highest_precedence",
|
||||
"review_reason": "Search text may be supplied as positional keyword or public --query; hidden --keyword remains a runtime compatibility alias and is intentionally not published as a parameter. The versioned binding owns query -\u003e keyword.",
|
||||
"source": "internal/cli/schema_hints/metadata/devdoc.json",
|
||||
"value": "mcp"
|
||||
},
|
||||
"interface_ref": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "imported",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/imported/wukong.json",
|
||||
"value": {
|
||||
"product_id": "devdoc",
|
||||
"rpc_name": "search_open_platform_docs"
|
||||
}
|
||||
},
|
||||
{
|
||||
"precedence": "mcp_fallback",
|
||||
"selected": false,
|
||||
"source": "internal/cli/schema_mcp_metadata.json#tools.devdoc.search_open_platform_docs_rag.interface_ref",
|
||||
"value": "devdoc.search_open_platform_docs"
|
||||
}
|
||||
],
|
||||
"precedence": "imported",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "internal/cli/schema_hints/imported/wukong.json",
|
||||
"value": {
|
||||
"product_id": "devdoc",
|
||||
"rpc_name": "search_open_platform_docs"
|
||||
}
|
||||
},
|
||||
"metadata_source": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "derived_resolution",
|
||||
"selected": true,
|
||||
"source": "metadata_source_resolution",
|
||||
"value": "embedded-mcp-metadata"
|
||||
}
|
||||
],
|
||||
"precedence": "derived_resolution",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "metadata_source_resolution",
|
||||
"value": "embedded-mcp-metadata"
|
||||
},
|
||||
"reviewed": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "Search text may be supplied as positional keyword or public --query; hidden --keyword remains a runtime compatibility alias and is intentionally not published as a parameter. The versioned binding owns query -\u003e keyword.",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/metadata/devdoc.json",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"selected": false,
|
||||
"source": "internal/cli/schema_hints/selection/devdoc.json",
|
||||
"value": true
|
||||
}
|
||||
],
|
||||
"precedence": "reviewed_explicit",
|
||||
"resolution": "highest_precedence",
|
||||
"review_reason": "Search text may be supplied as positional keyword or public --query; hidden --keyword remains a runtime compatibility alias and is intentionally not published as a parameter. The versioned binding owns query -\u003e keyword.",
|
||||
"source": "internal/cli/schema_hints/metadata/devdoc.json",
|
||||
"value": true
|
||||
},
|
||||
"risk": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "inference_or_default",
|
||||
"selected": true,
|
||||
"source": "effect-default",
|
||||
"value": "low"
|
||||
}
|
||||
],
|
||||
"precedence": "inference_or_default",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "effect-default",
|
||||
"value": "low"
|
||||
},
|
||||
"title": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "cobra_help",
|
||||
"selected": true,
|
||||
"source": "cobra_help",
|
||||
"value": "搜索开放平台文档"
|
||||
},
|
||||
{
|
||||
"precedence": "mcp_metadata",
|
||||
"selected": false,
|
||||
"source": "mcp_metadata",
|
||||
"value": "search_open_platform_docs"
|
||||
}
|
||||
],
|
||||
"precedence": "cobra_help",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "cobra_help",
|
||||
"value": "搜索开放平台文档"
|
||||
},
|
||||
"use_when": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/selection/devdoc.json",
|
||||
"value": [
|
||||
"查 OpenAPI、字段、错误码、OAuth2、接入指南等开放平台开发问题"
|
||||
]
|
||||
}
|
||||
],
|
||||
"precedence": "reviewed_explicit",
|
||||
"resolution": "highest_precedence",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"source": "internal/cli/schema_hints/selection/devdoc.json",
|
||||
"value": [
|
||||
"查 OpenAPI、字段、错误码、OAuth2、接入指南等开放平台开发问题"
|
||||
]
|
||||
}
|
||||
},
|
||||
"group": "article",
|
||||
"has_parameters": true,
|
||||
"idempotency": "idempotent",
|
||||
"interface_mode": "mcp",
|
||||
"interface_ref": {
|
||||
"product_id": "devdoc",
|
||||
"rpc_name": "search_open_platform_docs"
|
||||
},
|
||||
"is_alias": false,
|
||||
"metadata_source": "embedded-mcp-metadata",
|
||||
"name": "search_open_platform_docs_rag",
|
||||
"parameter_count": 3,
|
||||
"parameters": {
|
||||
"page": {
|
||||
"default": "1",
|
||||
"description": "页码,默认 1",
|
||||
"field_provenance": {
|
||||
"description": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "cobra_contract",
|
||||
"selected": true,
|
||||
"source": "cobra_usage",
|
||||
"value": "页码,默认 1"
|
||||
},
|
||||
{
|
||||
"precedence": "mcp_metadata",
|
||||
"selected": false,
|
||||
"source": "mcp_metadata",
|
||||
"value": "分页页码"
|
||||
},
|
||||
{
|
||||
"precedence": "default",
|
||||
"selected": false,
|
||||
"source": "default",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"precedence": "cobra_contract",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "cobra_usage",
|
||||
"value": "页码,默认 1"
|
||||
},
|
||||
"interface_type": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "mcp_metadata",
|
||||
"selected": true,
|
||||
"source": "mcp_metadata",
|
||||
"value": "number"
|
||||
},
|
||||
{
|
||||
"precedence": "fallback",
|
||||
"selected": false,
|
||||
"source": "cobra_flag_type",
|
||||
"value": "string"
|
||||
}
|
||||
],
|
||||
"precedence": "mcp_metadata",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "mcp_metadata",
|
||||
"value": "number"
|
||||
},
|
||||
"property": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "inference",
|
||||
"selected": true,
|
||||
"source": "flag_name_inference",
|
||||
"value": "page"
|
||||
}
|
||||
],
|
||||
"precedence": "inference",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "flag_name_inference",
|
||||
"value": "page"
|
||||
},
|
||||
"required": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "cobra_contract",
|
||||
"selected": true,
|
||||
"source": "cobra_nonzero_default",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"precedence": "default",
|
||||
"selected": false,
|
||||
"source": "default",
|
||||
"value": false
|
||||
}
|
||||
],
|
||||
"precedence": "cobra_contract",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "cobra_nonzero_default",
|
||||
"value": false
|
||||
},
|
||||
"required_when": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "default",
|
||||
"selected": true,
|
||||
"source": "default",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"precedence": "default",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "default",
|
||||
"value": ""
|
||||
},
|
||||
"type": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "cobra_contract",
|
||||
"selected": true,
|
||||
"source": "cobra_flag_type",
|
||||
"value": "string"
|
||||
}
|
||||
],
|
||||
"precedence": "cobra_contract",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "cobra_flag_type",
|
||||
"value": "string"
|
||||
}
|
||||
},
|
||||
"interface_description": "分页页码",
|
||||
"interface_type": "number",
|
||||
"property": "page",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
"query": {
|
||||
"description": "搜索关键词 (必填)",
|
||||
"field_provenance": {
|
||||
"description": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "cobra_contract",
|
||||
"selected": true,
|
||||
"source": "cobra_usage",
|
||||
"value": "搜索关键词 (必填)"
|
||||
},
|
||||
{
|
||||
"precedence": "mcp_metadata",
|
||||
"selected": false,
|
||||
"source": "mcp_metadata",
|
||||
"value": "搜索关键词"
|
||||
},
|
||||
{
|
||||
"precedence": "default",
|
||||
"selected": false,
|
||||
"source": "default",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"precedence": "cobra_contract",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "cobra_usage",
|
||||
"value": "搜索关键词 (必填)"
|
||||
},
|
||||
"property": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "versioned_binding",
|
||||
"selected": true,
|
||||
"source": "versioned_parameter_binding",
|
||||
"value": "keyword"
|
||||
},
|
||||
{
|
||||
"precedence": "inference",
|
||||
"selected": false,
|
||||
"source": "flag_name_inference",
|
||||
"value": "query"
|
||||
}
|
||||
],
|
||||
"precedence": "versioned_binding",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "versioned_parameter_binding",
|
||||
"value": "keyword"
|
||||
},
|
||||
"required": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "reviewed_manual",
|
||||
"review_reason": "Search text may be supplied as positional keyword or public --query; hidden --keyword remains a runtime compatibility alias and is intentionally not published as a parameter. The versioned binding owns query -\u003e keyword.",
|
||||
"selected": true,
|
||||
"source": "reviewed_manual_hint",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"precedence": "command_constraint",
|
||||
"selected": false,
|
||||
"source": "require_one_of_constraint",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"precedence": "mcp_metadata",
|
||||
"selected": false,
|
||||
"source": "mcp_metadata",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"precedence": "inference",
|
||||
"selected": false,
|
||||
"source": "usage_required_inference",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"precedence": "default",
|
||||
"selected": false,
|
||||
"source": "default",
|
||||
"value": false
|
||||
}
|
||||
],
|
||||
"precedence": "reviewed_manual",
|
||||
"resolution": "highest_precedence",
|
||||
"review_reason": "Search text may be supplied as positional keyword or public --query; hidden --keyword remains a runtime compatibility alias and is intentionally not published as a parameter. The versioned binding owns query -\u003e keyword.",
|
||||
"source": "reviewed_manual_hint",
|
||||
"value": false
|
||||
},
|
||||
"required_when": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "default",
|
||||
"selected": true,
|
||||
"source": "default",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"precedence": "default",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "default",
|
||||
"value": ""
|
||||
},
|
||||
"type": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "cobra_contract",
|
||||
"selected": true,
|
||||
"source": "cobra_flag_type",
|
||||
"value": "string"
|
||||
}
|
||||
],
|
||||
"precedence": "cobra_contract",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "cobra_flag_type",
|
||||
"value": "string"
|
||||
}
|
||||
},
|
||||
"interface_description": "搜索关键词",
|
||||
"property": "keyword",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"default": "10",
|
||||
"description": "每页数量,默认 10",
|
||||
"field_provenance": {
|
||||
"description": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "cobra_contract",
|
||||
"selected": true,
|
||||
"source": "cobra_usage",
|
||||
"value": "每页数量,默认 10"
|
||||
},
|
||||
{
|
||||
"precedence": "mcp_metadata",
|
||||
"selected": false,
|
||||
"source": "mcp_metadata",
|
||||
"value": "分页大小"
|
||||
},
|
||||
{
|
||||
"precedence": "default",
|
||||
"selected": false,
|
||||
"source": "default",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"precedence": "cobra_contract",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "cobra_usage",
|
||||
"value": "每页数量,默认 10"
|
||||
},
|
||||
"interface_type": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "mcp_metadata",
|
||||
"selected": true,
|
||||
"source": "mcp_metadata",
|
||||
"value": "number"
|
||||
},
|
||||
{
|
||||
"precedence": "fallback",
|
||||
"selected": false,
|
||||
"source": "cobra_flag_type",
|
||||
"value": "string"
|
||||
}
|
||||
],
|
||||
"precedence": "mcp_metadata",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "mcp_metadata",
|
||||
"value": "number"
|
||||
},
|
||||
"property": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "inference",
|
||||
"selected": true,
|
||||
"source": "flag_name_inference",
|
||||
"value": "size"
|
||||
}
|
||||
],
|
||||
"precedence": "inference",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "flag_name_inference",
|
||||
"value": "size"
|
||||
},
|
||||
"required": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "cobra_contract",
|
||||
"selected": true,
|
||||
"source": "cobra_nonzero_default",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"precedence": "default",
|
||||
"selected": false,
|
||||
"source": "default",
|
||||
"value": false
|
||||
}
|
||||
],
|
||||
"precedence": "cobra_contract",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "cobra_nonzero_default",
|
||||
"value": false
|
||||
},
|
||||
"required_when": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "default",
|
||||
"selected": true,
|
||||
"source": "default",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"precedence": "default",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "default",
|
||||
"value": ""
|
||||
},
|
||||
"type": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "cobra_contract",
|
||||
"selected": true,
|
||||
"source": "cobra_flag_type",
|
||||
"value": "string"
|
||||
}
|
||||
],
|
||||
"precedence": "cobra_contract",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "cobra_flag_type",
|
||||
"value": "string"
|
||||
}
|
||||
},
|
||||
"interface_description": "分页大小",
|
||||
"interface_type": "number",
|
||||
"property": "size",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"path": "devdoc.search_open_platform_docs_rag",
|
||||
"positionals": [
|
||||
{
|
||||
"description": "搜索关键词;也可通过 --query 传入",
|
||||
"index": 0,
|
||||
"name": "keyword",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"primary_cli_path": "devdoc article search",
|
||||
"product_id": "devdoc",
|
||||
"reviewed": true,
|
||||
"risk": "low",
|
||||
"source": "reviewed_command_registry",
|
||||
"title": "搜索开放平台文档",
|
||||
"use_when": [
|
||||
"查 OpenAPI、字段、错误码、OAuth2、接入指南等开放平台开发问题"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,360 @@
|
||||
{
|
||||
"product": "live",
|
||||
"tools": {
|
||||
"live.get_my_lives": {
|
||||
"agent_metadata_source": "embedded-skill-metadata",
|
||||
"agent_source_refs": [
|
||||
"CommandRegistry:canonical_path=live.get_my_lives",
|
||||
"Skill:skills/multi/dingtalk-live/SKILL.md",
|
||||
"cobra-help:dws live stream list",
|
||||
"dws-wukong-envelope@4574f7022c32:dws-wukong-discovery.live.prod.json#live.get_my_lives",
|
||||
"internal/cli/schema_command_registry.json#live.get_my_lives",
|
||||
"internal/cli/schema_hints/imported/wukong.json",
|
||||
"internal/cli/schema_hints/metadata/live.json",
|
||||
"internal/cli/schema_hints/selection/live.json",
|
||||
"internal/cli/schema_mcp_metadata.json#tools.live.get_my_lives",
|
||||
"live-dws-schema:live.get_my_lives",
|
||||
"skills/mono/references/products/live.md",
|
||||
"structured-hint:internal/cli/schema_hints/imported/wukong.json#live.get_my_lives",
|
||||
"structured-hint:internal/cli/schema_hints/selection-review.json#live.get_my_lives"
|
||||
],
|
||||
"agent_summary": "查看当前用户发起的直播列表与基础统计",
|
||||
"agent_summary_source": "dws-agent-selection/live",
|
||||
"availability": "available",
|
||||
"avoid_when": [
|
||||
"需要创建/开播/结束直播时不要使用;当前公开面仅列表查询"
|
||||
],
|
||||
"canonical_path": "live.get_my_lives",
|
||||
"cli_name": "list",
|
||||
"cli_path": "live stream list",
|
||||
"confirmation": "not_required",
|
||||
"description": "查看我的直播列表",
|
||||
"display": "直播列表 / 信息",
|
||||
"effect": "read",
|
||||
"effect_source": "command-verb",
|
||||
"examples": [
|
||||
"dws live stream list"
|
||||
],
|
||||
"field_provenance": {
|
||||
"agent_summary": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/selection/live.json",
|
||||
"value": "查看当前用户发起的直播列表与基础统计"
|
||||
}
|
||||
],
|
||||
"precedence": "reviewed_explicit",
|
||||
"resolution": "highest_precedence",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"source": "internal/cli/schema_hints/selection/live.json",
|
||||
"value": "查看当前用户发起的直播列表与基础统计"
|
||||
},
|
||||
"availability": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "dws-tool-metadata/live marks this tool as reviewed",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/metadata/live.json",
|
||||
"value": "available"
|
||||
},
|
||||
{
|
||||
"precedence": "mcp_fallback",
|
||||
"selected": false,
|
||||
"source": "internal/cli/schema_mcp_metadata.json#tools.live.get_my_lives.interface_ref",
|
||||
"value": "available"
|
||||
}
|
||||
],
|
||||
"precedence": "reviewed_explicit",
|
||||
"resolution": "highest_precedence",
|
||||
"review_reason": "dws-tool-metadata/live marks this tool as reviewed",
|
||||
"source": "internal/cli/schema_hints/metadata/live.json",
|
||||
"value": "available"
|
||||
},
|
||||
"avoid_when": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/selection/live.json",
|
||||
"value": [
|
||||
"需要创建/开播/结束直播时不要使用;当前公开面仅列表查询"
|
||||
]
|
||||
}
|
||||
],
|
||||
"precedence": "reviewed_explicit",
|
||||
"resolution": "highest_precedence",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"source": "internal/cli/schema_hints/selection/live.json",
|
||||
"value": [
|
||||
"需要创建/开播/结束直播时不要使用;当前公开面仅列表查询"
|
||||
]
|
||||
},
|
||||
"canonical_path": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "command_registry",
|
||||
"selected": true,
|
||||
"source": "reviewed_command_registry",
|
||||
"source_ref": "live stream list",
|
||||
"value": "live.get_my_lives"
|
||||
}
|
||||
],
|
||||
"precedence": "command_registry",
|
||||
"resolution": "registry_identity",
|
||||
"source": "reviewed_command_registry",
|
||||
"source_ref": "live stream list",
|
||||
"value": "live.get_my_lives"
|
||||
},
|
||||
"confirmation": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "inference_or_default",
|
||||
"selected": true,
|
||||
"source": "risk-default",
|
||||
"value": "not_required"
|
||||
}
|
||||
],
|
||||
"precedence": "inference_or_default",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "risk-default",
|
||||
"value": "not_required"
|
||||
},
|
||||
"description": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "cobra_help",
|
||||
"selected": true,
|
||||
"source": "cobra_help",
|
||||
"value": "查看我的直播列表"
|
||||
},
|
||||
{
|
||||
"precedence": "mcp_metadata",
|
||||
"selected": false,
|
||||
"source": "mcp_metadata",
|
||||
"value": "获取当前用户发起的直播列表,包含每场直播的基础信息与统计数据。返回字段包括:直播标题、封面图 URL、直播 ID、主播昵称、开始/结束时间戳、播放时长(毫秒)、观看量(UV)及直播状态(如已结束)。数据按分页返回,支持判断是否还有更多内容。适用于个人直播管理、历史记录查看等场景,仅展示当前用户有权限访问的直播内容。"
|
||||
}
|
||||
],
|
||||
"precedence": "cobra_help",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "cobra_help",
|
||||
"value": "查看我的直播列表"
|
||||
},
|
||||
"effect": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "inference_or_default",
|
||||
"selected": true,
|
||||
"source": "command-verb",
|
||||
"value": "read"
|
||||
}
|
||||
],
|
||||
"precedence": "inference_or_default",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "command-verb",
|
||||
"value": "read"
|
||||
},
|
||||
"examples": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/selection/live.json",
|
||||
"value": [
|
||||
"dws live stream list"
|
||||
]
|
||||
}
|
||||
],
|
||||
"precedence": "reviewed_explicit",
|
||||
"resolution": "highest_precedence",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"source": "internal/cli/schema_hints/selection/live.json",
|
||||
"value": [
|
||||
"dws live stream list"
|
||||
]
|
||||
},
|
||||
"idempotency": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "inference_or_default",
|
||||
"selected": true,
|
||||
"source": "effect-default",
|
||||
"value": "idempotent"
|
||||
}
|
||||
],
|
||||
"precedence": "inference_or_default",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "effect-default",
|
||||
"value": "idempotent"
|
||||
},
|
||||
"interface_mode": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "dws-tool-metadata/live marks this tool as reviewed",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/metadata/live.json",
|
||||
"value": "mcp"
|
||||
},
|
||||
{
|
||||
"precedence": "mcp_fallback",
|
||||
"selected": false,
|
||||
"source": "internal/cli/schema_mcp_metadata.json#tools.live.get_my_lives.interface_ref",
|
||||
"value": "mcp"
|
||||
}
|
||||
],
|
||||
"precedence": "reviewed_explicit",
|
||||
"resolution": "highest_precedence",
|
||||
"review_reason": "dws-tool-metadata/live marks this tool as reviewed",
|
||||
"source": "internal/cli/schema_hints/metadata/live.json",
|
||||
"value": "mcp"
|
||||
},
|
||||
"interface_ref": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "imported",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/imported/wukong.json",
|
||||
"value": {
|
||||
"product_id": "live",
|
||||
"rpc_name": "get_my_lives"
|
||||
}
|
||||
},
|
||||
{
|
||||
"precedence": "mcp_fallback",
|
||||
"selected": false,
|
||||
"source": "internal/cli/schema_mcp_metadata.json#tools.live.get_my_lives.interface_ref",
|
||||
"value": "live.get_my_lives"
|
||||
}
|
||||
],
|
||||
"precedence": "imported",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "internal/cli/schema_hints/imported/wukong.json",
|
||||
"value": {
|
||||
"product_id": "live",
|
||||
"rpc_name": "get_my_lives"
|
||||
}
|
||||
},
|
||||
"metadata_source": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "derived_resolution",
|
||||
"selected": true,
|
||||
"source": "metadata_source_resolution",
|
||||
"value": "embedded-mcp-metadata"
|
||||
}
|
||||
],
|
||||
"precedence": "derived_resolution",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "metadata_source_resolution",
|
||||
"value": "embedded-mcp-metadata"
|
||||
},
|
||||
"reviewed": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "dws-tool-metadata/live marks this tool as reviewed",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/metadata/live.json",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"selected": false,
|
||||
"source": "internal/cli/schema_hints/selection/live.json",
|
||||
"value": true
|
||||
}
|
||||
],
|
||||
"precedence": "reviewed_explicit",
|
||||
"resolution": "highest_precedence",
|
||||
"review_reason": "dws-tool-metadata/live marks this tool as reviewed",
|
||||
"source": "internal/cli/schema_hints/metadata/live.json",
|
||||
"value": true
|
||||
},
|
||||
"risk": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "inference_or_default",
|
||||
"selected": true,
|
||||
"source": "effect-default",
|
||||
"value": "low"
|
||||
}
|
||||
],
|
||||
"precedence": "inference_or_default",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "effect-default",
|
||||
"value": "low"
|
||||
},
|
||||
"title": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "cobra_help",
|
||||
"selected": true,
|
||||
"source": "cobra_help",
|
||||
"value": "查看我的直播列表"
|
||||
},
|
||||
{
|
||||
"precedence": "mcp_metadata",
|
||||
"selected": false,
|
||||
"source": "mcp_metadata",
|
||||
"value": "获取当前用户发起的直播列表"
|
||||
}
|
||||
],
|
||||
"precedence": "cobra_help",
|
||||
"resolution": "highest_precedence",
|
||||
"source": "cobra_help",
|
||||
"value": "查看我的直播列表"
|
||||
},
|
||||
"use_when": {
|
||||
"candidates": [
|
||||
{
|
||||
"precedence": "reviewed_explicit",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"selected": true,
|
||||
"source": "internal/cli/schema_hints/selection/live.json",
|
||||
"value": [
|
||||
"用户要看自己发起过的直播、状态或观看量等列表信息"
|
||||
]
|
||||
}
|
||||
],
|
||||
"precedence": "reviewed_explicit",
|
||||
"resolution": "highest_precedence",
|
||||
"review_reason": "人工依据实时 dws schema(或 Skill/Cobra/pinned MCP 对照)决策化选型文案与门禁;不改写命令身份与参数契约;示例不含 --yes。",
|
||||
"source": "internal/cli/schema_hints/selection/live.json",
|
||||
"value": [
|
||||
"用户要看自己发起过的直播、状态或观看量等列表信息"
|
||||
]
|
||||
}
|
||||
},
|
||||
"group": "stream",
|
||||
"has_parameters": false,
|
||||
"idempotency": "idempotent",
|
||||
"interface_mode": "mcp",
|
||||
"interface_ref": {
|
||||
"product_id": "live",
|
||||
"rpc_name": "get_my_lives"
|
||||
},
|
||||
"is_alias": false,
|
||||
"metadata_source": "embedded-mcp-metadata",
|
||||
"name": "get_my_lives",
|
||||
"parameter_count": 0,
|
||||
"parameters": {},
|
||||
"path": "live.get_my_lives",
|
||||
"primary_cli_path": "live stream list",
|
||||
"product_id": "live",
|
||||
"reviewed": true,
|
||||
"risk": "low",
|
||||
"source": "reviewed_command_registry",
|
||||
"title": "查看我的直播列表",
|
||||
"use_when": [
|
||||
"用户要看自己发起过的直播、状态或观看量等列表信息"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,373 @@
|
||||
// Copyright 2026 Alibaba Group
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// schema_catalog.json is generated, but every command entry it delivers to
|
||||
// Agents must follow one unified closed structure: a fixed required core plus
|
||||
// a whitelisted optional set. Any new field must be registered here first,
|
||||
// which keeps the delivered command data structure uniform across products.
|
||||
// Command identity (names/paths) is owned by schema_command_registry.json and
|
||||
// is deliberately out of scope for this validator.
|
||||
|
||||
const schemaCatalogStructureMaxViolations = 25
|
||||
|
||||
// schemaCatalogToolRequiredKeys is the required core present on every tool
|
||||
// entry. Keep sorted; ValidateCatalogStructure rejects entries missing any of
|
||||
// these.
|
||||
var schemaCatalogToolRequiredKeys = []string{
|
||||
"agent_metadata_source",
|
||||
"agent_source_refs",
|
||||
"agent_summary",
|
||||
"agent_summary_source",
|
||||
"availability",
|
||||
"avoid_when",
|
||||
"canonical_path",
|
||||
"cli_name",
|
||||
"cli_path",
|
||||
"confirmation",
|
||||
"description",
|
||||
"display",
|
||||
"effect",
|
||||
"effect_source",
|
||||
"examples",
|
||||
"field_provenance",
|
||||
"has_parameters",
|
||||
"idempotency",
|
||||
"interface_mode",
|
||||
"is_alias",
|
||||
"name",
|
||||
"parameter_count",
|
||||
"parameters",
|
||||
"path",
|
||||
"primary_cli_path",
|
||||
"product_id",
|
||||
"reviewed",
|
||||
"risk",
|
||||
"source",
|
||||
"title",
|
||||
"use_when",
|
||||
}
|
||||
|
||||
// schemaCatalogToolOptionalKeys is the optional whitelist. interface_ref and
|
||||
// interface_reason are mutually exclusive and gated by interface_mode.
|
||||
var schemaCatalogToolOptionalKeys = []string{
|
||||
"aliases",
|
||||
"constraints",
|
||||
"dry_run",
|
||||
"group",
|
||||
"interface_reason",
|
||||
"interface_ref",
|
||||
"metadata_source",
|
||||
"positionals",
|
||||
}
|
||||
|
||||
var schemaCatalogToolEnums = map[string][]string{
|
||||
"effect": {"read", "write", "destructive"},
|
||||
"risk": {"low", "medium", "high"},
|
||||
"confirmation": {"not_required", "user_required"},
|
||||
"interface_mode": {InterfaceModeMCP, InterfaceModeComposite, InterfaceModeLocal},
|
||||
"availability": {InterfaceAvailable, InterfaceUnavailable},
|
||||
}
|
||||
|
||||
// schemaCatalogParamRequiredKeys is the required core of every parameter.
|
||||
var schemaCatalogParamRequiredKeys = []string{
|
||||
"description",
|
||||
"field_provenance",
|
||||
"required",
|
||||
"type",
|
||||
}
|
||||
|
||||
// schemaCatalogParamOptionalKeys is the parameter optional whitelist.
|
||||
var schemaCatalogParamOptionalKeys = []string{
|
||||
"cli_required",
|
||||
"default",
|
||||
"enum",
|
||||
"example",
|
||||
"format",
|
||||
"interface_description",
|
||||
"interface_type",
|
||||
"property",
|
||||
"required_when",
|
||||
}
|
||||
|
||||
var schemaCatalogParamTypes = []string{"string", "integer", "number", "boolean", "array", "object"}
|
||||
|
||||
type schemaCatalogStructureViolation struct {
|
||||
tool string
|
||||
message string
|
||||
}
|
||||
|
||||
// ValidateCatalogStructure checks that every tool entry in a schema_catalog
|
||||
// snapshot conforms to the unified command data structure. It returns an
|
||||
// error aggregating up to schemaCatalogStructureMaxViolations violations.
|
||||
func ValidateCatalogStructure(data []byte) error {
|
||||
var snapshot struct {
|
||||
Version int `json:"version"`
|
||||
Tools map[string]map[string]any `json:"tools"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &snapshot); err != nil {
|
||||
return fmt.Errorf("decode schema catalog: %w", err)
|
||||
}
|
||||
if snapshot.Version != SchemaCatalogSnapshotVersion {
|
||||
return fmt.Errorf("schema catalog version = %d, want %d", snapshot.Version, SchemaCatalogSnapshotVersion)
|
||||
}
|
||||
if len(snapshot.Tools) == 0 {
|
||||
return fmt.Errorf("schema catalog has no tools")
|
||||
}
|
||||
|
||||
violations := []schemaCatalogStructureViolation{}
|
||||
for toolID, entry := range snapshot.Tools {
|
||||
validateCatalogToolEntry(toolID, entry, &violations)
|
||||
}
|
||||
if len(violations) == 0 {
|
||||
return nil
|
||||
}
|
||||
sort.Slice(violations, func(i, j int) bool {
|
||||
if violations[i].tool != violations[j].tool {
|
||||
return violations[i].tool < violations[j].tool
|
||||
}
|
||||
return violations[i].message < violations[j].message
|
||||
})
|
||||
var b strings.Builder
|
||||
shown := violations
|
||||
truncated := 0
|
||||
if len(shown) > schemaCatalogStructureMaxViolations {
|
||||
truncated = len(shown) - schemaCatalogStructureMaxViolations
|
||||
shown = shown[:schemaCatalogStructureMaxViolations]
|
||||
}
|
||||
for _, v := range shown {
|
||||
fmt.Fprintf(&b, "\n %s: %s", v.tool, v.message)
|
||||
}
|
||||
if truncated > 0 {
|
||||
fmt.Fprintf(&b, "\n ... and %d more violations", truncated)
|
||||
}
|
||||
return fmt.Errorf("schema catalog entries violate the unified command structure (%d total):%s", len(violations), b.String())
|
||||
}
|
||||
|
||||
func validateCatalogToolEntry(toolID string, entry map[string]any, violations *[]schemaCatalogStructureViolation) {
|
||||
report := func(format string, args ...any) {
|
||||
*violations = append(*violations, schemaCatalogStructureViolation{
|
||||
tool: toolID,
|
||||
message: fmt.Sprintf(format, args...),
|
||||
})
|
||||
}
|
||||
|
||||
allowed := make(map[string]bool, len(schemaCatalogToolRequiredKeys)+len(schemaCatalogToolOptionalKeys))
|
||||
for _, k := range schemaCatalogToolRequiredKeys {
|
||||
allowed[k] = true
|
||||
}
|
||||
for _, k := range schemaCatalogToolOptionalKeys {
|
||||
allowed[k] = true
|
||||
}
|
||||
for key := range entry {
|
||||
if !allowed[key] {
|
||||
report("unknown field %q (register it in schema_catalog_structure.go first)", key)
|
||||
}
|
||||
}
|
||||
|
||||
stringKeys := []string{
|
||||
"agent_metadata_source", "agent_summary", "agent_summary_source",
|
||||
"availability", "canonical_path", "cli_name", "cli_path", "confirmation",
|
||||
"description", "display", "effect", "effect_source", "idempotency",
|
||||
"interface_mode", "name", "path", "primary_cli_path", "product_id",
|
||||
"risk", "source", "title",
|
||||
}
|
||||
for _, key := range stringKeys {
|
||||
if !requireNonEmptyString(entry, key) {
|
||||
report("field %q must be a non-empty string", key)
|
||||
}
|
||||
}
|
||||
stringArrayKeys := []string{"agent_source_refs", "avoid_when", "examples", "use_when"}
|
||||
for _, key := range stringArrayKeys {
|
||||
if !requireStringArray(entry, key) {
|
||||
report("field %q must be an array of strings", key)
|
||||
}
|
||||
}
|
||||
for _, key := range []string{"has_parameters", "is_alias", "reviewed"} {
|
||||
if _, ok := entry[key].(bool); !ok {
|
||||
report("field %q must be a boolean", key)
|
||||
}
|
||||
}
|
||||
if _, ok := entry["field_provenance"].(map[string]any); !ok {
|
||||
report("field %q must be an object", "field_provenance")
|
||||
}
|
||||
for field, values := range schemaCatalogToolEnums {
|
||||
raw, ok := entry[field].(string)
|
||||
if !ok {
|
||||
continue // already reported as missing/typed above
|
||||
}
|
||||
if !stringSliceContains(values, raw) {
|
||||
report("field %q = %q, want one of {%s}", field, raw, strings.Join(values, ", "))
|
||||
}
|
||||
}
|
||||
|
||||
parameters, paramsOK := entry["parameters"].(map[string]any)
|
||||
if !paramsOK {
|
||||
report("field %q must be an object", "parameters")
|
||||
parameters = nil
|
||||
}
|
||||
count, countOK := entry["parameter_count"].(float64)
|
||||
if !countOK {
|
||||
report("field %q must be a number", "parameter_count")
|
||||
} else if paramsOK && int(count) != len(parameters) {
|
||||
report("parameter_count = %d, want %d (len(parameters))", int(count), len(parameters))
|
||||
}
|
||||
if has, ok := entry["has_parameters"].(bool); ok && paramsOK && has != (len(parameters) > 0) {
|
||||
report("has_parameters = %v, want %v (len(parameters) > 0)", has, len(parameters) > 0)
|
||||
}
|
||||
|
||||
validateCatalogInterface(toolID, entry, violations)
|
||||
for paramName, raw := range parameters {
|
||||
param, ok := raw.(map[string]any)
|
||||
if !ok {
|
||||
report("parameter %q must be an object", paramName)
|
||||
continue
|
||||
}
|
||||
validateCatalogParam(toolID, paramName, param, violations)
|
||||
}
|
||||
}
|
||||
|
||||
func validateCatalogInterface(toolID string, entry map[string]any, violations *[]schemaCatalogStructureViolation) {
|
||||
report := func(format string, args ...any) {
|
||||
*violations = append(*violations, schemaCatalogStructureViolation{
|
||||
tool: toolID,
|
||||
message: fmt.Sprintf(format, args...),
|
||||
})
|
||||
}
|
||||
mode, _ := entry["interface_mode"].(string)
|
||||
ref, hasRef := entry["interface_ref"]
|
||||
reason, _ := entry["interface_reason"].(string)
|
||||
switch mode {
|
||||
case InterfaceModeMCP:
|
||||
if !hasRef {
|
||||
report("interface_mode=mcp requires interface_ref")
|
||||
return
|
||||
}
|
||||
refObj, ok := ref.(map[string]any)
|
||||
if !ok {
|
||||
report("interface_ref must be an object")
|
||||
return
|
||||
}
|
||||
for _, key := range []string{"product_id", "rpc_name"} {
|
||||
if s, ok := refObj[key].(string); !ok || strings.TrimSpace(s) == "" {
|
||||
report("interface_ref.%s must be a non-empty string", key)
|
||||
}
|
||||
}
|
||||
if strings.TrimSpace(reason) != "" {
|
||||
report("interface_mode=mcp must not set interface_reason")
|
||||
}
|
||||
case InterfaceModeComposite, InterfaceModeLocal:
|
||||
if hasRef {
|
||||
report("interface_mode=%s must not set interface_ref", mode)
|
||||
}
|
||||
if strings.TrimSpace(reason) == "" {
|
||||
report("interface_mode=%s requires a non-empty interface_reason", mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func validateCatalogParam(toolID, paramName string, param map[string]any, violations *[]schemaCatalogStructureViolation) {
|
||||
report := func(format string, args ...any) {
|
||||
*violations = append(*violations, schemaCatalogStructureViolation{
|
||||
tool: toolID,
|
||||
message: fmt.Sprintf(format, args...),
|
||||
})
|
||||
}
|
||||
|
||||
allowed := make(map[string]bool, len(schemaCatalogParamRequiredKeys)+len(schemaCatalogParamOptionalKeys))
|
||||
for _, k := range schemaCatalogParamRequiredKeys {
|
||||
allowed[k] = true
|
||||
}
|
||||
for _, k := range schemaCatalogParamOptionalKeys {
|
||||
allowed[k] = true
|
||||
}
|
||||
for key := range param {
|
||||
if !allowed[key] {
|
||||
report("parameter %q: unknown field %q", paramName, key)
|
||||
}
|
||||
}
|
||||
|
||||
typ, _ := param["type"].(string)
|
||||
if !stringSliceContains(schemaCatalogParamTypes, typ) {
|
||||
report("parameter %q: type = %q, want one of {%s}", paramName, typ, strings.Join(schemaCatalogParamTypes, ", "))
|
||||
}
|
||||
if s, ok := param["description"].(string); !ok || strings.TrimSpace(s) == "" {
|
||||
report("parameter %q: description must be a non-empty string", paramName)
|
||||
}
|
||||
if _, ok := param["required"].(bool); !ok {
|
||||
report("parameter %q: required must be a boolean", paramName)
|
||||
}
|
||||
if _, ok := param["field_provenance"].(map[string]any); !ok {
|
||||
report("parameter %q: field_provenance must be an object", paramName)
|
||||
}
|
||||
|
||||
for _, key := range []string{"property", "interface_description", "interface_type", "format", "default", "example", "required_when"} {
|
||||
if raw, present := param[key]; present {
|
||||
if _, ok := raw.(string); !ok {
|
||||
report("parameter %q: %s must be a string", paramName, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
if raw, present := param["cli_required"]; present {
|
||||
if _, ok := raw.(bool); !ok {
|
||||
report("parameter %q: cli_required must be a boolean", paramName)
|
||||
}
|
||||
}
|
||||
if raw, present := param["enum"]; present {
|
||||
items, ok := raw.([]any)
|
||||
if !ok {
|
||||
report("parameter %q: enum must be an array", paramName)
|
||||
} else {
|
||||
for i, item := range items {
|
||||
if _, ok := item.(string); !ok {
|
||||
report("parameter %q: enum[%d] must be a string", paramName, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func requireNonEmptyString(entry map[string]any, key string) bool {
|
||||
s, ok := entry[key].(string)
|
||||
return ok && strings.TrimSpace(s) != ""
|
||||
}
|
||||
|
||||
func requireStringArray(entry map[string]any, key string) bool {
|
||||
raw, ok := entry[key].([]any)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
for _, item := range raw {
|
||||
if _, ok := item.(string); !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func stringSliceContains(values []string, target string) bool {
|
||||
for _, v := range values {
|
||||
if v == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
// Copyright 2026 Alibaba Group
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestEmbeddedSchemaCatalogStructure gates the delivered catalog: every tool
|
||||
// entry must conform to the unified closed structure. If this fails after
|
||||
// regeneration, either fix the generator inputs or deliberately extend the
|
||||
// whitelist in schema_catalog_structure.go.
|
||||
func TestEmbeddedSchemaCatalogStructure(t *testing.T) {
|
||||
// After PR #656 the catalog is embedded as per-product shards, not a single
|
||||
// JSON file. The loaded snapshot is the reassembled result — serialize it
|
||||
// back to JSON and validate the same closed structure.
|
||||
loaded := embeddedSchemaCatalog()
|
||||
data, err := json.Marshal(loaded.Snapshot)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal embedded catalog snapshot: %v", err)
|
||||
}
|
||||
if err := ValidateCatalogStructure(data); err != nil {
|
||||
t.Fatalf("embedded schema catalog violates the unified command structure: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func validCatalogToolEntry() map[string]any {
|
||||
return map[string]any{
|
||||
"agent_metadata_source": "embedded-skill-metadata",
|
||||
"agent_source_refs": []any{"skills/mono/references/products/aitable.md"},
|
||||
"agent_summary": "创建多维表格记录",
|
||||
"agent_summary_source": "dws-agent-selection/aitable",
|
||||
"availability": "available",
|
||||
"avoid_when": []any{"批量更新时请用 record update"},
|
||||
"canonical_path": "aitable.record_create",
|
||||
"cli_name": "create",
|
||||
"cli_path": "aitable record create",
|
||||
"confirmation": "not_required",
|
||||
"description": "在数据表中创建一条或多条记录。",
|
||||
"display": "多维表格",
|
||||
"effect": "write",
|
||||
"effect_source": "command-verb",
|
||||
"examples": []any{"dws aitable record create --base-id x"},
|
||||
"field_provenance": map[string]any{"effect": map[string]any{"precedence": "reviewed_explicit"}},
|
||||
"has_parameters": true,
|
||||
"idempotency": "non_idempotent",
|
||||
"interface_mode": "mcp",
|
||||
"interface_ref": map[string]any{"product_id": "aitable", "rpc_name": "create_records"},
|
||||
"is_alias": false,
|
||||
"name": "record create",
|
||||
"parameter_count": float64(1),
|
||||
"parameters": map[string]any{
|
||||
"base-id": map[string]any{
|
||||
"type": "string",
|
||||
"description": "目标多维表格 ID。",
|
||||
"required": true,
|
||||
"field_provenance": map[string]any{"description": map[string]any{"precedence": "reviewed_explicit"}},
|
||||
},
|
||||
},
|
||||
"path": "aitable.record_create",
|
||||
"primary_cli_path": "aitable record create",
|
||||
"product_id": "aitable",
|
||||
"reviewed": true,
|
||||
"risk": "medium",
|
||||
"source": "cobra+registry",
|
||||
"title": "创建记录",
|
||||
"use_when": []any{"需要向多维表格写入新记录时"},
|
||||
}
|
||||
}
|
||||
|
||||
func catalogPayload(t *testing.T, entry map[string]any) []byte {
|
||||
t.Helper()
|
||||
payload, err := json.Marshal(map[string]any{
|
||||
"version": SchemaCatalogSnapshotVersion,
|
||||
"tools": map[string]any{"aitable.record_create": entry},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("marshal payload: %v", err)
|
||||
}
|
||||
return payload
|
||||
}
|
||||
|
||||
func TestValidateCatalogStructureAcceptsValidEntry(t *testing.T) {
|
||||
if err := ValidateCatalogStructure(catalogPayload(t, validCatalogToolEntry())); err != nil {
|
||||
t.Fatalf("ValidateCatalogStructure() error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCatalogStructureRejectsViolations(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
mutate func(entry map[string]any)
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "unknown tool field",
|
||||
mutate: func(e map[string]any) { e["surprise"] = "x" },
|
||||
want: `unknown field "surprise"`,
|
||||
},
|
||||
{
|
||||
name: "missing required core field",
|
||||
mutate: func(e map[string]any) { delete(e, "agent_summary") },
|
||||
want: `"agent_summary" must be a non-empty string`,
|
||||
},
|
||||
{
|
||||
name: "bad effect enum",
|
||||
mutate: func(e map[string]any) { e["effect"] = "mutate" },
|
||||
want: `"effect" = "mutate"`,
|
||||
},
|
||||
{
|
||||
name: "mcp without interface_ref",
|
||||
mutate: func(e map[string]any) { delete(e, "interface_ref") },
|
||||
want: "interface_mode=mcp requires interface_ref",
|
||||
},
|
||||
{
|
||||
name: "composite without interface_reason",
|
||||
mutate: func(e map[string]any) {
|
||||
e["interface_mode"] = "composite"
|
||||
delete(e, "interface_ref")
|
||||
},
|
||||
want: "interface_mode=composite requires a non-empty interface_reason",
|
||||
},
|
||||
{
|
||||
name: "composite must not keep interface_ref",
|
||||
mutate: func(e map[string]any) {
|
||||
e["interface_mode"] = "composite"
|
||||
e["interface_reason"] = "本地组合多个 MCP 调用"
|
||||
},
|
||||
want: "interface_mode=composite must not set interface_ref",
|
||||
},
|
||||
{
|
||||
name: "parameter_count mismatch",
|
||||
mutate: func(e map[string]any) { e["parameter_count"] = float64(2) },
|
||||
want: "parameter_count = 2, want 1",
|
||||
},
|
||||
{
|
||||
name: "has_parameters mismatch",
|
||||
mutate: func(e map[string]any) { e["has_parameters"] = false },
|
||||
want: "has_parameters = false, want true",
|
||||
},
|
||||
{
|
||||
name: "param missing required",
|
||||
mutate: func(e map[string]any) {
|
||||
params := e["parameters"].(map[string]any)
|
||||
delete(params["base-id"].(map[string]any), "required")
|
||||
},
|
||||
want: `parameter "base-id": required must be a boolean`,
|
||||
},
|
||||
{
|
||||
name: "param unknown field",
|
||||
mutate: func(e map[string]any) {
|
||||
params := e["parameters"].(map[string]any)
|
||||
params["base-id"].(map[string]any)["mystery"] = true
|
||||
},
|
||||
want: `parameter "base-id": unknown field "mystery"`,
|
||||
},
|
||||
{
|
||||
name: "param bad type enum",
|
||||
mutate: func(e map[string]any) {
|
||||
params := e["parameters"].(map[string]any)
|
||||
params["base-id"].(map[string]any)["type"] = "text"
|
||||
},
|
||||
want: `parameter "base-id": type = "text"`,
|
||||
},
|
||||
{
|
||||
name: "param default must be string",
|
||||
mutate: func(e map[string]any) {
|
||||
params := e["parameters"].(map[string]any)
|
||||
params["base-id"].(map[string]any)["default"] = float64(3)
|
||||
},
|
||||
want: `parameter "base-id": default must be a string`,
|
||||
},
|
||||
{
|
||||
name: "reviewed must be bool",
|
||||
mutate: func(e map[string]any) { e["reviewed"] = "yes" },
|
||||
want: `"reviewed" must be a boolean`,
|
||||
},
|
||||
{
|
||||
name: "examples must be string array",
|
||||
mutate: func(e map[string]any) { e["examples"] = []any{"ok", float64(1)} },
|
||||
want: `"examples" must be an array of strings`,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
entry := validCatalogToolEntry()
|
||||
tc.mutate(entry)
|
||||
err := ValidateCatalogStructure(catalogPayload(t, entry))
|
||||
if err == nil {
|
||||
t.Fatalf("ValidateCatalogStructure() = nil, want violation containing %q", tc.want)
|
||||
}
|
||||
if !strings.Contains(err.Error(), tc.want) {
|
||||
t.Fatalf("ValidateCatalogStructure() error = %v, want substring %q", err, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCatalogStructureRejectsBadEnvelope(t *testing.T) {
|
||||
if err := ValidateCatalogStructure([]byte(`{"version":99,"tools":{}}`)); err == nil {
|
||||
t.Fatal("ValidateCatalogStructure() = nil, want version error")
|
||||
}
|
||||
if err := ValidateCatalogStructure([]byte(`{"version":1,"tools":{}}`)); err == nil {
|
||||
t.Fatal("ValidateCatalogStructure() = nil, want empty-tools error")
|
||||
}
|
||||
if err := ValidateCatalogStructure([]byte(`not json`)); err == nil {
|
||||
t.Fatal("ValidateCatalogStructure() = nil, want decode error")
|
||||
}
|
||||
}
|
||||
@@ -849,7 +849,13 @@ func TestAssemblerUsesReviewedCommandVisibility(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCommandRegistrySourceValidationIsFailClosed(t *testing.T) {
|
||||
registry, err := ValidateCommandRegistrySource(embeddedSchemaCommandRegistryJSON)
|
||||
// After splitting registry into per-product shards, tests use the merged
|
||||
// JSON (reassembled from shards) for byte-level operations.
|
||||
merged, err := EmbeddedCommandRegistryMergedJSON()
|
||||
if err != nil {
|
||||
t.Fatalf("EmbeddedCommandRegistryMergedJSON() error = %v", err)
|
||||
}
|
||||
registry, err := ValidateCommandRegistrySource(merged)
|
||||
if err != nil {
|
||||
t.Fatalf("ValidateCommandRegistrySource(embedded) error = %v", err)
|
||||
}
|
||||
@@ -861,8 +867,9 @@ func TestCommandRegistrySourceValidationIsFailClosed(t *testing.T) {
|
||||
t.Fatalf("embedded hash = %q, decoded hash = %q", hash, registry.SourceHash())
|
||||
}
|
||||
|
||||
drifted := strings.Replace(string(embeddedSchemaCommandRegistryJSON), `"cli_path": "aisearch person"`, `"cli_path": "aisearch people"`, 1)
|
||||
if drifted == string(embeddedSchemaCommandRegistryJSON) {
|
||||
// Match both pretty-printed ("cli_path": "...") and compact ("cli_path":"...") JSON.
|
||||
drifted := strings.Replace(string(merged), `"aisearch person"`, `"aisearch people"`, 1)
|
||||
if drifted == string(merged) {
|
||||
t.Fatal("test fixture did not mutate embedded registry")
|
||||
}
|
||||
_, err = ValidateCommandRegistrySource([]byte(drifted))
|
||||
@@ -870,7 +877,12 @@ func TestCommandRegistrySourceValidationIsFailClosed(t *testing.T) {
|
||||
t.Fatalf("drift error = %v", err)
|
||||
}
|
||||
|
||||
unknownField := strings.Replace(string(embeddedSchemaCommandRegistryJSON), `"version": 1`, `"version": 1, "unreviewed": true`, 1)
|
||||
// Test unknown-field rejection: inject an unrecognized top-level key.
|
||||
unknownField := strings.Replace(string(merged), `"version":1`, `"version":1,"unreviewed":true`, 1)
|
||||
if unknownField == string(merged) {
|
||||
// Try with space (pretty-printed format).
|
||||
unknownField = strings.Replace(string(merged), `"version": 1`, `"version": 1, "unreviewed": true`, 1)
|
||||
}
|
||||
_, err = ValidateCommandRegistrySource([]byte(unknownField))
|
||||
if err == nil || !strings.Contains(err.Error(), "unknown field") {
|
||||
t.Fatalf("unknown-field error = %v", err)
|
||||
|
||||
@@ -6,7 +6,7 @@ package cli
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
_ "embed"
|
||||
"embed"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -25,8 +25,11 @@ const commandRegistrySchemaRef = "./schema_command_registry.schema.json"
|
||||
// sole source of stable command identity and navigation. Catalog and generated
|
||||
// metadata are downstream views and must never be read back here.
|
||||
|
||||
//go:embed schema_command_registry.json
|
||||
var embeddedSchemaCommandRegistryJSON []byte
|
||||
//go:embed schema_command_registry/registry.json
|
||||
var embeddedSchemaCommandRegistryEnvelopeJSON []byte
|
||||
|
||||
//go:embed schema_command_registry/products
|
||||
var embeddedSchemaCommandRegistryProducts embed.FS
|
||||
|
||||
//go:embed schema_command_registry.schema.json
|
||||
var embeddedSchemaCommandRegistrySchemaJSON []byte
|
||||
@@ -96,11 +99,99 @@ var (
|
||||
|
||||
func loadEmbeddedCommandRegistry() (CommandRegistry, error) {
|
||||
embeddedSchemaCommandRegistryOnce.Do(func() {
|
||||
embeddedSchemaCommandRegistryData, embeddedSchemaCommandRegistryErr = decodeCommandRegistry(embeddedSchemaCommandRegistryJSON)
|
||||
embeddedSchemaCommandRegistryData, embeddedSchemaCommandRegistryErr = assembleCommandRegistry()
|
||||
})
|
||||
return cloneCommandRegistry(embeddedSchemaCommandRegistryData), embeddedSchemaCommandRegistryErr
|
||||
}
|
||||
|
||||
// assembleCommandRegistry reads the per-product shards embedded at build time
|
||||
// and reassembles them into a single CommandRegistry, identical to the previous
|
||||
// single-file layout. Mirrors assembleEmbeddedSchemaCatalog for catalog shards.
|
||||
func assembleCommandRegistry() (CommandRegistry, error) {
|
||||
var envelope struct {
|
||||
Schema string `json:"$schema,omitempty"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
if err := json.Unmarshal(embeddedSchemaCommandRegistryEnvelopeJSON, &envelope); err != nil {
|
||||
return CommandRegistry{}, fmt.Errorf("decode embedded command registry envelope: %w", err)
|
||||
}
|
||||
|
||||
entries, err := embeddedSchemaCommandRegistryProducts.ReadDir("schema_command_registry/products")
|
||||
if err != nil {
|
||||
return CommandRegistry{}, fmt.Errorf("read embedded command registry products: %w", err)
|
||||
}
|
||||
|
||||
var snapshot schemaCommandRegistrySnapshot
|
||||
snapshot.Schema = envelope.Schema
|
||||
snapshot.Version = envelope.Version
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".json") {
|
||||
continue
|
||||
}
|
||||
data, readErr := embeddedSchemaCommandRegistryProducts.ReadFile("schema_command_registry/products/" + entry.Name())
|
||||
if readErr != nil {
|
||||
return CommandRegistry{}, fmt.Errorf("read embedded command registry shard %s: %w", entry.Name(), readErr)
|
||||
}
|
||||
var product schemaCommandRegistryProduct
|
||||
if err := json.Unmarshal(data, &product); err != nil {
|
||||
return CommandRegistry{}, fmt.Errorf("decode embedded command registry shard %s: %w", entry.Name(), err)
|
||||
}
|
||||
snapshot.Products = append(snapshot.Products, product)
|
||||
}
|
||||
|
||||
// Encode to bytes and decode via the existing pipeline so all validation
|
||||
// (canonical patterns, duplicate detection, visibility) runs identically.
|
||||
data, err := json.Marshal(snapshot)
|
||||
if err != nil {
|
||||
return CommandRegistry{}, fmt.Errorf("marshal reassembled command registry: %w", err)
|
||||
}
|
||||
return decodeCommandRegistry(data)
|
||||
}
|
||||
|
||||
// EmbeddedCommandRegistryMergedJSON returns the per-product shards reassembled
|
||||
// into a single JSON document matching the pre-split layout. Used by tests that
|
||||
// need the full registry bytes.
|
||||
func EmbeddedCommandRegistryMergedJSON() ([]byte, error) {
|
||||
var envelope struct {
|
||||
Schema string `json:"$schema,omitempty"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
if err := json.Unmarshal(embeddedSchemaCommandRegistryEnvelopeJSON, &envelope); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
entries, err := embeddedSchemaCommandRegistryProducts.ReadDir("schema_command_registry/products")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
products := make([]json.RawMessage, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".json") {
|
||||
continue
|
||||
}
|
||||
data, err := embeddedSchemaCommandRegistryProducts.ReadFile("schema_command_registry/products/" + entry.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
products = append(products, json.RawMessage(data))
|
||||
}
|
||||
result := struct {
|
||||
Schema string `json:"$schema,omitempty"`
|
||||
Version int `json:"version"`
|
||||
Products json.RawMessage `json:"products"`
|
||||
}{
|
||||
Schema: envelope.Schema,
|
||||
Version: envelope.Version,
|
||||
}
|
||||
if result.Schema == "" {
|
||||
result.Schema = "./schema_command_registry.schema.json"
|
||||
}
|
||||
result.Products, err = json.Marshal(products)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(result)
|
||||
}
|
||||
|
||||
// ValidateCommandRegistrySource validates a compatibility --surface input and
|
||||
// requires it to be semantically identical to the embedded reviewed registry.
|
||||
// Generators may retain the flag for migration, but cannot use it to introduce
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"id": "aisearch",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "aisearch.search_enterprise_behavior",
|
||||
"cli_path": "aisearch behavior"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aisearch.search_enterprise",
|
||||
"cli_path": "aisearch enterprise"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aisearch.enterprise_person_search",
|
||||
"cli_path": "aisearch person"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,472 @@
|
||||
{
|
||||
"id": "aitable",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "aitable.advperm_disable",
|
||||
"cli_path": "aitable advperm disable"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.advperm_enable",
|
||||
"cli_path": "aitable advperm enable"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.advperm_role_create",
|
||||
"cli_path": "aitable advperm role-create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.advperm_role_delete",
|
||||
"cli_path": "aitable advperm role-delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.advperm_role_get",
|
||||
"cli_path": "aitable advperm role-get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.advperm_role_list",
|
||||
"cli_path": "aitable advperm role-list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.advperm_role_update",
|
||||
"cli_path": "aitable advperm role-update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.attachment_upload",
|
||||
"cli_path": "aitable attachment upload"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.base_copy",
|
||||
"cli_path": "aitable base copy"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.base_create",
|
||||
"cli_path": "aitable base create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.base_delete",
|
||||
"cli_path": "aitable base delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.base_get",
|
||||
"cli_path": "aitable base get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.base_get_primary_doc_id",
|
||||
"cli_path": "aitable base get-primary-doc-id"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.base_list",
|
||||
"cli_path": "aitable base list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.base_search",
|
||||
"cli_path": "aitable base search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.base_update",
|
||||
"cli_path": "aitable base update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.chart_create",
|
||||
"cli_path": "aitable chart create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.chart_delete",
|
||||
"cli_path": "aitable chart delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.chart_get",
|
||||
"cli_path": "aitable chart get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.chart_share_get",
|
||||
"cli_path": "aitable chart share get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.chart_share_update",
|
||||
"cli_path": "aitable chart share update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.chart_update",
|
||||
"cli_path": "aitable chart update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.chart_widgets_example",
|
||||
"cli_path": "aitable chart widgets-example"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.create",
|
||||
"cli_path": "aitable create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.dashboard_arrange",
|
||||
"cli_path": "aitable dashboard arrange"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.dashboard_config_example",
|
||||
"cli_path": "aitable dashboard config-example"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.dashboard_create",
|
||||
"cli_path": "aitable dashboard create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.dashboard_delete",
|
||||
"cli_path": "aitable dashboard delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.dashboard_get",
|
||||
"cli_path": "aitable dashboard get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.dashboard_share_get",
|
||||
"cli_path": "aitable dashboard share get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.dashboard_share_update",
|
||||
"cli_path": "aitable dashboard share update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.dashboard_update",
|
||||
"cli_path": "aitable dashboard update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.export_data",
|
||||
"cli_path": "aitable export data"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.field_create",
|
||||
"cli_path": "aitable field create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.field_delete",
|
||||
"cli_path": "aitable field delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.field_get",
|
||||
"cli_path": "aitable field get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.field_list",
|
||||
"cli_path": "aitable field list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.field_search_options",
|
||||
"cli_path": "aitable field search-options"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.field_update",
|
||||
"cli_path": "aitable field update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.form_create",
|
||||
"cli_path": "aitable form create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.form_delete",
|
||||
"cli_path": "aitable form delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.form_field_hide",
|
||||
"cli_path": "aitable form field hide"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.form_field_list",
|
||||
"cli_path": "aitable form field list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.form_field_update",
|
||||
"cli_path": "aitable form field update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.form_get",
|
||||
"cli_path": "aitable form get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.form_list",
|
||||
"cli_path": "aitable form list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.form_questions_create",
|
||||
"cli_path": "aitable form questions create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.form_questions_delete",
|
||||
"cli_path": "aitable form questions delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.form_share_get",
|
||||
"cli_path": "aitable form share get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.form_share_update",
|
||||
"cli_path": "aitable form share update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.form_update",
|
||||
"cli_path": "aitable form update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.import_data",
|
||||
"cli_path": "aitable import data"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.import_upload",
|
||||
"cli_path": "aitable import upload"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.info",
|
||||
"cli_path": "aitable info"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.list",
|
||||
"cli_path": "aitable list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.record_batch_update",
|
||||
"cli_path": "aitable record batch-update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.record_create",
|
||||
"cli_path": "aitable record create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.record_delete",
|
||||
"cli_path": "aitable record delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.record_get",
|
||||
"cli_path": "aitable record get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.record_history_list",
|
||||
"cli_path": "aitable record history-list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.record_primary_doc_create",
|
||||
"cli_path": "aitable record primary-doc-create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.record_primary_doc_get",
|
||||
"cli_path": "aitable record primary-doc-get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.query_records",
|
||||
"cli_path": "aitable record query",
|
||||
"aliases": [
|
||||
"aitable record list"
|
||||
]
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.record_query_empty",
|
||||
"cli_path": "aitable record query-empty"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.record_share_url",
|
||||
"cli_path": "aitable record share-url"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.record_update",
|
||||
"cli_path": "aitable record update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.record_upsert",
|
||||
"cli_path": "aitable record upsert"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.search",
|
||||
"cli_path": "aitable search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.section_create",
|
||||
"cli_path": "aitable section create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.section_delete",
|
||||
"cli_path": "aitable section delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.section_list_empty",
|
||||
"cli_path": "aitable section list-empty"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.section_list_nodes",
|
||||
"cli_path": "aitable section list-nodes"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.section_move_node",
|
||||
"cli_path": "aitable section move-node"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.section_rename",
|
||||
"cli_path": "aitable section rename"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.section_reorder",
|
||||
"cli_path": "aitable section reorder"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.table_create",
|
||||
"cli_path": "aitable table create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.table_delete",
|
||||
"cli_path": "aitable table delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.table_get",
|
||||
"cli_path": "aitable table get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.table_list",
|
||||
"cli_path": "aitable table list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.table_update",
|
||||
"cli_path": "aitable table update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.template_search",
|
||||
"cli_path": "aitable template search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_create",
|
||||
"cli_path": "aitable view create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_delete",
|
||||
"cli_path": "aitable view delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_duplicate",
|
||||
"cli_path": "aitable view duplicate"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_get_aggregate",
|
||||
"cli_path": "aitable view get aggregate"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_get_card",
|
||||
"cli_path": "aitable view get card"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_get_field_widths",
|
||||
"cli_path": "aitable view get field-widths"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_get_fill_color_rule",
|
||||
"cli_path": "aitable view get fill-color-rule"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_get_filter",
|
||||
"cli_path": "aitable view get filter"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_get_frozen_cols",
|
||||
"cli_path": "aitable view get frozen-cols"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_get_group",
|
||||
"cli_path": "aitable view get group"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_get_lock",
|
||||
"cli_path": "aitable view get lock"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_get_row_height",
|
||||
"cli_path": "aitable view get row-height"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_get_sort",
|
||||
"cli_path": "aitable view get sort"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_get_timebar",
|
||||
"cli_path": "aitable view get timebar"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_get_visible_fields",
|
||||
"cli_path": "aitable view get visible-fields"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_list",
|
||||
"cli_path": "aitable view list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_lock",
|
||||
"cli_path": "aitable view lock"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_update_aggregate",
|
||||
"cli_path": "aitable view update aggregate"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_update_card",
|
||||
"cli_path": "aitable view update card"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_update_field_widths",
|
||||
"cli_path": "aitable view update field-widths"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_update_fill_color_rule",
|
||||
"cli_path": "aitable view update fill-color-rule"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_update_filter",
|
||||
"cli_path": "aitable view update filter"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_update_frozen_cols",
|
||||
"cli_path": "aitable view update frozen-cols"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_update_group",
|
||||
"cli_path": "aitable view update group"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_update_name",
|
||||
"cli_path": "aitable view update name"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_update_row_height",
|
||||
"cli_path": "aitable view update row-height"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_update_sort",
|
||||
"cli_path": "aitable view update sort"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_update_timebar",
|
||||
"cli_path": "aitable view update timebar"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.view_update_visible_fields",
|
||||
"cli_path": "aitable view update visible-fields"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.workflow_create",
|
||||
"cli_path": "aitable workflow create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.workflow_disable",
|
||||
"cli_path": "aitable workflow disable"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.workflow_enable",
|
||||
"cli_path": "aitable workflow enable"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.workflow_get",
|
||||
"cli_path": "aitable workflow get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.workflow_list",
|
||||
"cli_path": "aitable workflow list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "aitable.workflow_update",
|
||||
"cli_path": "aitable workflow update"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
{
|
||||
"id": "attendance",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "attendance.adjustment_get",
|
||||
"cli_path": "attendance adjustment get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.adjustment_search",
|
||||
"cli_path": "attendance adjustment search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.approve_list",
|
||||
"cli_path": "attendance approve list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.approve_templates",
|
||||
"cli_path": "attendance approve templates"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.boss_check",
|
||||
"cli_path": "attendance boss-check"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.check_record",
|
||||
"cli_path": "attendance check record"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.check_result",
|
||||
"cli_path": "attendance check result"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.checkin_records",
|
||||
"cli_path": "attendance checkin records"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.class_create",
|
||||
"cli_path": "attendance class create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.class_get",
|
||||
"cli_path": "attendance class get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.class_search",
|
||||
"cli_path": "attendance class search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.class_update",
|
||||
"cli_path": "attendance class update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.globalsetting_get",
|
||||
"cli_path": "attendance globalsetting get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.globalsetting_save",
|
||||
"cli_path": "attendance globalsetting save"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.group_create",
|
||||
"cli_path": "attendance group create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.group_filtered_get",
|
||||
"cli_path": "attendance group filtered-get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.group_get",
|
||||
"cli_path": "attendance group get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.group_search",
|
||||
"cli_path": "attendance group search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.group_update",
|
||||
"cli_path": "attendance group update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.group_update_members",
|
||||
"cli_path": "attendance group update-members"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.overtime_get",
|
||||
"cli_path": "attendance overtime get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.overtime_search",
|
||||
"cli_path": "attendance overtime search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.get_user_attendance_record",
|
||||
"cli_path": "attendance record get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.report_columns",
|
||||
"cli_path": "attendance report columns"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.report_query_data",
|
||||
"cli_path": "attendance report query-data"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.report_query_leave",
|
||||
"cli_path": "attendance report query-leave"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.query_attendance_group_or_rules",
|
||||
"cli_path": "attendance rules"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.schedule_get",
|
||||
"cli_path": "attendance schedule get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.schedule_import",
|
||||
"cli_path": "attendance schedule import"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.selfsetting_get",
|
||||
"cli_path": "attendance selfsetting get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.selfsetting_save",
|
||||
"cli_path": "attendance selfsetting save"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.batch_get_employee_shifts",
|
||||
"cli_path": "attendance shift list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.get_attendance_summary",
|
||||
"cli_path": "attendance summary"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.vacation_balance",
|
||||
"cli_path": "attendance vacation balance"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.vacation_records",
|
||||
"cli_path": "attendance vacation records"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.vacation_save_balance",
|
||||
"cli_path": "attendance vacation save-balance"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.vacation_types",
|
||||
"cli_path": "attendance vacation types"
|
||||
},
|
||||
{
|
||||
"canonical_path": "attendance.vacation_update_type",
|
||||
"cli_path": "attendance vacation update-type"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"id": "audit",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "audit.export",
|
||||
"cli_path": "audit export"
|
||||
},
|
||||
{
|
||||
"canonical_path": "audit.tail",
|
||||
"cli_path": "audit tail"
|
||||
},
|
||||
{
|
||||
"canonical_path": "audit.verify",
|
||||
"cli_path": "audit verify"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"id": "calendar",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "calendar.list_acls",
|
||||
"cli_path": "calendar acl list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.add_attachments",
|
||||
"cli_path": "calendar attachment add"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.add_calendar_participant",
|
||||
"cli_path": "calendar attendee add"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.remove_calendar_participant",
|
||||
"cli_path": "calendar attendee delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.get_calendar_participants",
|
||||
"cli_path": "calendar attendee list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.get_calendar",
|
||||
"cli_path": "calendar book get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.list_calendars",
|
||||
"cli_path": "calendar book list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.search_calendar",
|
||||
"cli_path": "calendar book search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.query_busy_status",
|
||||
"cli_path": "calendar busy search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.create_calendar_event",
|
||||
"cli_path": "calendar event create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.delete_calendar_event",
|
||||
"cli_path": "calendar event delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.get_calendar_detail",
|
||||
"cli_path": "calendar event get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.list_calendar_events",
|
||||
"cli_path": "calendar event list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.respond",
|
||||
"cli_path": "calendar event respond"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.list_suggested_event_times",
|
||||
"cli_path": "calendar event suggest"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.update_calendar_event",
|
||||
"cli_path": "calendar event update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.add_meeting_room",
|
||||
"cli_path": "calendar room add"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.delete_meeting_room",
|
||||
"cli_path": "calendar room delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.list_meeting_room_groups",
|
||||
"cli_path": "calendar room list-groups"
|
||||
},
|
||||
{
|
||||
"canonical_path": "calendar.query_available_meeting_room",
|
||||
"cli_path": "calendar room search"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
{
|
||||
"id": "chat",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "chat.search_bots",
|
||||
"cli_path": "chat bot find"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.search_my_robots",
|
||||
"cli_path": "chat bot search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.create_smart_conv_category",
|
||||
"cli_path": "chat category create-smart"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.list_user_define_conv_categories",
|
||||
"cli_path": "chat category list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.list_conversations_by_category",
|
||||
"cli_path": "chat category list-conversations"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.get_conversation_info",
|
||||
"cli_path": "chat conversation-info"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.list_group_bots",
|
||||
"cli_path": "chat group bots"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.create_group_conversation",
|
||||
"cli_path": "chat group create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.dismiss_group",
|
||||
"cli_path": "chat group dismiss"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.get_conv_info_by_group_id",
|
||||
"cli_path": "chat group get-by-group-id"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.get_group_invite_url",
|
||||
"cli_path": "chat group invite-url"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.list_owned_or_admin_groups",
|
||||
"cli_path": "chat group list-my-groups"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.add_group_member",
|
||||
"cli_path": "chat group members add"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.add_robot_to_group",
|
||||
"cli_path": "chat group members add-bot"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.remove_group_member",
|
||||
"cli_path": "chat group members remove"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.remove_robot_in_group",
|
||||
"cli_path": "chat group members remove-bot"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.quit_group",
|
||||
"cli_path": "chat group quit"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.update_group_name",
|
||||
"cli_path": "chat group rename"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.update_conv_member_roles",
|
||||
"cli_path": "chat group set-admin"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.update_show_history_msg_option",
|
||||
"cli_path": "chat group set-history"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.transfer_group_owner",
|
||||
"cli_path": "chat group transfer-owner"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.update_group_icon",
|
||||
"cli_path": "chat group update-icon"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.update_group_settings",
|
||||
"cli_path": "chat group update-settings"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.set_group_mute",
|
||||
"cli_path": "chat group-mute"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.set_group_member_mute_list",
|
||||
"cli_path": "chat group-mute-member"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.add_custom_group_role",
|
||||
"cli_path": "chat group-role add"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.list_custom_group_roles",
|
||||
"cli_path": "chat group-role list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.query_custom_user_roles",
|
||||
"cli_path": "chat group-role query-user"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.remove_custom_group_role",
|
||||
"cli_path": "chat group-role remove"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.remove_custom_user_roles",
|
||||
"cli_path": "chat group-role remove-user"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.set_custom_user_roles",
|
||||
"cli_path": "chat group-role set-user"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.update_custom_group_role",
|
||||
"cli_path": "chat group-role update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.list_top_conversations",
|
||||
"cli_path": "chat list-top-conversations"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.add_emoji_reaction",
|
||||
"cli_path": "chat message add-emoji"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.add_message_favorite",
|
||||
"cli_path": "chat message add-favorite"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.add_text_emotion",
|
||||
"cli_path": "chat message add-text-emotion"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.combine_forward_messages",
|
||||
"cli_path": "chat message combine-forward"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.create_text_emotion",
|
||||
"cli_path": "chat message create-text-emotion"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.download_media",
|
||||
"cli_path": "chat message download-media"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.forward_message",
|
||||
"cli_path": "chat message forward"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.forward_topic",
|
||||
"cli_path": "chat message forward-topic"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.list_conversation_message_v2",
|
||||
"cli_path": "chat message list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.search_messages_by_time_range",
|
||||
"cli_path": "chat message list-all"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.list_messages_by_ids",
|
||||
"cli_path": "chat message list-by-ids"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.search_messages_by_sender",
|
||||
"cli_path": "chat message list-by-sender"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.list_individual_chat_message",
|
||||
"cli_path": "chat message list-direct"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.list_message_favorites",
|
||||
"cli_path": "chat message list-favorites"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.list_special_focus_messages",
|
||||
"cli_path": "chat message list-focused"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.search_at_me_message",
|
||||
"cli_path": "chat message list-mentions"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.list_pin_messages",
|
||||
"cli_path": "chat message list-pin-msg"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.list_topic_replies",
|
||||
"cli_path": "chat message list-topic-replies"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.unread_message_conversation_list",
|
||||
"cli_path": "chat message list-unread-conversations"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.query_message_send_status",
|
||||
"cli_path": "chat message query-send-status"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.query_msg_read_status",
|
||||
"cli_path": "chat message read-status"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.recall_message",
|
||||
"cli_path": "chat message recall"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.recall_robot_message",
|
||||
"cli_path": "chat message recall-by-bot"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.remove_emoji_reaction",
|
||||
"cli_path": "chat message remove-emoji"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.remove_message_favorite",
|
||||
"cli_path": "chat message remove-favorite"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.remove_text_emotion",
|
||||
"cli_path": "chat message remove-text-emotion"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.reply_personal_message",
|
||||
"cli_path": "chat message reply"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.search_messages_by_keyword",
|
||||
"cli_path": "chat message search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.search_messages",
|
||||
"cli_path": "chat message search-advanced"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.send_personal_message",
|
||||
"cli_path": "chat message send"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.send_robot_message",
|
||||
"cli_path": "chat message send-by-bot"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.send_message_by_custom_robot",
|
||||
"cli_path": "chat message send-by-webhook"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.create_and_send_card",
|
||||
"cli_path": "chat message send-card"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.set_pin_message",
|
||||
"cli_path": "chat message set-pin-msg"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.unset_pin_message",
|
||||
"cli_path": "chat message unset-pin-msg"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.update_streaming_card",
|
||||
"cli_path": "chat message update-card"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.update_notification_off",
|
||||
"cli_path": "chat mute"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.search_groups",
|
||||
"cli_path": "chat search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.search_common_groups",
|
||||
"cli_path": "chat search-common"
|
||||
},
|
||||
{
|
||||
"canonical_path": "chat.set_top_conversation",
|
||||
"cli_path": "chat set-top"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"id": "contact",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "contact.add_employee",
|
||||
"cli_path": "contact user invite"
|
||||
},
|
||||
{
|
||||
"canonical_path": "contact.exclusive_account_create",
|
||||
"cli_path": "contact account create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "contact.get_dept_info_by_dept_id",
|
||||
"cli_path": "contact dept get-info"
|
||||
},
|
||||
{
|
||||
"canonical_path": "contact.get_sub_depts_by_dept_id",
|
||||
"cli_path": "contact dept list-children"
|
||||
},
|
||||
{
|
||||
"canonical_path": "contact.get_dept_members_by_deptId",
|
||||
"cli_path": "contact dept list-members"
|
||||
},
|
||||
{
|
||||
"canonical_path": "contact.search_dept_by_keyword",
|
||||
"cli_path": "contact dept search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "contact.list_my_followings",
|
||||
"cli_path": "contact relation list-my-followings"
|
||||
},
|
||||
{
|
||||
"canonical_path": "contact.org_create",
|
||||
"cli_path": "contact org create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "contact.query_dismission_employee_list",
|
||||
"cli_path": "contact user dismission search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "contact.get_user_info_by_user_ids",
|
||||
"cli_path": "contact user get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "contact.get_current_user_profile",
|
||||
"cli_path": "contact user get-self"
|
||||
},
|
||||
{
|
||||
"canonical_path": "contact.list_authorized_roster_fields",
|
||||
"cli_path": "contact user profile fields"
|
||||
},
|
||||
{
|
||||
"canonical_path": "contact.get_authorized_emp_rosterInfo",
|
||||
"cli_path": "contact user profile get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "contact.search_contact_by_key_word",
|
||||
"cli_path": "contact user search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "contact.search_user_by_mobile",
|
||||
"cli_path": "contact user search-mobile"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
{
|
||||
"id": "dev",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "dev.create_dev_app",
|
||||
"cli_path": "dev app create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.get_dev_app_credentials",
|
||||
"cli_path": "dev app credentials get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.delete_dev_app",
|
||||
"cli_path": "dev app delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.disable_dev_app",
|
||||
"cli_path": "dev app disable"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.enable_dev_app",
|
||||
"cli_path": "dev app enable"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.list_dev_app_events",
|
||||
"cli_path": "dev app event list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.subscribe_dev_app_events",
|
||||
"cli_path": "dev app event subscribe"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.unsubscribe_dev_app_events",
|
||||
"cli_path": "dev app event unsubscribe"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.get_dev_app",
|
||||
"cli_path": "dev app get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.list_dev_app",
|
||||
"cli_path": "dev app list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.add_dev_app_members",
|
||||
"cli_path": "dev app member add"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.list_dev_app_members",
|
||||
"cli_path": "dev app member list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.remove_dev_app_members",
|
||||
"cli_path": "dev app member remove"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.apply_dev_app_permissions",
|
||||
"cli_path": "dev app permission add"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.list_dev_app_permissions",
|
||||
"cli_path": "dev app permission list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.remove_dev_app_permissions",
|
||||
"cli_path": "dev app permission remove"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.set_extension_robot_config",
|
||||
"cli_path": "dev app robot config"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.disable_dev_app_robot",
|
||||
"cli_path": "dev app robot disable"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.enable_dev_app_robot",
|
||||
"cli_path": "dev app robot enable"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.get_extension_robot_config",
|
||||
"cli_path": "dev app robot get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.query_robot_create_result",
|
||||
"cli_path": "dev app robot result"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.submit_robot_create_task",
|
||||
"cli_path": "dev app robot submit"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.update_dev_app_security_config",
|
||||
"cli_path": "dev app security config"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.update_dev_app",
|
||||
"cli_path": "dev app update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.create_dev_app_version",
|
||||
"cli_path": "dev app version create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.get_dev_app_version_detail",
|
||||
"cli_path": "dev app version get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.list_dev_app_versions",
|
||||
"cli_path": "dev app version list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.publish_dev_app_version",
|
||||
"cli_path": "dev app version publish"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.get_dev_app_version_status",
|
||||
"cli_path": "dev app version status"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.set_extension_webapp_config",
|
||||
"cli_path": "dev app webapp config"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.get_extension_webapp_config",
|
||||
"cli_path": "dev app webapp get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.connect_status",
|
||||
"cli_path": "dev connect status"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.connect_stop",
|
||||
"cli_path": "dev connect stop"
|
||||
},
|
||||
{
|
||||
"canonical_path": "dev.search_open_platform_docs_rag",
|
||||
"cli_path": "dev doc search"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"id": "devdoc",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "devdoc.search_open_platform_docs_rag",
|
||||
"cli_path": "devdoc article search"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"id": "ding",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "ding.recall_ding_message",
|
||||
"cli_path": "ding message recall"
|
||||
},
|
||||
{
|
||||
"canonical_path": "ding.send_ding_message",
|
||||
"cli_path": "ding message send"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
{
|
||||
"id": "doc",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "doc.delete_document_block",
|
||||
"cli_path": "doc block delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.insert_document_block",
|
||||
"cli_path": "doc block insert"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.list_document_blocks",
|
||||
"cli_path": "doc block list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.update_document_block",
|
||||
"cli_path": "doc block update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.create_comment",
|
||||
"cli_path": "doc comment create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.create_inline_comment",
|
||||
"cli_path": "doc comment create-inline"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.delete_comment",
|
||||
"cli_path": "doc comment delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.list_comments",
|
||||
"cli_path": "doc comment list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.reply_comment",
|
||||
"cli_path": "doc comment reply"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.update_comment",
|
||||
"cli_path": "doc comment update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.copy_document",
|
||||
"cli_path": "doc copy"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.create_document",
|
||||
"cli_path": "doc create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.delete_document",
|
||||
"cli_path": "doc delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.download_file",
|
||||
"cli_path": "doc download"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.query_export_job",
|
||||
"cli_path": "doc export get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.create_file",
|
||||
"cli_path": "doc file create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.create_folder",
|
||||
"cli_path": "doc folder create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.import_get",
|
||||
"cli_path": "doc import get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.get_document_info",
|
||||
"cli_path": "doc info"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.list_nodes",
|
||||
"cli_path": "doc list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.download_doc_attachment",
|
||||
"cli_path": "doc media download"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.media_insert",
|
||||
"cli_path": "doc media insert"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.move_document",
|
||||
"cli_path": "doc move"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.add_permission",
|
||||
"cli_path": "doc permission add"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.list_permission",
|
||||
"cli_path": "doc permission list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.remove_permission",
|
||||
"cli_path": "doc permission remove"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.update_permission",
|
||||
"cli_path": "doc permission update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.get_document_content",
|
||||
"cli_path": "doc read"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.rename_document",
|
||||
"cli_path": "doc rename"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.search_documents",
|
||||
"cli_path": "doc search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.template_apply",
|
||||
"cli_path": "doc template apply"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.template_list",
|
||||
"cli_path": "doc template list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.template_search",
|
||||
"cli_path": "doc template search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.update_document",
|
||||
"cli_path": "doc update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.upload",
|
||||
"cli_path": "doc upload"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.version_list",
|
||||
"cli_path": "doc version list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.version_revert",
|
||||
"cli_path": "doc version revert"
|
||||
},
|
||||
{
|
||||
"canonical_path": "doc.version_save",
|
||||
"cli_path": "doc version save"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
{
|
||||
"id": "drive",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "drive.commit_upload",
|
||||
"cli_path": "drive commit"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.copy_document",
|
||||
"cli_path": "drive copy"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.delete_document",
|
||||
"cli_path": "drive delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.download_file",
|
||||
"cli_path": "drive download"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.get_file_info",
|
||||
"cli_path": "drive info"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.list_files",
|
||||
"cli_path": "drive list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.list_spaces",
|
||||
"cli_path": "drive list-spaces"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.create_folder",
|
||||
"cli_path": "drive mkdir"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.move_document",
|
||||
"cli_path": "drive move"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.add_permission",
|
||||
"cli_path": "drive permission add"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.list_permission",
|
||||
"cli_path": "drive permission list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.permission_remove",
|
||||
"cli_path": "drive permission remove"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.permission_update",
|
||||
"cli_path": "drive permission update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.publish_get",
|
||||
"cli_path": "drive publish get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.publish_set",
|
||||
"cli_path": "drive publish set"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.publish_unset",
|
||||
"cli_path": "drive publish unset"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.recent",
|
||||
"cli_path": "drive recent"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.recycle_list",
|
||||
"cli_path": "drive recycle list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.recycle_restore",
|
||||
"cli_path": "drive recycle restore"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.rename_document",
|
||||
"cli_path": "drive rename"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.search_files",
|
||||
"cli_path": "drive search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.create_shortcut",
|
||||
"cli_path": "drive shortcut"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.get_node_stats",
|
||||
"cli_path": "drive stats"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.upload",
|
||||
"cli_path": "drive upload"
|
||||
},
|
||||
{
|
||||
"canonical_path": "drive.get_upload_info",
|
||||
"cli_path": "drive upload-info"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"id": "event",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "event.consume",
|
||||
"cli_path": "event consume"
|
||||
},
|
||||
{
|
||||
"canonical_path": "event.list",
|
||||
"cli_path": "event list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "event.schema",
|
||||
"cli_path": "event schema"
|
||||
},
|
||||
{
|
||||
"canonical_path": "event.status",
|
||||
"cli_path": "event status"
|
||||
},
|
||||
{
|
||||
"canonical_path": "event.stop",
|
||||
"cli_path": "event stop"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"id": "live",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "live.get_my_lives",
|
||||
"cli_path": "live stream list"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
{
|
||||
"id": "mail",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "mail.create_download_session",
|
||||
"cli_path": "mail attachment download"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.list_mail_attachments",
|
||||
"cli_path": "mail attachment list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.batch_delete_user_mail_contacts",
|
||||
"cli_path": "mail contact batch-delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.create_user_mail_contact",
|
||||
"cli_path": "mail contact create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.list_user_mail_contacts",
|
||||
"cli_path": "mail contact list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.update_user_mail_contact",
|
||||
"cli_path": "mail contact update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.create_draft",
|
||||
"cli_path": "mail draft create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.send_draft",
|
||||
"cli_path": "mail draft send"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.update_draft",
|
||||
"cli_path": "mail draft update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.create_mail_folder",
|
||||
"cli_path": "mail folder create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.delete_mail_folder",
|
||||
"cli_path": "mail folder delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.list_folders",
|
||||
"cli_path": "mail folder list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.update_mail_folder",
|
||||
"cli_path": "mail folder update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.list_user_mailboxes",
|
||||
"cli_path": "mail mailbox list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.batch_delete_message",
|
||||
"cli_path": "mail message batch-delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.batch_move_message",
|
||||
"cli_path": "mail message batch-move"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.create_forward_draft",
|
||||
"cli_path": "mail message forward"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.get_email_by_message_id",
|
||||
"cli_path": "mail message get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.create_reply_draft",
|
||||
"cli_path": "mail message reply"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.create_replyall_draft",
|
||||
"cli_path": "mail message reply-all"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.search_emails",
|
||||
"cli_path": "mail message search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.list_emails",
|
||||
"cli_path": "mail message list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.send_email",
|
||||
"cli_path": "mail message send"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.list_tags",
|
||||
"cli_path": "mail tag list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.create_user_message_template",
|
||||
"cli_path": "mail template create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.delete_user_message_template",
|
||||
"cli_path": "mail template delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.get_user_message_template",
|
||||
"cli_path": "mail template get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.list_user_message_templates",
|
||||
"cli_path": "mail template list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.update_user_message_template",
|
||||
"cli_path": "mail template update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.get_thread",
|
||||
"cli_path": "mail thread get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "mail.search_mail_users",
|
||||
"cli_path": "mail user search"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
{
|
||||
"id": "minutes",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "minutes.query_minutes_audio_url",
|
||||
"cli_path": "minutes get audio"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.batch_get_minutes_details",
|
||||
"cli_path": "minutes get batch"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.get_minutes_basic_info",
|
||||
"cli_path": "minutes get info"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.get_minutes_keywords",
|
||||
"cli_path": "minutes get keywords"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.get_minutes_ai_summary",
|
||||
"cli_path": "minutes get summary"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.list_minutes_todos",
|
||||
"cli_path": "minutes get todos"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.get_minutes_transcription",
|
||||
"cli_path": "minutes get transcription"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.add_personal_hot_word",
|
||||
"cli_path": "minutes hot-word add"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.list_my_hotwords",
|
||||
"cli_path": "minutes hot-word list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.list_accessible_minutes",
|
||||
"cli_path": "minutes list all"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.list_by_keyword_and_time_range",
|
||||
"cli_path": "minutes list mine"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.list_shared_minutes",
|
||||
"cli_path": "minutes list shared"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.create_mind_graph",
|
||||
"cli_path": "minutes mind-graph create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.query_mind_graph_status",
|
||||
"cli_path": "minutes mind-graph status"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.add_member_permission",
|
||||
"cli_path": "minutes permission add"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.remove_member_permission",
|
||||
"cli_path": "minutes permission remove"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.record_pause",
|
||||
"cli_path": "minutes record pause"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.record_resume",
|
||||
"cli_path": "minutes record resume"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.record_start",
|
||||
"cli_path": "minutes record start"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.record_stop",
|
||||
"cli_path": "minutes record stop"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.replace_minutes_text",
|
||||
"cli_path": "minutes replace-text"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.replace_speaker",
|
||||
"cli_path": "minutes speaker replace"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.create_speaker_summary",
|
||||
"cli_path": "minutes speaker summary create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.get_speaker_summary",
|
||||
"cli_path": "minutes speaker summary get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.query_user_tag_list",
|
||||
"cli_path": "minutes tag list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.query_minutes_by_tag_id",
|
||||
"cli_path": "minutes tag query"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.update_minutes_summary",
|
||||
"cli_path": "minutes update summary"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.update_minutes_title",
|
||||
"cli_path": "minutes update title"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.cancel_upload_session",
|
||||
"cli_path": "minutes upload cancel"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.complete_upload_session",
|
||||
"cli_path": "minutes upload complete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "minutes.create_upload_session",
|
||||
"cli_path": "minutes upload create"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"id": "oa",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "oa.approve_processInstance",
|
||||
"cli_path": "oa approval approve"
|
||||
},
|
||||
{
|
||||
"canonical_path": "oa.get_processInstance_detail",
|
||||
"cli_path": "oa approval detail"
|
||||
},
|
||||
{
|
||||
"canonical_path": "oa.get_noticed_instances",
|
||||
"cli_path": "oa approval list-cc"
|
||||
},
|
||||
{
|
||||
"canonical_path": "oa.get_done_tasks",
|
||||
"cli_path": "oa approval list-executed"
|
||||
},
|
||||
{
|
||||
"canonical_path": "oa.list_user_visible_process",
|
||||
"cli_path": "oa approval list-forms"
|
||||
},
|
||||
{
|
||||
"canonical_path": "oa.list_initiated_instances",
|
||||
"cli_path": "oa approval list-initiated"
|
||||
},
|
||||
{
|
||||
"canonical_path": "oa.list_pending_approvals",
|
||||
"cli_path": "oa approval list-pending"
|
||||
},
|
||||
{
|
||||
"canonical_path": "oa.get_submitted_instances",
|
||||
"cli_path": "oa approval list-submitted"
|
||||
},
|
||||
{
|
||||
"canonical_path": "oa.oa_cc_noticer",
|
||||
"cli_path": "oa approval oa-cc-noticer"
|
||||
},
|
||||
{
|
||||
"canonical_path": "oa.dingflow_comments",
|
||||
"cli_path": "oa approval oa-comments"
|
||||
},
|
||||
{
|
||||
"canonical_path": "oa.get_processInstance_records",
|
||||
"cli_path": "oa approval records"
|
||||
},
|
||||
{
|
||||
"canonical_path": "oa.redirect_task",
|
||||
"cli_path": "oa approval redirect-task"
|
||||
},
|
||||
{
|
||||
"canonical_path": "oa.reject_processInstance",
|
||||
"cli_path": "oa approval reject"
|
||||
},
|
||||
{
|
||||
"canonical_path": "oa.revoke_processInstance",
|
||||
"cli_path": "oa approval revoke"
|
||||
},
|
||||
{
|
||||
"canonical_path": "oa.list_pending_tasks",
|
||||
"cli_path": "oa approval tasks"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"id": "pat",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "pat.browser_policy",
|
||||
"cli_path": "pat browser-policy"
|
||||
},
|
||||
{
|
||||
"canonical_path": "pat.batch_grant",
|
||||
"cli_path": "pat chmod"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"id": "report",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "report.get_report_entry_details",
|
||||
"cli_path": "report entry get",
|
||||
"aliases": [
|
||||
"report detail"
|
||||
]
|
||||
},
|
||||
{
|
||||
"canonical_path": "report.get_report_statistics_by_id",
|
||||
"cli_path": "report entry stats",
|
||||
"aliases": [
|
||||
"report stats"
|
||||
]
|
||||
},
|
||||
{
|
||||
"canonical_path": "report.create_report",
|
||||
"cli_path": "report entry submit",
|
||||
"aliases": [
|
||||
"report create"
|
||||
]
|
||||
},
|
||||
{
|
||||
"canonical_path": "report.get_received_report_list",
|
||||
"cli_path": "report inbox list",
|
||||
"aliases": [
|
||||
"report list"
|
||||
]
|
||||
},
|
||||
{
|
||||
"canonical_path": "report.get_send_report_list",
|
||||
"cli_path": "report outbox list",
|
||||
"aliases": [
|
||||
"report created",
|
||||
"report sent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"canonical_path": "report.get_template_details_by_name",
|
||||
"cli_path": "report template get",
|
||||
"aliases": [
|
||||
"report template detail"
|
||||
]
|
||||
},
|
||||
{
|
||||
"canonical_path": "report.get_available_report_templates",
|
||||
"cli_path": "report template list"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
{
|
||||
"id": "sheet",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "sheet.add_dimension",
|
||||
"cli_path": "sheet add-dimension"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.append_rows",
|
||||
"cli_path": "sheet append"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.batch_update",
|
||||
"cli_path": "sheet batch-update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.chart_create",
|
||||
"cli_path": "sheet chart create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.chart_delete",
|
||||
"cli_path": "sheet chart delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.chart_list",
|
||||
"cli_path": "sheet chart list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.chart_update",
|
||||
"cli_path": "sheet chart update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.create_cond_format",
|
||||
"cli_path": "sheet cond-format create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.delete_cond_format",
|
||||
"cli_path": "sheet cond-format delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.get_cond_format",
|
||||
"cli_path": "sheet cond-format list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.update_cond_format",
|
||||
"cli_path": "sheet cond-format update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.copy_sheet",
|
||||
"cli_path": "sheet copy"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.create_workspace_sheet",
|
||||
"cli_path": "sheet create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.create_float_image",
|
||||
"cli_path": "sheet create-float-image"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.get_range_as_csv",
|
||||
"cli_path": "sheet csv-get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.set_range_from_csv",
|
||||
"cli_path": "sheet csv-put"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.delete_dimension",
|
||||
"cli_path": "sheet delete-dimension"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.delete_dropdown_lists",
|
||||
"cli_path": "sheet delete-dropdown"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.delete_float_image",
|
||||
"cli_path": "sheet delete-float-image"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.delete_sheet",
|
||||
"cli_path": "sheet delete-sheet"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.submit_export_job",
|
||||
"cli_path": "sheet export"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.filter_clear_criteria",
|
||||
"cli_path": "sheet filter clear-criteria"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.create_filter",
|
||||
"cli_path": "sheet filter create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.delete_filter",
|
||||
"cli_path": "sheet filter delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.get_filter",
|
||||
"cli_path": "sheet filter get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.sort_filter",
|
||||
"cli_path": "sheet filter sort"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.update_filter",
|
||||
"cli_path": "sheet filter update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.create_filter_view",
|
||||
"cli_path": "sheet filter-view create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.delete_filter_view",
|
||||
"cli_path": "sheet filter-view delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.filter_view_delete_criteria",
|
||||
"cli_path": "sheet filter-view delete-criteria"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.filter_view_get_criteria",
|
||||
"cli_path": "sheet filter-view get-criteria"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.filter_view_info",
|
||||
"cli_path": "sheet filter-view info"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.get_filter_views",
|
||||
"cli_path": "sheet filter-view list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.filter_view_list_criteria",
|
||||
"cli_path": "sheet filter-view list-criteria"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.update_filter_view",
|
||||
"cli_path": "sheet filter-view update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.filter_view_update_criteria",
|
||||
"cli_path": "sheet filter-view update-criteria"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.find_cells",
|
||||
"cli_path": "sheet find"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.get_dropdown_lists",
|
||||
"cli_path": "sheet get-dropdown"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.get_float_image",
|
||||
"cli_path": "sheet get-float-image"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.group_dimension",
|
||||
"cli_path": "sheet group-dimension"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.hide_gridline",
|
||||
"cli_path": "sheet hide-gridline"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.info",
|
||||
"cli_path": "sheet info"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.import",
|
||||
"cli_path": "sheet import create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.import_get",
|
||||
"cli_path": "sheet import get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.insert_dimension",
|
||||
"cli_path": "sheet insert-dimension"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.get_all_sheets",
|
||||
"cli_path": "sheet list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.list_float_images",
|
||||
"cli_path": "sheet list-float-images"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.media_upload",
|
||||
"cli_path": "sheet media-upload"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.merge_cells",
|
||||
"cli_path": "sheet merge-cells"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.move_dimension",
|
||||
"cli_path": "sheet move-dimension"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.create_sheet",
|
||||
"cli_path": "sheet new"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.create_pivot_table",
|
||||
"cli_path": "sheet pivot-table create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.delete_pivot_table",
|
||||
"cli_path": "sheet pivot-table delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.list_pivot_tables",
|
||||
"cli_path": "sheet pivot-table list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.update_pivot_table",
|
||||
"cli_path": "sheet pivot-table update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.range_batch_clear",
|
||||
"cli_path": "sheet range batch-clear"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.range_batch_set_style",
|
||||
"cli_path": "sheet range batch-set-style"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.clear_range",
|
||||
"cli_path": "sheet range clear"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.range_copy_to",
|
||||
"cli_path": "sheet range copy-to"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.fill_range",
|
||||
"cli_path": "sheet range fill"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.range_move_to",
|
||||
"cli_path": "sheet range move-to"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.range_read",
|
||||
"cli_path": "sheet range read"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.range_set_style",
|
||||
"cli_path": "sheet range set-style"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.sort_range",
|
||||
"cli_path": "sheet range sort"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.range_update",
|
||||
"cli_path": "sheet range update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.replace_all",
|
||||
"cli_path": "sheet replace"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.set_dropdown_lists",
|
||||
"cli_path": "sheet set-dropdown"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.show_gridline",
|
||||
"cli_path": "sheet show-gridline"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.table_get",
|
||||
"cli_path": "sheet table-get",
|
||||
"aliases": [
|
||||
"sheet table-read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.table_put",
|
||||
"cli_path": "sheet table-put",
|
||||
"aliases": [
|
||||
"sheet table-write"
|
||||
]
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.template_apply",
|
||||
"cli_path": "sheet template apply"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.template_list",
|
||||
"cli_path": "sheet template list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.template_search",
|
||||
"cli_path": "sheet template search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.ungroup_dimension",
|
||||
"cli_path": "sheet ungroup-dimension"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.unmerge_range",
|
||||
"cli_path": "sheet unmerge-cells"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.update_sheet",
|
||||
"cli_path": "sheet update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.update_dimension",
|
||||
"cli_path": "sheet update-dimension"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.update_float_image",
|
||||
"cli_path": "sheet update-float-image"
|
||||
},
|
||||
{
|
||||
"canonical_path": "sheet.write_image",
|
||||
"cli_path": "sheet write-image"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"id": "todo",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "todo.add_todo_comment",
|
||||
"cli_path": "todo comment add"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.delete_todo_comment",
|
||||
"cli_path": "todo comment delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.list_todo_comment",
|
||||
"cli_path": "todo comment list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.add_todo_attachment",
|
||||
"cli_path": "todo task add-attachment"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.list_todo_attachment",
|
||||
"cli_path": "todo task list-attachment"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.add_task_executors",
|
||||
"cli_path": "todo task add-executor"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.add_task_participants",
|
||||
"cli_path": "todo task add-participant"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.add_todo_reminder",
|
||||
"cli_path": "todo task add-reminder"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.create_personal_todo",
|
||||
"cli_path": "todo task create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.create_personal_sub_todo",
|
||||
"cli_path": "todo task create-sub"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.delete_todo",
|
||||
"cli_path": "todo task delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.update_todo_done_status",
|
||||
"cli_path": "todo task done"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.get_todo_detail",
|
||||
"cli_path": "todo task get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.get_user_todos_in_current_org",
|
||||
"cli_path": "todo task list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.remove_task_executors",
|
||||
"cli_path": "todo task remove-executor"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.remove_task_participants",
|
||||
"cli_path": "todo task remove-participant"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.reset_todo_reminder",
|
||||
"cli_path": "todo task reset-reminder"
|
||||
},
|
||||
{
|
||||
"canonical_path": "todo.update_todo_task",
|
||||
"cli_path": "todo task update"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"id": "wiki",
|
||||
"tools": [
|
||||
{
|
||||
"canonical_path": "wiki.add_member",
|
||||
"cli_path": "wiki member add"
|
||||
},
|
||||
{
|
||||
"canonical_path": "wiki.list_member",
|
||||
"cli_path": "wiki member list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "wiki.remove_member",
|
||||
"cli_path": "wiki member remove"
|
||||
},
|
||||
{
|
||||
"canonical_path": "wiki.update_member",
|
||||
"cli_path": "wiki member update"
|
||||
},
|
||||
{
|
||||
"canonical_path": "wiki.node_copy",
|
||||
"cli_path": "wiki node copy"
|
||||
},
|
||||
{
|
||||
"canonical_path": "wiki.create_file",
|
||||
"cli_path": "wiki node create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "wiki.delete_document",
|
||||
"cli_path": "wiki node delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "wiki.list_nodes",
|
||||
"cli_path": "wiki node list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "wiki.node_move",
|
||||
"cli_path": "wiki node move"
|
||||
},
|
||||
{
|
||||
"canonical_path": "wiki.node_search",
|
||||
"cli_path": "wiki node search"
|
||||
},
|
||||
{
|
||||
"canonical_path": "wiki.create_wikiSpace",
|
||||
"cli_path": "wiki space create"
|
||||
},
|
||||
{
|
||||
"canonical_path": "wiki.delete_wikiSpace",
|
||||
"cli_path": "wiki space delete"
|
||||
},
|
||||
{
|
||||
"canonical_path": "wiki.get_wikiSpace",
|
||||
"cli_path": "wiki space get"
|
||||
},
|
||||
{
|
||||
"canonical_path": "wiki.list_wikiSpaces",
|
||||
"cli_path": "wiki space list"
|
||||
},
|
||||
{
|
||||
"canonical_path": "wiki.search_wikiSpaces",
|
||||
"cli_path": "wiki space search"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"$schema": "./schema_command_registry.schema.json",
|
||||
"version": 1
|
||||
}
|
||||
@@ -34,8 +34,12 @@ func TestCommandRegistryJSONSchemaDocumentsClosedCommandSpec(t *testing.T) {
|
||||
}
|
||||
|
||||
var source map[string]any
|
||||
if err := json.Unmarshal(embeddedSchemaCommandRegistryJSON, &source); err != nil {
|
||||
t.Fatalf("decode schema_command_registry.json: %v", err)
|
||||
merged, err := EmbeddedCommandRegistryMergedJSON()
|
||||
if err != nil {
|
||||
t.Fatalf("EmbeddedCommandRegistryMergedJSON() error = %v", err)
|
||||
}
|
||||
if err := json.Unmarshal(merged, &source); err != nil {
|
||||
t.Fatalf("decode merged registry: %v", err)
|
||||
}
|
||||
if source["$schema"] != commandRegistrySchemaRef {
|
||||
t.Fatalf("registry source $schema = %#v, want %q", source["$schema"], commandRegistrySchemaRef)
|
||||
|
||||
@@ -22,7 +22,14 @@ func TestCrossPlatformCoverageCommandRegistryLoaderErrorWrappers(t *testing.T) {
|
||||
})
|
||||
|
||||
loadReviewedCommandRegistry = func() (CommandRegistry, error) { return CommandRegistry{}, errors.New("registry failed") }
|
||||
if _, err := ValidateCommandRegistrySource(embeddedSchemaCommandRegistryJSON); err == nil || !strings.Contains(err.Error(), "registry failed") {
|
||||
// ValidateCommandRegistrySource first decodes the input independently, then
|
||||
// compares against embedded. The decode path succeeds even when the lazy
|
||||
// accessor is broken, so this test catches the accessor failure.
|
||||
merged, err := EmbeddedCommandRegistryMergedJSON()
|
||||
if err != nil {
|
||||
t.Fatalf("EmbeddedCommandRegistryMergedJSON() error = %v", err)
|
||||
}
|
||||
if _, err := ValidateCommandRegistrySource(merged); err == nil || !strings.Contains(err.Error(), "registry failed") {
|
||||
t.Fatalf("ValidateCommandRegistrySource() error = %v", err)
|
||||
}
|
||||
if _, err := EmbeddedCommandRegistrySourceHash(); err == nil || !strings.Contains(err.Error(), "registry failed") {
|
||||
|
||||
Reference in New Issue
Block a user