diff --git a/AGENTS.md b/AGENTS.md index 40c6f618..c356bc97 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -162,6 +162,14 @@ semantically concatenate Markdown into the selected Agent prose. They may only read, validate, resolve, and project the committed values. Markdown and Help are evidence for authoring and drift checks, not hidden description winners. +`make generate-schema` is a full deterministic snapshot rebuild, not an +incremental patch over the previous Catalog. It rereads every reviewed input, +removes stale generated product metadata, and rewrites the exact metadata and +Catalog projections. Incremental work happens only when an Agent or human +edits selected reviewed Manual Hint entries; the next publication still +recomputes all outputs. Generated files must never be read back as merge input, +and byte guards fail generation if it changes the Manual Hint or CommandRegistry. + The initial AI-authored baseline must cover the exact Effective CommandRegistry tool set and all published products in one revision. Each product/tool entry references a declared revision record. Later human or Agent @@ -177,6 +185,31 @@ bypass command completeness. Examples must use an executable primary/alias path and flags accepted by the live Cobra command; never add `--yes` to stored examples. +Every example is always checked against its real `BoundCommand`: exact path, +accepted flags, Cobra required flags/positionals, and the effective +`require_one_of`, `require_together`, and `mutually_exclusive` constraints must +all pass before execution eligibility is considered. A missing required value, +constraint failure, runtime error, or MCP resolution error is a contract bug; +none is a valid reason to skip an example. + +Example execution defaults to `dry_run`. Final typed safety with `risk=high` +or `confirmation=user_required` automatically selects `contract_only`, because +a test must never inject `--yes`. A narrow runtime precondition that cannot be +derived from the typed contract may use an exact zero-based +`example_dispositions` entry with `mode=contract_only`, `reviewed=true`, one of +the schema-enumerated reason codes, and a concrete non-empty reason. Manual +confirmation dispositions are forbidden because confirmation comes from typed +safety. Duplicate, missing, and out-of-range indexes fail validation. Never +catch a dry-run failure and dynamically downgrade it to `contract_only`. + +Normal Go tests run the exhaustive contract gate. Run +`make test-schema-agent-examples` to additionally execute the eligible subset +through the real Cobra `--dry-run` path with isolated HOME and blocked proxies. +The test reports stable `total`, `dry_run`, `contract_only`, `typed_safety`, +`reviewed_manual`, and per-reason counts; changing those counts requires a +review of the corresponding manual hint or typed safety change. This target is +also part of `make policy`. + Treat every tool `use_when` entry as a reviewed positive selection scenario whose expected result is that tool's canonical path, and every `avoid_when` entry as a reviewed negative scenario that must not choose that tool. The diff --git a/Makefile b/Makefile index 9602a3bd..e86c0fad 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ GO ?= go -.PHONY: all help build rebuild test lint fmt policy edition-test generate-schema generate-schema-agent-metadata generate-schema-catalog package release publish-homebrew-formula setup-hooks +.PHONY: all help build rebuild test lint fmt policy edition-test test-schema-agent-examples generate-schema generate-schema-agent-metadata generate-schema-catalog package release publish-homebrew-formula setup-hooks all: setup-hooks fmt lint build test rebuild @@ -11,6 +11,7 @@ help: @printf " make lint - Run formatting checks and golangci-lint when available\n" @printf " make fmt - Format Go source files\n" @printf " make policy - Run open-source asset and Schema registry checks\n" + @printf " make test-schema-agent-examples - Contract-check all Agent examples and dry-run the eligible subset\n" @printf " make generate-schema - Regenerate embedded Agent metadata and the release Catalog\n" @printf " make generate-schema-agent-metadata - Regenerate versioned Agent metadata\n" @printf " make generate-schema-catalog - Regenerate the embedded release Catalog\n" @@ -40,10 +41,14 @@ policy: @./scripts/policy/check-generated-drift.sh @./scripts/policy/check-schema-catalog.sh @./scripts/policy/check-schema-binary.sh + @$(MAKE) test-schema-agent-examples edition-test: $(GO) test -v -count=1 ./pkg/editiontest/... +test-schema-agent-examples: + DWS_AGENT_EXAMPLES_DRY_RUN=1 $(GO) test -v -count=1 ./internal/app -run '^TestManualAgentExamplesDryRun$$' + generate-schema: @set -e; \ registry_guard=$$(mktemp); \ diff --git a/internal/app/schema_agent_examples_dry_run_test.go b/internal/app/schema_agent_examples_dry_run_test.go index df4ac1c0..da16219e 100644 --- a/internal/app/schema_agent_examples_dry_run_test.go +++ b/internal/app/schema_agent_examples_dry_run_test.go @@ -15,6 +15,7 @@ package app import ( "bytes" + "context" "fmt" "io" "os" @@ -22,30 +23,105 @@ import ( "regexp" "sort" "strings" + "sync/atomic" "testing" "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/cli" + "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/helpers" + "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/edition" + "github.com/fatih/color" ) var manualAgentExamplePlaceholderPattern = regexp.MustCompile(`<([^>]+)>`) -// TestManualAgentExamplesDryRun executes every reviewed example through the -// real Cobra command and argument-validation path with global --dry-run forced -// on. The test is opt-in because it is intentionally exhaustive; normal CI -// already validates every path and flag in-process. No shell is involved and -// HOME is isolated, so examples cannot expand shell syntax or consume a -// developer's local DWS configuration. +// TestManualAgentExamplesContract is the always-on gate. It validates every +// example, including contract_only entries, against the live bound Cobra path, +// flags, required arguments, constraints, and final typed safety. +func TestManualAgentExamplesContract(t *testing.T) { + plan := manualAgentExampleExecutionPlan(t) + if plan.Total == 0 { + t.Fatal("no reviewed Agent examples were contract validated") + } + t.Logf("Agent example contract: total=%d dry_run=%d contract_only=%d", plan.Total, plan.DryRun, plan.ContractOnly) +} + +// TestManualAgentExamplesDryRun first validates every reviewed example against +// its real BoundCommand, Cobra required arguments, and final typed constraints. +// It then executes only the deterministic dry_run subset. Final typed +// confirmation and exact reviewed manual dispositions account for the stable +// contract_only subset; runtime failures never create implicit skips. No shell +// is involved and HOME is isolated. func TestManualAgentExamplesDryRun(t *testing.T) { if os.Getenv("DWS_AGENT_EXAMPLES_DRY_RUN") != "1" { t.Skip("set DWS_AGENT_EXAMPLES_DRY_RUN=1 to execute every reviewed Agent example through Cobra --dry-run") } - t.Setenv("HOME", t.TempDir()) + sandboxRoot := t.TempDir() + homeDir := filepath.Join(sandboxRoot, "home") + configDir := filepath.Join(sandboxRoot, "config") + for _, dir := range []string{homeDir, configDir} { + if err := os.MkdirAll(dir, 0o700); err != nil { + t.Fatalf("create isolated test directory %s: %v", dir, err) + } + } + t.Setenv("HOME", homeDir) + t.Setenv("DWS_CONFIG_DIR", configDir) t.Setenv("HTTP_PROXY", "http://127.0.0.1:1") t.Setenv("HTTPS_PROXY", "http://127.0.0.1:1") t.Setenv("NO_PROXY", "") - files := newManualAgentExampleFiles(t) + plan := manualAgentExampleExecutionPlan(t) + if plan.Total == 0 { + t.Fatal("no reviewed Agent examples were contract validated") + } + t.Chdir(sandboxRoot) + files := newManualAgentExampleFiles(t, sandboxRoot) + + executed := 0 + for _, execution := range plan.Examples { + if execution.Mode == cli.ManualAgentExampleModeContractOnly { + continue + } + execution := execution + t.Run(fmt.Sprintf("%s/%d", strings.ReplaceAll(execution.CanonicalPath, ".", "/"), execution.Index), func(t *testing.T) { + argv, err := cli.ParseManualAgentExampleArgv(execution.Example) + if err != nil { + t.Fatalf("parse example %q: %v", execution.Example, err) + } + args := materializeManualAgentExampleArgv(argv[1:], files) + if !manualAgentExampleHasFlag(args, "dry-run") { + args = append([]string{"--dry-run"}, args...) + } + + capture, err := executeManualAgentExampleCapture(t, args) + if capture.ToolCallAttempts != 0 { + t.Fatalf("eligible dry-run attempted %d ToolCaller invocation(s)\nsource: %s\nargv: %q\noutput:\n%s", capture.ToolCallAttempts, execution.Example, args, capture.Output) + } + if err != nil { + t.Fatalf("dry-run example failed: %v\nsource: %s\nargv: %q\noutput:\n%s", err, execution.Example, args, capture.Output) + } + if !manualAgentExampleDryRunObserved(capture.Output, capture.DryRunChecks) { + t.Fatalf("example returned without audited dry-run evidence (caller dry-run checks: %d)\nsource: %s\nargv: %q\noutput:\n%s", capture.DryRunChecks, execution.Example, args, capture.Output) + } + executed++ + }) + } + if executed != plan.DryRun { + t.Fatalf("executed dry_run examples = %d, plan requires %d", executed, plan.DryRun) + } + t.Logf("Agent examples: total=%d dry_run=%d contract_only=%d typed_safety=%d reviewed_manual=%d", plan.Total, plan.DryRun, plan.ContractOnly, plan.TypedSafetyContractOnly, plan.ReviewedContractOnly) + reasonCodes := make([]string, 0, len(plan.ContractOnlyByReason)) + for reasonCode := range plan.ContractOnlyByReason { + reasonCodes = append(reasonCodes, string(reasonCode)) + } + sort.Strings(reasonCodes) + for _, reasonCode := range reasonCodes { + t.Logf("Agent examples contract_only[%s]=%d", reasonCode, plan.ContractOnlyByReason[cli.ManualAgentExampleReasonCode(reasonCode)]) + } +} + +func manualAgentExampleExecutionPlan(t testing.TB) cli.ManualAgentExampleExecutionPlan { + t.Helper() data, err := os.ReadFile("../cli/schema_manual_hints.json") if err != nil { t.Fatalf("read reviewed Manual Agent hints: %v", err) @@ -54,85 +130,122 @@ func TestManualAgentExamplesDryRun(t *testing.T) { if err != nil { t.Fatalf("DecodeManualSchemaHintSource() error = %v", err) } - - canonicals := make([]string, 0, len(snapshot.AgentHints.Tools)) - for canonical := range snapshot.AgentHints.Tools { - canonicals = append(canonicals, canonical) + contractRoot := NewRootCommand() + if _, err := cli.ApplyEmbeddedManualSchemaHints(contractRoot); err != nil { + t.Fatalf("ApplyEmbeddedManualSchemaHints() error = %v", err) } - sort.Strings(canonicals) - - validated := 0 - for _, canonical := range canonicals { - for index, example := range snapshot.AgentHints.Tools[canonical].Examples { - canonical, index, example := canonical, index, example - t.Run(fmt.Sprintf("%s/%d", strings.ReplaceAll(canonical, ".", "/"), index), func(t *testing.T) { - argv, err := cli.ParseManualAgentExampleArgv(example) - if err != nil { - t.Fatalf("parse example %q: %v", example, err) - } - args := materializeManualAgentExampleArgv(argv[1:], files) - if !manualAgentExampleHasFlag(args, "dry-run") { - args = append([]string{"--dry-run"}, args...) - } - - output, err := executeManualAgentExampleCapture(t, args) - if err != nil { - t.Fatalf("dry-run example failed: %v\nsource: %s\nargv: %q\noutput:\n%s", err, example, args, output) - } - if !manualAgentExampleDryRunObserved(output) { - t.Fatalf("example returned without dry-run evidence\nsource: %s\nargv: %q\noutput:\n%s", example, args, output) - } - validated++ - }) - } + effective, err := cli.BuildEffectiveCommandRegistry(contractRoot) + if err != nil { + t.Fatalf("BuildEffectiveCommandRegistry() error = %v", err) } - if validated == 0 { - t.Fatal("no reviewed Agent examples were executed") + bound, err := cli.BindEffectiveCommandRegistry(contractRoot, effective) + if err != nil { + t.Fatalf("BindEffectiveCommandRegistry() error = %v", err) } - t.Logf("executed %d reviewed Agent examples through real Cobra --dry-run", validated) + registry, err := cli.AssembleSchemaRegistryFromBound(bound) + if err != nil { + t.Fatalf("AssembleSchemaRegistryFromBound() error = %v", err) + } + plan, err := cli.BuildManualAgentExampleExecutionPlan(bound, registry, snapshot.AgentHints) + if err != nil { + t.Fatalf("BuildManualAgentExampleExecutionPlan() error = %v", err) + } + return plan } -func executeManualAgentExampleCapture(t testing.TB, args []string) (string, error) { +type manualAgentExampleCapture struct { + Output string + DryRunChecks int64 + ToolCallAttempts int64 +} + +type manualAgentExampleFailClosedCaller struct { + dryRunChecks atomic.Int64 + toolCallAttempts atomic.Int64 +} + +func (c *manualAgentExampleFailClosedCaller) CallTool(_ context.Context, productID, toolName string, _ map[string]any) (*edition.ToolResult, error) { + c.toolCallAttempts.Add(1) + return nil, fmt.Errorf("real ToolCaller invocation blocked during Agent example dry-run: %s/%s", productID, toolName) +} + +func (c *manualAgentExampleFailClosedCaller) Format() string { return "json" } + +func (c *manualAgentExampleFailClosedCaller) DryRun() bool { + c.dryRunChecks.Add(1) + return true +} + +func (c *manualAgentExampleFailClosedCaller) Fields() string { return "" } +func (c *manualAgentExampleFailClosedCaller) JQ() string { return "" } + +func executeManualAgentExampleCapture(t testing.TB, args []string) (manualAgentExampleCapture, error) { t.Helper() + oldArgs := os.Args + os.Args = append([]string{"dws"}, args...) + defer func() { os.Args = oldArgs }() + oldStdout, oldStderr := os.Stdout, os.Stderr - readPipe, writePipe, err := os.Pipe() + oldColorOutput, oldColorError := color.Output, color.Error + captureFile, err := os.CreateTemp(t.TempDir(), "agent-example-output-*.log") if err != nil { - t.Fatalf("open output capture pipe: %v", err) + t.Fatalf("open output capture file: %v", err) } - os.Stdout, os.Stderr = writePipe, writePipe + defer captureFile.Close() + os.Stdout, os.Stderr = captureFile, captureFile + color.Output, color.Error = captureFile, captureFile + defer func() { + os.Stdout, os.Stderr = oldStdout, oldStderr + color.Output, color.Error = oldColorOutput, oldColorError + }() root := NewRootCommand() + originalCaller := helpers.GetCaller() + auditCaller := &manualAgentExampleFailClosedCaller{} + helpers.InitDeps(auditCaller) + defer helpers.InitDeps(originalCaller) var output bytes.Buffer root.SetOut(&output) root.SetErr(&output) root.SetArgs(args) execErr := root.Execute() - _ = writePipe.Close() os.Stdout, os.Stderr = oldStdout, oldStderr - captured, readErr := io.ReadAll(readPipe) - _ = readPipe.Close() - if readErr != nil { - t.Fatalf("read output capture pipe: %v", readErr) + color.Output, color.Error = oldColorOutput, oldColorError + if _, err := captureFile.Seek(0, io.SeekStart); err != nil { + t.Fatalf("rewind output capture file: %v", err) } - return output.String() + string(captured), execErr + captured, readErr := io.ReadAll(captureFile) + if readErr != nil { + t.Fatalf("read output capture file: %v", readErr) + } + return manualAgentExampleCapture{ + Output: output.String() + string(captured), + DryRunChecks: auditCaller.dryRunChecks.Load(), + ToolCallAttempts: auditCaller.toolCallAttempts.Load(), + }, execErr } type manualAgentExampleFiles struct { root string markdown string + json string + batch string binary string image string } -func newManualAgentExampleFiles(t testing.TB) manualAgentExampleFiles { +func newManualAgentExampleFiles(t testing.TB, root string) manualAgentExampleFiles { t.Helper() - root := t.TempDir() markdown := filepath.Join(root, "content.md") + jsonFile := filepath.Join(root, "report.json") + batch := filepath.Join(root, "styles.json") binary := filepath.Join(root, "report.pdf") image := filepath.Join(root, "chart.png") for path, content := range map[string][]byte{ markdown: []byte("# Agent dry-run fixture\n\nNo business call is allowed.\n"), + jsonFile: []byte(`[{"content":"Agent dry-run fixture","sort":"0","key":"fixture","contentType":"markdown","type":"1"}]`), + batch: []byte(`[{"sheetId":"Sheet1","range":"A1:B2","fontWeight":"bold"}]`), binary: []byte("%PDF-1.4\n%%EOF\n"), image: {0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n'}, } { @@ -140,7 +253,7 @@ func newManualAgentExampleFiles(t testing.TB) manualAgentExampleFiles { t.Fatalf("write dry-run fixture %s: %v", path, err) } } - return manualAgentExampleFiles{root: root, markdown: markdown, binary: binary, image: image} + return manualAgentExampleFiles{root: root, markdown: markdown, json: jsonFile, batch: batch, binary: binary, image: image} } func materializeManualAgentExampleArgv(argv []string, files manualAgentExampleFiles) []string { @@ -184,8 +297,14 @@ func materializeManualAgentExampleArgv(argv []string, files manualAgentExampleFi } else { replacement = files.binary } - case "content-file", "contents-file": + case "content-file": replacement = files.markdown + case "contents-file": + replacement = files.json + case "batch": + if strings.HasSuffix(strings.ToLower(value), "styles.json") { + replacement = files.batch + } case "output": if value == "." || value == "" { replacement = files.root @@ -223,10 +342,77 @@ func manualAgentExampleHasFlag(argv []string, target string) bool { return false } -func manualAgentExampleDryRunObserved(output string) bool { +func manualAgentExampleDryRunObserved(output string, auditedDryRunChecks int64) bool { normalized := strings.ToLower(output) return strings.Contains(normalized, "dry-run") || strings.Contains(normalized, `"dry_run":true`) || strings.Contains(normalized, `"dry_run": true`) || - (strings.Contains(output, "Tool:") && strings.Contains(output, "Arguments:")) + (auditedDryRunChecks > 0 && strings.Contains(output, "操作:")) +} + +func TestManualAgentExampleDryRunObservedSupportsNilArguments(t *testing.T) { + if !manualAgentExampleDryRunObserved("[DRY-RUN] Preview only, not executed:\nTool: calendar_list", 0) { + t.Fatal("dry-run output with a Tool and nil Arguments was not recognized") + } + if manualAgentExampleDryRunObserved("Tool: calendar_list", 0) { + t.Fatal("a Tool line without dry-run evidence must not be accepted") + } + operationSummary := "操作: 下载钉盘文件\n文件ID: test" + if manualAgentExampleDryRunObserved(operationSummary, 0) { + t.Fatal("a bare operation summary without an audited caller dry-run check must not be accepted") + } + if !manualAgentExampleDryRunObserved(operationSummary, 1) { + t.Fatal("an operation summary guarded by the injected caller's dry-run check was not recognized") + } +} + +func TestManualAgentExampleFailClosedCallerRecordsToolCalls(t *testing.T) { + caller := &manualAgentExampleFailClosedCaller{} + if !caller.DryRun() { + t.Fatal("fail-closed caller must advertise dry-run mode") + } + if _, err := caller.CallTool(context.Background(), "calendar", "list_events", nil); err == nil { + t.Fatal("fail-closed caller accepted a ToolCaller invocation") + } + if got := caller.dryRunChecks.Load(); got != 1 { + t.Fatalf("DryRun() checks = %d, want 1", got) + } + if got := caller.toolCallAttempts.Load(); got != 1 { + t.Fatalf("CallTool() attempts = %d, want 1", got) + } +} + +func TestManualAgentExampleChatGroupMuteMemberDryRunKeepsUserIDsWithoutToolCall(t *testing.T) { + sandboxRoot := t.TempDir() + configDir := filepath.Join(sandboxRoot, "config") + if err := os.MkdirAll(configDir, 0o700); err != nil { + t.Fatalf("create isolated config directory: %v", err) + } + t.Setenv("HOME", sandboxRoot) + t.Setenv("DWS_CONFIG_DIR", configDir) + + capture, err := executeManualAgentExampleCapture(t, []string{ + "--dry-run", + "chat", "group-mute-member", + "--group", "test_openConversationId", + "--users", "userId1,userId2", + "--mute-time", "3600000", + }) + if err != nil { + t.Fatalf("group-mute-member dry-run failed: %v\noutput:\n%s", err, capture.Output) + } + if capture.ToolCallAttempts != 0 { + t.Fatalf("group-mute-member dry-run attempted %d ToolCaller invocation(s)\noutput:\n%s", capture.ToolCallAttempts, capture.Output) + } + if capture.DryRunChecks == 0 { + t.Fatalf("group-mute-member did not check the injected caller's dry-run state\noutput:\n%s", capture.Output) + } + for _, expected := range []string{`"uids"`, `"userId1"`, `"userId2"`} { + if !strings.Contains(capture.Output, expected) { + t.Fatalf("group-mute-member dry-run preview missing %s\noutput:\n%s", expected, capture.Output) + } + } + if strings.Contains(capture.Output, `"openDingTalkIds"`) { + t.Fatalf("group-mute-member dry-run unexpectedly resolved user IDs remotely\noutput:\n%s", capture.Output) + } } diff --git a/internal/app/schema_contract_test.go b/internal/app/schema_contract_test.go index b028dd6a..e12735a0 100644 --- a/internal/app/schema_contract_test.go +++ b/internal/app/schema_contract_test.go @@ -358,6 +358,50 @@ func TestCalendarAttendeeDeleteSchemaRequiresUserConfirmation(t *testing.T) { } } +func TestPromptingWritesRequireUserConfirmation(t *testing.T) { + wantEffects := map[string]string{ + "attendance.class_create": "write", + "attendance.class_update": "write", + "doc.version_revert": "destructive", + "drive.publish_set": "write", + "drive.publish_unset": "write", + "sheet.chart_delete": "write", + } + wantSources := map[string]string{ + "attendance.class_create": "skills/mono/schema-hints/zz-attendance-review.json", + "attendance.class_update": "skills/mono/schema-hints/zz-attendance-review.json", + "doc.version_revert": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "drive.publish_set": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "drive.publish_unset": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "sheet.chart_delete": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + } + canonicals := make([]string, 0, len(wantEffects)) + for canonical := range wantEffects { + canonicals = append(canonicals, canonical) + } + sort.Strings(canonicals) + snapshot := schemaContractPayloadForBoundCanonicals(t, NewRootCommand(), canonicals...) + for _, canonical := range canonicals { + tool := snapshot.Tools[canonical] + if got := tool["effect"]; got != wantEffects[canonical] { + t.Errorf("%s effect = %#v, want %s", canonical, got, wantEffects[canonical]) + } + if got := tool["risk"]; got != "high" { + t.Errorf("%s risk = %#v, want high", canonical, got) + } + if got := tool["confirmation"]; got != "user_required" { + t.Errorf("%s confirmation = %#v, want user_required", canonical, got) + } + provenance, _ := tool["field_provenance"].(map[string]any) + for _, field := range []string{"effect", "risk", "confirmation"} { + selected, _ := provenance[field].(map[string]any) + if got := selected["source"]; got != wantSources[canonical] { + t.Errorf("%s %s provenance source = %#v, want %s", canonical, field, got, wantSources[canonical]) + } + } + } +} + func TestDefaultedPaginationSchemaFlagsAreOptional(t *testing.T) { wants := map[string][]string{ "chat.search_messages_by_time_range": {"limit"}, diff --git a/internal/cli/schema_agent_metadata/aitable.json b/internal/cli/schema_agent_metadata/aitable.json index 1b6406ed..02ee8d84 100644 --- a/internal/cli/schema_agent_metadata/aitable.json +++ b/internal/cli/schema_agent_metadata/aitable.json @@ -24998,7 +24998,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update aggregate --view-id VIEW_ID --field-id fldX --action SUM" + "dws aitable view update aggregate --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-id fldX --action SUM" ], "field_provenance": { "agent_summary": { @@ -25089,7 +25089,7 @@ }, "examples": { "value": [ - "dws aitable view update aggregate --view-id VIEW_ID --field-id fldX --action SUM" + "dws aitable view update aggregate --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-id fldX --action SUM" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -25098,7 +25098,7 @@ "candidates": [ { "value": [ - "dws aitable view update aggregate --view-id VIEW_ID --field-id fldX --action SUM" + "dws aitable view update aggregate --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-id fldX --action SUM" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -25258,7 +25258,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update card --view-id VIEW_ID --cover-field-id fldXXX --cover-resize-mode contain" + "dws aitable view update card --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --cover-field-id fldXXX --cover-resize-mode contain" ], "field_provenance": { "agent_summary": { @@ -25349,7 +25349,7 @@ }, "examples": { "value": [ - "dws aitable view update card --view-id VIEW_ID --cover-field-id fldXXX --cover-resize-mode contain" + "dws aitable view update card --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --cover-field-id fldXXX --cover-resize-mode contain" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -25358,7 +25358,7 @@ "candidates": [ { "value": [ - "dws aitable view update card --view-id VIEW_ID --cover-field-id fldXXX --cover-resize-mode contain" + "dws aitable view update card --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --cover-field-id fldXXX --cover-resize-mode contain" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -25518,7 +25518,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update field-widths --view-id VIEW_ID --field-id fldX --width 200" + "dws aitable view update field-widths --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-id fldX --width 200" ], "field_provenance": { "agent_summary": { @@ -25609,7 +25609,7 @@ }, "examples": { "value": [ - "dws aitable view update field-widths --view-id VIEW_ID --field-id fldX --width 200" + "dws aitable view update field-widths --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-id fldX --width 200" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -25618,7 +25618,7 @@ "candidates": [ { "value": [ - "dws aitable view update field-widths --view-id VIEW_ID --field-id fldX --width 200" + "dws aitable view update field-widths --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-id fldX --width 200" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -25778,7 +25778,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update fill-color-rule --view-id VIEW_ID --json '[]'" + "dws aitable view update fill-color-rule --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[]'" ], "field_provenance": { "agent_summary": { @@ -25869,7 +25869,7 @@ }, "examples": { "value": [ - "dws aitable view update fill-color-rule --view-id VIEW_ID --json '[]'" + "dws aitable view update fill-color-rule --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[]'" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -25878,7 +25878,7 @@ "candidates": [ { "value": [ - "dws aitable view update fill-color-rule --view-id VIEW_ID --json '[]'" + "dws aitable view update fill-color-rule --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[]'" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -26030,7 +26030,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update filter --view-id VIEW_ID --json '[{\"operator\":\"and\",\"operands\":[{\"operator\":\"eq\",\"operands\":[\"fldX\",\"value\"]}]}]'" + "dws aitable view update filter --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"operator\":\"and\",\"operands\":[{\"operator\":\"eq\",\"operands\":[\"fldX\",\"value\"]}]}]'" ], "field_provenance": { "agent_summary": { @@ -26121,7 +26121,7 @@ }, "examples": { "value": [ - "dws aitable view update filter --view-id VIEW_ID --json '[{\"operator\":\"and\",\"operands\":[{\"operator\":\"eq\",\"operands\":[\"fldX\",\"value\"]}]}]'" + "dws aitable view update filter --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"operator\":\"and\",\"operands\":[{\"operator\":\"eq\",\"operands\":[\"fldX\",\"value\"]}]}]'" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -26130,7 +26130,7 @@ "candidates": [ { "value": [ - "dws aitable view update filter --view-id VIEW_ID --json '[{\"operator\":\"and\",\"operands\":[{\"operator\":\"eq\",\"operands\":[\"fldX\",\"value\"]}]}]'" + "dws aitable view update filter --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"operator\":\"and\",\"operands\":[{\"operator\":\"eq\",\"operands\":[\"fldX\",\"value\"]}]}]'" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -26290,7 +26290,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update frozen-cols --view-id VIEW_ID --count 1" + "dws aitable view update frozen-cols --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --count 1" ], "field_provenance": { "agent_summary": { @@ -26381,7 +26381,7 @@ }, "examples": { "value": [ - "dws aitable view update frozen-cols --view-id VIEW_ID --count 1" + "dws aitable view update frozen-cols --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --count 1" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -26390,7 +26390,7 @@ "candidates": [ { "value": [ - "dws aitable view update frozen-cols --view-id VIEW_ID --count 1" + "dws aitable view update frozen-cols --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --count 1" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -26542,7 +26542,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update group --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" + "dws aitable view update group --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" ], "field_provenance": { "agent_summary": { @@ -26633,7 +26633,7 @@ }, "examples": { "value": [ - "dws aitable view update group --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" + "dws aitable view update group --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -26642,7 +26642,7 @@ "candidates": [ { "value": [ - "dws aitable view update group --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" + "dws aitable view update group --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -26802,7 +26802,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update name --view-id VIEW_ID --name \"新视图名\"" + "dws aitable view update name --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --name \"新视图名\"" ], "field_provenance": { "agent_summary": { @@ -26893,7 +26893,7 @@ }, "examples": { "value": [ - "dws aitable view update name --view-id VIEW_ID --name \"新视图名\"" + "dws aitable view update name --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --name \"新视图名\"" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -26902,7 +26902,7 @@ "candidates": [ { "value": [ - "dws aitable view update name --view-id VIEW_ID --name \"新视图名\"" + "dws aitable view update name --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --name \"新视图名\"" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -27062,7 +27062,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update row-height --view-id VIEW_ID --cell-height 32" + "dws aitable view update row-height --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --cell-height 32" ], "field_provenance": { "agent_summary": { @@ -27153,7 +27153,7 @@ }, "examples": { "value": [ - "dws aitable view update row-height --view-id VIEW_ID --cell-height 32" + "dws aitable view update row-height --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --cell-height 32" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -27162,7 +27162,7 @@ "candidates": [ { "value": [ - "dws aitable view update row-height --view-id VIEW_ID --cell-height 32" + "dws aitable view update row-height --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --cell-height 32" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -27314,7 +27314,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update sort --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" + "dws aitable view update sort --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" ], "field_provenance": { "agent_summary": { @@ -27405,7 +27405,7 @@ }, "examples": { "value": [ - "dws aitable view update sort --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" + "dws aitable view update sort --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -27414,7 +27414,7 @@ "candidates": [ { "value": [ - "dws aitable view update sort --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" + "dws aitable view update sort --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -27574,7 +27574,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update timebar --view-id VIEW_ID --start-field fldStart --end-field fldEnd --timeline-scale month" + "dws aitable view update timebar --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --start-field fldStart --end-field fldEnd --timeline-scale month" ], "field_provenance": { "agent_summary": { @@ -27665,7 +27665,7 @@ }, "examples": { "value": [ - "dws aitable view update timebar --view-id VIEW_ID --start-field fldStart --end-field fldEnd --timeline-scale month" + "dws aitable view update timebar --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --start-field fldStart --end-field fldEnd --timeline-scale month" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -27674,7 +27674,7 @@ "candidates": [ { "value": [ - "dws aitable view update timebar --view-id VIEW_ID --start-field fldStart --end-field fldEnd --timeline-scale month" + "dws aitable view update timebar --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --start-field fldStart --end-field fldEnd --timeline-scale month" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -27834,7 +27834,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update visible-fields --view-id VIEW_ID --field-ids fld1,fld2,fld3" + "dws aitable view update visible-fields --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-ids fld1,fld2,fld3" ], "field_provenance": { "agent_summary": { @@ -27925,7 +27925,7 @@ }, "examples": { "value": [ - "dws aitable view update visible-fields --view-id VIEW_ID --field-ids fld1,fld2,fld3" + "dws aitable view update visible-fields --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-ids fld1,fld2,fld3" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -27934,7 +27934,7 @@ "candidates": [ { "value": [ - "dws aitable view update visible-fields --view-id VIEW_ID --field-ids fld1,fld2,fld3" + "dws aitable view update visible-fields --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-ids fld1,fld2,fld3" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", diff --git a/internal/cli/schema_agent_metadata/attendance.json b/internal/cli/schema_agent_metadata/attendance.json index a5c1542c..38527e4d 100644 --- a/internal/cli/schema_agent_metadata/attendance.json +++ b/internal/cli/schema_agent_metadata/attendance.json @@ -2447,7 +2447,7 @@ "avoid_when": [ "当用户实际需要按当前用户权限分页搜索可管理的班次定义时,改用 dws attendance class search。" ], - "confirmation": "not_required", + "confirmation": "user_required", "effect": "write", "effect_source": "agent-hint", "examples": [ @@ -2505,14 +2505,14 @@ ] }, "confirmation": { - "value": "not_required", + "value": "user_required", "source": "skills/mono/schema-hints/zz-attendance-review.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", "review_reason": "attendance-agent-review-v1 marks this tool as reviewed", "candidates": [ { - "value": "not_required", + "value": "user_required", "source": "skills/mono/schema-hints/zz-attendance-review.json", "precedence": "reviewed_explicit", "selected": true, @@ -2682,14 +2682,14 @@ ] }, "risk": { - "value": "medium", + "value": "high", "source": "skills/mono/schema-hints/zz-attendance-review.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", "review_reason": "attendance-agent-review-v1 marks this tool as reviewed", "candidates": [ { - "value": "medium", + "value": "high", "source": "skills/mono/schema-hints/zz-attendance-review.json", "precedence": "reviewed_explicit", "selected": true, @@ -2734,7 +2734,7 @@ "interface_mode": "local", "interface_reason": "当前命令来自本地 Cobra 命令树或复合 helper,无固定 MCP interface_ref", "reviewed": true, - "risk": "medium", + "risk": "high", "source_refs": [ "cobra-help:dws attendance class create --help", "internal/cli/schema_command_registry.json", @@ -3368,7 +3368,7 @@ "avoid_when": [ "当用户实际需要根据班次 ID 查询班次详情时,改用 dws attendance class get。" ], - "confirmation": "not_required", + "confirmation": "user_required", "effect": "write", "effect_source": "agent-hint", "examples": [ @@ -3426,14 +3426,14 @@ ] }, "confirmation": { - "value": "not_required", + "value": "user_required", "source": "skills/mono/schema-hints/zz-attendance-review.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", "review_reason": "attendance-agent-review-v1 marks this tool as reviewed", "candidates": [ { - "value": "not_required", + "value": "user_required", "source": "skills/mono/schema-hints/zz-attendance-review.json", "precedence": "reviewed_explicit", "selected": true, @@ -3603,14 +3603,14 @@ ] }, "risk": { - "value": "medium", + "value": "high", "source": "skills/mono/schema-hints/zz-attendance-review.json", "precedence": "reviewed_explicit", "resolution": "highest_precedence", "review_reason": "attendance-agent-review-v1 marks this tool as reviewed", "candidates": [ { - "value": "medium", + "value": "high", "source": "skills/mono/schema-hints/zz-attendance-review.json", "precedence": "reviewed_explicit", "selected": true, @@ -3655,7 +3655,7 @@ "interface_mode": "local", "interface_reason": "当前命令来自本地 Cobra 命令树或复合 helper,无固定 MCP interface_ref", "reviewed": true, - "risk": "medium", + "risk": "high", "source_refs": [ "cobra-help:dws attendance class update --help", "internal/cli/schema_command_registry.json", @@ -8233,7 +8233,7 @@ "effect": "read", "effect_source": "agent-hint", "examples": [ - "dws attendance schedule get --users USER_IDS --start BEGIN_DATE --end END_DATE" + "dws attendance schedule get --users user001,user002 --start 2026-04-01 --end 2026-04-30" ], "field_provenance": { "agent_summary": { @@ -8344,7 +8344,7 @@ }, "examples": { "value": [ - "dws attendance schedule get --users USER_IDS --start BEGIN_DATE --end END_DATE" + "dws attendance schedule get --users user001,user002 --start 2026-04-01 --end 2026-04-30" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -8353,7 +8353,7 @@ "candidates": [ { "value": [ - "dws attendance schedule get --users USER_IDS --start BEGIN_DATE --end END_DATE" + "dws attendance schedule get --users user001,user002 --start 2026-04-01 --end 2026-04-30" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -8541,7 +8541,7 @@ "effect": "write", "effect_source": "agent-hint", "examples": [ - "dws attendance schedule import --groupId GROUP_ID --scheduleVOS JSON_STRING" + "dws attendance schedule import --groupId 123456 --scheduleVOS '[{\"userId\":\"user001\",\"workDate\":\"2026-04-22 09:00:00\",\"classId\":123,\"isRest\":\"N\"}]'" ], "field_provenance": { "agent_summary": { @@ -8652,7 +8652,7 @@ }, "examples": { "value": [ - "dws attendance schedule import --groupId GROUP_ID --scheduleVOS JSON_STRING" + "dws attendance schedule import --groupId 123456 --scheduleVOS '[{\"userId\":\"user001\",\"workDate\":\"2026-04-22 09:00:00\",\"classId\":123,\"isRest\":\"N\"}]'" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -8661,7 +8661,7 @@ "candidates": [ { "value": [ - "dws attendance schedule import --groupId GROUP_ID --scheduleVOS JSON_STRING" + "dws attendance schedule import --groupId 123456 --scheduleVOS '[{\"userId\":\"user001\",\"workDate\":\"2026-04-22 09:00:00\",\"classId\":123,\"isRest\":\"N\"}]'" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", diff --git a/internal/cli/schema_agent_metadata/chat.json b/internal/cli/schema_agent_metadata/chat.json index b18a59be..f4eec86b 100644 --- a/internal/cli/schema_agent_metadata/chat.json +++ b/internal/cli/schema_agent_metadata/chat.json @@ -10955,7 +10955,7 @@ "effect": "read", "effect_source": "command-verb", "examples": [ - "dws chat message list-direct --user \u003cuserId\u003e --time \"2026-07-01 00:00:00\" --direction forward --limit 50" + "dws chat message list-direct --user \u003cuserId\u003e --time \"2026-07-01 00:00:00\" --direction newer --limit 50" ], "field_provenance": { "agent_summary": { @@ -11046,7 +11046,7 @@ }, "examples": { "value": [ - "dws chat message list-direct --user \u003cuserId\u003e --time \"2026-07-01 00:00:00\" --direction forward --limit 50" + "dws chat message list-direct --user \u003cuserId\u003e --time \"2026-07-01 00:00:00\" --direction newer --limit 50" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -11055,7 +11055,7 @@ "candidates": [ { "value": [ - "dws chat message list-direct --user \u003cuserId\u003e --time \"2026-07-01 00:00:00\" --direction forward --limit 50" + "dws chat message list-direct --user \u003cuserId\u003e --time \"2026-07-01 00:00:00\" --direction newer --limit 50" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", diff --git a/internal/cli/schema_agent_metadata/dev.json b/internal/cli/schema_agent_metadata/dev.json index 45dd0cc5..6b94a6f4 100644 --- a/internal/cli/schema_agent_metadata/dev.json +++ b/internal/cli/schema_agent_metadata/dev.json @@ -8660,7 +8660,7 @@ "effect": "read", "effect_source": "agent-hint", "examples": [ - "dws dev connect status --json" + "dws dev connect status --unified-app-id \u003cunifiedAppId\u003e --json" ], "field_provenance": { "agent_summary": { @@ -8753,7 +8753,7 @@ }, "examples": { "value": [ - "dws dev connect status --json" + "dws dev connect status --unified-app-id \u003cunifiedAppId\u003e --json" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -8762,7 +8762,7 @@ "candidates": [ { "value": [ - "dws dev connect status --json" + "dws dev connect status --unified-app-id \u003cunifiedAppId\u003e --json" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", diff --git a/internal/cli/schema_agent_metadata/doc.json b/internal/cli/schema_agent_metadata/doc.json index 6e38f6bd..65c83ae3 100644 --- a/internal/cli/schema_agent_metadata/doc.json +++ b/internal/cli/schema_agent_metadata/doc.json @@ -2857,7 +2857,7 @@ "effect": "read", "effect_source": "command-verb", "examples": [ - "dws doc download --node NODE_ID --format json", + "dws doc download --node NODE_ID --output ./downloads/ --format json", "dws doc download --node NODE_ID --output ./report.pdf --format json" ], "field_provenance": { @@ -2949,7 +2949,7 @@ }, "examples": { "value": [ - "dws doc download --node NODE_ID --format json", + "dws doc download --node NODE_ID --output ./downloads/ --format json", "dws doc download --node NODE_ID --output ./report.pdf --format json" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", @@ -2959,7 +2959,7 @@ "candidates": [ { "value": [ - "dws doc download --node NODE_ID --format json", + "dws doc download --node NODE_ID --output ./downloads/ --format json", "dws doc download --node NODE_ID --output ./report.pdf --format json" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", @@ -8664,8 +8664,8 @@ "avoid_when": [ "只需查看版本或保存快照时不要使用;未明确目标版本时不要回滚" ], - "confirmation": "not_required", - "effect": "read", + "confirmation": "user_required", + "effect": "destructive", "effect_source": "agent-hint", "examples": [ "dws doc version revert --node DOC_ID --version 3 --format json" @@ -8722,30 +8722,46 @@ ] }, "confirmation": { - "value": "not_required", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "precedence": "unreviewed_explicit", + "value": "user_required", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "candidates": [ + { + "value": "user_required", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": true, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": "not_required", "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "precedence": "unreviewed_explicit", - "selected": true + "selected": false } ] }, "effect": { - "value": "read", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "precedence": "unreviewed_explicit", + "value": "destructive", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "candidates": [ + { + "value": "destructive", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": true, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": "read", "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "precedence": "unreviewed_explicit", - "selected": true + "selected": false } ] }, @@ -8770,16 +8786,24 @@ ] }, "idempotency": { - "value": "idempotent", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "precedence": "unreviewed_explicit", + "value": "unknown", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "candidates": [ + { + "value": "unknown", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": true, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": "idempotent", "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "precedence": "unreviewed_explicit", - "selected": true + "selected": false } ] }, @@ -8841,6 +8865,13 @@ "selected": true, "review_reason": "依据真实 Cobra leaf、对应产品 Skill 与现有 structured hints 审阅选择语义和示例;不改变命令身份、参数、安全或接口事实。" }, + { + "value": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": false, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", @@ -8850,16 +8881,24 @@ ] }, "risk": { - "value": "low", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "precedence": "unreviewed_explicit", + "value": "high", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "candidates": [ + { + "value": "high", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": true, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": "low", "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "precedence": "unreviewed_explicit", - "selected": true + "selected": false } ] }, @@ -8884,17 +8923,18 @@ ] } }, - "idempotency": "idempotent", + "idempotency": "unknown", "interface_mode": "local", "interface_reason": "当前命令来自本地 Cobra 命令树或复合 helper,无固定 MCP interface_ref", "reviewed": true, - "risk": "low", + "risk": "high", "source_refs": [ "CommandRegistry:canonical_path=doc.version_revert", "Skill:skills/mono/references/products/doc.md", "cobra-help:dws doc version revert", "internal/cli/schema_manual_hints.json", - "skills/mono/schema-hints/runtime-surface-completeness.json" + "skills/mono/schema-hints/runtime-surface-completeness.json", + "skills/mono/schema-hints/zz-runtime-confirmation-review.json" ], "use_when": [ "需要将文档回滚到指定版本时" diff --git a/internal/cli/schema_agent_metadata/drive.json b/internal/cli/schema_agent_metadata/drive.json index 3b010246..65935433 100644 --- a/internal/cli/schema_agent_metadata/drive.json +++ b/internal/cli/schema_agent_metadata/drive.json @@ -3627,7 +3627,7 @@ "avoid_when": [ "只需查询公开状态或关闭公开发布时不要使用;目标文件和公开范围未明确时不要开启" ], - "confirmation": "not_required", + "confirmation": "user_required", "effect": "write", "effect_source": "agent-hint", "examples": [ @@ -3686,16 +3686,24 @@ ] }, "confirmation": { - "value": "not_required", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "precedence": "unreviewed_explicit", + "value": "user_required", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "candidates": [ + { + "value": "user_required", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": true, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": "not_required", "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "precedence": "unreviewed_explicit", - "selected": true + "selected": false }, { "value": "not_required", @@ -3707,15 +3715,23 @@ }, "effect": { "value": "write", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "precedence": "unreviewed_explicit", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "candidates": [ + { + "value": "write", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": true, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": "write", "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "precedence": "unreviewed_explicit", - "selected": true + "selected": false }, { "value": "write", @@ -3749,15 +3765,23 @@ }, "idempotency": { "value": "unknown", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "precedence": "unreviewed_explicit", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "candidates": [ + { + "value": "unknown", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": true, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": "unknown", "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "precedence": "unreviewed_explicit", - "selected": true + "selected": false }, { "value": "unknown", @@ -3825,6 +3849,13 @@ "selected": true, "review_reason": "依据真实 Cobra leaf、对应产品 Skill 与现有 structured hints 审阅选择语义和示例;不改变命令身份、参数、安全或接口事实。" }, + { + "value": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": false, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", @@ -3834,16 +3865,24 @@ ] }, "risk": { - "value": "medium", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "precedence": "unreviewed_explicit", + "value": "high", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "candidates": [ + { + "value": "high", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": true, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": "medium", "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "precedence": "unreviewed_explicit", - "selected": true + "selected": false }, { "value": "medium", @@ -3878,14 +3917,15 @@ "interface_mode": "local", "interface_reason": "当前命令来自本地 Cobra 命令树或复合 helper,无固定 MCP interface_ref", "reviewed": true, - "risk": "medium", + "risk": "high", "source_refs": [ "CommandRegistry:canonical_path=drive.publish_set", "Skill:skills/mono/references/products/drive.md", "cobra-help:dws drive publish set", "internal/cli/schema_manual_hints.json", "skills/mono/references/products/drive.md", - "skills/mono/schema-hints/runtime-surface-completeness.json" + "skills/mono/schema-hints/runtime-surface-completeness.json", + "skills/mono/schema-hints/zz-runtime-confirmation-review.json" ], "use_when": [ "用户明确要求开启文件的互联网公开发布时" @@ -3898,7 +3938,7 @@ "avoid_when": [ "只需查询公开状态或开启公开发布时不要使用;目标文件未明确时不要关闭" ], - "confirmation": "not_required", + "confirmation": "user_required", "effect": "write", "effect_source": "agent-hint", "examples": [ @@ -3956,16 +3996,24 @@ ] }, "confirmation": { - "value": "not_required", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "precedence": "unreviewed_explicit", + "value": "user_required", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "candidates": [ + { + "value": "user_required", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": true, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": "not_required", "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "precedence": "unreviewed_explicit", - "selected": true + "selected": false }, { "value": "not_required", @@ -3977,15 +4025,23 @@ }, "effect": { "value": "write", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "precedence": "unreviewed_explicit", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "candidates": [ + { + "value": "write", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": true, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": "write", "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "precedence": "unreviewed_explicit", - "selected": true + "selected": false }, { "value": "write", @@ -4017,15 +4073,23 @@ }, "idempotency": { "value": "unknown", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "precedence": "unreviewed_explicit", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "candidates": [ + { + "value": "unknown", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": true, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": "unknown", "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "precedence": "unreviewed_explicit", - "selected": true + "selected": false }, { "value": "unknown", @@ -4093,6 +4157,13 @@ "selected": true, "review_reason": "依据真实 Cobra leaf、对应产品 Skill 与现有 structured hints 审阅选择语义和示例;不改变命令身份、参数、安全或接口事实。" }, + { + "value": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": false, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", @@ -4102,16 +4173,24 @@ ] }, "risk": { - "value": "medium", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "precedence": "unreviewed_explicit", + "value": "high", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "candidates": [ + { + "value": "high", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": true, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": "medium", "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "precedence": "unreviewed_explicit", - "selected": true + "selected": false }, { "value": "medium", @@ -4146,14 +4225,15 @@ "interface_mode": "local", "interface_reason": "当前命令来自本地 Cobra 命令树或复合 helper,无固定 MCP interface_ref", "reviewed": true, - "risk": "medium", + "risk": "high", "source_refs": [ "CommandRegistry:canonical_path=drive.publish_unset", "Skill:skills/mono/references/products/drive.md", "cobra-help:dws drive publish unset", "internal/cli/schema_manual_hints.json", "skills/mono/references/products/drive.md", - "skills/mono/schema-hints/runtime-surface-completeness.json" + "skills/mono/schema-hints/runtime-surface-completeness.json", + "skills/mono/schema-hints/zz-runtime-confirmation-review.json" ], "use_when": [ "用户明确要求关闭文件的互联网公开发布时" diff --git a/internal/cli/schema_agent_metadata/index.json b/internal/cli/schema_agent_metadata/index.json index 45c61a61..92472be1 100644 --- a/internal/cli/schema_agent_metadata/index.json +++ b/internal/cli/schema_agent_metadata/index.json @@ -1,6 +1,6 @@ { "version": 1, - "source_hash": "sha256:505582c28fd979d7018fe4def9f59d7cfd3911199606594b82cc64b978277656", + "source_hash": "sha256:be1ea2ead798ced7298f457b7b6fca9b4d13816dcb24c47dc6cf1e9c30710ce2", "surface_hash": "sha256:49f79c3ddb1b4513faded7f513952ec49904a28a1f1fea99f4a439ff848df7c7", "coverage": { "surface_products": 20, diff --git a/internal/cli/schema_agent_metadata/sheet.json b/internal/cli/schema_agent_metadata/sheet.json index 6a4edf15..0b9399ae 100644 --- a/internal/cli/schema_agent_metadata/sheet.json +++ b/internal/cli/schema_agent_metadata/sheet.json @@ -1029,7 +1029,7 @@ "avoid_when": [ "当用户实际需要获取钉钉电子表格指定工作表中的浮动图表时,改用 dws sheet chart list。" ], - "confirmation": "not_required", + "confirmation": "user_required", "effect": "write", "effect_source": "agent-hint", "examples": [ @@ -1087,16 +1087,24 @@ ] }, "confirmation": { - "value": "not_required", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "precedence": "unreviewed_explicit", + "value": "user_required", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "candidates": [ + { + "value": "user_required", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": true, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": "not_required", "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "precedence": "unreviewed_explicit", - "selected": true + "selected": false }, { "value": "not_required", @@ -1108,15 +1116,23 @@ }, "effect": { "value": "write", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "precedence": "unreviewed_explicit", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "candidates": [ + { + "value": "write", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": true, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": "write", "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "precedence": "unreviewed_explicit", - "selected": true + "selected": false }, { "value": "write", @@ -1148,15 +1164,23 @@ }, "idempotency": { "value": "unknown", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "precedence": "unreviewed_explicit", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "candidates": [ + { + "value": "unknown", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": true, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": "unknown", "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "precedence": "unreviewed_explicit", - "selected": true + "selected": false }, { "value": "unknown", @@ -1224,6 +1248,13 @@ "selected": true, "review_reason": "依据 reviewed CommandRegistry、dws sheet chart delete --help 与 mono 产品参考,审阅该工具的 Agent 选择语义和示例。" }, + { + "value": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": false, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", @@ -1233,16 +1264,24 @@ ] }, "risk": { - "value": "medium", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "precedence": "unreviewed_explicit", + "value": "high", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "candidates": [ + { + "value": "high", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "precedence": "reviewed_explicit", + "selected": true, + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed" + }, { "value": "medium", "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "precedence": "unreviewed_explicit", - "selected": true + "selected": false }, { "value": "medium", @@ -1277,14 +1316,15 @@ "interface_mode": "local", "interface_reason": "当前命令来自本地 Cobra 命令树或复合 helper,无固定 MCP interface_ref", "reviewed": true, - "risk": "medium", + "risk": "high", "source_refs": [ "cobra-help:dws sheet chart delete --help", "internal/cli/schema_command_registry.json", "internal/cli/schema_manual_hints.json", "skills/mono/references/products/sheet.md", "skills/mono/references/products/sheet/sheet-chart.md", - "skills/mono/schema-hints/runtime-surface-completeness.json" + "skills/mono/schema-hints/runtime-surface-completeness.json", + "skills/mono/schema-hints/zz-runtime-confirmation-review.json" ], "use_when": [ "当用户需要删除钉钉电子表格中指定的浮动图表,并能提供命令所需的查询条件时使用。" diff --git a/internal/cli/schema_agent_metadata/todo.json b/internal/cli/schema_agent_metadata/todo.json index 2cd276c4..b21999ba 100644 --- a/internal/cli/schema_agent_metadata/todo.json +++ b/internal/cli/schema_agent_metadata/todo.json @@ -2007,8 +2007,8 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws todo task create-sub --parent-id \u003cparentId\u003e --title \"子任务标题\" --executors userId1,userId2 --priority 40 --format json", - "dws todo task create-sub --parent-id \u003cparentId\u003e --title \"子任务标题\" --executors userId1 --due \"2026-03-10T18:00:00+08:00\" --format json" + "dws todo task create-sub --parent-id 1234567890 --title \"子任务标题\" --executors userId1,userId2 --priority 40 --format json", + "dws todo task create-sub --parent-id 1234567890 --title \"子任务标题\" --executors userId1 --due \"2026-03-10T18:00:00+08:00\" --format json" ], "field_provenance": { "agent_summary": { @@ -2099,8 +2099,8 @@ }, "examples": { "value": [ - "dws todo task create-sub --parent-id \u003cparentId\u003e --title \"子任务标题\" --executors userId1,userId2 --priority 40 --format json", - "dws todo task create-sub --parent-id \u003cparentId\u003e --title \"子任务标题\" --executors userId1 --due \"2026-03-10T18:00:00+08:00\" --format json" + "dws todo task create-sub --parent-id 1234567890 --title \"子任务标题\" --executors userId1,userId2 --priority 40 --format json", + "dws todo task create-sub --parent-id 1234567890 --title \"子任务标题\" --executors userId1 --due \"2026-03-10T18:00:00+08:00\" --format json" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", @@ -2109,8 +2109,8 @@ "candidates": [ { "value": [ - "dws todo task create-sub --parent-id \u003cparentId\u003e --title \"子任务标题\" --executors userId1,userId2 --priority 40 --format json", - "dws todo task create-sub --parent-id \u003cparentId\u003e --title \"子任务标题\" --executors userId1 --due \"2026-03-10T18:00:00+08:00\" --format json" + "dws todo task create-sub --parent-id 1234567890 --title \"子任务标题\" --executors userId1,userId2 --priority 40 --format json", + "dws todo task create-sub --parent-id 1234567890 --title \"子任务标题\" --executors userId1 --due \"2026-03-10T18:00:00+08:00\" --format json" ], "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "precedence": "reviewed_manual", diff --git a/internal/cli/schema_agent_metadata_audit.json b/internal/cli/schema_agent_metadata_audit.json index 7886e830..facd0b96 100644 --- a/internal/cli/schema_agent_metadata_audit.json +++ b/internal/cli/schema_agent_metadata_audit.json @@ -1,11 +1,11 @@ { "version": 1, - "source_hash": "sha256:505582c28fd979d7018fe4def9f59d7cfd3911199606594b82cc64b978277656", + "source_hash": "sha256:be1ea2ead798ced7298f457b7b6fca9b4d13816dcb24c47dc6cf1e9c30710ce2", "surface_hash": "sha256:49f79c3ddb1b4513faded7f513952ec49904a28a1f1fea99f4a439ff848df7c7", - "source_files": 103, - "hint_files": 15, + "source_files": 104, + "hint_files": 16, "hint_products": 43, - "hint_tools": 2043, + "hint_tools": 2047, "interface_metadata": { "source": "mcp-tools-list+cli-registry", "revision": "4574f7022c32cf4c033e9b7b4156e2fec815fed8", diff --git a/internal/cli/schema_catalog.json b/internal/cli/schema_catalog.json index d2eb7b85..a7bf8cc1 100644 --- a/internal/cli/schema_catalog.json +++ b/internal/cli/schema_catalog.json @@ -1,12 +1,12 @@ { "version": 1, - "source_hash": "sha256:4f6c09f9e8932fb107e90cfaef962c3cd791d6c503793ac4d6d6d5c5e7fae432", + "source_hash": "sha256:38b71630ff2cde00ec04cba145380bfbe04d887c6a174bc331abff7808e6de78", "surface_hash": "sha256:49f79c3ddb1b4513faded7f513952ec49904a28a1f1fea99f4a439ff848df7c7", "catalog": { "agent_metadata": { "products_with_metadata": 20, "source": "embedded-skill-metadata", - "source_hash": "sha256:505582c28fd979d7018fe4def9f59d7cfd3911199606594b82cc64b978277656", + "source_hash": "sha256:be1ea2ead798ced7298f457b7b6fca9b4d13816dcb24c47dc6cf1e9c30710ce2", "surface_hash": "sha256:49f79c3ddb1b4513faded7f513952ec49904a28a1f1fea99f4a439ff848df7c7", "surface_products": 20, "surface_tools": 539, @@ -4096,7 +4096,7 @@ "canonical_path": "attendance.class_create", "cli_name": "create", "cli_path": "attendance class create", - "confirmation": "not_required", + "confirmation": "user_required", "description": "调用 MCP 工具 create_class_setting,创建一个新的班次。\n--name 和 --sections 必填,其余参数可选。由于保存班次耗时较久,指令需要带上 --timeout 10\n--yes 需要用户二次确认之后才允许带入,参考attendance.md中对于创建班次的说明\n\n常用 flag:\n --name 班次名称(必填)\n --owner 班次负责人 userId(可选)\n --class-vo 完整 TopAtClassVO JSON 字符串(可选,用于传入复杂结构)\n\n当使用 --class-vo 传入完整 JSON 时,--name 和 --owner 仍可覆写 JSON 中的同名字段。\ncheckTime 字段统一使用 \"HH:mm\" 格式(如 \"09:00\"),CLI 自动转换为服务端所需的时间戳。\n\n--class-vo JSON 可用字段说明:\n\n name string 班次名称(必填)\n owner string 班次负责人 userId\n sections []object 班次上下班时间段(必填),支持多段上下班,每段包含 times 数组:\n - times []object 每段有且只能有两个对象(上班+下班),每个对象字段:\n checkType string 打卡类型:OnDuty(上班)/ OffDuty(下班)(必填)\n checkTime string 打卡时间,格式 \"HH:mm\"(必填,如 \"09:00\"、\"17:30\")\n across number 是否跨天:0(不跨天)/ 1(跨天)(必填)\n freeCheck bool 是否免打卡\n beginMin number 允许最早提前打卡时间(分钟,-1 表示不限制)\n endMin number 允许最晚打卡时间(分钟,-1 表示不限制)\n setting object 班次其他配置:\n - seriousLateMinutes number 晚到多少分钟记为严重迟到\n - absenteeismLateMinutes number 晚到多少分钟记为旷工迟到\n - attendDays number 本班次记为多少天出勤(支持两位小数)\n - topRestTimeList []object 班次休息时间(仅 sections 只有一段上下班时可用,最多 3 段休息时间):\n checkType string 休息类型:OnDuty(开始休息)/ OffDuty(结束休息)\n checkTime string 休息时间,格式 \"HH:mm\"(如 \"12:00\"、\"13:00\")\n across number 是否跨天:0/1", "effect": "write", "group": "class", @@ -4106,7 +4106,7 @@ "name": "class_create", "primary_cli_path": "attendance class create", "reviewed": true, - "risk": "medium", + "risk": "high", "title": "创建班次", "use_when": [ "当用户需要创建新的考勤班次,并能提供命令所需的查询条件时使用。" @@ -4177,7 +4177,7 @@ "canonical_path": "attendance.class_update", "cli_name": "update", "cli_path": "attendance class update", - "confirmation": "not_required", + "confirmation": "user_required", "description": "调用 MCP 工具 update_class_setting,更新一个已有的班次。\n--class-id 必填;其余参数均可选,仅需对要修改的字段进行赋値,未传的字段会自动从已有配置补充。由于保存班次耗时较久,指令需要带上 --timeout 10\n--yes 需要用户二次确认之后才允许带入,参考attendance.md中对于更新班次的说明\n\n常用 flag:\n --class-id 班次 ID(必填)\n --name 班次名称(可选,不传则保持原值)\n --owner 班次负责人 userId(可选,不传则保持原值)\n --class-vo 完整 TopAtClassVO JSON 字符串(可选,用于传入复杂结构)\n\n当使用 --class-vo 传入完整 JSON 时,--name 和 --owner 仍可覆写 JSON 中的同名字段。\ncheckTime 字段统一使用 \"HH:mm\" 格式(如 \"09:00\"),CLI 自动转换为服务端所需的时间戳。\n\n--class-vo JSON 可用字段说明:\n\n name string 班次名称(可选,不传则保持原值)\n owner string 班次负责人 userId(可选,不传则保持原值)\n sections []object 班次上下班时间段(可选,不传则保持原值),支持多段上下班,每段包含 times 数组:\n - times []object 每段有且只能有两个对象(上班+下班),每个对象字段:\n checkType string 打卡类型:OnDuty(上班)/ OffDuty(下班)(必填)\n checkTime string 打卡时间,格式 \"HH:mm\"(必填,如 \"09:00\"、\"17:30\")\n across number 是否跨天:0(不跨天)/ 1(跨天)(必填)\n freeCheck bool 是否免打卡\n beginMin number 允许最早提前打卡时间(分钟,-1 表示不限制)\n endMin number 允许最晚打卡时间(分钟,-1 表示不限制)\n setting object 班次其他配置:\n - seriousLateMinutes number 晚到多少分钟记为严重迟到\n - absenteeismLateMinutes number 晚到多少分钟记为旷工迟到\n - attendDays number 本班次记为多少天出勤(支持两位小数)\n - topRestTimeList []object 班次休息时间(仅 sections 只有一段上下班时可用,最多 3 段休息时间):\n checkType string 休息类型:OnDuty(开始休息)/ OffDuty(结束休息)\n checkTime string 休息时间,格式 \"HH:mm\"(如 \"12:00\"、\"13:00\")\n across number 是否跨天:0/1", "effect": "write", "group": "class", @@ -4187,7 +4187,7 @@ "name": "class_update", "primary_cli_path": "attendance class update", "reviewed": true, - "risk": "medium", + "risk": "high", "title": "更新班次", "use_when": [ "当用户需要更新已有考勤班次的配置,并能提供命令所需的查询条件时使用。" @@ -10616,17 +10616,17 @@ "canonical_path": "doc.version_revert", "cli_name": "revert", "cli_path": "doc version revert", - "confirmation": "not_required", + "confirmation": "user_required", "description": "回滚文档到指定版本", - "effect": "read", + "effect": "destructive", "group": "version", - "idempotency": "idempotent", + "idempotency": "unknown", "interface_mode": "local", "interface_reason": "当前命令来自本地 Cobra 命令树或复合 helper,无固定 MCP interface_ref", "name": "version_revert", "primary_cli_path": "doc version revert", "reviewed": true, - "risk": "low", + "risk": "high", "title": "回滚文档到指定版本", "use_when": [ "需要将文档回滚到指定版本时" @@ -11199,7 +11199,7 @@ "canonical_path": "drive.publish_set", "cli_name": "set", "cli_path": "drive publish set", - "confirmation": "not_required", + "confirmation": "user_required", "description": "[危险] 将文件设置为互联网公开发布。公开后任何人通过链接即可访问,无需登录钉钉。\n操作者需要是该文件的管理员或拥有者。执行前需要确认,或传入 --yes 跳过确认。\n\n公开权限 (--permission): READER(仅可查看) / DOWNLOADER(可查看和下载,默认) / EDITOR(可编辑)", "effect": "write", "group": "publish", @@ -11209,7 +11209,7 @@ "name": "publish_set", "primary_cli_path": "drive publish set", "reviewed": true, - "risk": "medium", + "risk": "high", "title": "[危险] 设置文件为互联网公开", "use_when": [ "用户明确要求开启文件的互联网公开发布时" @@ -11226,7 +11226,7 @@ "canonical_path": "drive.publish_unset", "cli_name": "unset", "cli_path": "drive publish unset", - "confirmation": "not_required", + "confirmation": "user_required", "description": "[危险] 关闭文件的互联网公开发布。关闭后外部用户将无法再通过链接访问。执行前需要确认,或传入 --yes 跳过确认。", "effect": "write", "group": "publish", @@ -11236,7 +11236,7 @@ "name": "publish_unset", "primary_cli_path": "drive publish unset", "reviewed": true, - "risk": "medium", + "risk": "high", "title": "[危险] 关闭文件互联网公开", "use_when": [ "用户明确要求关闭文件的互联网公开发布时" @@ -14712,7 +14712,7 @@ "canonical_path": "sheet.chart_delete", "cli_name": "delete", "cli_path": "sheet chart delete", - "confirmation": "not_required", + "confirmation": "user_required", "description": "删除钉钉电子表格中指定的浮动图表。\n\n注意: 这是一个危险操作,删除后图表不可恢复。执行前需要确认,或传入 --yes 跳过确认。\nchart-id 可通过 chart list 获取。", "effect": "write", "group": "chart", @@ -14722,7 +14722,7 @@ "name": "chart_delete", "primary_cli_path": "sheet chart delete", "reviewed": true, - "risk": "medium", + "risk": "high", "title": "删除浮动图表", "use_when": [ "当用户需要删除钉钉电子表格中指定的浮动图表,并能提供命令所需的查询条件时使用。" @@ -87353,7 +87353,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update aggregate --view-id VIEW_ID --field-id fldX --action SUM" + "dws aitable view update aggregate --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-id fldX --action SUM" ], "field_provenance": { "agent_summary": { @@ -87486,7 +87486,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update aggregate --view-id VIEW_ID --field-id fldX --action SUM" + "dws aitable view update aggregate --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-id fldX --action SUM" ] } ], @@ -87495,7 +87495,7 @@ "review_reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update aggregate --view-id VIEW_ID --field-id fldX --action SUM" + "dws aitable view update aggregate --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-id fldX --action SUM" ] }, "idempotency": { @@ -88359,7 +88359,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update card --view-id VIEW_ID --cover-field-id fldXXX --cover-resize-mode contain" + "dws aitable view update card --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --cover-field-id fldXXX --cover-resize-mode contain" ], "field_provenance": { "agent_summary": { @@ -88492,7 +88492,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update card --view-id VIEW_ID --cover-field-id fldXXX --cover-resize-mode contain" + "dws aitable view update card --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --cover-field-id fldXXX --cover-resize-mode contain" ] } ], @@ -88501,7 +88501,7 @@ "review_reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update card --view-id VIEW_ID --cover-field-id fldXXX --cover-resize-mode contain" + "dws aitable view update card --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --cover-field-id fldXXX --cover-resize-mode contain" ] }, "idempotency": { @@ -89617,7 +89617,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update field-widths --view-id VIEW_ID --field-id fldX --width 200" + "dws aitable view update field-widths --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-id fldX --width 200" ], "field_provenance": { "agent_summary": { @@ -89750,7 +89750,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update field-widths --view-id VIEW_ID --field-id fldX --width 200" + "dws aitable view update field-widths --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-id fldX --width 200" ] } ], @@ -89759,7 +89759,7 @@ "review_reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update field-widths --view-id VIEW_ID --field-id fldX --width 200" + "dws aitable view update field-widths --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-id fldX --width 200" ] }, "idempotency": { @@ -90538,7 +90538,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update fill-color-rule --view-id VIEW_ID --json '[]'" + "dws aitable view update fill-color-rule --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[]'" ], "field_provenance": { "agent_summary": { @@ -90671,7 +90671,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update fill-color-rule --view-id VIEW_ID --json '[]'" + "dws aitable view update fill-color-rule --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[]'" ] } ], @@ -90680,7 +90680,7 @@ "review_reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update fill-color-rule --view-id VIEW_ID --json '[]'" + "dws aitable view update fill-color-rule --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[]'" ] }, "idempotency": { @@ -91285,7 +91285,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update filter --view-id VIEW_ID --json '[{\"operator\":\"and\",\"operands\":[{\"operator\":\"eq\",\"operands\":[\"fldX\",\"value\"]}]}]'" + "dws aitable view update filter --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"operator\":\"and\",\"operands\":[{\"operator\":\"eq\",\"operands\":[\"fldX\",\"value\"]}]}]'" ], "field_provenance": { "agent_summary": { @@ -91418,7 +91418,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update filter --view-id VIEW_ID --json '[{\"operator\":\"and\",\"operands\":[{\"operator\":\"eq\",\"operands\":[\"fldX\",\"value\"]}]}]'" + "dws aitable view update filter --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"operator\":\"and\",\"operands\":[{\"operator\":\"eq\",\"operands\":[\"fldX\",\"value\"]}]}]'" ] } ], @@ -91427,7 +91427,7 @@ "review_reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update filter --view-id VIEW_ID --json '[{\"operator\":\"and\",\"operands\":[{\"operator\":\"eq\",\"operands\":[\"fldX\",\"value\"]}]}]'" + "dws aitable view update filter --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"operator\":\"and\",\"operands\":[{\"operator\":\"eq\",\"operands\":[\"fldX\",\"value\"]}]}]'" ] }, "idempotency": { @@ -92040,7 +92040,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update frozen-cols --view-id VIEW_ID --count 1" + "dws aitable view update frozen-cols --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --count 1" ], "field_provenance": { "agent_summary": { @@ -92173,7 +92173,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update frozen-cols --view-id VIEW_ID --count 1" + "dws aitable view update frozen-cols --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --count 1" ] } ], @@ -92182,7 +92182,7 @@ "review_reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update frozen-cols --view-id VIEW_ID --count 1" + "dws aitable view update frozen-cols --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --count 1" ] }, "idempotency": { @@ -92821,7 +92821,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update group --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" + "dws aitable view update group --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" ], "field_provenance": { "agent_summary": { @@ -92954,7 +92954,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update group --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" + "dws aitable view update group --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" ] } ], @@ -92963,7 +92963,7 @@ "review_reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update group --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" + "dws aitable view update group --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" ] }, "idempotency": { @@ -93577,7 +93577,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update name --view-id VIEW_ID --name \"新视图名\"" + "dws aitable view update name --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --name \"新视图名\"" ], "field_provenance": { "agent_summary": { @@ -93710,7 +93710,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update name --view-id VIEW_ID --name \"新视图名\"" + "dws aitable view update name --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --name \"新视图名\"" ] } ], @@ -93719,7 +93719,7 @@ "review_reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update name --view-id VIEW_ID --name \"新视图名\"" + "dws aitable view update name --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --name \"新视图名\"" ] }, "idempotency": { @@ -94330,7 +94330,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update row-height --view-id VIEW_ID --cell-height 32" + "dws aitable view update row-height --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --cell-height 32" ], "field_provenance": { "agent_summary": { @@ -94463,7 +94463,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update row-height --view-id VIEW_ID --cell-height 32" + "dws aitable view update row-height --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --cell-height 32" ] } ], @@ -94472,7 +94472,7 @@ "review_reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update row-height --view-id VIEW_ID --cell-height 32" + "dws aitable view update row-height --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --cell-height 32" ] }, "idempotency": { @@ -95111,7 +95111,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update sort --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" + "dws aitable view update sort --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" ], "field_provenance": { "agent_summary": { @@ -95244,7 +95244,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update sort --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" + "dws aitable view update sort --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" ] } ], @@ -95253,7 +95253,7 @@ "review_reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update sort --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" + "dws aitable view update sort --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" ] }, "idempotency": { @@ -95867,7 +95867,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update timebar --view-id VIEW_ID --start-field fldStart --end-field fldEnd --timeline-scale month" + "dws aitable view update timebar --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --start-field fldStart --end-field fldEnd --timeline-scale month" ], "field_provenance": { "agent_summary": { @@ -96000,7 +96000,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update timebar --view-id VIEW_ID --start-field fldStart --end-field fldEnd --timeline-scale month" + "dws aitable view update timebar --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --start-field fldStart --end-field fldEnd --timeline-scale month" ] } ], @@ -96009,7 +96009,7 @@ "review_reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update timebar --view-id VIEW_ID --start-field fldStart --end-field fldEnd --timeline-scale month" + "dws aitable view update timebar --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --start-field fldStart --end-field fldEnd --timeline-scale month" ] }, "idempotency": { @@ -97125,7 +97125,7 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws aitable view update visible-fields --view-id VIEW_ID --field-ids fld1,fld2,fld3" + "dws aitable view update visible-fields --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-ids fld1,fld2,fld3" ], "field_provenance": { "agent_summary": { @@ -97258,7 +97258,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update visible-fields --view-id VIEW_ID --field-ids fld1,fld2,fld3" + "dws aitable view update visible-fields --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-ids fld1,fld2,fld3" ] } ], @@ -97267,7 +97267,7 @@ "review_reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws aitable view update visible-fields --view-id VIEW_ID --field-ids fld1,fld2,fld3" + "dws aitable view update visible-fields --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-ids fld1,fld2,fld3" ] }, "idempotency": { @@ -106512,7 +106512,7 @@ "canonical_path": "attendance.class_create", "cli_name": "create", "cli_path": "attendance class create", - "confirmation": "not_required", + "confirmation": "user_required", "description": "调用 MCP 工具 create_class_setting,创建一个新的班次。\n--name 和 --sections 必填,其余参数可选。由于保存班次耗时较久,指令需要带上 --timeout 10\n--yes 需要用户二次确认之后才允许带入,参考attendance.md中对于创建班次的说明\n\n常用 flag:\n --name 班次名称(必填)\n --owner 班次负责人 userId(可选)\n --class-vo 完整 TopAtClassVO JSON 字符串(可选,用于传入复杂结构)\n\n当使用 --class-vo 传入完整 JSON 时,--name 和 --owner 仍可覆写 JSON 中的同名字段。\ncheckTime 字段统一使用 \"HH:mm\" 格式(如 \"09:00\"),CLI 自动转换为服务端所需的时间戳。\n\n--class-vo JSON 可用字段说明:\n\n name string 班次名称(必填)\n owner string 班次负责人 userId\n sections []object 班次上下班时间段(必填),支持多段上下班,每段包含 times 数组:\n - times []object 每段有且只能有两个对象(上班+下班),每个对象字段:\n checkType string 打卡类型:OnDuty(上班)/ OffDuty(下班)(必填)\n checkTime string 打卡时间,格式 \"HH:mm\"(必填,如 \"09:00\"、\"17:30\")\n across number 是否跨天:0(不跨天)/ 1(跨天)(必填)\n freeCheck bool 是否免打卡\n beginMin number 允许最早提前打卡时间(分钟,-1 表示不限制)\n endMin number 允许最晚打卡时间(分钟,-1 表示不限制)\n setting object 班次其他配置:\n - seriousLateMinutes number 晚到多少分钟记为严重迟到\n - absenteeismLateMinutes number 晚到多少分钟记为旷工迟到\n - attendDays number 本班次记为多少天出勤(支持两位小数)\n - topRestTimeList []object 班次休息时间(仅 sections 只有一段上下班时可用,最多 3 段休息时间):\n checkType string 休息类型:OnDuty(开始休息)/ OffDuty(结束休息)\n checkTime string 休息时间,格式 \"HH:mm\"(如 \"12:00\"、\"13:00\")\n across number 是否跨天:0/1", "display": "考勤打卡 / 排班 / 统计", "effect": "write", @@ -106594,7 +106594,7 @@ "review_reason": "attendance-agent-review-v1 marks this tool as reviewed", "selected": true, "source": "skills/mono/schema-hints/zz-attendance-review.json", - "value": "not_required" + "value": "user_required" }, { "precedence": "unreviewed_explicit", @@ -106613,7 +106613,7 @@ "resolution": "highest_precedence", "review_reason": "attendance-agent-review-v1 marks this tool as reviewed", "source": "skills/mono/schema-hints/zz-attendance-review.json", - "value": "not_required" + "value": "user_required" }, "description": { "candidates": [ @@ -106785,7 +106785,7 @@ "review_reason": "attendance-agent-review-v1 marks this tool as reviewed", "selected": true, "source": "skills/mono/schema-hints/zz-attendance-review.json", - "value": "medium" + "value": "high" }, { "precedence": "unreviewed_explicit", @@ -106804,7 +106804,7 @@ "resolution": "highest_precedence", "review_reason": "attendance-agent-review-v1 marks this tool as reviewed", "source": "skills/mono/schema-hints/zz-attendance-review.json", - "value": "medium" + "value": "high" }, "title": { "candidates": [ @@ -107203,7 +107203,7 @@ "primary_cli_path": "attendance class create", "product_id": "attendance", "reviewed": true, - "risk": "medium", + "risk": "high", "source": "reviewed_command_registry", "title": "创建班次", "use_when": [ @@ -108407,7 +108407,7 @@ "canonical_path": "attendance.class_update", "cli_name": "update", "cli_path": "attendance class update", - "confirmation": "not_required", + "confirmation": "user_required", "description": "调用 MCP 工具 update_class_setting,更新一个已有的班次。\n--class-id 必填;其余参数均可选,仅需对要修改的字段进行赋値,未传的字段会自动从已有配置补充。由于保存班次耗时较久,指令需要带上 --timeout 10\n--yes 需要用户二次确认之后才允许带入,参考attendance.md中对于更新班次的说明\n\n常用 flag:\n --class-id 班次 ID(必填)\n --name 班次名称(可选,不传则保持原值)\n --owner 班次负责人 userId(可选,不传则保持原值)\n --class-vo 完整 TopAtClassVO JSON 字符串(可选,用于传入复杂结构)\n\n当使用 --class-vo 传入完整 JSON 时,--name 和 --owner 仍可覆写 JSON 中的同名字段。\ncheckTime 字段统一使用 \"HH:mm\" 格式(如 \"09:00\"),CLI 自动转换为服务端所需的时间戳。\n\n--class-vo JSON 可用字段说明:\n\n name string 班次名称(可选,不传则保持原值)\n owner string 班次负责人 userId(可选,不传则保持原值)\n sections []object 班次上下班时间段(可选,不传则保持原值),支持多段上下班,每段包含 times 数组:\n - times []object 每段有且只能有两个对象(上班+下班),每个对象字段:\n checkType string 打卡类型:OnDuty(上班)/ OffDuty(下班)(必填)\n checkTime string 打卡时间,格式 \"HH:mm\"(必填,如 \"09:00\"、\"17:30\")\n across number 是否跨天:0(不跨天)/ 1(跨天)(必填)\n freeCheck bool 是否免打卡\n beginMin number 允许最早提前打卡时间(分钟,-1 表示不限制)\n endMin number 允许最晚打卡时间(分钟,-1 表示不限制)\n setting object 班次其他配置:\n - seriousLateMinutes number 晚到多少分钟记为严重迟到\n - absenteeismLateMinutes number 晚到多少分钟记为旷工迟到\n - attendDays number 本班次记为多少天出勤(支持两位小数)\n - topRestTimeList []object 班次休息时间(仅 sections 只有一段上下班时可用,最多 3 段休息时间):\n checkType string 休息类型:OnDuty(开始休息)/ OffDuty(结束休息)\n checkTime string 休息时间,格式 \"HH:mm\"(如 \"12:00\"、\"13:00\")\n across number 是否跨天:0/1", "display": "考勤打卡 / 排班 / 统计", "effect": "write", @@ -108489,7 +108489,7 @@ "review_reason": "attendance-agent-review-v1 marks this tool as reviewed", "selected": true, "source": "skills/mono/schema-hints/zz-attendance-review.json", - "value": "not_required" + "value": "user_required" }, { "precedence": "unreviewed_explicit", @@ -108508,7 +108508,7 @@ "resolution": "highest_precedence", "review_reason": "attendance-agent-review-v1 marks this tool as reviewed", "source": "skills/mono/schema-hints/zz-attendance-review.json", - "value": "not_required" + "value": "user_required" }, "description": { "candidates": [ @@ -108680,7 +108680,7 @@ "review_reason": "attendance-agent-review-v1 marks this tool as reviewed", "selected": true, "source": "skills/mono/schema-hints/zz-attendance-review.json", - "value": "medium" + "value": "high" }, { "precedence": "unreviewed_explicit", @@ -108699,7 +108699,7 @@ "resolution": "highest_precedence", "review_reason": "attendance-agent-review-v1 marks this tool as reviewed", "source": "skills/mono/schema-hints/zz-attendance-review.json", - "value": "medium" + "value": "high" }, "title": { "candidates": [ @@ -109176,7 +109176,7 @@ "primary_cli_path": "attendance class update", "product_id": "attendance", "reviewed": true, - "risk": "medium", + "risk": "high", "source": "reviewed_command_registry", "title": "更新班次", "use_when": [ @@ -121242,7 +121242,7 @@ "effect": "read", "effect_source": "agent-hint", "examples": [ - "dws attendance schedule get --users USER_IDS --start BEGIN_DATE --end END_DATE" + "dws attendance schedule get --users user001,user002 --start 2026-04-01 --end 2026-04-30" ], "field_provenance": { "agent_summary": { @@ -121389,7 +121389,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws attendance schedule get --users USER_IDS --start BEGIN_DATE --end END_DATE" + "dws attendance schedule get --users user001,user002 --start 2026-04-01 --end 2026-04-30" ] } ], @@ -121398,7 +121398,7 @@ "review_reason": "依据 reviewed CommandRegistry、dws attendance schedule get --help 与 mono 产品参考,审阅该工具的 Agent 选择语义和示例。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws attendance schedule get --users USER_IDS --start BEGIN_DATE --end END_DATE" + "dws attendance schedule get --users user001,user002 --start 2026-04-01 --end 2026-04-30" ] }, "idempotency": { @@ -121883,7 +121883,7 @@ "effect": "write", "effect_source": "agent-hint", "examples": [ - "dws attendance schedule import --groupId GROUP_ID --scheduleVOS JSON_STRING" + "dws attendance schedule import --groupId 123456 --scheduleVOS '[{\"userId\":\"user001\",\"workDate\":\"2026-04-22 09:00:00\",\"classId\":123,\"isRest\":\"N\"}]'" ], "field_provenance": { "agent_summary": { @@ -122030,7 +122030,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws attendance schedule import --groupId GROUP_ID --scheduleVOS JSON_STRING" + "dws attendance schedule import --groupId 123456 --scheduleVOS '[{\"userId\":\"user001\",\"workDate\":\"2026-04-22 09:00:00\",\"classId\":123,\"isRest\":\"N\"}]'" ] } ], @@ -122039,7 +122039,7 @@ "review_reason": "依据 reviewed CommandRegistry、dws attendance schedule import --help 与 mono 产品参考,审阅该工具的 Agent 选择语义和示例。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws attendance schedule import --groupId GROUP_ID --scheduleVOS JSON_STRING" + "dws attendance schedule import --groupId 123456 --scheduleVOS '[{\"userId\":\"user001\",\"workDate\":\"2026-04-22 09:00:00\",\"classId\":123,\"isRest\":\"N\"}]'" ] }, "idempotency": { @@ -160473,7 +160473,7 @@ "effect": "read", "effect_source": "command-verb", "examples": [ - "dws chat message list-direct --user \u003cuserId\u003e --time \"2026-07-01 00:00:00\" --direction forward --limit 50" + "dws chat message list-direct --user \u003cuserId\u003e --time \"2026-07-01 00:00:00\" --direction newer --limit 50" ], "field_provenance": { "agent_summary": { @@ -160606,7 +160606,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws chat message list-direct --user \u003cuserId\u003e --time \"2026-07-01 00:00:00\" --direction forward --limit 50" + "dws chat message list-direct --user \u003cuserId\u003e --time \"2026-07-01 00:00:00\" --direction newer --limit 50" ] } ], @@ -160615,7 +160615,7 @@ "review_reason": "AI 生成并复核的 Agent 选择语义,依据精确 CommandRegistry identity、真实 Cobra help 与产品参考,不改写执行、安全或接口事实。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws chat message list-direct --user \u003cuserId\u003e --time \"2026-07-01 00:00:00\" --direction forward --limit 50" + "dws chat message list-direct --user \u003cuserId\u003e --time \"2026-07-01 00:00:00\" --direction newer --limit 50" ] }, "idempotency": { @@ -204855,7 +204855,7 @@ "effect": "read", "effect_source": "agent-hint", "examples": [ - "dws dev connect status --json" + "dws dev connect status --unified-app-id \u003cunifiedAppId\u003e --json" ], "field_provenance": { "agent_summary": { @@ -204984,7 +204984,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws dev connect status --json" + "dws dev connect status --unified-app-id \u003cunifiedAppId\u003e --json" ] } ], @@ -204993,7 +204993,7 @@ "review_reason": "AI 生成并复核的 Agent 选择语义,依据精确 CommandRegistry identity、真实 Cobra help 与产品参考,不改写执行、安全或接口事实。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws dev connect status --json" + "dws dev connect status --unified-app-id \u003cunifiedAppId\u003e --json" ] }, "idempotency": { @@ -233712,7 +233712,7 @@ "effect": "read", "effect_source": "command-verb", "examples": [ - "dws doc download --node NODE_ID --format json", + "dws doc download --node NODE_ID --output ./downloads/ --format json", "dws doc download --node NODE_ID --output ./report.pdf --format json" ], "field_provenance": { @@ -233846,7 +233846,7 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws doc download --node NODE_ID --format json", + "dws doc download --node NODE_ID --output ./downloads/ --format json", "dws doc download --node NODE_ID --output ./report.pdf --format json" ] } @@ -233856,7 +233856,7 @@ "review_reason": "依据真实 Cobra leaf、对应产品 Skill 与现有 structured hints 审阅选择语义和示例;不改变命令身份、参数、安全或接口事实。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws doc download --node NODE_ID --format json", + "dws doc download --node NODE_ID --output ./downloads/ --format json", "dws doc download --node NODE_ID --output ./report.pdf --format json" ] }, @@ -251891,7 +251891,8 @@ "Skill:skills/mono/references/products/doc.md", "cobra-help:dws doc version revert", "internal/cli/schema_manual_hints.json", - "skills/mono/schema-hints/runtime-surface-completeness.json" + "skills/mono/schema-hints/runtime-surface-completeness.json", + "skills/mono/schema-hints/zz-runtime-confirmation-review.json" ], "agent_summary": "将文档回滚到指定版本", "agent_summary_source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", @@ -251902,10 +251903,10 @@ "canonical_path": "doc.version_revert", "cli_name": "revert", "cli_path": "doc version revert", - "confirmation": "not_required", + "confirmation": "user_required", "description": "回滚文档到指定版本", "display": "钉钉文档管理", - "effect": "read", + "effect": "destructive", "effect_source": "agent-hint", "examples": [ "dws doc version revert --node DOC_ID --version 3 --format json" @@ -251980,16 +251981,24 @@ "confirmation": { "candidates": [ { - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "selected": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "user_required" + }, + { + "precedence": "unreviewed_explicit", + "selected": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "value": "not_required" } ], - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "value": "not_required" + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "user_required" }, "description": { "candidates": [ @@ -252008,16 +252017,24 @@ "effect": { "candidates": [ { - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "selected": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "destructive" + }, + { + "precedence": "unreviewed_explicit", + "selected": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "value": "read" } ], - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "value": "read" + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "destructive" }, "examples": { "candidates": [ @@ -252042,16 +252059,24 @@ "idempotency": { "candidates": [ { - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "selected": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "unknown" + }, + { + "precedence": "unreviewed_explicit", + "selected": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "value": "idempotent" } ], - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "value": "idempotent" + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "unknown" }, "interface_mode": { "candidates": [ @@ -252106,6 +252131,13 @@ "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": true }, + { + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "selected": false, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": true + }, { "precedence": "unreviewed_explicit", "selected": false, @@ -252122,16 +252154,24 @@ "risk": { "candidates": [ { - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "selected": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "high" + }, + { + "precedence": "unreviewed_explicit", + "selected": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "value": "low" } ], - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "value": "low" + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "high" }, "title": { "candidates": [ @@ -252170,7 +252210,7 @@ }, "group": "version", "has_parameters": true, - "idempotency": "idempotent", + "idempotency": "unknown", "interface_mode": "local", "interface_reason": "当前命令来自本地 Cobra 命令树或复合 helper,无固定 MCP interface_ref", "is_alias": false, @@ -252362,7 +252402,7 @@ "primary_cli_path": "doc version revert", "product_id": "doc", "reviewed": true, - "risk": "low", + "risk": "high", "source": "reviewed_command_registry", "title": "回滚文档到指定版本", "use_when": [ @@ -262787,7 +262827,8 @@ "cobra-help:dws drive publish set", "internal/cli/schema_manual_hints.json", "skills/mono/references/products/drive.md", - "skills/mono/schema-hints/runtime-surface-completeness.json" + "skills/mono/schema-hints/runtime-surface-completeness.json", + "skills/mono/schema-hints/zz-runtime-confirmation-review.json" ], "agent_summary": "开启文件的互联网公开发布", "agent_summary_source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", @@ -262798,7 +262839,7 @@ "canonical_path": "drive.publish_set", "cli_name": "set", "cli_path": "drive publish set", - "confirmation": "not_required", + "confirmation": "user_required", "description": "[危险] 将文件设置为互联网公开发布。公开后任何人通过链接即可访问,无需登录钉钉。\n操作者需要是该文件的管理员或拥有者。执行前需要确认,或传入 --yes 跳过确认。\n\n公开权限 (--permission): READER(仅可查看) / DOWNLOADER(可查看和下载,默认) / EDITOR(可编辑)", "display": "钉盘文件管理", "effect": "write", @@ -262877,8 +262918,15 @@ "confirmation": { "candidates": [ { - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "selected": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "user_required" + }, + { + "precedence": "unreviewed_explicit", + "selected": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "value": "not_required" }, @@ -262889,10 +262937,11 @@ "value": "not_required" } ], - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "value": "not_required" + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "user_required" }, "description": { "candidates": [ @@ -262911,8 +262960,15 @@ "effect": { "candidates": [ { - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "selected": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "write" + }, + { + "precedence": "unreviewed_explicit", + "selected": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "value": "write" }, @@ -262923,9 +262979,10 @@ "value": "write" } ], - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", "value": "write" }, "examples": { @@ -262953,8 +263010,15 @@ "idempotency": { "candidates": [ { - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "selected": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "unknown" + }, + { + "precedence": "unreviewed_explicit", + "selected": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "value": "unknown" }, @@ -262965,9 +263029,10 @@ "value": "unknown" } ], - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", "value": "unknown" }, "interface_mode": { @@ -263023,6 +263088,13 @@ "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": true }, + { + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "selected": false, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": true + }, { "precedence": "unreviewed_explicit", "selected": false, @@ -263039,8 +263111,15 @@ "risk": { "candidates": [ { - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "selected": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "high" + }, + { + "precedence": "unreviewed_explicit", + "selected": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "value": "medium" }, @@ -263051,10 +263130,11 @@ "value": "medium" } ], - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "value": "medium" + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "high" }, "title": { "candidates": [ @@ -263285,7 +263365,7 @@ "primary_cli_path": "drive publish set", "product_id": "drive", "reviewed": true, - "risk": "medium", + "risk": "high", "source": "reviewed_command_registry", "title": "[危险] 设置文件为互联网公开", "use_when": [ @@ -263300,7 +263380,8 @@ "cobra-help:dws drive publish unset", "internal/cli/schema_manual_hints.json", "skills/mono/references/products/drive.md", - "skills/mono/schema-hints/runtime-surface-completeness.json" + "skills/mono/schema-hints/runtime-surface-completeness.json", + "skills/mono/schema-hints/zz-runtime-confirmation-review.json" ], "agent_summary": "关闭文件的互联网公开发布", "agent_summary_source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", @@ -263311,7 +263392,7 @@ "canonical_path": "drive.publish_unset", "cli_name": "unset", "cli_path": "drive publish unset", - "confirmation": "not_required", + "confirmation": "user_required", "description": "[危险] 关闭文件的互联网公开发布。关闭后外部用户将无法再通过链接访问。执行前需要确认,或传入 --yes 跳过确认。", "display": "钉盘文件管理", "effect": "write", @@ -263389,8 +263470,15 @@ "confirmation": { "candidates": [ { - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "selected": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "user_required" + }, + { + "precedence": "unreviewed_explicit", + "selected": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "value": "not_required" }, @@ -263401,10 +263489,11 @@ "value": "not_required" } ], - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "value": "not_required" + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "user_required" }, "description": { "candidates": [ @@ -263423,8 +263512,15 @@ "effect": { "candidates": [ { - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "selected": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "write" + }, + { + "precedence": "unreviewed_explicit", + "selected": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "value": "write" }, @@ -263435,9 +263531,10 @@ "value": "write" } ], - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", "value": "write" }, "examples": { @@ -263463,8 +263560,15 @@ "idempotency": { "candidates": [ { - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "selected": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "unknown" + }, + { + "precedence": "unreviewed_explicit", + "selected": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "value": "unknown" }, @@ -263475,9 +263579,10 @@ "value": "unknown" } ], - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", "value": "unknown" }, "interface_mode": { @@ -263533,6 +263638,13 @@ "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": true }, + { + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "selected": false, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": true + }, { "precedence": "unreviewed_explicit", "selected": false, @@ -263549,8 +263661,15 @@ "risk": { "candidates": [ { - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "selected": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "high" + }, + { + "precedence": "unreviewed_explicit", + "selected": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "value": "medium" }, @@ -263561,10 +263680,11 @@ "value": "medium" } ], - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "value": "medium" + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "high" }, "title": { "candidates": [ @@ -263705,7 +263825,7 @@ "primary_cli_path": "drive publish unset", "product_id": "drive", "reviewed": true, - "risk": "medium", + "risk": "high", "source": "reviewed_command_registry", "title": "[危险] 关闭文件互联网公开", "use_when": [ @@ -326501,7 +326621,8 @@ "internal/cli/schema_manual_hints.json", "skills/mono/references/products/sheet.md", "skills/mono/references/products/sheet/sheet-chart.md", - "skills/mono/schema-hints/runtime-surface-completeness.json" + "skills/mono/schema-hints/runtime-surface-completeness.json", + "skills/mono/schema-hints/zz-runtime-confirmation-review.json" ], "agent_summary": "删除钉钉电子表格中指定的浮动图表。", "agent_summary_source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", @@ -326512,7 +326633,7 @@ "canonical_path": "sheet.chart_delete", "cli_name": "delete", "cli_path": "sheet chart delete", - "confirmation": "not_required", + "confirmation": "user_required", "description": "删除钉钉电子表格中指定的浮动图表。\n\n注意: 这是一个危险操作,删除后图表不可恢复。执行前需要确认,或传入 --yes 跳过确认。\nchart-id 可通过 chart list 获取。", "display": "钉钉表格管理", "effect": "write", @@ -326590,8 +326711,15 @@ "confirmation": { "candidates": [ { - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "selected": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "user_required" + }, + { + "precedence": "unreviewed_explicit", + "selected": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "value": "not_required" }, @@ -326602,10 +326730,11 @@ "value": "not_required" } ], - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "value": "not_required" + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "user_required" }, "description": { "candidates": [ @@ -326624,8 +326753,15 @@ "effect": { "candidates": [ { - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "selected": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "write" + }, + { + "precedence": "unreviewed_explicit", + "selected": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "value": "write" }, @@ -326636,9 +326772,10 @@ "value": "write" } ], - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", "value": "write" }, "examples": { @@ -326664,8 +326801,15 @@ "idempotency": { "candidates": [ { - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "selected": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "unknown" + }, + { + "precedence": "unreviewed_explicit", + "selected": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "value": "unknown" }, @@ -326676,9 +326820,10 @@ "value": "unknown" } ], - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", "value": "unknown" }, "interface_mode": { @@ -326734,6 +326879,13 @@ "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": true }, + { + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "selected": false, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": true + }, { "precedence": "unreviewed_explicit", "selected": false, @@ -326750,8 +326902,15 @@ "risk": { "candidates": [ { - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", "selected": true, + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "high" + }, + { + "precedence": "unreviewed_explicit", + "selected": false, "source": "skills/mono/schema-hints/runtime-surface-completeness.json", "value": "medium" }, @@ -326762,10 +326921,11 @@ "value": "medium" } ], - "precedence": "unreviewed_explicit", + "precedence": "reviewed_explicit", "resolution": "highest_precedence", - "source": "skills/mono/schema-hints/runtime-surface-completeness.json", - "value": "medium" + "review_reason": "runtime-confirmation-review-v1 marks this tool as reviewed", + "source": "skills/mono/schema-hints/zz-runtime-confirmation-review.json", + "value": "high" }, "title": { "candidates": [ @@ -327086,7 +327246,7 @@ "primary_cli_path": "sheet chart delete", "product_id": "sheet", "reviewed": true, - "risk": "medium", + "risk": "high", "source": "reviewed_command_registry", "title": "删除浮动图表", "use_when": [ @@ -380927,8 +381087,8 @@ "effect": "write", "effect_source": "command-verb", "examples": [ - "dws todo task create-sub --parent-id \u003cparentId\u003e --title \"子任务标题\" --executors userId1,userId2 --priority 40 --format json", - "dws todo task create-sub --parent-id \u003cparentId\u003e --title \"子任务标题\" --executors userId1 --due \"2026-03-10T18:00:00+08:00\" --format json" + "dws todo task create-sub --parent-id 1234567890 --title \"子任务标题\" --executors userId1,userId2 --priority 40 --format json", + "dws todo task create-sub --parent-id 1234567890 --title \"子任务标题\" --executors userId1 --due \"2026-03-10T18:00:00+08:00\" --format json" ], "field_provenance": { "agent_summary": { @@ -381061,8 +381221,8 @@ "selected": true, "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws todo task create-sub --parent-id \u003cparentId\u003e --title \"子任务标题\" --executors userId1,userId2 --priority 40 --format json", - "dws todo task create-sub --parent-id \u003cparentId\u003e --title \"子任务标题\" --executors userId1 --due \"2026-03-10T18:00:00+08:00\" --format json" + "dws todo task create-sub --parent-id 1234567890 --title \"子任务标题\" --executors userId1,userId2 --priority 40 --format json", + "dws todo task create-sub --parent-id 1234567890 --title \"子任务标题\" --executors userId1 --due \"2026-03-10T18:00:00+08:00\" --format json" ] } ], @@ -381071,8 +381231,8 @@ "review_reason": "依据真实 Cobra leaf、对应产品 Skill 与现有 structured hints 审阅选择语义和示例;不改变命令身份、参数、安全或接口事实。", "source": "internal/cli/schema_manual_hints.json#agent_hints@ai-agent-contract-2026-07-13-v1", "value": [ - "dws todo task create-sub --parent-id \u003cparentId\u003e --title \"子任务标题\" --executors userId1,userId2 --priority 40 --format json", - "dws todo task create-sub --parent-id \u003cparentId\u003e --title \"子任务标题\" --executors userId1 --due \"2026-03-10T18:00:00+08:00\" --format json" + "dws todo task create-sub --parent-id 1234567890 --title \"子任务标题\" --executors userId1,userId2 --priority 40 --format json", + "dws todo task create-sub --parent-id 1234567890 --title \"子任务标题\" --executors userId1 --due \"2026-03-10T18:00:00+08:00\" --format json" ] }, "idempotency": { diff --git a/internal/cli/schema_manual_hints.go b/internal/cli/schema_manual_hints.go index d1073cc9..cfb986e8 100644 --- a/internal/cli/schema_manual_hints.go +++ b/internal/cli/schema_manual_hints.go @@ -83,18 +83,94 @@ type ManualAgentProductHint struct { Evidence []string `json:"evidence"` } -// ManualAgentToolHint defines the four reviewed fields used to select and -// demonstrate one existing effective command. It deliberately has no fields -// for identity, parameters, safety, or interface disposition. +// ManualAgentToolHint defines the reviewed prose used to select and +// demonstrate one existing effective command. ExampleDispositions contains +// only test eligibility exceptions; it cannot change identity, parameters, +// safety, or interface disposition. type ManualAgentToolHint struct { - AgentSummary string `json:"agent_summary"` - UseWhen []string `json:"use_when"` - AvoidWhen []string `json:"avoid_when"` - Examples []string `json:"examples"` - Reviewed bool `json:"reviewed"` - Revision string `json:"revision"` - Reason string `json:"reason"` - Evidence []string `json:"evidence"` + AgentSummary string `json:"agent_summary"` + UseWhen []string `json:"use_when"` + AvoidWhen []string `json:"avoid_when"` + Examples []string `json:"examples"` + ExampleDispositions []ManualAgentExampleDisposition `json:"example_dispositions,omitempty"` + Reviewed bool `json:"reviewed"` + Revision string `json:"revision"` + Reason string `json:"reason"` + Evidence []string `json:"evidence"` +} + +// ManualAgentExampleMode controls only how an already contract-validated +// example is exercised. Every example defaults to dry_run. contract_only is a +// precise reviewed exception for examples whose runtime preconditions cannot +// be exercised safely and deterministically in the isolated test process. +type ManualAgentExampleMode string + +const ( + ManualAgentExampleModeDryRun ManualAgentExampleMode = "dry_run" + ManualAgentExampleModeContractOnly ManualAgentExampleMode = "contract_only" +) + +// ManualAgentExampleReasonCode is a closed taxonomy for reviewed +// contract-only exceptions. There is deliberately no generic "skip" or +// "unsupported" value: a reviewer must identify the concrete precondition. +type ManualAgentExampleReasonCode string + +const ( + // confirmation_required is assigned automatically from final typed safety; + // it is not accepted as a manual disposition reason. + ManualAgentExampleReasonConfirmationRequired ManualAgentExampleReasonCode = "confirmation_required" + ManualAgentExampleReasonInteractiveInput ManualAgentExampleReasonCode = "interactive_input" + ManualAgentExampleReasonFileInput ManualAgentExampleReasonCode = "file_input" + ManualAgentExampleReasonFileOutput ManualAgentExampleReasonCode = "file_output" + ManualAgentExampleReasonStdinInput ManualAgentExampleReasonCode = "stdin_input" + ManualAgentExampleReasonLocalState ManualAgentExampleReasonCode = "local_state" + ManualAgentExampleReasonStatefulPreflight ManualAgentExampleReasonCode = "stateful_preflight" +) + +// ManualAgentExampleDisposition changes one exact example index from the +// default dry-run mode to contract-only. Index is a pointer so a missing JSON +// field cannot silently select example zero. +type ManualAgentExampleDisposition struct { + Index *int `json:"index"` + Mode ManualAgentExampleMode `json:"mode"` + ReasonCode ManualAgentExampleReasonCode `json:"reason_code"` + Reason string `json:"reason"` + Reviewed bool `json:"reviewed"` +} + +// ManualAgentExampleExecution is one resolved example and its effective test +// mode. Contract validation has already succeeded when this value is returned. +type ManualAgentExampleExecution struct { + CanonicalPath string + Index int + Example string + Mode ManualAgentExampleMode + ReasonCode ManualAgentExampleReasonCode + Reason string + Source ManualAgentExampleDispositionSource +} + +// ManualAgentExampleDispositionSource makes automatic typed-safety +// classification distinguishable from narrow reviewed manual exceptions. +type ManualAgentExampleDispositionSource string + +const ( + ManualAgentExampleDispositionDefault ManualAgentExampleDispositionSource = "default" + ManualAgentExampleDispositionTypedSafety ManualAgentExampleDispositionSource = "typed_safety" + ManualAgentExampleDispositionReviewedManual ManualAgentExampleDispositionSource = "reviewed_manual" +) + +// ManualAgentExampleExecutionPlan is a stable, typed report used by the +// exhaustive real-Cobra dry-run test. Counts are derived only from committed +// reviewed dispositions; runtime failures can never add implicit skips. +type ManualAgentExampleExecutionPlan struct { + Examples []ManualAgentExampleExecution + Total int + DryRun int + ContractOnly int + TypedSafetyContractOnly int + ReviewedContractOnly int + ContractOnlyByReason map[ManualAgentExampleReasonCode]int } // ManualSchemaCommandHint opts one exact existing Cobra leaf into @@ -245,6 +321,9 @@ func ValidateManualAgentHintSet(hints ManualAgentHintSet, expectedProducts, expe } } } + if err := validateManualAgentExampleDispositions(canonical, hint.Examples, hint.ExampleDispositions); err != nil { + return err + } } if err := validateManualAgentHintExactSet("products", expectedProducts, mapKeysManualAgentProducts(hints.Products)); err != nil { @@ -256,6 +335,50 @@ func ValidateManualAgentHintSet(hints ManualAgentHintSet, expectedProducts, expe return nil } +func validateManualAgentExampleDispositions(canonical string, examples []string, dispositions []ManualAgentExampleDisposition) error { + seen := make(map[int]bool, len(dispositions)) + for _, disposition := range dispositions { + if disposition.Index == nil { + return fmt.Errorf("agent_hints tool %s example disposition requires index", canonical) + } + index := *disposition.Index + if index < 0 || index >= len(examples) { + return fmt.Errorf("agent_hints tool %s example disposition index %d is out of range for %d examples", canonical, index, len(examples)) + } + if seen[index] { + return fmt.Errorf("agent_hints tool %s has duplicate example disposition index %d", canonical, index) + } + seen[index] = true + if !disposition.Reviewed { + return fmt.Errorf("agent_hints tool %s example disposition index %d must be reviewed", canonical, index) + } + if disposition.Mode != ManualAgentExampleModeContractOnly { + return fmt.Errorf("agent_hints tool %s example disposition index %d has invalid mode %q; only %q overrides the default %q mode", canonical, index, disposition.Mode, ManualAgentExampleModeContractOnly, ManualAgentExampleModeDryRun) + } + if !validManualAgentExampleReasonCode(disposition.ReasonCode) { + return fmt.Errorf("agent_hints tool %s example disposition index %d has invalid reason_code %q", canonical, index, disposition.ReasonCode) + } + if strings.TrimSpace(disposition.Reason) == "" { + return fmt.Errorf("agent_hints tool %s example disposition index %d requires a non-empty reason", canonical, index) + } + } + return nil +} + +func validManualAgentExampleReasonCode(code ManualAgentExampleReasonCode) bool { + switch code { + case ManualAgentExampleReasonInteractiveInput, + ManualAgentExampleReasonFileInput, + ManualAgentExampleReasonFileOutput, + ManualAgentExampleReasonStdinInput, + ManualAgentExampleReasonLocalState, + ManualAgentExampleReasonStatefulPreflight: + return true + default: + return false + } +} + func validateManualAgentHintFields(scope, summary string, useWhen, avoidWhen, examples []string, reviewed bool, revision, reason string, evidence []string, revisions map[string]ManualAgentHintRevision) error { if !reviewed { return fmt.Errorf("agent_hints %s must be reviewed", scope) @@ -342,10 +465,56 @@ func mapKeysManualAgentTools(values map[string]ManualAgentToolHint) map[string]b return keys } -// ValidateManualAgentHintExamples binds every authored example to the exact -// reviewed primary/alias path and rejects flags not accepted by the live Cobra -// command. It validates syntax only and never executes an example. +// ValidateManualAgentHintExamples is the pre-generation validation layer. It +// binds every authored example to the exact reviewed primary/alias path and +// rejects flags and required arguments not accepted by the live Cobra command. +// Final typed constraints, safety, and exact delivery coverage are validated +// later by BuildManualAgentExampleExecutionPlan after generated Agent metadata +// exists. It never executes an example. func ValidateManualAgentHintExamples(bound BoundCommandRegistry, hints ManualAgentHintSet) error { + _, err := buildManualAgentExampleExecutionPlan(bound, nil, hints) + return err +} + +// ValidateEmbeddedManualAgentExampleDelivery is the final generation gate. It +// validates the committed Manual Agent hints against the fully assembled typed +// SchemaRegistry, after generated Agent metadata has been compiled in. This is +// deliberately stronger than the pre-generation path/flag validation above. +func ValidateEmbeddedManualAgentExampleDelivery(bound BoundCommandRegistry, registry SchemaRegistry) (ManualAgentExampleExecutionPlan, error) { + snapshot, err := embeddedManualSchemaHints() + if err != nil { + return ManualAgentExampleExecutionPlan{}, err + } + return BuildManualAgentExampleExecutionPlan(bound, registry, snapshot.AgentHints) +} + +// BuildManualAgentExampleExecutionPlan validates every example against its +// real BoundCommand/Cobra contract. High-risk or user-confirmed operations are +// classified automatically from the final typed SchemaRegistry; only +// non-safety runtime preconditions may use exact reviewed manual dispositions. +// Missing dispositions always remain dry_run, and callers must never turn a +// runtime failure into an implicit skip. +func BuildManualAgentExampleExecutionPlan(bound BoundCommandRegistry, registry SchemaRegistry, hints ManualAgentHintSet) (ManualAgentExampleExecutionPlan, error) { + tools := make(map[string]ToolSpec, len(bound.Commands)) + for _, product := range registry.Products { + for _, tool := range product.Tools { + canonical := strings.TrimSpace(tool.Identity.CanonicalPath) + if canonical == "" { + return ManualAgentExampleExecutionPlan{}, fmt.Errorf("typed SchemaRegistry contains a tool with empty canonical path") + } + if _, duplicate := tools[canonical]; duplicate { + return ManualAgentExampleExecutionPlan{}, fmt.Errorf("typed SchemaRegistry contains duplicate tool %q", canonical) + } + tools[canonical] = tool + } + } + return buildManualAgentExampleExecutionPlan(bound, tools, hints) +} + +func buildManualAgentExampleExecutionPlan(bound BoundCommandRegistry, typedTools map[string]ToolSpec, hints ManualAgentHintSet) (ManualAgentExampleExecutionPlan, error) { + plan := ManualAgentExampleExecutionPlan{ + ContractOnlyByReason: map[ManualAgentExampleReasonCode]int{}, + } canonicalPaths := make([]string, 0, len(hints.Tools)) for canonical := range hints.Tools { canonicalPaths = append(canonicalPaths, canonical) @@ -354,7 +523,23 @@ func ValidateManualAgentHintExamples(bound BoundCommandRegistry, hints ManualAge for _, canonical := range canonicalPaths { spec, ok := bound.ByCanonical[canonical] if !ok { - return fmt.Errorf("agent_hints example references unknown canonical tool %q", canonical) + return ManualAgentExampleExecutionPlan{}, fmt.Errorf("agent_hints example references unknown canonical tool %q", canonical) + } + hint := hints.Tools[canonical] + var typedTool ToolSpec + if typedTools != nil { + var found bool + typedTool, found = typedTools[canonical] + if !found { + return ManualAgentExampleExecutionPlan{}, fmt.Errorf("agent_hints example tool %q is missing from final typed SchemaRegistry", canonical) + } + } + if err := validateManualAgentExampleDispositions(canonical, hint.Examples, hint.ExampleDispositions); err != nil { + return ManualAgentExampleExecutionPlan{}, err + } + dispositions := make(map[int]ManualAgentExampleDisposition, len(hint.ExampleDispositions)) + for _, disposition := range hint.ExampleDispositions { + dispositions[*disposition.Index] = disposition } paths := []manualAgentExamplePath{{Path: spec.PrimaryCLIPath, Argv: strings.Fields(spec.PrimaryCLIPath), Command: spec.PrimaryCommand}} for _, alias := range spec.AliasCommands { @@ -366,24 +551,85 @@ func ValidateManualAgentHintExamples(bound BoundCommandRegistry, hints ManualAge } return paths[i].Path < paths[j].Path }) - for _, example := range hints.Tools[canonical].Examples { + for index, example := range hint.Examples { argv, err := tokenizeManualAgentExample(example) if err != nil { - return fmt.Errorf("agent_hints tool %s example has invalid argv syntax: %w", canonical, err) + return ManualAgentExampleExecutionPlan{}, fmt.Errorf("agent_hints tool %s example has invalid argv syntax: %w", canonical, err) } remainder, matched, ok := matchManualAgentExamplePath(argv, paths) if !ok { - return fmt.Errorf("agent_hints tool %s example does not use its reviewed primary/alias path: %q", canonical, example) + return ManualAgentExampleExecutionPlan{}, fmt.Errorf("agent_hints tool %s example does not use its reviewed primary/alias path: %q", canonical, example) } if matched.Command == nil { - return fmt.Errorf("agent_hints tool %s reviewed path %q has no bound Cobra command", canonical, matched.Path) + return ManualAgentExampleExecutionPlan{}, fmt.Errorf("agent_hints tool %s reviewed path %q has no bound Cobra command", canonical, matched.Path) } - if err := validateManualAgentExampleFlags(matched.Command, remainder); err != nil { - return fmt.Errorf("agent_hints tool %s example for %q: %w", canonical, matched.Path, err) + constraints, err := strictCompatibilityConstraints(matched.Command, canonical) + if err != nil { + return ManualAgentExampleExecutionPlan{}, fmt.Errorf("agent_hints tool %s example for %q has invalid executable constraints: %w", canonical, matched.Path, err) } + if typedTools != nil { + constraints.MutuallyExclusive = append(constraints.MutuallyExclusive, typedTool.Constraints.MutuallyExclusive...) + constraints.RequireOneOf = append(constraints.RequireOneOf, typedTool.Constraints.RequireOneOf...) + constraints.RequireTogether = append(constraints.RequireTogether, typedTool.Constraints.RequireTogether...) + constraints = normalizeRuntimeSchemaConstraints(constraints) + } + positionals, err := strictCompatibilityPositionals(matched.Command) + if err != nil { + return ManualAgentExampleExecutionPlan{}, fmt.Errorf("agent_hints tool %s example for %q has invalid executable positionals: %w", canonical, matched.Path, err) + } + if typedTools != nil { + positionals = mergeManualAgentExamplePositionals(positionals, typedTool.Positionals) + } + if err := validateManualAgentExampleCobraContract(matched.Command, remainder, constraints, positionals); err != nil { + return ManualAgentExampleExecutionPlan{}, fmt.Errorf("agent_hints tool %s example for %q: %w", canonical, matched.Path, err) + } + + execution := ManualAgentExampleExecution{ + CanonicalPath: canonical, + Index: index, + Example: example, + Mode: ManualAgentExampleModeDryRun, + Source: ManualAgentExampleDispositionDefault, + } + disposition, hasManualDisposition := dispositions[index] + confirmationRequired := typedTools != nil && manualAgentExampleNeedsTypedConfirmation(typedTool) + if confirmationRequired { + if hasManualDisposition { + return ManualAgentExampleExecutionPlan{}, fmt.Errorf("agent_hints tool %s example disposition index %d is redundant: final typed safety already requires confirmation", canonical, index) + } + execution.Mode = ManualAgentExampleModeContractOnly + execution.ReasonCode = ManualAgentExampleReasonConfirmationRequired + execution.Reason = "Final typed safety marks the operation high risk or requires explicit user confirmation; tests must not inject --yes." + execution.Source = ManualAgentExampleDispositionTypedSafety + plan.ContractOnly++ + plan.TypedSafetyContractOnly++ + plan.ContractOnlyByReason[execution.ReasonCode]++ + } else if hasManualDisposition { + execution.Mode = disposition.Mode + execution.ReasonCode = disposition.ReasonCode + execution.Reason = strings.TrimSpace(disposition.Reason) + execution.Source = ManualAgentExampleDispositionReviewedManual + plan.ContractOnly++ + plan.ReviewedContractOnly++ + plan.ContractOnlyByReason[disposition.ReasonCode]++ + } else { + plan.DryRun++ + } + plan.Examples = append(plan.Examples, execution) + plan.Total++ } } - return nil + for canonical := range typedTools { + if _, ok := hints.Tools[canonical]; !ok { + return ManualAgentExampleExecutionPlan{}, fmt.Errorf("final typed SchemaRegistry tool %q has no Manual Agent hint examples", canonical) + } + } + return plan, nil +} + +func manualAgentExampleNeedsTypedConfirmation(tool ToolSpec) bool { + return strings.EqualFold(strings.TrimSpace(tool.Safety.Risk), "high") || + strings.EqualFold(strings.TrimSpace(tool.Safety.Confirmation), "user_required") } type manualAgentExamplePath struct { @@ -529,7 +775,12 @@ func manualAgentPlaceholderAt(input string, start int) (string, int, bool) { return input[start : end+1], end, true } -func validateManualAgentExampleFlags(command *cobra.Command, arguments []string) error { +func validateManualAgentExampleCobraContract(command *cobra.Command, arguments []string, constraints RuntimeSchemaConstraints, positionalSpecs []RuntimeSchemaPositional) error { + if command == nil { + return fmt.Errorf("bound Cobra command is nil") + } + providedFacts := map[string]bool{} + positionals := make([]string, 0) for index := 0; index < len(arguments); index++ { argument := arguments[index] if argument == "--" { @@ -548,6 +799,7 @@ func validateManualAgentExampleFlags(command *cobra.Command, arguments []string) if flag == nil { return fmt.Errorf("uses unknown flag --%s", name) } + providedFacts[flag.Name] = true if !hasValue && flag.NoOptDefVal == "" { if index+1 >= len(arguments) { return fmt.Errorf("flag --%s requires a value", name) @@ -557,6 +809,7 @@ func validateManualAgentExampleFlags(command *cobra.Command, arguments []string) continue } if !strings.HasPrefix(argument, "-") || argument == "-" { + positionals = append(positionals, argument) continue } @@ -577,6 +830,7 @@ func validateManualAgentExampleFlags(command *cobra.Command, arguments []string) if flag == nil { return fmt.Errorf("uses unknown shorthand flag -%s", shorthand) } + providedFacts[flag.Name] = true if flag.NoOptDefVal == "" { if offset+1 < len(shorthands) || hasExplicitValue { break @@ -589,9 +843,141 @@ func validateManualAgentExampleFlags(command *cobra.Command, arguments []string) } } } + missingRequired := make([]string, 0) + visitManualAgentCommandFlags(command, func(flag *pflag.Flag) { + if flag != nil && len(flag.Annotations[cobra.BashCompOneRequiredFlag]) > 0 && !providedFacts[flag.Name] { + missingRequired = append(missingRequired, "--"+flag.Name) + } + }) + if len(missingRequired) != 0 { + sort.Strings(missingRequired) + return fmt.Errorf("missing required flag(s): %s", strings.Join(missingRequired, ", ")) + } + missingPositionals := make([]string, 0) + for _, positional := range positionalSpecs { + provided := positional.Index >= 0 && positional.Index < len(positionals) + if positional.Variadic { + provided = positional.Index >= 0 && len(positionals) > positional.Index + } + if provided && strings.TrimSpace(positional.Name) != "" { + providedFacts[strings.TrimLeft(strings.TrimSpace(positional.Name), "-")] = true + } + if positional.Required && !provided { + missingPositionals = append(missingPositionals, strings.TrimSpace(positional.Name)) + } + } + if len(missingPositionals) != 0 { + sort.Strings(missingPositionals) + return fmt.Errorf("missing required positional argument(s): %s", strings.Join(missingPositionals, ", ")) + } + if err := validateManualAgentExampleConstraints(providedFacts, constraints); err != nil { + return err + } + // Runtime positional annotations are the stable Cobra contract and can + // express flag/positional alternatives. Do not call a closure-backed Args + // validator in that case: invoking it without mutating the live FlagSet + // would observe default captured flag values (for example pat chmod's + // --products alternative) and report a false missing positional. Commands + // without typed positional facts still use their real Cobra Args validator. + if command.Args != nil && len(positionalSpecs) == 0 { + if err := command.Args(command, positionals); err != nil { + return fmt.Errorf("invalid positional arguments: %w", err) + } + } return nil } +func mergeManualAgentExamplePositionals(groups ...[]RuntimeSchemaPositional) []RuntimeSchemaPositional { + byIdentity := map[string]RuntimeSchemaPositional{} + for _, group := range groups { + for _, positional := range group { + key := fmt.Sprintf("%d\x00%s", positional.Index, strings.TrimSpace(positional.Name)) + if _, exists := byIdentity[key]; !exists { + byIdentity[key] = positional + } + } + } + result := make([]RuntimeSchemaPositional, 0, len(byIdentity)) + for _, positional := range byIdentity { + result = append(result, positional) + } + sort.Slice(result, func(i, j int) bool { + if result[i].Index != result[j].Index { + return result[i].Index < result[j].Index + } + return result[i].Name < result[j].Name + }) + return result +} + +func validateManualAgentExampleConstraints(provided map[string]bool, constraints RuntimeSchemaConstraints) error { + for _, group := range constraints.RequireOneOf { + if !manualAgentExampleAnyFlagProvided(provided, group) { + return fmt.Errorf("missing require_one_of flags: %s", manualAgentExampleFlagGroup(group)) + } + } + for _, group := range constraints.RequireTogether { + providedCount := manualAgentExampleProvidedFlagCount(provided, group) + if providedCount != 0 && providedCount != len(group) { + return fmt.Errorf("incomplete require_together flags: %s", manualAgentExampleFlagGroup(group)) + } + } + for _, group := range constraints.MutuallyExclusive { + if manualAgentExampleProvidedFlagCount(provided, group) > 1 { + return fmt.Errorf("mutually_exclusive flags used together: %s", manualAgentExampleFlagGroup(group)) + } + } + return nil +} + +func manualAgentExampleAnyFlagProvided(provided map[string]bool, group []string) bool { + return manualAgentExampleProvidedFlagCount(provided, group) > 0 +} + +func manualAgentExampleProvidedFlagCount(provided map[string]bool, group []string) int { + count := 0 + seen := map[string]bool{} + for _, raw := range group { + name := strings.TrimLeft(strings.TrimSpace(raw), "-") + if name != "" && !seen[name] && provided[name] { + seen[name] = true + count++ + } + } + return count +} + +func manualAgentExampleFlagGroup(group []string) string { + flags := make([]string, 0, len(group)) + for _, raw := range group { + if name := strings.TrimLeft(strings.TrimSpace(raw), "-"); name != "" { + flags = append(flags, "--"+name) + } + } + sort.Strings(flags) + return strings.Join(flags, ", ") +} + +func visitManualAgentCommandFlags(command *cobra.Command, visit func(*pflag.Flag)) { + seen := map[string]bool{} + visitSet := func(flags *pflag.FlagSet) { + if flags == nil { + return + } + flags.VisitAll(func(flag *pflag.Flag) { + if flag == nil || seen[flag.Name] { + return + } + seen[flag.Name] = true + visit(flag) + }) + } + visitSet(command.Flags()) + for current := command; current != nil; current = current.Parent() { + visitSet(current.PersistentFlags()) + } +} + func runtimeCommandFlagByShorthand(command *cobra.Command, shorthand string) *pflag.Flag { if command == nil || len(shorthand) != 1 { return nil diff --git a/internal/cli/schema_manual_hints.json b/internal/cli/schema_manual_hints.json index 478d1624..d314ae2c 100644 --- a/internal/cli/schema_manual_hints.json +++ b/internal/cli/schema_manual_hints.json @@ -1288,6 +1288,15 @@ "examples": [ "dws aitable form get --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The isolated dry-run has no tenant login and cannot read the existing remote Base, Table, and form View metadata required by this command.", + "reviewed": true + } + ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -2088,6 +2097,15 @@ "examples": [ "dws aitable view get aggregate --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The isolated dry-run has no tenant login and cannot read the remote View's current aggregate configuration.", + "reviewed": true + } + ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -2108,6 +2126,15 @@ "examples": [ "dws aitable view get card --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The isolated dry-run has no tenant login and cannot read the remote View type and current card configuration.", + "reviewed": true + } + ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -2128,6 +2155,15 @@ "examples": [ "dws aitable view get field-widths --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The isolated dry-run has no tenant login and cannot read the remote View's current field-width configuration.", + "reviewed": true + } + ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -2148,6 +2184,15 @@ "examples": [ "dws aitable view get fill-color-rule --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The isolated dry-run has no tenant login and cannot read the remote View's current conditional fill-color rules.", + "reviewed": true + } + ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -2168,6 +2213,15 @@ "examples": [ "dws aitable view get filter --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The isolated dry-run has no tenant login and cannot read the remote View's current filter configuration.", + "reviewed": true + } + ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -2208,6 +2262,15 @@ "examples": [ "dws aitable view get group --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The isolated dry-run has no tenant login and cannot read the remote View's current group configuration.", + "reviewed": true + } + ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -2268,6 +2331,15 @@ "examples": [ "dws aitable view get sort --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The isolated dry-run has no tenant login and cannot read the remote View's current sort configuration.", + "reviewed": true + } + ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -2288,6 +2360,15 @@ "examples": [ "dws aitable view get timebar --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The isolated dry-run has no tenant login and cannot read the remote Gantt View's current timebar configuration.", + "reviewed": true + } + ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -2308,6 +2389,15 @@ "examples": [ "dws aitable view get visible-fields --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The isolated dry-run has no tenant login and cannot read the remote View's current visible fields and column order.", + "reviewed": true + } + ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -2366,7 +2456,16 @@ "skills/mono/references/products/aitable.md" ], "examples": [ - "dws aitable view update aggregate --view-id VIEW_ID --field-id fldX --action SUM" + "dws aitable view update aggregate --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-id fldX --action SUM" + ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "Before its dry-run branch, this command requires tenant login and a get_views lookup of the remote View type; the isolated environment has neither state.", + "reviewed": true + } ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, @@ -2386,7 +2485,16 @@ "skills/mono/references/products/aitable.md" ], "examples": [ - "dws aitable view update card --view-id VIEW_ID --cover-field-id fldXXX --cover-resize-mode contain" + "dws aitable view update card --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --cover-field-id fldXXX --cover-resize-mode contain" + ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "Before its dry-run branch, this command requires tenant login and a get_views lookup to distinguish a remote Kanban from Gallery View.", + "reviewed": true + } ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, @@ -2406,7 +2514,16 @@ "skills/mono/references/products/aitable.md" ], "examples": [ - "dws aitable view update field-widths --view-id VIEW_ID --field-id fldX --width 200" + "dws aitable view update field-widths --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-id fldX --width 200" + ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "Before its dry-run branch, this command requires tenant login and a get_views lookup that validates the remote View type.", + "reviewed": true + } ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, @@ -2426,7 +2543,7 @@ "skills/mono/references/products/aitable.md" ], "examples": [ - "dws aitable view update fill-color-rule --view-id VIEW_ID --json '[]'" + "dws aitable view update fill-color-rule --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[]'" ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, @@ -2446,7 +2563,7 @@ "skills/mono/references/products/aitable.md" ], "examples": [ - "dws aitable view update filter --view-id VIEW_ID --json '[{\"operator\":\"and\",\"operands\":[{\"operator\":\"eq\",\"operands\":[\"fldX\",\"value\"]}]}]'" + "dws aitable view update filter --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"operator\":\"and\",\"operands\":[{\"operator\":\"eq\",\"operands\":[\"fldX\",\"value\"]}]}]'" ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, @@ -2466,7 +2583,7 @@ "skills/mono/references/products/aitable.md" ], "examples": [ - "dws aitable view update frozen-cols --view-id VIEW_ID --count 1" + "dws aitable view update frozen-cols --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --count 1" ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, @@ -2486,7 +2603,7 @@ "skills/mono/references/products/aitable.md" ], "examples": [ - "dws aitable view update group --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" + "dws aitable view update group --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, @@ -2506,7 +2623,7 @@ "skills/mono/references/products/aitable.md" ], "examples": [ - "dws aitable view update name --view-id VIEW_ID --name \"新视图名\"" + "dws aitable view update name --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --name \"新视图名\"" ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, @@ -2526,7 +2643,7 @@ "skills/mono/references/products/aitable.md" ], "examples": [ - "dws aitable view update row-height --view-id VIEW_ID --cell-height 32" + "dws aitable view update row-height --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --cell-height 32" ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, @@ -2546,7 +2663,7 @@ "skills/mono/references/products/aitable.md" ], "examples": [ - "dws aitable view update sort --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" + "dws aitable view update sort --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --json '[{\"fieldId\":\"fldX\",\"direction\":\"asc\"}]'" ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, @@ -2566,7 +2683,16 @@ "skills/mono/references/products/aitable.md" ], "examples": [ - "dws aitable view update timebar --view-id VIEW_ID --start-field fldStart --end-field fldEnd --timeline-scale month" + "dws aitable view update timebar --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --start-field fldStart --end-field fldEnd --timeline-scale month" + ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "Before its dry-run branch, this command requires tenant login and a get_views lookup confirming that the remote View is Gantt.", + "reviewed": true + } ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, @@ -2586,7 +2712,7 @@ "skills/mono/references/products/aitable.md" ], "examples": [ - "dws aitable view update visible-fields --view-id VIEW_ID --field-ids fld1,fld2,fld3" + "dws aitable view update visible-fields --base-id BASE_ID --table-id TABLE_ID --view-id VIEW_ID --field-ids fld1,fld2,fld3" ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 AITable 参考文档明确命令选择边界并校验示例。", "reviewed": true, @@ -3278,7 +3404,7 @@ "skills/mono/references/products/attendance-schedule.md" ], "examples": [ - "dws attendance schedule get --users USER_IDS --start BEGIN_DATE --end END_DATE" + "dws attendance schedule get --users user001,user002 --start 2026-04-01 --end 2026-04-30" ], "reason": "依据 reviewed CommandRegistry、dws attendance schedule get --help 与 mono 产品参考,审阅该工具的 Agent 选择语义和示例。", "reviewed": true, @@ -3299,7 +3425,7 @@ "skills/mono/references/products/attendance-schedule.md" ], "examples": [ - "dws attendance schedule import --groupId GROUP_ID --scheduleVOS JSON_STRING" + "dws attendance schedule import --groupId 123456 --scheduleVOS '[{\"userId\":\"user001\",\"workDate\":\"2026-04-22 09:00:00\",\"classId\":123,\"isRest\":\"N\"}]'" ], "reason": "依据 reviewed CommandRegistry、dws attendance schedule import --help 与 mono 产品参考,审阅该工具的 Agent 选择语义和示例。", "reviewed": true, @@ -3746,6 +3872,15 @@ "examples": [ "dws calendar room search --room-name 永澄亭" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The isolated dry-run has no tenant login and cannot query the organization's remote meeting-room inventory and availability state.", + "reviewed": true + } + ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 Calendar 参考文档明确命令选择边界并校验示例。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -3766,6 +3901,15 @@ "examples": [ "dws calendar busy search --users userId1,userId2 --start \"2026-03-10T14:00:00+08:00\" --end \"2026-03-10T18:00:00+08:00\"" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The isolated dry-run has no tenant login and cannot query remote calendar busy-time state for the requested users.", + "reviewed": true + } + ], "reason": "AI 语义审阅:依据 Registry 主路径、Cobra help 与 Calendar 参考文档明确命令选择边界并校验示例。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -4014,6 +4158,15 @@ "examples": [ "dws chat group create --name \"项目冲刺群\" --users userId1,userId2" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "Before dry-run output, group creation resolves the authenticated current user and remote member identities, which are absent in the isolated environment.", + "reviewed": true + } + ], "reason": "AI 生成并复核的 Agent 选择语义,依据精确 CommandRegistry identity、真实 Cobra help 与产品参考,不改写执行、安全或接口事实。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -4306,7 +4459,7 @@ "skills/mono/references/products/chat.md" ], "examples": [ - "dws chat message list-direct --user --time \"2026-07-01 00:00:00\" --direction forward --limit 50" + "dws chat message list-direct --user --time \"2026-07-01 00:00:00\" --direction newer --limit 50" ], "reason": "AI 生成并复核的 Agent 选择语义,依据精确 CommandRegistry identity、真实 Cobra help 与产品参考,不改写执行、安全或接口事实。", "reviewed": true, @@ -4728,6 +4881,15 @@ "examples": [ "dws chat message reply --conversation-id --ref-msg-id --ref-sender --text \"收到\"" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The isolated dry-run has no tenant login or remote conversation and referenced-message state required to prepare this reply.", + "reviewed": true + } + ], "reason": "AI 生成并复核的 Agent 选择语义,依据精确 CommandRegistry identity、真实 Cobra help 与产品参考,不改写执行、安全或接口事实。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -5637,7 +5799,16 @@ "skills/mono/references/products/dev.md" ], "examples": [ - "dws dev connect status --json" + "dws dev connect status --unified-app-id --json" + ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "local_state", + "reason": "This status command inspects the local connector daemon heartbeat and supervisor state, which do not exist in the isolated test HOME.", + "reviewed": true + } ], "reason": "AI 生成并复核的 Agent 选择语义,依据精确 CommandRegistry identity、真实 Cobra help 与产品参考,不改写执行、安全或接口事实。", "reviewed": true, @@ -5660,6 +5831,15 @@ "examples": [ "dws dev connect stop --unified-app-id " ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "local_state", + "reason": "Stopping a connector depends on a locally running daemon and its PID or supervisor state, which the isolated test HOME intentionally lacks.", + "reviewed": true + } + ], "reason": "AI 生成并复核的 Agent 选择语义,依据精确 CommandRegistry identity、真实 Cobra help 与产品参考,不改写执行、安全或接口事实。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -6601,7 +6781,7 @@ "structured-hint:skills/mono/schema-hints/selection-review.json#doc.download_file" ], "examples": [ - "dws doc download --node NODE_ID --format json", + "dws doc download --node NODE_ID --output ./downloads/ --format json", "dws doc download --node NODE_ID --output ./report.pdf --format json" ], "reason": "依据真实 Cobra leaf、对应产品 Skill 与现有 structured hints 审阅选择语义和示例;不改变命令身份、参数、安全或接口事实。", @@ -7024,6 +7204,22 @@ "dws doc update --node DOC_ID --content \"# 新内容\" --mode append --format json", "dws doc update --node DOC_ID --content \"# 完整替换\" --mode overwrite --format json" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The append example requires tenant login plus an existing remote document node and edit permission before its dry-run path can be reached.", + "reviewed": true + }, + { + "index": 1, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The overwrite example requires tenant login plus an existing remote document node and edit permission before its dry-run path can be reached.", + "reviewed": true + } + ], "reason": "依据真实 Cobra leaf、对应产品 Skill 与现有 structured hints 审阅选择语义和示例;不改变命令身份、参数、安全或接口事实。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -7306,6 +7502,15 @@ "examples": [ "dws drive info --node --format json" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The isolated dry-run has no tenant login and cannot resolve the existing remote dentry and its access permissions.", + "reviewed": true + } + ], "reason": "依据真实 Cobra leaf、对应产品 Skill 与现有 structured hints 审阅选择语义和示例;不改变命令身份、参数、安全或接口事实。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -7626,6 +7831,15 @@ "dws drive search --query \"季度汇报\" --format json", "dws drive search --query \"合同\" --target file --extensions pdf,docx --format json" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "Drive search requires tenant login and the user's remote drive index, neither of which is available in the isolated dry-run.", + "reviewed": true + } + ], "reason": "依据真实 Cobra leaf、对应产品 Skill 与现有 structured hints 审阅选择语义和示例;不改变命令身份、参数、安全或接口事实。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -7754,6 +7968,15 @@ "examples": [ "dws mail attachment download --email user@company.com --message-id --attachment-id --name report.pdf --output ." ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "Creating an attachment download session requires tenant login and an existing remote mailbox, message, and attachment before dry-run can proceed.", + "reviewed": true + } + ], "reason": "AI 生成并复核的 Agent 选择语义,依据精确 CommandRegistry identity、真实 Cobra help 与产品参考,不改写执行、安全或接口事实。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -7796,6 +8019,15 @@ "examples": [ "dws mail message forward --from user@company.com --to colleague@company.com --id --subject \"Fwd: 周报\"" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "Forward-draft creation requires tenant login and an existing remote source message in the specified mailbox before dry-run can proceed.", + "reviewed": true + } + ], "reason": "AI 生成并复核的 Agent 选择语义,依据精确 CommandRegistry identity、真实 Cobra help 与产品参考,不改写执行、安全或接口事实。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -7838,6 +8070,15 @@ "examples": [ "dws mail message reply --from user@company.com --id --subject \"Re: 周报\" --content \"已收到\"" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "Reply-draft creation requires tenant login and an existing remote source message in the specified mailbox before dry-run can proceed.", + "reviewed": true + } + ], "reason": "AI 生成并复核的 Agent 选择语义,依据精确 CommandRegistry identity、真实 Cobra help 与产品参考,不改写执行、安全或接口事实。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -7859,6 +8100,15 @@ "examples": [ "dws mail message reply-all --from user@company.com --id --subject \"Re: 周报\" --content \"感谢大家\"" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "Reply-all draft creation requires tenant login and an existing remote source message with recipient state before dry-run can proceed.", + "reviewed": true + } + ], "reason": "AI 生成并复核的 Agent 选择语义,依据精确 CommandRegistry identity、真实 Cobra help 与产品参考,不改写执行、安全或接口事实。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -9301,6 +9551,22 @@ "dws pat browser-policy --enabled --format json", "dws pat browser-policy --enabled=false --agentCode --format json" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "local_state", + "reason": "This example inspects and changes browser policy state on the local machine, which is intentionally absent from the isolated test HOME.", + "reviewed": true + }, + { + "index": 1, + "mode": "contract_only", + "reason_code": "local_state", + "reason": "This agent-scoped example depends on the local browser installation and its existing policy state, which the isolated test HOME does not provide.", + "reviewed": true + } + ], "reason": "依据真实 Cobra leaf、对应产品 Skill 与现有 structured hints 审阅选择语义和示例;不改变命令身份、参数、安全或接口事实。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -10486,6 +10752,15 @@ "examples": [ "dws sheet range read --node NODE_ID" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The isolated dry-run has no tenant login and cannot resolve the remote spreadsheet node, default sheet, and readable range state.", + "reviewed": true + } + ], "reason": "依据 reviewed CommandRegistry、dws sheet range read --help 与 mono 产品参考,审阅该工具的 Agent 选择语义和示例。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", @@ -11031,8 +11306,8 @@ "structured-hint:skills/mono/schema-hints/selection-review.json#todo.create_personal_sub_todo" ], "examples": [ - "dws todo task create-sub --parent-id --title \"子任务标题\" --executors userId1,userId2 --priority 40 --format json", - "dws todo task create-sub --parent-id --title \"子任务标题\" --executors userId1 --due \"2026-03-10T18:00:00+08:00\" --format json" + "dws todo task create-sub --parent-id 1234567890 --title \"子任务标题\" --executors userId1,userId2 --priority 40 --format json", + "dws todo task create-sub --parent-id 1234567890 --title \"子任务标题\" --executors userId1 --due \"2026-03-10T18:00:00+08:00\" --format json" ], "reason": "依据真实 Cobra leaf、对应产品 Skill 与现有 structured hints 审阅选择语义和示例;不改变命令身份、参数、安全或接口事实。", "reviewed": true, @@ -11122,6 +11397,15 @@ "examples": [ "dws todo task get --task-id --format json" ], + "example_dispositions": [ + { + "index": 0, + "mode": "contract_only", + "reason_code": "stateful_preflight", + "reason": "The isolated dry-run has no tenant login and cannot resolve the existing remote task or verify that the current user may view it.", + "reviewed": true + } + ], "reason": "依据真实 Cobra leaf、对应产品 Skill 与现有 structured hints 审阅选择语义和示例;不改变命令身份、参数、安全或接口事实。", "reviewed": true, "revision": "ai-agent-contract-2026-07-13-v1", diff --git a/internal/cli/schema_manual_hints.schema.json b/internal/cli/schema_manual_hints.schema.json index 616eb48f..e43e1dcc 100644 --- a/internal/cli/schema_manual_hints.schema.json +++ b/internal/cli/schema_manual_hints.schema.json @@ -143,13 +143,62 @@ "examples": { "$ref": "#/$defs/nonEmptyStringArray", "maxItems": 2, - "description": "Executable examples using a reviewed primary/alias path and real Cobra flags. Do not include --yes or a help-only example." + "description": "Executable examples using a reviewed primary/alias path and real Cobra flags and required arguments. Do not include --yes or a help-only example." + }, + "example_dispositions": { + "type": "array", + "uniqueItems": true, + "items": { + "$ref": "#/$defs/agentExampleDisposition" + }, + "description": "Exact reviewed exceptions by zero-based example index. An omitted index always defaults to dry_run; runtime failures must never create an implicit exception." } } } ], "unevaluatedProperties": false }, + "agentExampleDisposition": { + "type": "object", + "additionalProperties": false, + "required": [ + "index", + "mode", + "reason_code", + "reason", + "reviewed" + ], + "properties": { + "index": { + "type": "integer", + "minimum": 0, + "description": "Zero-based index into the enclosing tool's examples array. Go validation rejects duplicate and out-of-range indexes." + }, + "mode": { + "const": "contract_only", + "description": "The only explicit override. dry_run is the default and is never stored as a disposition." + }, + "reason_code": { + "enum": [ + "interactive_input", + "file_input", + "file_output", + "stdin_input", + "local_state", + "stateful_preflight" + ], + "description": "Narrow manual exception taxonomy. confirmation_required is derived automatically from final typed high-risk/user-confirmed safety and cannot be authored here; runtime errors, MCP resolution errors, and missing required arguments are never valid exceptions." + }, + "reason": { + "type": "string", + "minLength": 1, + "description": "Concrete reviewed explanation of why isolated dry-run execution is unsafe or nondeterministic." + }, + "reviewed": { + "const": true + } + } + }, "agentHintCommon": { "type": "object", "required": [ diff --git a/internal/cli/schema_manual_hints_test.go b/internal/cli/schema_manual_hints_test.go index 610c5b2c..f3088e63 100644 --- a/internal/cli/schema_manual_hints_test.go +++ b/internal/cli/schema_manual_hints_test.go @@ -404,6 +404,303 @@ func TestValidateManualAgentHintExamplesRejectsUnsafeOrNonExecutingArgv(t *testi } } +func TestBuildManualAgentExampleExecutionPlanUsesExplicitReviewedDispositions(t *testing.T) { + _, leaf := manualSchemaHintTestTree() + boundSpec := BoundCommandSpec{ + CommandSpec: CommandSpec{ + CanonicalPath: "sample.search_items", + PrimaryCLIPath: "sample item search", + }, + PrimaryCommand: leaf, + } + bound := BoundCommandRegistry{ + Commands: []BoundCommandSpec{boundSpec}, + ByCanonical: map[string]BoundCommandSpec{"sample.search_items": boundSpec}, + ByCLIPath: map[string]BoundCommandSpec{"sample item search": boundSpec}, + } + hints := manualAgentHintSetFixture() + tool := hints.Tools["sample.search_items"] + tool.Examples = []string{ + "dws sample item search --query first", + "dws sample item search --query second", + } + hints.Tools["sample.search_items"] = tool + + registry := manualAgentExampleSchemaRegistry("sample.search_items", SafetySpec{}) + plan, err := BuildManualAgentExampleExecutionPlan(bound, registry, hints) + if err != nil { + t.Fatalf("BuildManualAgentExampleExecutionPlan() error = %v", err) + } + if plan.Total != 2 || plan.DryRun != 2 || plan.ContractOnly != 0 { + t.Fatalf("default plan counts = total:%d dry_run:%d contract_only:%d", plan.Total, plan.DryRun, plan.ContractOnly) + } + for _, execution := range plan.Examples { + if execution.Mode != ManualAgentExampleModeDryRun { + t.Fatalf("default example mode = %q, want %q", execution.Mode, ManualAgentExampleModeDryRun) + } + } + + index := 1 + tool.ExampleDispositions = []ManualAgentExampleDisposition{{ + Index: &index, + Mode: ManualAgentExampleModeContractOnly, + ReasonCode: ManualAgentExampleReasonStatefulPreflight, + Reason: "The command checks an authenticated tenant before its dry-run branch.", + Reviewed: true, + }} + hints.Tools["sample.search_items"] = tool + plan, err = BuildManualAgentExampleExecutionPlan(bound, registry, hints) + if err != nil { + t.Fatalf("BuildManualAgentExampleExecutionPlan() with disposition error = %v", err) + } + if plan.Total != 2 || plan.DryRun != 1 || plan.ContractOnly != 1 || plan.ReviewedContractOnly != 1 || plan.ContractOnlyByReason[ManualAgentExampleReasonStatefulPreflight] != 1 { + t.Fatalf("reviewed plan = %#v", plan) + } + if plan.Examples[0].Mode != ManualAgentExampleModeDryRun || plan.Examples[1].Mode != ManualAgentExampleModeContractOnly { + t.Fatalf("resolved example modes = %#v", plan.Examples) + } + + tool.ExampleDispositions = nil + hints.Tools["sample.search_items"] = tool + registry = manualAgentExampleSchemaRegistry("sample.search_items", SafetySpec{Risk: "high", Confirmation: "user_required"}) + plan, err = BuildManualAgentExampleExecutionPlan(bound, registry, hints) + if err != nil { + t.Fatalf("BuildManualAgentExampleExecutionPlan() with typed safety error = %v", err) + } + if plan.DryRun != 0 || plan.ContractOnly != 2 || plan.TypedSafetyContractOnly != 2 || plan.ContractOnlyByReason[ManualAgentExampleReasonConfirmationRequired] != 2 { + t.Fatalf("typed safety plan = %#v", plan) + } + for _, execution := range plan.Examples { + if execution.Source != ManualAgentExampleDispositionTypedSafety { + t.Fatalf("typed safety execution source = %q", execution.Source) + } + } + tool.ExampleDispositions = []ManualAgentExampleDisposition{{ + Index: &index, + Mode: ManualAgentExampleModeContractOnly, + ReasonCode: ManualAgentExampleReasonStatefulPreflight, + Reason: "A manual exception must not shadow typed confirmation.", + Reviewed: true, + }} + hints.Tools["sample.search_items"] = tool + if _, err := BuildManualAgentExampleExecutionPlan(bound, registry, hints); err == nil || !strings.Contains(err.Error(), "typed safety already requires confirmation") { + t.Fatalf("redundant manual disposition error = %v", err) + } +} + +func TestBuildManualAgentExampleExecutionPlanRejectsInvalidDisposition(t *testing.T) { + _, leaf := manualSchemaHintTestTree() + boundSpec := BoundCommandSpec{ + CommandSpec: CommandSpec{CanonicalPath: "sample.search_items", PrimaryCLIPath: "sample item search"}, + PrimaryCommand: leaf, + } + bound := BoundCommandRegistry{ + Commands: []BoundCommandSpec{boundSpec}, + ByCanonical: map[string]BoundCommandSpec{"sample.search_items": boundSpec}, + ByCLIPath: map[string]BoundCommandSpec{"sample item search": boundSpec}, + } + zero, one := 0, 1 + tests := []struct { + name string + dispositions []ManualAgentExampleDisposition + wantErr string + }{ + {name: "missing index", dispositions: []ManualAgentExampleDisposition{{Mode: ManualAgentExampleModeContractOnly, ReasonCode: ManualAgentExampleReasonLocalState, Reason: "Requires local state", Reviewed: true}}, wantErr: "requires index"}, + {name: "out of range", dispositions: []ManualAgentExampleDisposition{{Index: &one, Mode: ManualAgentExampleModeContractOnly, ReasonCode: ManualAgentExampleReasonLocalState, Reason: "Requires local state", Reviewed: true}}, wantErr: "out of range"}, + {name: "duplicate", dispositions: []ManualAgentExampleDisposition{{Index: &zero, Mode: ManualAgentExampleModeContractOnly, ReasonCode: ManualAgentExampleReasonLocalState, Reason: "Requires local state", Reviewed: true}, {Index: &zero, Mode: ManualAgentExampleModeContractOnly, ReasonCode: ManualAgentExampleReasonLocalState, Reason: "Requires local state", Reviewed: true}}, wantErr: "duplicate"}, + {name: "not reviewed", dispositions: []ManualAgentExampleDisposition{{Index: &zero, Mode: ManualAgentExampleModeContractOnly, ReasonCode: ManualAgentExampleReasonLocalState, Reason: "Requires local state"}}, wantErr: "must be reviewed"}, + {name: "stores default", dispositions: []ManualAgentExampleDisposition{{Index: &zero, Mode: ManualAgentExampleModeDryRun, ReasonCode: ManualAgentExampleReasonLocalState, Reason: "Requires local state", Reviewed: true}}, wantErr: "invalid mode"}, + {name: "unknown mode", dispositions: []ManualAgentExampleDisposition{{Index: &zero, Mode: "skip", ReasonCode: ManualAgentExampleReasonLocalState, Reason: "Requires local state", Reviewed: true}}, wantErr: "invalid mode"}, + {name: "unknown reason code", dispositions: []ManualAgentExampleDisposition{{Index: &zero, Mode: ManualAgentExampleModeContractOnly, ReasonCode: "safe", Reason: "Skip a safe example", Reviewed: true}}, wantErr: "invalid reason_code"}, + {name: "empty reason", dispositions: []ManualAgentExampleDisposition{{Index: &zero, Mode: ManualAgentExampleModeContractOnly, ReasonCode: ManualAgentExampleReasonLocalState, Reviewed: true}}, wantErr: "non-empty reason"}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + hints := manualAgentHintSetFixture() + tool := hints.Tools["sample.search_items"] + tool.ExampleDispositions = test.dispositions + hints.Tools["sample.search_items"] = tool + err := ValidateManualAgentHintExamples(bound, hints) + if err == nil || !strings.Contains(err.Error(), test.wantErr) { + t.Fatalf("error = %v, want containing %q", err, test.wantErr) + } + }) + } +} + +func TestManualAgentExampleContractRequiresCobraFlagsAndPositionalsEvenWhenContractOnly(t *testing.T) { + _, leaf := manualSchemaHintTestTree() + if err := leaf.MarkFlagRequired("query"); err != nil { + t.Fatalf("MarkFlagRequired(query): %v", err) + } + leaf.Args = cobra.ExactArgs(1) + boundSpec := BoundCommandSpec{ + CommandSpec: CommandSpec{CanonicalPath: "sample.search_items", PrimaryCLIPath: "sample item search"}, + PrimaryCommand: leaf, + } + bound := BoundCommandRegistry{ + Commands: []BoundCommandSpec{boundSpec}, + ByCanonical: map[string]BoundCommandSpec{"sample.search_items": boundSpec}, + ByCLIPath: map[string]BoundCommandSpec{"sample item search": boundSpec}, + } + index := 0 + hints := manualAgentHintSetFixture() + tool := hints.Tools["sample.search_items"] + tool.ExampleDispositions = []ManualAgentExampleDisposition{{ + Index: &index, + Mode: ManualAgentExampleModeContractOnly, + ReasonCode: ManualAgentExampleReasonInteractiveInput, + Reason: "Reviewed interactive precondition", + Reviewed: true, + }} + + tool.Examples = []string{"dws sample item search item-id"} + hints.Tools["sample.search_items"] = tool + if err := ValidateManualAgentHintExamples(bound, hints); err == nil || !strings.Contains(err.Error(), "missing required flag") { + t.Fatalf("missing required flag error = %v", err) + } + + tool.Examples = []string{"dws sample item search --query value"} + hints.Tools["sample.search_items"] = tool + if err := ValidateManualAgentHintExamples(bound, hints); err == nil || !strings.Contains(err.Error(), "invalid positional arguments") { + t.Fatalf("missing positional error = %v", err) + } + + tool.Examples = []string{"dws sample item search --query value item-id"} + hints.Tools["sample.search_items"] = tool + if err := ValidateManualAgentHintExamples(bound, hints); err != nil { + t.Fatalf("valid contract-only example error = %v", err) + } +} + +func TestManualAgentExampleContractEnforcesTypedFlagGroupsBeforeDisposition(t *testing.T) { + _, leaf := manualSchemaHintTestTree() + leaf.Flags().String("robot-client-id", "", "robot client ID") + leaf.Flags().String("unified-app-id", "", "unified app ID") + leaf.Flags().String("start", "", "start value") + leaf.Flags().String("end", "", "end value") + leaf.Flags().String("brief", "", "brief output") + leaf.Flags().String("verbose-output", "", "verbose output") + AnnotateRuntimeConstraints(leaf, RuntimeSchemaConstraints{ + RequireOneOf: [][]string{{"robot-client-id", "unified-app-id"}}, + RequireTogether: [][]string{{"start", "end"}}, + MutuallyExclusive: [][]string{{"brief", "verbose-output"}}, + }) + boundSpec := BoundCommandSpec{ + CommandSpec: CommandSpec{CanonicalPath: "sample.search_items", PrimaryCLIPath: "sample item search"}, + PrimaryCommand: leaf, + } + bound := BoundCommandRegistry{ + Commands: []BoundCommandSpec{boundSpec}, + ByCanonical: map[string]BoundCommandSpec{"sample.search_items": boundSpec}, + ByCLIPath: map[string]BoundCommandSpec{"sample item search": boundSpec}, + } + index := 0 + hints := manualAgentHintSetFixture() + tool := hints.Tools["sample.search_items"] + tool.ExampleDispositions = []ManualAgentExampleDisposition{{ + Index: &index, + Mode: ManualAgentExampleModeContractOnly, + ReasonCode: ManualAgentExampleReasonStatefulPreflight, + Reason: "A reviewed local connection is required after argument validation.", + Reviewed: true, + }} + + tests := []struct { + name string + example string + wantErr string + }{ + {name: "require one of", example: "dws sample item search --query value", wantErr: "missing require_one_of"}, + {name: "require together", example: "dws sample item search --query value --robot-client-id robot --start now", wantErr: "incomplete require_together"}, + {name: "mutually exclusive", example: "dws sample item search --query value --robot-client-id robot --brief yes --verbose-output yes", wantErr: "mutually_exclusive"}, + {name: "valid", example: "dws sample item search --query value --unified-app-id app --start now --end later --brief yes"}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + tool.Examples = []string{test.example} + hints.Tools["sample.search_items"] = tool + err := ValidateManualAgentHintExamples(bound, hints) + if test.wantErr == "" { + if err != nil { + t.Fatalf("ValidateManualAgentHintExamples() error = %v", err) + } + return + } + if err == nil || !strings.Contains(err.Error(), test.wantErr) { + t.Fatalf("error = %v, want containing %q", err, test.wantErr) + } + }) + } +} + +func TestManualAgentExampleExecutionPlanEnforcesFinalTypedConstraints(t *testing.T) { + _, leaf := manualSchemaHintTestTree() + leaf.Flags().String("robot-client-id", "", "robot client ID") + leaf.Flags().String("unified-app-id", "", "unified app ID") + boundSpec := BoundCommandSpec{ + CommandSpec: CommandSpec{CanonicalPath: "sample.search_items", PrimaryCLIPath: "sample item search"}, + PrimaryCommand: leaf, + } + bound := BoundCommandRegistry{ + Commands: []BoundCommandSpec{boundSpec}, + ByCanonical: map[string]BoundCommandSpec{"sample.search_items": boundSpec}, + ByCLIPath: map[string]BoundCommandSpec{"sample item search": boundSpec}, + } + hints := manualAgentHintSetFixture() + registry := manualAgentExampleSchemaRegistry("sample.search_items", SafetySpec{}) + registry.Products[0].Tools[0].Constraints = RuntimeSchemaConstraints{ + RequireOneOf: [][]string{{"robot-client-id", "unified-app-id"}}, + } + + if _, err := BuildManualAgentExampleExecutionPlan(bound, registry, hints); err == nil || !strings.Contains(err.Error(), "missing require_one_of") { + t.Fatalf("final typed constraint error = %v", err) + } + tool := hints.Tools["sample.search_items"] + tool.Examples = []string{"dws sample item search --query value --unified-app-id app"} + hints.Tools["sample.search_items"] = tool + if _, err := BuildManualAgentExampleExecutionPlan(bound, registry, hints); err != nil { + t.Fatalf("valid final typed constraint error = %v", err) + } +} + +func TestManualAgentExampleExecutionPlanRejectsManualConfirmationClassification(t *testing.T) { + _, leaf := manualSchemaHintTestTree() + boundSpec := BoundCommandSpec{ + CommandSpec: CommandSpec{CanonicalPath: "sample.search_items", PrimaryCLIPath: "sample item search"}, + PrimaryCommand: leaf, + } + bound := BoundCommandRegistry{ + Commands: []BoundCommandSpec{boundSpec}, + ByCanonical: map[string]BoundCommandSpec{"sample.search_items": boundSpec}, + ByCLIPath: map[string]BoundCommandSpec{"sample item search": boundSpec}, + } + index := 0 + hints := manualAgentHintSetFixture() + tool := hints.Tools["sample.search_items"] + tool.ExampleDispositions = []ManualAgentExampleDisposition{{ + Index: &index, + Mode: ManualAgentExampleModeContractOnly, + ReasonCode: ManualAgentExampleReasonConfirmationRequired, + Reason: "Do not author a typed safety fact manually.", + Reviewed: true, + }} + hints.Tools["sample.search_items"] = tool + if err := ValidateManualAgentHintExamples(bound, hints); err == nil || !strings.Contains(err.Error(), "invalid reason_code") { + t.Fatalf("manual confirmation disposition error = %v", err) + } +} + +func manualAgentExampleSchemaRegistry(canonical string, safety SafetySpec) SchemaRegistry { + return SchemaRegistry{Products: []ProductSpec{{ + ID: "sample", + Tools: []ToolSpec{{ + Identity: ToolIdentitySpec{CanonicalPath: canonical}, + Safety: safety, + }}, + }}} +} + func manualAgentHintSetFixture() ManualAgentHintSet { const revision = "ai-agent-contract-v1" return ManualAgentHintSet{ diff --git a/internal/generator/cmd_schema_catalog/main.go b/internal/generator/cmd_schema_catalog/main.go index 3a3d6fcd..dbaaeb6e 100644 --- a/internal/generator/cmd_schema_catalog/main.go +++ b/internal/generator/cmd_schema_catalog/main.go @@ -96,9 +96,17 @@ func generateSchemaCatalog(root *cobra.Command, surfacePath, outputPath string) if err != nil { return fmt.Errorf("build effective CommandRegistry: %w", err) } - if _, err := cli.BindEffectiveCommandRegistry(root, effective); err != nil { + bound, err := cli.BindEffectiveCommandRegistry(root, effective) + if err != nil { return fmt.Errorf("bind effective CommandRegistry: %w", err) } + registry, err := cli.AssembleSchemaRegistryFromBound(bound) + if err != nil { + return fmt.Errorf("assemble final typed SchemaRegistry: %w", err) + } + if _, err := cli.ValidateEmbeddedManualAgentExampleDelivery(bound, registry); err != nil { + return fmt.Errorf("validate final Manual Agent example delivery: %w", err) + } if err := cli.ValidateEmbeddedRuntimeSchemaCompleteness(root); err != nil { return fmt.Errorf("validate reverse command-tree completeness: %w", err) } diff --git a/internal/helpers/chat.go b/internal/helpers/chat.go index 91b97b64..db566346 100644 --- a/internal/helpers/chat.go +++ b/internal/helpers/chat.go @@ -3661,7 +3661,9 @@ flow-status 取值:1=处理中(PROCESSING),2=输入中(INPUTTING),3=完成 // 服务端 set_group_member_mute_list 的 uids(staffId)入参存在缺陷: // 即使传了 uids 仍返回 "uids is required",而 openDingTalkIds 路径正常。 // 与 message send 一致:先把 userId 解析为 openDingTalkId;解析失败再降级透传 uids。 - if len(userIDs) > 0 { + // Resolving userId to openDingTalkId is a remote preflight. A dry-run + // must preserve the supplied uids in its preview without calling MCP. + if len(userIDs) > 0 && !deps.Caller.DryRun() { if resolved, err := resolveOpenDingTalkIDs(cmd.Context(), userIDs); err == nil { openDingTalkIDs = append(openDingTalkIDs, resolved...) userIDs = nil diff --git a/internal/helpers/confirmation_test.go b/internal/helpers/confirmation_test.go new file mode 100644 index 00000000..e4feda08 --- /dev/null +++ b/internal/helpers/confirmation_test.go @@ -0,0 +1,52 @@ +// 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. + +package helpers + +import ( + "bytes" + "strings" + "testing" + + "github.com/spf13/cobra" +) + +func TestConfirmDangerousActionDoesNotDescribePublicationAsDelete(t *testing.T) { + cmd := &cobra.Command{Use: "set"} + cmd.Flags().Bool("yes", false, "skip confirmation") + cmd.SetIn(strings.NewReader("no\n")) + var output bytes.Buffer + cmd.SetErr(&output) + + confirmed := confirmDangerousAction(cmd, "enable internet publishing", "file-1") + + if confirmed { + t.Fatal("negative answer unexpectedly confirmed the action") + } + text := output.String() + if !strings.Contains(text, "About to enable internet publishing: file-1") { + t.Fatalf("confirmation output does not name the real action: %q", text) + } + if strings.Contains(strings.ToLower(text), "delete") { + t.Fatalf("non-delete confirmation still describes a delete: %q", text) + } +} + +func TestConfirmDangerousActionUsesParsedCobraYesFlag(t *testing.T) { + cmd := &cobra.Command{Use: "set"} + cmd.Flags().Bool("yes", false, "skip confirmation") + if err := cmd.Flags().Set("yes", "true"); err != nil { + t.Fatal(err) + } + cmd.SetIn(strings.NewReader("no\n")) + var output bytes.Buffer + cmd.SetErr(&output) + + if !confirmDangerousAction(cmd, "enable internet publishing", "file-1") { + t.Fatal("parsed --yes=true did not bypass the interactive prompt") + } + if output.Len() != 0 { + t.Fatalf("--yes=true unexpectedly produced a prompt: %q", output.String()) + } +} diff --git a/internal/helpers/doc.go b/internal/helpers/doc.go index f2c9a0cc..23c28cf8 100644 --- a/internal/helpers/doc.go +++ b/internal/helpers/doc.go @@ -2744,7 +2744,7 @@ CLI 内部自动完成全部流程: if !exists { return fmt.Errorf("文档版本 %d 不存在,已停止回滚;请先执行 dws doc version list --node %s --format json 获取可回滚版本", version, nodeID) } - if !confirmDelete("文档版本回滚", nodeID) { + if !confirmDangerousAction(cmd, fmt.Sprintf("revert document to version %d", version), nodeID) { return nil } return callMCPToolOnServer("doc", "revert_doc_version", map[string]any{ diff --git a/internal/helpers/drive.go b/internal/helpers/drive.go index 810faa0a..31452063 100644 --- a/internal/helpers/drive.go +++ b/internal/helpers/drive.go @@ -1165,7 +1165,7 @@ func newDriveCommand() *cobra.Command { if err != nil { return err } - if !confirmDelete("互联网公开设置", nodeID) { + if !confirmDangerousAction(cmd, "enable internet publishing", nodeID) { return nil } toolArgs := map[string]any{ @@ -1193,7 +1193,7 @@ func newDriveCommand() *cobra.Command { if err != nil { return err } - if !confirmDelete("互联网公开关闭", nodeID) { + if !confirmDangerousAction(cmd, "disable internet publishing", nodeID) { return nil } return callMCPTool("set_file_publish", map[string]any{ diff --git a/internal/helpers/helpers.go b/internal/helpers/helpers.go index dd3e13de..ed983253 100644 --- a/internal/helpers/helpers.go +++ b/internal/helpers/helpers.go @@ -559,6 +559,32 @@ func confirmDelete(resourceType, resourceName string) bool { return false } +// confirmDangerousAction confirms a high-impact action whose semantics are +// not deletion. Keeping this separate from confirmDelete prevents enable, +// disable, or publication operations from being described as deletes. +func confirmDangerousAction(cmd *cobra.Command, action, resourceName string) bool { + if cmd == nil { + return false + } + if yes, err := cmd.Flags().GetBool("yes"); err == nil && yes { + return true + } + + output := cmd.ErrOrStderr() + fmt.Fprintf(output, "About to %s: %s\n", action, resourceName) + fmt.Fprint(output, "Confirm action? (yes/no): ") + + reader := bufio.NewReader(cmd.InOrStdin()) + answer, _ := reader.ReadString('\n') + answer = strings.TrimSpace(strings.ToLower(answer)) + if answer == "yes" || answer == "y" { + return true + } + + fmt.Fprintln(output, "Operation cancelled") + return false +} + // toCamelCase converts a kebab-case string to camelCase. // Examples: "base-id" -> "baseId", "open-dingtalk-id" -> "openDingtalkId" func toCamelCase(kebab string) string { diff --git a/internal/helpers/sheet_style.go b/internal/helpers/sheet_style.go index 5676ac51..24fc2fbe 100644 --- a/internal/helpers/sheet_style.go +++ b/internal/helpers/sheet_style.go @@ -461,6 +461,27 @@ func newRangeBatchSetStyleCmd() *cobra.Command { continue } fmt.Fprintf(os.Stderr, "[%d/%d] update_range sheet=%s range=%s\n", i+1, total, item.SheetID, item.Range) + if deps.Caller.DryRun() { + // The batch command normally uses callMCPToolReturnText in + // JSON mode, which intentionally performs a real call. Keep + // the dry-run guard before both output branches so neither + // format can bypass the shared no-network preview path. + if err := callMCPTool("update_range", toolArgs); err != nil { + return fmt.Errorf("第 %d/%d 条 update_range dry-run 失败: %w", i+1, total, err) + } + if jsonMode { + jsonResults = append(jsonResults, map[string]any{ + "index": i + 1, + "sheetId": item.SheetID, + "range": item.Range, + "ok": true, + "dryRun": true, + "tool": "update_range", + "arguments": toolArgs, + }) + } + continue + } if jsonMode { text, cerr := callMCPToolReturnText(ctx, "update_range", toolArgs) entry := map[string]any{"index": i + 1, "sheetId": item.SheetID, "range": item.Range} diff --git a/internal/helpers/sheet_style_test.go b/internal/helpers/sheet_style_test.go new file mode 100644 index 00000000..e89c293f --- /dev/null +++ b/internal/helpers/sheet_style_test.go @@ -0,0 +1,69 @@ +// 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. + +package helpers + +import ( + "bytes" + "context" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/edition" +) + +type sheetStyleDryRunCaller struct { + format string + calls int +} + +func (c *sheetStyleDryRunCaller) CallTool(context.Context, string, string, map[string]any) (*edition.ToolResult, error) { + c.calls++ + return &edition.ToolResult{}, nil +} + +func (c *sheetStyleDryRunCaller) Format() string { return c.format } +func (*sheetStyleDryRunCaller) DryRun() bool { return true } +func (*sheetStyleDryRunCaller) Fields() string { return "" } +func (*sheetStyleDryRunCaller) JQ() string { return "" } + +func TestRangeBatchSetStyleDryRunNeverCallsRemote(t *testing.T) { + previousDeps := deps + t.Cleanup(func() { deps = previousDeps }) + + batchPath := filepath.Join(t.TempDir(), "styles.json") + if err := os.WriteFile(batchPath, []byte(`[{"sheetId":"Sheet1","range":"A1:B2","fontWeight":"bold"}]`), 0o600); err != nil { + t.Fatalf("write batch fixture: %v", err) + } + + for _, format := range []string{"table", "json"} { + t.Run(format, func(t *testing.T) { + caller := &sheetStyleDryRunCaller{format: format} + InitDeps(caller) + var output bytes.Buffer + deps.Out.w = &output + deps.Out.errW = &output + + cmd := newRangeBatchSetStyleCmd() + cmd.SetArgs([]string{"--node", "NODE_ID", "--batch", batchPath}) + if err := cmd.Execute(); err != nil { + t.Fatalf("batch-set-style dry-run error: %v", err) + } + if caller.calls != 0 { + t.Fatalf("remote CallTool count = %d, want 0", caller.calls) + } + preview := output.String() + for _, want := range []string{"Tool:", "update_range", "Arguments:"} { + if !strings.Contains(preview, want) { + t.Fatalf("dry-run preview missing %q:\n%s", want, preview) + } + } + if format == "json" && !strings.Contains(preview, `"dryRun": true`) { + t.Fatalf("JSON dry-run summary missing typed dryRun evidence:\n%s", preview) + } + }) + } +} diff --git a/skills/mono/schema-hints/zz-attendance-review.json b/skills/mono/schema-hints/zz-attendance-review.json index 8b96ff27..46ac3f6b 100644 --- a/skills/mono/schema-hints/zz-attendance-review.json +++ b/skills/mono/schema-hints/zz-attendance-review.json @@ -198,8 +198,8 @@ "导入员工排班时使用 attendance schedule import" ], "effect": "write", - "risk": "medium", - "confirmation": "not_required", + "risk": "high", + "confirmation": "user_required", "idempotency": "unknown", "reviewed": true }, @@ -214,8 +214,8 @@ "调整员工排班时使用 attendance schedule import" ], "effect": "write", - "risk": "medium", - "confirmation": "not_required", + "risk": "high", + "confirmation": "user_required", "idempotency": "unknown", "reviewed": true }, diff --git a/skills/mono/schema-hints/zz-runtime-confirmation-review.json b/skills/mono/schema-hints/zz-runtime-confirmation-review.json new file mode 100644 index 00000000..7d76d526 --- /dev/null +++ b/skills/mono/schema-hints/zz-runtime-confirmation-review.json @@ -0,0 +1,71 @@ +{ + "version": 1, + "source": { + "kind": "explicit", + "name": "runtime-confirmation-review-v1", + "repository": "DingTalk-Real-AI/dingtalk-workspace-cli", + "channel": "open-source" + }, + "coverage": { + "source_tools": 4, + "matched_tools": 4 + }, + "tools": { + "doc.version_revert": { + "agent_summary": "将文档回滚到指定版本", + "use_when": [ + "用户明确要求并确认将文档回滚到指定历史版本时" + ], + "avoid_when": [ + "只需查看版本或保存快照时不要使用;未明确目标版本时不要回滚" + ], + "effect": "destructive", + "risk": "high", + "confirmation": "user_required", + "idempotency": "unknown", + "reviewed": true + }, + "drive.publish_set": { + "agent_summary": "开启文件的互联网公开发布", + "use_when": [ + "用户明确要求开启文件的互联网公开发布时" + ], + "avoid_when": [ + "只需查询公开状态或关闭公开发布时不要使用;目标文件和公开范围未明确时不要开启" + ], + "effect": "write", + "risk": "high", + "confirmation": "user_required", + "idempotency": "unknown", + "reviewed": true + }, + "drive.publish_unset": { + "agent_summary": "关闭文件的互联网公开发布", + "use_when": [ + "用户明确要求关闭文件的互联网公开发布时" + ], + "avoid_when": [ + "只需查询公开状态或开启公开发布时不要使用;目标文件未明确时不要关闭" + ], + "effect": "write", + "risk": "high", + "confirmation": "user_required", + "idempotency": "unknown", + "reviewed": true + }, + "sheet.chart_delete": { + "agent_summary": "删除钉钉电子表格中指定的浮动图表。", + "use_when": [ + "当用户需要删除钉钉电子表格中指定的浮动图表,并能提供命令所需的查询条件时使用。" + ], + "avoid_when": [ + "当用户实际需要获取钉钉电子表格指定工作表中的浮动图表时,改用 dws sheet chart list。" + ], + "effect": "write", + "risk": "high", + "confirmation": "user_required", + "idempotency": "unknown", + "reviewed": true + } + } +}