Skip to content

Commit d09d9dd

Browse files
committed
docs(changelog): note breaking arg/marker checks; parse required
Review follow-ups: an [Unreleased] entry documents the two behaviour changes operators must know about (undeclared tool arguments are now rejected; ambiguous multi-marker directories refuse creates instead of silently picking the first — previously production). The required-list parser accepts both a Go-literal []string and a decoded-JSON []interface{}, with a test — a bare type assertion would silently disable the CLI env-default for a registry entry loaded from JSON. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> 🤖 Generated with [Claude Code](https://claude.com/claude-code)
1 parent 5b88797 commit d09d9dd

3 files changed

Lines changed: 47 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@
3737
- Fix: `deploy-stage` failures are now diagnosable. A failed compare (e.g. "One or more processes has errors") carries a nested `errors` tree naming the exact stage → process → node and the reason (empty scheme, orphan node, a reference into another project, …); the tool previously swallowed it and printed only the bare description. A genuinely unrecognized compare status now also lists each offending object with its id, title and the literal status value instead of an anonymous count.
3838
- Fix: `deploy-stage` gives a definitive good/bad verdict when the progress WebSocket fails (small merges routinely finish and close it before the monitor subscribes). The outcome is decided by the scheme itself: compare is re-run with retries — an empty diff reports a verified success, a leftover diff reports UNCONFIRMED as an error. Previously every fast merge ended with a scary "completion could not be confirmed over the WebSocket" warning on a successful deploy.
3939
- Feat: full env-var lifecycle from the IDE — `list-variables`, `modify-variable` and `delete-variable` MCP tools. Both write tools are dry-run-by-default and confirm-gated (`confirm="<short_name>#<obj_id>"`): modify shows a current → new diff (rename additionally scans local `.conv.json` files for `{{env_var[@old-name]}}` references), delete shows a red permanent-deletion warning block that the AI must present to the user verbatim — env vars have NO recycle bin. Secrets are always masked in every output; server semantics verified live: modify is partial (omitted fields — including a secret's value — are preserved), `env_var_type` cannot be changed after creation (the server silently ignores it), delete requires project/stage ids.
40+
- **Breaking / behaviour**: tool calls now REJECT undeclared arguments with an
41+
error naming the unknown keys and the accepted list (previously unknown keys
42+
were silently dropped — a call could quietly act on the wrong object).
43+
Integrations passing stray keys must remove them.
44+
- **Breaking / behaviour**: `create-process` / `create-state-diagram` /
45+
`create-folder` refuse a working directory that contains MORE than one
46+
`<id>_<name>.folder/stage.json` marker instead of silently picking the first
47+
one (which could target a production stage). Pass the new explicit
48+
`folder_id` argument or run from the specific folder's directory.
49+
- Feature: create tools accept an explicit `folder_id` and report the resolved
50+
target ("created in Corezoid folder #N (explicit folder_id / resolved from
51+
marker X)") in the result.
4052

4153
## [2.8.0]
4254

plugins/corezoid/mcp-server/tool_args_validation.go

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,8 @@ func buildToolAllowedArgs() {
3636
}
3737
}
3838
}
39-
if req, ok := schema["required"].([]string); ok {
40-
for _, k := range req {
41-
required[k] = true
42-
}
39+
for _, k := range schemaRequiredList(schema["required"]) {
40+
required[k] = true
4341
}
4442
}
4543
toolAllowedArgs[t.Name] = allowed
@@ -78,6 +76,27 @@ func coerceCLIArgs(tool string, args map[string]interface{}) error {
7876
return nil
7977
}
8078

79+
// schemaRequiredList extracts a schema's "required" list whether it is a
80+
// Go-literal []string (the registry today) or a decoded-JSON []interface{}
81+
// (a future registry entry loaded from a file) — a bare []string assertion
82+
// would silently treat the latter as "nothing required" and disable the CLI
83+
// env-default for that tool.
84+
func schemaRequiredList(v interface{}) []string {
85+
switch req := v.(type) {
86+
case []string:
87+
return req
88+
case []interface{}:
89+
out := make([]string, 0, len(req))
90+
for _, item := range req {
91+
if s, ok := item.(string); ok {
92+
out = append(out, s)
93+
}
94+
}
95+
return out
96+
}
97+
return nil
98+
}
99+
81100
// toolRequiresArg reports whether the tool's InputSchema marks the argument
82101
// as required. Used by the CLI to decide when an env-based default is safe
83102
// to inject.

plugins/corezoid/mcp-server/tool_args_validation_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,15 @@ func TestUnknownArgsError_EveryToolHasSchema(t *testing.T) {
6060
}
6161
}
6262
}
63+
64+
func TestSchemaRequiredList_BothShapes(t *testing.T) {
65+
if got := schemaRequiredList([]string{"a", "b"}); len(got) != 2 {
66+
t.Errorf("[]string shape: got %v", got)
67+
}
68+
if got := schemaRequiredList([]interface{}{"a", "b"}); len(got) != 2 {
69+
t.Errorf("[]interface{} shape (decoded JSON): got %v", got)
70+
}
71+
if got := schemaRequiredList(nil); got != nil {
72+
t.Errorf("nil: got %v", got)
73+
}
74+
}

0 commit comments

Comments
 (0)