docs(crates): add design_skeleton/content/refine to tool catalog

Layered design workflow shipped in 7cee053d. Update CLAUDE.md:
- 3 new rows in the tool catalog table (21 tools total now)
- Tools/list note updated 18 → 21
- Pending list trimmed (design_* line removed; replaced with
  the next-tier work: per-phase apply semantics, JSON Node parser
  for subtree shapes, HttpServer wire protocol verification)
This commit is contained in:
Kayshen-X 2026-05-14 23:24:28 +08:00
parent 18c827d620
commit 9985caeccf

View file

@ -401,26 +401,29 @@ Every host close path clears its respective hover state so reopening starts un-h
Eight first-party tools registered today (v0.8.0+):
| Tool | Kind | Args | Command emitted | File |
| ----------------------- | ----- | -------------------------------------------------------------------------------------------------- | -------------------- | --------------------- |
| `get_document_info` | read | — | — | `mcp/tools.rs` |
| `get_selection` | read | — | — | `mcp/tools.rs` |
| `get_node` | read | `node_id` | — | `mcp/tools.rs` |
| `list_pages` | read | — | — | `mcp/tools.rs` |
| `list_variables` | read | — | — | `mcp/tools.rs` |
| `get_active_theme` | read | — | — | `mcp/tools.rs` |
| `set_variable_color` | write | `name`, `hex` | `SetVariableColor` | `mcp/write_tools.rs` |
| `set_active_axis_value` | write | `axis`, `value` | `SetActiveAxisValue` | `mcp/write_tools.rs` |
| `insert_node` | write | `kind`, `name`, `x`/`y`/`width`/`height`, optional `fill_hex` | `InsertNode` | `mcp/write_tools.rs` |
| `update_node` | write | `node_id` + any of `x`/`y`/`width`/`height`/`name`/`fill_hex` | `UpdateNode` | `mcp/write_tools.rs` |
| `delete_node` | write | `node_id` | `DeleteNode` | `mcp/write_tools.rs` |
| `move_node` | write | `node_id`, `target_parent_id` (0 = page root) | `MoveNode` | `mcp/write_tools.rs` |
| `copy_node` | write | `node_id`, `target_parent_id` (0 = page root) | `CopyNode` | `mcp/write_tools.rs` |
| `replace_node` | write | `node_id`, `kind`, `name`, `x`/`y`/`width`/`height`, optional `fill_hex`, optional `drop_children` | `ReplaceNode` | `mcp/write_tools.rs` |
| `batch_design` | write | `nodes_json` (JSON array of `{kind,name,x,y,width,height,fill_hex?}`) | `BatchInsert` | `mcp/batch_design.rs` |
| `set_variable_number` | write | `name`, `value` (finite f64) | `SetVariableScalar` | `mcp/scalar_vars.rs` |
| `set_variable_string` | write | `name`, `value` (free-form text) | `SetVariableScalar` | `mcp/scalar_vars.rs` |
| `set_variable_boolean` | write | `name`, `value` (`"true"`/`"false"`) | `SetVariableScalar` | `mcp/scalar_vars.rs` |
| Tool | Kind | Args | Command emitted | File |
| ----------------------- | ----- | -------------------------------------------------------------------------------------------------- | ------------------------------ | --------------------- |
| `get_document_info` | read | — | — | `mcp/tools.rs` |
| `get_selection` | read | — | — | `mcp/tools.rs` |
| `get_node` | read | `node_id` | — | `mcp/tools.rs` |
| `list_pages` | read | — | — | `mcp/tools.rs` |
| `list_variables` | read | — | — | `mcp/tools.rs` |
| `get_active_theme` | read | — | — | `mcp/tools.rs` |
| `set_variable_color` | write | `name`, `hex` | `SetVariableColor` | `mcp/write_tools.rs` |
| `set_active_axis_value` | write | `axis`, `value` | `SetActiveAxisValue` | `mcp/write_tools.rs` |
| `insert_node` | write | `kind`, `name`, `x`/`y`/`width`/`height`, optional `fill_hex` | `InsertNode` | `mcp/write_tools.rs` |
| `update_node` | write | `node_id` + any of `x`/`y`/`width`/`height`/`name`/`fill_hex` | `UpdateNode` | `mcp/write_tools.rs` |
| `delete_node` | write | `node_id` | `DeleteNode` | `mcp/write_tools.rs` |
| `move_node` | write | `node_id`, `target_parent_id` (0 = page root) | `MoveNode` | `mcp/write_tools.rs` |
| `copy_node` | write | `node_id`, `target_parent_id` (0 = page root) | `CopyNode` | `mcp/write_tools.rs` |
| `replace_node` | write | `node_id`, `kind`, `name`, `x`/`y`/`width`/`height`, optional `fill_hex`, optional `drop_children` | `ReplaceNode` | `mcp/write_tools.rs` |
| `batch_design` | write | `nodes_json` (JSON array of `{kind,name,x,y,width,height,fill_hex?}`) | `BatchInsert` | `mcp/batch_design.rs` |
| `set_variable_number` | write | `name`, `value` (finite f64) | `SetVariableScalar` | `mcp/scalar_vars.rs` |
| `set_variable_string` | write | `name`, `value` (free-form text) | `SetVariableScalar` | `mcp/scalar_vars.rs` |
| `set_variable_boolean` | write | `name`, `value` (`"true"`/`"false"`) | `SetVariableScalar` | `mcp/scalar_vars.rs` |
| `design_skeleton` | write | `nodes_json` (same as batch_design) | `BatchInsert` (phase=skeleton) | `mcp/batch_design.rs` |
| `design_content` | write | `nodes_json` (same as batch_design) | `BatchInsert` (phase=content) | `mcp/batch_design.rs` |
| `design_refine` | write | `nodes_json` (same as batch_design) | `BatchInsert` (phase=refine) | `mcp/batch_design.rs` |
Read tools snapshot `Document` state at registration time. Write tools stay `&self`: they validate args and return `ToolOutcome::OkWithCommand(result, command)` for the host to apply via `Document::apply_mcp_command(command)`. The apply path follows pre-validate-then-mutate discipline (id space, target existence, geometry, hex, container-children consent) so a bad arg never leaves the document half-mutated.
@ -457,12 +460,13 @@ mcp_tests.rs (in crate root) Cross-cutting: stdio dispatch, parser invariants, w
`openpencil-desktop --mcp <path>` (`crates/openpencil-desktop/src/mcp_serve.rs`) runs a JSON-RPC stdio MCP server backed by the .op file at `<path>`. External CLIs (Claude Code / Codex / Gemini / Copilot) spawn the binary in this mode to drive the Rust editor the same way they drive TS pen-mcp.
- Handshake: `initialize` returns protocol version + capabilities + serverInfo; `tools/list` enumerates all 18 tools with JSON inputSchemas; `notifications/initialized` + `ping` handled inline.
- Handshake: `initialize` returns protocol version + capabilities + serverInfo; `tools/list` enumerates all 21 tools with JSON inputSchemas; `notifications/initialized` + `ping` handled inline.
- Per-call lifecycle: re-build the `ToolRegistry` against the live document (so read-tool snapshots reflect prior writes) → dispatch through `run_stdio_with_applier` → applier closure mutates the doc + saves to disk on each successful write.
- Top-level method / id sniffing uses the same key-walker discipline as the wire parser so nested keys can't shadow the real top-level fields.
### Pending
- Layered design workflow tools (`design_skeleton`, `design_content`, `design_refine`) — currently `batch_design` covers single-shot leaf generation; the layered variants need either intent-phase metadata or richer subtree shapes.
- A real JSON Node parser would unlock `replace_node`'s subtree path + grow batch_design beyond leaf-only.
- A real JSON Node parser would unlock `replace_node`'s subtree path + grow batch_design / design_skeleton beyond leaf-only.
- Per-phase apply semantics for the design\_\* workflow (e.g. design_refine emitting UpdateNode batches against existing nodes instead of fresh inserts).
- HttpServer / streamable-http MCP transport (lifecycle scaffold exists in `chat_http_server.rs`; wire protocol unverified).
- HttpServer / streamable-http transport (currently the spawn-from-IPC scaffold has the lifecycle but not the wire format).