@xiaobuyu/nodesign 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +266 -79
- package/README.zh-CN.md +254 -67
- package/package.json +2 -2
- package/server/api/admin.js +7 -0
- package/server/api/assets/docx-page.js +5 -4
- package/server/api/assets/helpers.js +26 -0
- package/server/api/assets/notes.js +50 -0
- package/server/api/assets.js +31 -38
- package/server/api/board.js +29 -1
- package/server/api/browse.js +3 -2
- package/server/api/chatai.js +9 -8
- package/server/api/exports/cards.js +7 -6
- package/server/api/exports/docx-pdf.js +4 -1
- package/server/api/instruction.js +3 -3
- package/server/api/local.js +10 -8
- package/server/api/projects.js +19 -3
- package/server/api/publish.js +3 -2
- package/server/api/sessions-rewind.js +220 -0
- package/server/api/sessions.js +58 -194
- package/server/api/stage.js +35 -0
- package/server/api/turn-model-switch.js +109 -0
- package/server/api/turn.js +52 -88
- package/server/auth/middleware.js +29 -6
- package/server/auth/tier.js +27 -7
- package/server/auth/users-store.js +14 -1
- package/server/engine/agent/actor-trail.js +110 -0
- package/server/engine/agent/agent-shared.js +22 -52
- package/server/engine/agent/beat-state.js +61 -0
- package/server/engine/agent/cast.js +322 -0
- package/server/engine/agent/events.js +18 -1
- package/server/engine/agent/hooks/beat-gate.js +73 -0
- package/server/engine/agent/hooks/failure.js +11 -1
- package/server/engine/agent/hooks/lifecycle.js +16 -41
- package/server/engine/agent/hooks/post-guidance.js +4 -38
- package/server/engine/agent/hooks/post-trim.js +1 -0
- package/server/engine/agent/hooks/pre-board-dirty.js +29 -0
- package/server/engine/agent/hooks/pre-defaults.js +206 -2
- package/server/engine/agent/hooks/pre-injectors.js +19 -2
- package/server/engine/agent/hooks/pre-peer-guard.js +88 -0
- package/server/engine/agent/hooks/pre-unknown-params.js +82 -0
- package/server/engine/agent/hooks/pre-workspace-scope-guard.js +33 -0
- package/server/engine/agent/hooks/resident-role-lifecycle.js +100 -0
- package/server/engine/agent/hooks/slot-alias.js +30 -0
- package/server/engine/agent/hooks/user-prompt-submit.js +208 -47
- package/server/engine/agent/hooks.js +80 -14
- package/server/engine/agent/isolation.js +25 -2
- package/server/engine/agent/memory-config.js +87 -0
- package/server/engine/agent/model-context.js +102 -18
- package/server/engine/agent/model-table.js +361 -58
- package/server/engine/agent/prompts/nodesign-prelude.md +579 -70
- package/server/engine/agent/prompts/tools/direct-edit-protocol.md +1 -1
- package/server/engine/agent/prompts/tools/generate-image-cookbook.md +26 -9
- package/server/engine/agent/prompts/tools/paint-still-cookbook.md +1 -1
- package/server/engine/agent/prompts/tools/site-reference.md +15 -4
- package/server/engine/agent/role-card.js +175 -0
- package/server/engine/agent/rp-mode.js +17 -0
- package/server/engine/agent/session-loop.js +55 -32
- package/server/engine/agent/stage-status.js +73 -0
- package/server/engine/agent/subagent-flight.js +73 -0
- package/server/engine/agent/system-prompts.js +41 -0
- package/server/engine/agent/tool-input-stream.js +165 -0
- package/server/engine/agents/explorer.md +1 -1
- package/server/engine/agents/index.js +1 -1
- package/server/engine/mcp/actor.js +59 -0
- package/server/engine/mcp/capability-gate.js +21 -2
- package/server/engine/mcp/index.js +118 -33
- package/server/engine/mcp/mode-profile.js +139 -0
- package/server/engine/mcp/server-name.js +19 -0
- package/server/engine/mcp/tools/artifact-session.js +2 -1
- package/server/engine/mcp/tools/browse-computer.js +2 -1
- package/server/engine/mcp/tools/browse-find-batch.js +95 -16
- package/server/engine/mcp/tools/browse.js +25 -3
- package/server/engine/mcp/tools/cast-role.js +167 -0
- package/server/engine/mcp/tools/crystallize-skill.js +1 -1
- package/server/engine/mcp/tools/draw-trend.js +104 -0
- package/server/engine/mcp/tools/edit-board-schema.js +56 -0
- package/server/engine/mcp/tools/edit-board.js +569 -0
- package/server/engine/mcp/tools/generate-image.js +50 -70
- package/server/engine/mcp/tools/helpers/codex-imagegen.js +139 -0
- package/server/engine/mcp/tools/helpers/rembg.js +7 -2
- package/server/engine/mcp/tools/helpers/shot-pipeline.js +109 -0
- package/server/engine/mcp/tools/list-pages.js +11 -5
- package/server/engine/mcp/tools/look-at-board.js +4 -3
- package/server/engine/mcp/tools/open-sheet.js +242 -0
- package/server/engine/mcp/tools/organize-board.js +45 -6
- package/server/engine/mcp/tools/paint-still.js +1 -1
- package/server/engine/mcp/tools/pin-to-board.js +103 -19
- package/server/engine/mcp/tools/read-board.js +123 -16
- package/server/engine/mcp/tools/read-tavern-json.js +87 -19
- package/server/engine/mcp/tools/report-issue.js +15 -7
- package/server/engine/mcp/tools/role-memory.js +83 -0
- package/server/engine/mcp/tools/roll-dice.js +82 -0
- package/server/engine/mcp/tools/roll-film.js +1 -1
- package/server/engine/mcp/tools/screenshot.js +19 -9
- package/server/engine/mcp/tools/set-vars.js +150 -0
- package/server/engine/mcp/tools/sheet-replan.js +46 -0
- package/server/engine/mcp/tools/web-search.js +12 -16
- package/server/engine/mcp/tools/write-on-board-flow.js +108 -0
- package/server/engine/mcp/tools/write-on-board-place.js +211 -0
- package/server/engine/mcp/tools/write-on-board-role-anchor.js +48 -0
- package/server/engine/mcp/tools/write-on-board-schema.js +125 -0
- package/server/engine/mcp/tools/write-on-board.js +568 -99
- package/server/engine/plugins/nodesign/skills/blackboard-rp/SKILL.md +215 -0
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/SKILL.md +14 -7
- package/server/engine/plugins/nodesign/skills/docx-craft/SKILL.md +44 -5
- package/server/engine/plugins/nodesign/skills/docx-craft/references/token-schema.md +16 -0
- package/server/engine/plugins/nodesign/skills/site-craft/SKILL.md +24 -8
- package/server/engine/plugins/nodesign/skills/story-craft/SKILL.md +94 -0
- package/server/engine/plugins/nodesign/skills/story-import/SKILL.md +112 -0
- package/server/engine/plugins/nodesign/skills/story-intimacy/SKILL.md +72 -0
- package/server/engine/plugins/nodesign/skills/story-voice/SKILL.md +66 -0
- package/server/engine/plugins/nodesign/skills/story-voice/voices//345/206/267/347/241/254.md +33 -0
- package/server/engine/plugins/nodesign/skills/story-voice/voices//346/203/205/346/204/237/347/233/264/347/273/231.md +42 -0
- package/server/engine/plugins/nodesign/skills/story-voice/voices//346/204/217/350/257/206/346/265/201.md +42 -0
- package/server/engine/plugins/nodesign/skills/story-voice/voices//346/255/246/344/276/240/347/231/275/350/257/235.md +34 -0
- package/server/engine/plugins/nodesign/skills/story-voice/voices//347/224/237/346/264/273/346/265/201.md +35 -0
- package/server/engine/plugins/nodesign/skills/story-voice/voices//347/231/275/346/217/217.md +37 -0
- package/server/engine/plugins/nodesign/skills/story-voice/voices//350/210/236/345/217/260/345/211/247.md +32 -0
- package/server/engine/plugins/nodesign/skills/story-voice/voices//351/230/266/346/256/265/345/210/207/346/215/242.md +42 -0
- package/server/engine/runs/board-seater.js +272 -0
- package/server/engine/runs/board-tasklist.js +90 -48
- package/server/engine/runs/turn-relay.js +24 -2
- package/server/engine/runs/user-chalk-echo.js +44 -0
- package/server/index.js +2 -2
- package/server/lib/artifact-target.js +31 -14
- package/server/lib/board-anchor.js +49 -0
- package/server/lib/board-dirty.js +93 -0
- package/server/lib/board-excerpt.js +80 -0
- package/server/lib/board-follow.js +111 -0
- package/server/lib/board-groups.js +1 -5
- package/server/lib/board-hero.js +3 -1
- package/server/lib/board-kind-sizes.js +38 -3
- package/server/lib/board-lanes.js +58 -0
- package/server/lib/board-obstacles.js +80 -0
- package/server/lib/board-relations.js +5 -1
- package/server/lib/board-sheets.js +467 -0
- package/server/lib/board-shelf.js +86 -0
- package/server/lib/board-transform.js +62 -0
- package/server/lib/canvas-id.js +46 -4
- package/server/lib/chalk-flow.js +88 -0
- package/server/lib/chalk-rewrite.js +63 -0
- package/server/lib/chalk-size-pref.js +48 -0
- package/server/lib/chalk.js +42 -3
- package/server/lib/export-collect.js +3 -1
- package/server/lib/ingress/forward-openai-chat.js +16 -4
- package/server/lib/ingress/openai-chat.js +23 -12
- package/server/lib/ingress/session-routes.js +3 -3
- package/server/lib/ingress/stream-watchdog.js +53 -0
- package/server/lib/ingress/upstream-billing.js +15 -0
- package/server/lib/ingress/upstream-error-hints.js +36 -0
- package/server/lib/issues-store.js +3 -1
- package/server/lib/json-preview.js +58 -0
- package/server/lib/kinds/docx.js +11 -4
- package/server/lib/kinds/index.js +6 -16
- package/server/lib/kinds/site.js +40 -7
- package/server/lib/model-ingress.js +26 -1
- package/server/lib/moderation.js +10 -5
- package/server/lib/quota.js +26 -6
- package/server/lib/rect.js +50 -0
- package/server/lib/rewrite-refs.js +110 -0
- package/server/lib/screen.js +36 -0
- package/server/lib/sheet-state.js +19 -0
- package/server/lib/sketch-array.js +118 -0
- package/server/lib/sketch-hatch.js +99 -0
- package/server/lib/sketch-layout.js +269 -69
- package/server/lib/sketch-shapes.js +152 -0
- package/server/lib/sketch-stencils.js +170 -0
- package/server/lib/ssrf-guard.js +9 -0
- package/server/lib/state-table.js +237 -0
- package/server/lib/state-trend.js +94 -0
- package/server/lib/state-triggers.js +199 -0
- package/server/lib/task-scan.js +18 -0
- package/server/lib/tavern-json.js +48 -0
- package/server/lib/user-uploads.js +88 -0
- package/server/projects/board-limits.js +5 -3
- package/server/projects/board-sanitize.js +220 -10
- package/server/projects/board-store.js +137 -7
- package/server/projects/memory-migration.js +85 -0
- package/server/projects/move-entry.js +11 -1
- package/server/projects/session-jsonl.js +110 -0
- package/server/projects/store.js +56 -3
- package/server/projects/ui-config.js +2 -1
- package/server/projects/viewpoint-store.js +35 -3
- package/server/projects/workspace-slots.js +30 -0
- package/server/projects/workspace-templates.js +42 -10
- package/server/projects/workspace.js +25 -26
- package/server/runtime/capabilities.js +6 -2
- package/server/services/rembg-launcher.js +5 -2
- package/server/shared/locales.js +70 -0
- package/server/shared/messages-en.js +69 -0
- package/server/shared/messages.js +65 -0
- package/server/ws/broker.js +3 -0
- package/server/ws/index.js +43 -3
- package/web/README.md +1 -1
- package/web/dist/assets/{BrowserWindow-P_vIdh-G.js → BrowserWindow-CcaGRWz5.js} +1 -1
- package/web/dist/assets/DeckWindow-BIr2KGFT.js +6 -0
- package/web/dist/assets/{DocxWindow-DSAU1-tD.js → DocxWindow-B9KZmU5z.js} +2 -2
- package/web/dist/assets/{MermaidBlock-DR1GikCv.js → MermaidBlock-DrfRnz8E.js} +43 -43
- package/web/dist/assets/{SiteWindow-92uBuRRR.js → SiteWindow-CJOjCF7d.js} +6 -6
- package/web/dist/assets/{abnfDiagram-VCTEODGH-uA8Esix4.js → abnfDiagram-VCTEODGH-CUZbQGIg.js} +1 -1
- package/web/dist/assets/{arc-D_khH_xN.js → arc-C1-HSUny.js} +1 -1
- package/web/dist/assets/{architectureDiagram-5GKGNRK7-DydJHqOt.js → architectureDiagram-5GKGNRK7-B5nwvu60.js} +2 -2
- package/web/dist/assets/{blockDiagram-NRAW4CY4-B7wBbKiW.js → blockDiagram-NRAW4CY4-uPPuFLwR.js} +1 -1
- package/web/dist/assets/{c4Diagram-UCG6FXSJ-6mrH0x7Y.js → c4Diagram-UCG6FXSJ-C0mKBFlz.js} +1 -1
- package/web/dist/assets/channel-BxpWNOGU.js +1 -0
- package/web/dist/assets/{chunk-2Q5K7J3B-Cuikho5Q.js → chunk-2Q5K7J3B-Cs0rlZ4q.js} +1 -1
- package/web/dist/assets/{chunk-5VM5RSS4-3-KZ5AUz.js → chunk-5VM5RSS4-DtR63oYb.js} +1 -1
- package/web/dist/assets/{chunk-F27PBJKO-Bkwq2gGU.js → chunk-F27PBJKO-B3MRdezJ.js} +1 -1
- package/web/dist/assets/{chunk-G27WJ6UU-BLyQzdGE.js → chunk-G27WJ6UU-BtwntwpS.js} +1 -1
- package/web/dist/assets/{chunk-JWPE2WC7-B7HxxQds.js → chunk-JWPE2WC7-BHsTe5PD.js} +1 -1
- package/web/dist/assets/{chunk-LCL6LL3I-CtXrnUwF.js → chunk-LCL6LL3I-knY15Qdm.js} +1 -1
- package/web/dist/assets/{chunk-POPQ4Y6H-dxddZlXt.js → chunk-POPQ4Y6H-C51tgK_I.js} +1 -1
- package/web/dist/assets/{chunk-SVP7TREG-DpkmrgHn.js → chunk-SVP7TREG-CnwRZmF_.js} +1 -1
- package/web/dist/assets/{chunk-XXDRQBXY-BwZ7RbpQ.js → chunk-XXDRQBXY-BtXzVF-_.js} +1 -1
- package/web/dist/assets/classDiagram-DTDB5LWJ-DUEKmDfo.js +1 -0
- package/web/dist/assets/classDiagram-v2-JRS7N3AN-DUEKmDfo.js +1 -0
- package/web/dist/assets/{cose-bilkent-JH36ORCC-DGFOsMUt.js → cose-bilkent-JH36ORCC-CzWlGP6i.js} +1 -1
- package/web/dist/assets/{cynefin-OW5HDTMX-DUwn3ehS.js → cynefin-OW5HDTMX-vK64EGSv.js} +1 -1
- package/web/dist/assets/{cynefinDiagram-5FMLGOSQ-DlLAOZ9x.js → cynefinDiagram-5FMLGOSQ-Bs3g1Gvh.js} +1 -1
- package/web/dist/assets/{dagre-3AP2YEHR-CyourLfz.js → dagre-3AP2YEHR-BhgkYe8V.js} +1 -1
- package/web/dist/assets/{diagram-S7CK7UJ4-BTMbx2np.js → diagram-S7CK7UJ4-C_6mvD2V.js} +1 -1
- package/web/dist/assets/{diagram-UQ7AKVKN-UK94_1-P.js → diagram-UQ7AKVKN-qW7tssUW.js} +1 -1
- package/web/dist/assets/{diagram-VSXAHHWV-C7zS-v9v.js → diagram-VSXAHHWV-txJPHpvG.js} +1 -1
- package/web/dist/assets/{diagram-VX7I27RA-DKJRa6CK.js → diagram-VX7I27RA-CQTMsCnL.js} +1 -1
- package/web/dist/assets/{diagram-Z3DM3KII-kUbAfGAp.js → diagram-Z3DM3KII--cb1hoE6.js} +1 -1
- package/web/dist/assets/{ebnfDiagram-PWID7BFC-CVW16_vb.js → ebnfDiagram-PWID7BFC-Da6lDU77.js} +1 -1
- package/web/dist/assets/{erDiagram-SSCWMZ5O-BRQMFQ5y.js → erDiagram-SSCWMZ5O-DGCMrsQn.js} +1 -1
- package/web/dist/assets/{flowDiagram-A5DVABFB-S34LpLtK.js → flowDiagram-A5DVABFB-GdOL_qno.js} +1 -1
- package/web/dist/assets/{ganttDiagram-EL5Y4UJY-BFiqk1-G.js → ganttDiagram-EL5Y4UJY-Cx1F_jBK.js} +4 -4
- package/web/dist/assets/{gitGraphDiagram-WWUBYQGX-LZsrdyyv.js → gitGraphDiagram-WWUBYQGX-B5_6JhR3.js} +1 -1
- package/web/dist/assets/hand-CuvZZQGW.webp +0 -0
- package/web/dist/assets/index-BYKfMnmv.js +2759 -0
- package/web/dist/assets/index-CW7VsrVg.css +1 -0
- package/web/dist/assets/{infoDiagram-RXCK75RN-0DvN6KIp.js → infoDiagram-RXCK75RN-CjvKpSPA.js} +1 -1
- package/web/dist/assets/{ishikawaDiagram-5VMMS53U-CaY3A-Bx.js → ishikawaDiagram-5VMMS53U-CxLoAPhx.js} +1 -1
- package/web/dist/assets/{journeyDiagram-EYS64GPL-BBeiaCrj.js → journeyDiagram-EYS64GPL-BfvS1upJ.js} +1 -1
- package/web/dist/assets/{kanban-definition-3QL26DDD-ux42DRXQ.js → kanban-definition-3QL26DDD-DKPPu0w4.js} +1 -1
- package/web/dist/assets/{layout-CnXiF_NB.js → layout-Dhgck-Zo.js} +1 -1
- package/web/dist/assets/{linear-BMW0u6G6.js → linear-DMSQ-aUw.js} +1 -1
- package/web/dist/assets/lxgw-nd-app-bold-D1pKA1bR.woff2 +0 -0
- package/web/dist/assets/lxgw-nd-app-regular-BDe3d26v.woff2 +0 -0
- package/web/dist/assets/lxgw-nd-bold-Bufvlg03.woff2 +0 -0
- package/web/dist/assets/lxgw-nd-regular-DQwoI4OP.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-100-DLPe7tEt.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-101-d3VsZKWT.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-102-ClzJuLq6.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-103-DuDnQ6K-.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-104-kPGW3Eem.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-105-BzD54h-0.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-106-BQ7fIzlx.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-107-D8tDfFHI.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-108-tGhkpwep.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-109-7SMVSrly.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-110-_uDKrFed.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-111-Bio825RE.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-112-D2ee0i-C.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-113-JPFVDrga.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-114-BcfxYA4w.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-115-B1HeeOsd.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-116-hY12tXpq.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-117-BvuZwmre.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-118-tzvs_H7j.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-119-J2DWuYDN.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-21-pDubCJV5.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-22-ChAPMpqp.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-23-BBx3oNpT.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-24-CYt-Oagk.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-25-Cx3j-ZUv.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-26-B9AfZ3LL.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-27-Bh2s9MNE.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-28-C02JPoKP.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-29-T_tbUGhk.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-30-DMfyNzhz.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-31-DFfdzbkg.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-32-Bs1fz2iW.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-33-cpB96OkZ.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-34-BhinPYWX.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-35-D_njRQqA.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-36-DqXlLE3t.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-37-j5LbvMph.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-38-oO4jWdKm.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-39-CabsX4rw.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-4-PatS3YHh.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-40-yrLg3C3e.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-41-DBXmCQhc.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-42-Bqij_UiQ.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-43-D3kp0Ntc.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-44-B_BNGvK4.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-45-CZc0cQWs.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-46-CHQX5Kd9.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-47-Ci8gLrHA.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-48-run3ugD3.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-49-DgfiUb6u.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-5-B0CtGbX_.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-50-CdCG-POr.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-51-L2okeQZ2.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-52-BZAqyGJW.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-53-B0xWqLeU.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-54-BZVQX-EA.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-55-093mkIUJ.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-56-CbhWG8G-.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-57-pLQuvo6c.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-58-BHhoY50x.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-59-D1_6DuIQ.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-6-BnAelmYU.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-60-HDBIuLTZ.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-61-C-c13SeU.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-62-kHRVOhZ2.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-63-C0MCsvFv.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-64-DZekguCj.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-65-CtP6c3IU.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-66-DLVWoMSf.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-67-BVuOnayH.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-68-DpxQ6Mnx.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-69-qesBxLmC.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-70-BBt1xN7h.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-71-BWqZacwB.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-72-B1wP_Yst.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-73-C99T7jNZ.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-74-DrUTsWBe.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-75-C4M5XXQe.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-76-Bq8spVWF.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-77-D9vNupE2.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-78-D6th7Gnu.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-79-bezM85cS.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-80-DD8pnhG2.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-81-N6jtSyBs.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-82-D6c180bZ.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-83-em17AadM.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-84-CJ8gdrMK.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-85-9PPGO1eB.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-86-CjWPf-u5.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-87-8D_X_yOC.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-88-9vtKFPBx.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-89-BhE5jAKX.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-90-D2Npfm5E.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-91-C6Ft1-Eu.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-97-CaExyQP9.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-98-CPoVbsUd.woff2 +0 -0
- package/web/dist/assets/lxgwwenkaiscreen-subset-99-ZUQZGVgH.woff2 +0 -0
- package/web/dist/assets/{mindmap-definition-FBJOCRG2-hUxSpdKn.js → mindmap-definition-FBJOCRG2-CalfL_Kn.js} +1 -1
- package/web/dist/assets/{pegDiagram-XKGWAZYB-aCaQPH0w.js → pegDiagram-XKGWAZYB-D9mVWz7l.js} +1 -1
- package/web/dist/assets/pending-edit-apply-kwMFWsUe.js +31 -0
- package/web/dist/assets/{pieDiagram-E7YTZNPT-CmOEZ8zg.js → pieDiagram-E7YTZNPT-DELzbZNS.js} +1 -1
- package/web/dist/assets/{quadrantDiagram-AXDQQJYC-VW6fAhsV.js → quadrantDiagram-AXDQQJYC-TZqp4mfA.js} +1 -1
- package/web/dist/assets/{railroadDiagram-O6MQD6OU-CKJ7Ba5K.js → railroadDiagram-O6MQD6OU-DxX59f0i.js} +1 -1
- package/web/dist/assets/{requirementDiagram-EFPCY7ZU-pNGkq9Vw.js → requirementDiagram-EFPCY7ZU-DFdsJLIe.js} +1 -1
- package/web/dist/assets/{rotate-cw-KAfChbGV.js → rotate-cw-62liz7LX.js} +1 -1
- package/web/dist/assets/{sankeyDiagram-P5KCCOFB-BIMmDTfZ.js → sankeyDiagram-P5KCCOFB-ByYcd3fG.js} +1 -1
- package/web/dist/assets/{sequenceDiagram-WJ2MYXX4-BBW7wzKY.js → sequenceDiagram-WJ2MYXX4-Bj-ml1jS.js} +1 -1
- package/web/dist/assets/{sizeCapture-X5ZJPWSS-DdkXmLYR.js → sizeCapture-X5ZJPWSS-KhsXThyD.js} +1 -1
- package/web/dist/assets/{square-dashed-mouse-pointer-CDUlhUP7.js → square-dashed-mouse-pointer-D_VrqVpy.js} +1 -1
- package/web/dist/assets/{stateDiagram-HBIQ2CUA-W313Uz16.js → stateDiagram-HBIQ2CUA-BJlpHfWU.js} +1 -1
- package/web/dist/assets/stateDiagram-v2-4QOOHH4V-CR2kYAH2.js +1 -0
- package/web/dist/assets/{swimlanes-XN3QIQJK-C29TL26K.js → swimlanes-XN3QIQJK-DUB9OJVs.js} +1 -1
- package/web/dist/assets/swimlanesDiagram-VK2B7HYN-BitOxnG2.js +8 -0
- package/web/dist/assets/{timeline-definition-24CTP7MA-CF0JMObX.js → timeline-definition-24CTP7MA-C03NX82A.js} +1 -1
- package/web/dist/assets/{vennDiagram-4TSXK5OY-DrDFsaH3.js → vennDiagram-4TSXK5OY-B9pjzngp.js} +1 -1
- package/web/dist/assets/{wardleyDiagram-VM6X3IG4-CVrnRIS_.js → wardleyDiagram-VM6X3IG4-UqWq_mcT.js} +1 -1
- package/web/dist/assets/{xychartDiagram-S5SC5T6Z-BvkN1zsT.js → xychartDiagram-S5SC5T6Z-D2pDKtOv.js} +1 -1
- package/web/dist/index.html +2 -2
- package/server/api/memory.js +0 -185
- package/server/engine/agent/prompts/tools/generate-image-cookbook.gemini-gateway.md +0 -583
- package/server/engine/mcp/tools/arrange-on-board.js +0 -124
- package/server/engine/mcp/tools/create-on-board.js +0 -152
- package/server/engine/mcp/tools/edit-sketch.js +0 -167
- package/server/engine/mcp/tools/record-decision.js +0 -140
- package/server/engine/mcp/tools/relate-on-board.js +0 -112
- package/server/engine/mcp/tools/sketch-on-board.js +0 -337
- package/server/engine/plugins/nodesign/skills/rp-craft/SKILL.md +0 -235
- package/server/engine/plugins/nodesign/skills/rp-craft/patterns//346/274/224/345/207/272/351/241/265-/346/234/200/345/260/217/345/256/236/347/216/260.html +0 -78
- package/server/engine/plugins/nodesign/skills/rp-craft//346/274/224/345/207/272.template.js +0 -268
- package/web/dist/assets/DeckWindow-BpLv5082.js +0 -16
- package/web/dist/assets/channel-DGkccMO1.js +0 -1
- package/web/dist/assets/classDiagram-DTDB5LWJ-BGscw3OD.js +0 -1
- package/web/dist/assets/classDiagram-v2-JRS7N3AN-BGscw3OD.js +0 -1
- package/web/dist/assets/index-C0KUf6Wd.css +0 -1
- package/web/dist/assets/index-GAamh1p4.js +0 -2152
- package/web/dist/assets/lxgw-nd-bold-DbRfiTgo.woff2 +0 -0
- package/web/dist/assets/lxgw-nd-regular-CpMw9Ehg.woff2 +0 -0
- package/web/dist/assets/pending-edit-apply-AcdOQ9Ij.js +0 -31
- package/web/dist/assets/stateDiagram-v2-4QOOHH4V-DDhJBZzf.js +0 -1
- package/web/dist/assets/swimlanesDiagram-VK2B7HYN-BfN-Xdmu.js +0 -8
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* 反馈层(用户在 canvas 上的直接编辑 + 评论 buffer):
|
|
11
11
|
* get_pending_changes / clear_pending_changes
|
|
12
12
|
* 产物层(NoDesign 差异化能力):
|
|
13
|
-
* expose_tweaks
|
|
13
|
+
* export_handoff …(expose_tweaks 08-24 暂退役待升级;record_decision 08-24 拆除,记忆体系接棒)
|
|
14
14
|
* 研究层:
|
|
15
15
|
* web_search(4 provider,CJK auto baidu)
|
|
16
16
|
*
|
|
@@ -29,11 +29,12 @@
|
|
|
29
29
|
|
|
30
30
|
import { createSdkMcpServer } from '@anthropic-ai/claude-agent-sdk';
|
|
31
31
|
import { withParamSanitizer } from './param-sanitizer.js';
|
|
32
|
-
import { withCapabilityGate } from './capability-gate.js';
|
|
32
|
+
import { withCapabilityGate, shouldRegisterTool } from './capability-gate.js';
|
|
33
|
+
import { shouldRegisterForMode, assertModeProfileNames } from './mode-profile.js';
|
|
34
|
+
import { MCP_SERVER_NAME } from './server-name.js';
|
|
33
35
|
import { makeScreenshotCanvasTool } from './tools/screenshot.js';
|
|
34
36
|
import { makeScreenshotUrlTool } from './tools/screenshot-url.js';
|
|
35
37
|
import { makeExportHandoffTool } from './tools/export-handoff.js';
|
|
36
|
-
import { makeRecordDecisionTool } from './tools/record-decision.js';
|
|
37
38
|
import { makeWebSearchTool } from './tools/web-search.js';
|
|
38
39
|
import { withTierGate } from './tools/tier-gate.js'; // 档位闸包装器(auth/tier.js;按项目 owner)
|
|
39
40
|
import { makeReadPageTool } from './tools/read-page.js';
|
|
@@ -48,26 +49,23 @@ import {
|
|
|
48
49
|
} from './tools/browse.js';
|
|
49
50
|
import { makeBrowserScreenshotTool } from './tools/browse-screenshot.js';
|
|
50
51
|
import { makeBrowserComputerTool } from './tools/browse-computer.js';
|
|
51
|
-
import { makeBrowserFindTool, makeBrowserBatchTool } from './tools/browse-find-batch.js';
|
|
52
|
+
import { makeBrowserFindTool, makeBrowserBatchTool, makeBatchTool } from './tools/browse-find-batch.js';
|
|
52
53
|
import { makeArtifactOpenTool, makeArtifactComputerTool, makeArtifactFindTool, makeArtifactMotionTool, makeArtifactBatchTool } from './tools/artifact-session.js';
|
|
53
54
|
import { makeGetComputedStylesTool } from './tools/get-computed-styles.js';
|
|
54
55
|
import { makeNavigateToPageTool } from './tools/navigate-to-page.js';
|
|
55
56
|
import { makeHighlightTool } from './tools/highlight.js';
|
|
56
57
|
import { makePreviewDeckTool } from './tools/preview-deck.js';
|
|
57
58
|
import { makeBuildDocxTool } from './tools/build-docx.js';
|
|
58
|
-
|
|
59
|
+
// expose-tweaks 08-24 暂退役(能力不足待升级再加回):本体与前端 TweaksPanel 留档休眠,不注册
|
|
59
60
|
import { makeGetPendingChangesTool } from './tools/get-pending-changes.js';
|
|
60
61
|
import { makeClearPendingChangesTool } from './tools/clear-pending-changes.js';
|
|
61
62
|
import { makeGenerateImageTool } from './tools/generate-image.js';
|
|
62
63
|
import { makeRemoveBackgroundTool } from './tools/remove-background.js';
|
|
63
64
|
import { makePinToBoardTool } from './tools/pin-to-board.js';
|
|
64
|
-
import {
|
|
65
|
+
import { makeEditBoardTool } from './tools/edit-board.js';
|
|
65
66
|
import { makeReadBoardTool } from './tools/read-board.js';
|
|
66
|
-
import { makeArrangeOnBoardTool } from './tools/arrange-on-board.js';
|
|
67
|
-
import { makeCreateOnBoardTool } from './tools/create-on-board.js';
|
|
68
|
-
import { makeSketchOnBoardTool, makeFinishSketchTool } from './tools/sketch-on-board.js';
|
|
69
|
-
import { makeEditSketchTool } from './tools/edit-sketch.js';
|
|
70
67
|
import { makeWriteOnBoardTool } from './tools/write-on-board.js';
|
|
68
|
+
import { makeOpenSheetTool } from './tools/open-sheet.js';
|
|
71
69
|
import { makeLookAtBoardTool } from './tools/look-at-board.js';
|
|
72
70
|
import { makeReadUserViewTool } from './tools/read-user-view.js';
|
|
73
71
|
import { makeOrganizeBoardTool } from './tools/organize-board.js';
|
|
@@ -75,6 +73,12 @@ import { makeReadDocumentTool } from './tools/read-document.js';
|
|
|
75
73
|
import { makeReadTavernJsonTool } from './tools/read-tavern-json.js';
|
|
76
74
|
import { makeDeliverFilesTool } from './tools/deliver-files.js';
|
|
77
75
|
import { makeCrystallizeSkillTool } from './tools/crystallize-skill.js';
|
|
76
|
+
import { makeCastRoleTool } from './tools/cast-role.js';
|
|
77
|
+
import { makeSetVarsTool } from './tools/set-vars.js';
|
|
78
|
+
import { makeDrawTrendTool } from './tools/draw-trend.js';
|
|
79
|
+
import { makeJotMemoryTool } from './tools/role-memory.js';
|
|
80
|
+
import { makeRollDiceTool } from './tools/roll-dice.js';
|
|
81
|
+
import { assertRoleToolsRegistered } from '../agent/cast.js';
|
|
78
82
|
import { makePublishSiteTool } from './tools/publish-site.js';
|
|
79
83
|
import { makeReportIssueTool } from './tools/report-issue.js';
|
|
80
84
|
import { makeRollFilmTool } from './tools/roll-film.js';
|
|
@@ -103,7 +107,7 @@ import { makeLookupTagsTool } from './tools/lookup-tags.js';
|
|
|
103
107
|
const ALWAYS_LOAD_TOOLS = new Set([
|
|
104
108
|
'screenshot_canvas', 'read_page', 'list_pages', 'query_elements',
|
|
105
109
|
'get_computed_styles', 'navigate_to_page', 'highlight', 'preview_deck',
|
|
106
|
-
'
|
|
110
|
+
'get_pending_changes', 'clear_pending_changes',
|
|
107
111
|
// screenshot_url 常驻:explorer 显式 tools 列表没有 ToolSearch,defer 了它就
|
|
108
112
|
// 永远拉不到 schema;schema 本身很小(4 字段),常驻成本可忽略
|
|
109
113
|
'screenshot_url',
|
|
@@ -128,12 +132,53 @@ const ALWAYS_LOAD_TOOLS = new Set([
|
|
|
128
132
|
// 08-21 产物会话五件:成品检查的交互半边(状态跨调用留着)。artifact_batch 的卖点
|
|
129
133
|
// "一趟跑完 + 结尾截图"和 live:true 的存在都只在描述里说,常驻。
|
|
130
134
|
'artifact_open', 'artifact_computer', 'artifact_find', 'artifact_batch', 'artifact_motion',
|
|
135
|
+
// ⭐ 板面核心五件(2026-08-27 用户拍板「板书是基础交互方式」):合计约 3.4k token
|
|
136
|
+
// 的描述量进缓存前缀,每轮增量趋零;换来的是 write 的件数判据/lane/ink、edit 的
|
|
137
|
+
// 18 个 op、batch 的按拍打包这些**只活在描述里的卖点**每回合都在场 —— 此前它们
|
|
138
|
+
// 全在 deferred 区,agent 只看得到名字,教义在 prelude 里教、schema 却要现搜。
|
|
139
|
+
// 膨胀由模式闸控:rp 模式 unregister 掉 artifact/量具族后常驻集自动收缩。
|
|
140
|
+
// read_user_view 不进:视口已经每回合自动进状态块,它降级成"看画面细节"的按需件。
|
|
141
|
+
// board_batch 2026-08-30 暂停(见下面注册处的注释),常驻表同步摘牌。
|
|
142
|
+
'write_on_board', 'edit_board', 'read_board', 'look_at_board',
|
|
143
|
+
// 纸范式(2026-08-29):铺纸是板面工作的起手式,卖点全在描述里(当前纸/坐标原点/
|
|
144
|
+
// 排不下就拒收、翻页归 agent),必须常驻。
|
|
145
|
+
'open_sheet',
|
|
131
146
|
]);
|
|
132
147
|
|
|
133
|
-
|
|
148
|
+
/**
|
|
149
|
+
* 常驻表的启动期对账(08-27 审计补):跟 mode-profile 同病同药 —— 工具改名后
|
|
150
|
+
* 这张表的旧名字不会报错,只会让那件工具静默退回 deferred(agent 又只看得到名字)。
|
|
151
|
+
* 对照的是**过滤前**的全量名单:能力/模式闸下架某件时它照常在 builtTools 里。
|
|
152
|
+
*/
|
|
153
|
+
function assertAlwaysLoadNames(registeredNames) {
|
|
154
|
+
const have = new Set(registeredNames);
|
|
155
|
+
const ghosts = [...ALWAYS_LOAD_TOOLS].filter((n) => !have.has(n));
|
|
156
|
+
if (ghosts.length) {
|
|
157
|
+
throw new Error(`[always-load] 常驻表里有注册表不存在的名字: ${ghosts.join(', ')} —— 改名后表没跟上,这些条目在静默空转`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* 工具名 → 它真正收的参数名集合。装配时回填(见下),PreToolUse 的未知键探针读它。
|
|
163
|
+
* 全进程共享一份:同一份 schema 跟项目无关。
|
|
164
|
+
*/
|
|
165
|
+
export const TOOL_PARAM_KEYS = new Map();
|
|
166
|
+
|
|
167
|
+
export function createNodesignMcpServer({ workspaceRoot, sharedRoot, projectId, sessionId, ctx, roleRoster = null, projectMode = 'design' } = {}) {
|
|
134
168
|
// 浏览通道里能被 browser_batch 串起来的七件:先建一次,batch 拿**同一批实例**
|
|
135
169
|
// (projectId/ctx 绑在 handler 里,不能再造第二份)。只有 request_help 不进
|
|
136
170
|
// batch(它阻塞等人);capture 在里面 —— 逐页采 token 正是 batch 要省的那种回合。
|
|
171
|
+
// batch 的运行时解析表(2026-08-27 重置):装配管线(能力闸/模式闸/消毒)跑完后
|
|
172
|
+
// 回填,三个 batch 的子调用一律取**包装后**的实例 —— 08-26「batch 绕闸」挂账在此清账。
|
|
173
|
+
const wrappedByName = new Map();
|
|
174
|
+
const resolveTool = (n) => wrappedByName.get(n);
|
|
175
|
+
const writeOnBoard = makeWriteOnBoardTool({ projectId, sharedRoot: workspaceRoot || sharedRoot, sessionId, ctx });
|
|
176
|
+
const boardBatchable = [
|
|
177
|
+
makeOpenSheetTool({ projectId, sessionId, ctx }),
|
|
178
|
+
writeOnBoard,
|
|
179
|
+
makeEditBoardTool({ projectId, sharedRoot, sessionId, ctx }),
|
|
180
|
+
makeReadBoardTool({ projectId, sharedRoot }),
|
|
181
|
+
];
|
|
137
182
|
const browseBatchable = [
|
|
138
183
|
makeBrowserNavigateTool({ projectId, ctx }),
|
|
139
184
|
makeBrowserReadTool({ projectId }),
|
|
@@ -160,7 +205,7 @@ export function createNodesignMcpServer({ workspaceRoot, sharedRoot, projectId,
|
|
|
160
205
|
// 自己的产物靠什么在动:跟 browser_capture motion 同一份引擎(engine/motion/inventory.js)
|
|
161
206
|
makeArtifactMotionTool({ projectId, workspaceRoot, sessionId }),
|
|
162
207
|
];
|
|
163
|
-
const
|
|
208
|
+
const builtTools = [
|
|
164
209
|
// C9 screenshot_canvas — playwright headless 截图 → image content block
|
|
165
210
|
screenshotCanvas,
|
|
166
211
|
|
|
@@ -182,8 +227,15 @@ export function createNodesignMcpServer({ workspaceRoot, sharedRoot, projectId,
|
|
|
182
227
|
// C10 export_handoff — 复用 exports.js 的 buildHandoffZip,写到 workspace/exports/
|
|
183
228
|
makeExportHandoffTool({ workspaceRoot, sharedRoot, projectId, sessionId, ctx }),
|
|
184
229
|
|
|
185
|
-
//
|
|
186
|
-
|
|
230
|
+
// cast_role — 写一张角色卡并登记名字(2026-08-26 建,08-29 简化)。
|
|
231
|
+
// 卡是数据,身体是预注册的角色位;写完当回合就能派,之后靠 SendMessage 叫醒。
|
|
232
|
+
makeCastRoleTool({ workspaceRoot, sessionId, ctx, roster: roleRoster }),
|
|
233
|
+
makeSetVarsTool({ projectId, sharedRoot: workspaceRoot || sharedRoot }),
|
|
234
|
+
makeDrawTrendTool({ projectId, sharedRoot: workspaceRoot || sharedRoot, sessionId, ctx }),
|
|
235
|
+
makeJotMemoryTool({ workspaceRoot }),
|
|
236
|
+
// roll_dice — 服务端真随机骰(08-28 沉浸感机制刀①):模型编的骰运不可信,
|
|
237
|
+
// 这把走 crypto + run.dice 事件直达用户屏幕。GM only(不进角色白名单)。
|
|
238
|
+
makeRollDiceTool({ projectId, ctx }),
|
|
187
239
|
|
|
188
240
|
// crystallize_skill — 把探索出来的方法论固化成用户自己的 skill + 作品进橱窗
|
|
189
241
|
// (2026-07-30)。用户明确要求才调;写的是判断依据不是成品 HTML。
|
|
@@ -259,12 +311,12 @@ export function createNodesignMcpServer({ workspaceRoot, sharedRoot, projectId,
|
|
|
259
311
|
// 或者第二个常驻名额;1 vCPU 上后者不成立。
|
|
260
312
|
...browseBatchable,
|
|
261
313
|
// 一次往返跑一串(串行、遇错即停、结尾补截图)—— 省的是模型回合数
|
|
262
|
-
makeBrowserBatchTool({ tools: browseBatchable }),
|
|
314
|
+
makeBrowserBatchTool({ tools: browseBatchable, resolve: resolveTool }),
|
|
263
315
|
// ── 产物会话(2026-08-21):成品检查的交互半边 ──
|
|
264
316
|
// artifact_open 把产物开进常驻会话,artifact_computer/find 对着它点、敲、找;
|
|
265
317
|
// 五个量具 live:true 就量会话里现在这一页;artifact_batch 一趟跑一串。
|
|
266
318
|
...artifactSessionTools,
|
|
267
|
-
makeArtifactBatchTool({ tools: [...artifactSessionTools, screenshotCanvas, queryElements, getComputedStyles, explainStyle, traceMotion] }),
|
|
319
|
+
makeArtifactBatchTool({ tools: [...artifactSessionTools, screenshotCanvas, queryElements, getComputedStyles, explainStyle, traceMotion], resolve: resolveTool }),
|
|
268
320
|
// 撞验证墙时举手叫人(阻塞等,默认 120 秒超时 —— 人可能就走了)
|
|
269
321
|
makeBrowserRequestHelpTool({ projectId, ctx }),
|
|
270
322
|
getComputedStyles,
|
|
@@ -284,9 +336,6 @@ export function createNodesignMcpServer({ workspaceRoot, sharedRoot, projectId,
|
|
|
284
336
|
makeGetPendingChangesTool({ workspaceRoot, ctx }),
|
|
285
337
|
makeClearPendingChangesTool({ workspaceRoot, ctx }),
|
|
286
338
|
|
|
287
|
-
// Tweaks 协议:agent 暴露 deck 专属可调参数 schema → 前端按 schema 渲染控件
|
|
288
|
-
makeExposeTweaksTool({ workspaceRoot, ctx }),
|
|
289
|
-
|
|
290
339
|
// 图片生成(gemini-3.1-flash-image-preview / Nano Banana 2,via NoDesk passthrough)
|
|
291
340
|
// 落档优先 sharedRoot/assets/generated/,fallback workspaceRoot/assets/generated/。
|
|
292
341
|
// 跨 session 共享靠 sessions/<sid>/assets softlink → shared/assets。
|
|
@@ -299,29 +348,49 @@ export function createNodesignMcpServer({ workspaceRoot, sharedRoot, projectId,
|
|
|
299
348
|
|
|
300
349
|
// 工作台分区画布(2026-07-27):agent 协助摆放 —— 把产物/文档/deck 钉进
|
|
301
350
|
// 某 session 的工作区。写 board.json(board-store 单锁)+ 广播 board.updated。
|
|
302
|
-
makePinToBoardTool({ sharedRoot, projectId, ctx }),
|
|
351
|
+
makePinToBoardTool({ sharedRoot, projectId, sessionId, ctx }),
|
|
303
352
|
|
|
304
353
|
// 关系线(2026-08-07):agent 把「这版改自那版」「这两个是对照」这类
|
|
305
354
|
// **只有它知道**的关系画到画布上。画布知道每个产物是什么,但不知道它们
|
|
306
355
|
// 之间是什么关系 —— 那是北极星(排出有版面感的布局)真正缺的那一块。
|
|
307
|
-
|
|
308
|
-
//
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
356
|
+
// 黑板核心三件(08-25 范式重做,08-28 别名收摊):写=write_on_board(件数
|
|
357
|
+
// 判据分流一句话/一张图,ink:'hand' 收编旧 create),改=edit_board(吞
|
|
358
|
+
// arrange/finish/relate/edit_sketch),看=read_board。board_batch 用
|
|
359
|
+
// **同一批实例**串行跑(一章 RP 的板面维护八次往返收成一次)。
|
|
360
|
+
...boardBatchable,
|
|
361
|
+
// board_batch 暂停(2026-08-30 用户拍板):batch 适合语法机械、单步几乎不会
|
|
362
|
+
// 语义性失败的家族(浏览器/产物检查照旧),板面动作不是 —— 拒收/容量/引用
|
|
363
|
+
// 都是单步就可能断的语义闸。真会话对账:batch 内每动作失败 16.1% vs 单调用
|
|
364
|
+
// 9.1%,另有 9.4% 好动作被连坐;今天 glm 一场 board_batch 0/6 全败,sonnet
|
|
365
|
+
// 同一张卡几乎不用 batch 反而顺。是暂停不是拆除:makeBatchTool/流式预知/
|
|
366
|
+
// beat-gate/角色白名单里的 batch 支路全保留原样,恢复 = git 翻回这一块注册
|
|
367
|
+
// (git log -S board_batch -- server/engine/mcp/index.js)+ 常驻表加回名字
|
|
368
|
+
// + prelude/SKILL 把"攒一车"的教学翻回来。
|
|
312
369
|
makeOrganizeBoardTool({ projectId, ctx }),
|
|
313
|
-
// 黑板(2026-08-23):一次落一整张草图 / 落定或擦掉 / 看一眼 / 用户在看哪
|
|
314
|
-
makeSketchOnBoardTool({ projectId, ctx }),
|
|
315
|
-
makeFinishSketchTool({ projectId, ctx }),
|
|
316
|
-
makeEditSketchTool({ projectId, ctx }),
|
|
317
|
-
makeWriteOnBoardTool({ projectId, sharedRoot: workspaceRoot || sharedRoot, sessionId, ctx }),
|
|
318
370
|
makeLookAtBoardTool({ projectId, ctx }),
|
|
319
371
|
makeReadUserViewTool({ projectId }),
|
|
320
372
|
|
|
321
373
|
// 注:Phase Image-2 的 request_image_approval 工具已废弃(2026-05-06)。
|
|
322
374
|
// generate_image 的 CallToolResult 已返 image content block,前端自动渲染;
|
|
323
375
|
// agent 在 caption / 自然回话邀请反馈,下一轮用户 chat 即天然 gate。
|
|
324
|
-
]
|
|
376
|
+
];
|
|
377
|
+
|
|
378
|
+
// 模式对照表的启动期对账(2026-08-27):必须对**过滤前**的全量名单 —— 表校验的
|
|
379
|
+
// 对象是「注册表里有没有这个名字」,跟本机能力/项目模式无关。工具改名后表没跟上
|
|
380
|
+
// 时这里当场炸,不让下架条目静默空转(判据本身要先验一遍)。
|
|
381
|
+
assertModeProfileNames(builtTools.map((t) => t.name));
|
|
382
|
+
assertAlwaysLoadNames(builtTools.map((t) => t.name));
|
|
383
|
+
|
|
384
|
+
const tools = builtTools.filter((t) => (
|
|
385
|
+
// 本机能力缺席且该工具是 unregister 档 → 整件不注册(连名字都不进上下文)。
|
|
386
|
+
// 现在只有本地 GPU 盒子那两件:盒子手动开关,关着时留名字只会让 agent 去撞
|
|
387
|
+
// SSH 拒连。对照表在 capability-gate.js 一份。
|
|
388
|
+
shouldRegisterTool(t)
|
|
389
|
+
)).filter((t) => (
|
|
390
|
+
// 项目模式闸(2026-08-27):rp 项目下架设计产线(deck/站点/交付/产物量具),
|
|
391
|
+
// 同样是 unregister 语义。对照表在 mode-profile.js 一份,下面还有启动期对账。
|
|
392
|
+
shouldRegisterForMode(t, projectMode)
|
|
393
|
+
)).map((t) => (
|
|
325
394
|
// SDK 用 _meta['anthropic/alwaysLoad'] 标记常驻(tool() 第 5 参的等价物,
|
|
326
395
|
// 集中在这打标避免改 16 个工具文件)
|
|
327
396
|
ALWAYS_LOAD_TOOLS.has(t.name)
|
|
@@ -338,8 +407,24 @@ export function createNodesignMcpServer({ workspaceRoot, sharedRoot, projectId,
|
|
|
338
407
|
withParamSanitizer(t, { projectId, sessionId })
|
|
339
408
|
));
|
|
340
409
|
|
|
410
|
+
// batch 解析表回填:此刻 tools 里的实例已过完 能力闸/模式闸/alwaysLoad/消毒 全套
|
|
411
|
+
for (const t of tools) wrappedByName.set(t.name, t);
|
|
412
|
+
// 参数名台账(2026-08-30):给 PreToolUse 的未知键探针用。SDK 在进 handler
|
|
413
|
+
// 之前就按 schema 把未知键 strip 掉了(zod object 默认行为,不报错),所以
|
|
414
|
+
// 工具自己**永远看不见**模型多传了什么 —— 真会话里 write_on_board 被塞过 20 次
|
|
415
|
+
// `facts`(整份剧情事实),一次都没留下痕迹。只有钩子拿得到原始 tool_input。
|
|
416
|
+
for (const t of tools) TOOL_PARAM_KEYS.set(t.name, new Set(Object.keys(t.inputSchema || {})));
|
|
417
|
+
|
|
418
|
+
// 角色工具白名单的启动期对账(2026-08-26):cast_role 会把白名单里的短名写进
|
|
419
|
+
// 角色文件的 frontmatter,名字写错**不会报错**,只会让角色少一只手(CLI 当那个
|
|
420
|
+
// 工具不存在)。所以对着真实注册表核一遍,错了当场炸在启动期。
|
|
421
|
+
assertRoleToolsRegistered(new Set(tools.map((t) => t.name)));
|
|
422
|
+
|
|
423
|
+
|
|
341
424
|
const server = createSdkMcpServer({
|
|
342
|
-
name
|
|
425
|
+
// 名字收在 mcp/server-name.js:它同时是 session-loop 里 mcpServers 的键
|
|
426
|
+
// (决定模型看到的 mcp__nodesign__* 前缀)和 isolation.js 那条 allow 规则要匹配的名
|
|
427
|
+
name: MCP_SERVER_NAME,
|
|
343
428
|
version: '0.1.0',
|
|
344
429
|
tools,
|
|
345
430
|
});
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* engine/mcp/mode-profile.js — 项目模式 × 工具面的唯一对照表 + 闸(2026-08-27)。
|
|
3
|
+
*
|
|
4
|
+
* 项目分两种模式(projects.mode,真相源在 projects/store.js):
|
|
5
|
+
* - design:设计工作台(现状默认)。工具面不动 —— 含全部 RP 工具,因为存量的
|
|
6
|
+
* 演出全发生在 design 项目里,在这里藏 RP 工具等于把它们全断掉。等演出模式
|
|
7
|
+
* 转正、真会话都迁过去之后,再考虑反向裁剪。
|
|
8
|
+
* - rp:演出(常驻角色演故事)。下架设计产线 —— 不是防误用那么简单:工具名
|
|
9
|
+
* 进上下文就是注意力,prelude 的设计教义也按同一模式剥(system-prompts.js
|
|
10
|
+
* 的 nd:mode 分区)。两边共用画布/黑板/会话/精灵全部基础设施。
|
|
11
|
+
*
|
|
12
|
+
* 跟 capability-gate.js 的关系:同一个注册期 filter 位置、不同判据 ——
|
|
13
|
+
* 那边按「本机能力在不在」,这边按「这个项目在演哪种戏」。都是 unregister 语义
|
|
14
|
+
* (连名字都不给模型看见),先后串联,谁说不注册都不注册。
|
|
15
|
+
*
|
|
16
|
+
* ⚠️ 改这张表必须跑 assertModeProfileNames(mcp/index.js 启动期已挂):
|
|
17
|
+
* 表里的名字对不上真实注册名时它当场炸 —— 不然一次工具改名就让这里静默空转,
|
|
18
|
+
* 「配置读数 ≠ 真在生效」这条线上已经栽过太多次。
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* rp 模式下整件不注册的工具。按产线分组 —— 拆的时候用户按功能拍的板
|
|
23
|
+
* (2026-08-27:「文档站点应用都移除,生图黑板精灵和浏览器感知留下」)。
|
|
24
|
+
*/
|
|
25
|
+
export const RP_HIDDEN_TOOLS = Object.freeze(new Set([
|
|
26
|
+
// deck / 文档产线
|
|
27
|
+
'build_docx', 'preview_deck', 'read_page', 'list_pages',
|
|
28
|
+
// 站点发布
|
|
29
|
+
'publish_site',
|
|
30
|
+
// 设计交付与方法论结晶
|
|
31
|
+
'export_handoff', 'crystallize_skill',
|
|
32
|
+
// ⚠️ get_pending_changes / clear_pending_changes **不在此列**:DirectEdit 是用户
|
|
33
|
+
// 输入通道(圈图说事 / 双击改字),不是设计产线 —— rp 项目里也得能收用户的圈注。
|
|
34
|
+
// HTML 产物量具(板的眼睛是 look_at_board / read_user_view,不在此列)
|
|
35
|
+
'screenshot_canvas', 'query_elements', 'get_computed_styles', 'explain_style',
|
|
36
|
+
'profile_scroll', 'trace_motion',
|
|
37
|
+
// 产物会话五量具
|
|
38
|
+
'artifact_open', 'artifact_computer', 'artifact_find', 'artifact_motion', 'artifact_batch',
|
|
39
|
+
]));
|
|
40
|
+
|
|
41
|
+
/** 这件工具在该模式下该不该注册(false = 连名字都不给) */
|
|
42
|
+
export function shouldRegisterForMode(toolDef, mode) {
|
|
43
|
+
if (mode !== 'rp') return true;
|
|
44
|
+
return !RP_HIDDEN_TOOLS.has(toolDef.name);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 启动期对账:表里每个名字必须真实存在于注册表。
|
|
49
|
+
* @param {string[]} registeredNames design 模式(全量)下的注册名单
|
|
50
|
+
* @throws 表里出现注册表没有的名字(改名 / 删除后表没跟上)
|
|
51
|
+
*/
|
|
52
|
+
export function assertModeProfileNames(registeredNames) {
|
|
53
|
+
const have = new Set(registeredNames);
|
|
54
|
+
const ghosts = [...RP_HIDDEN_TOOLS].filter((n) => !have.has(n));
|
|
55
|
+
if (ghosts.length) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`[mode-profile] RP_HIDDEN_TOOLS 里有注册表不存在的名字: ${ghosts.join(', ')} `
|
|
58
|
+
+ '—— 工具改名或下线后对照表没跟上,这些条目在静默空转',
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* skill × 模式(2026-08-30)。跟上面那张表同一个语义,另一个载体。
|
|
65
|
+
*
|
|
66
|
+
* ## 为什么 skill 也要按模式筛
|
|
67
|
+
*
|
|
68
|
+
* `session-loop.js` 把 `installed.skills` 整个交给 SDK,而 SDK **只把 description
|
|
69
|
+
* 注进系统提示词**(body 才是按需加载,见 agent/skill.js 头注)。所以每装一个 skill,
|
|
70
|
+
* 它那几百字节的描述就在**每一个会话**里常驻 —— 不分模式。
|
|
71
|
+
*
|
|
72
|
+
* 实测(08-30):RP 会话现在背着 deskskill-engine-mini(562B) / docx-craft(1123B) /
|
|
73
|
+
* site-craft(782B) 三份描述,合计 ~2.4KB,而这三个 skill 要用的工具
|
|
74
|
+
* (`build_docx` / `publish_site` / `preview_deck`)在 RP 模式下**根本没注册**
|
|
75
|
+
* ——上面那张 RP_HIDDEN_TOOLS 已经把它们摘掉了。工具没了描述还在,是纯亏。
|
|
76
|
+
* 反过来同理:演出侧的文风/技法包不该压在设计会话的常驻区里。
|
|
77
|
+
*
|
|
78
|
+
* ## 判据
|
|
79
|
+
*
|
|
80
|
+
* 表里没有的名字**一律放行** —— 用户自己装的 plugin(用户级 / 项目级)不归我们裁,
|
|
81
|
+
* 只管内置这几个。这条别改成白名单:那会让用户装的 skill 静默消失,
|
|
82
|
+
* 而「静默消失」是这条线上最难查的一类。
|
|
83
|
+
*/
|
|
84
|
+
export const SKILL_MODES = Object.freeze({
|
|
85
|
+
// 设计产线:工具在 RP 下已下架,描述跟着走
|
|
86
|
+
'deskskill-engine-mini': 'design',
|
|
87
|
+
'docx-craft': 'design',
|
|
88
|
+
'site-craft': 'design',
|
|
89
|
+
// 演出侧
|
|
90
|
+
'story-voice': 'rp',
|
|
91
|
+
'story-craft': 'rp',
|
|
92
|
+
'story-intimacy': 'rp',
|
|
93
|
+
// 两边都要:轻度演故事发生在设计项目里(prelude 设计区明写这条路),
|
|
94
|
+
// 而酒馆卡也常常被丢进设计项目
|
|
95
|
+
'blackboard-rp': 'both',
|
|
96
|
+
'story-import': 'both',
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
/** 按模式筛 skill 名单。表里没有的一律保留(用户装的不归我们裁)。 */
|
|
100
|
+
export function filterSkillsForMode(names, mode) {
|
|
101
|
+
const want = mode === 'rp' ? 'rp' : 'design';
|
|
102
|
+
return (Array.isArray(names) ? names : []).filter((n) => {
|
|
103
|
+
const m = SKILL_MODES[n];
|
|
104
|
+
return !m || m === 'both' || m === want;
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 启动期对账:表里每个名字必须真的装着。
|
|
110
|
+
* 跟 assertModeProfileNames 同样的狠法 —— skill 改名/下线后表没跟上就是静默空转。
|
|
111
|
+
* @param {string[]} installedNames 本次会话实际装上的 skill 名单
|
|
112
|
+
*/
|
|
113
|
+
export function assertSkillModeNames(installedNames) {
|
|
114
|
+
const have = new Set(installedNames || []);
|
|
115
|
+
const ghosts = Object.keys(SKILL_MODES).filter((n) => !have.has(n));
|
|
116
|
+
if (ghosts.length) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
`[mode-profile] SKILL_MODES 里有没装上的 skill: ${ghosts.join(', ')} `
|
|
119
|
+
+ '—— skill 改名或下线后对照表没跟上,这些条目在静默空转',
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* skill 按模式筛的总入口(08-30;从 session-loop 拆来 —— 行数棘轮)。
|
|
126
|
+
* SDK 只把 description 注进系统提示词(body 按需加载),所以每个 skill 的几百字节
|
|
127
|
+
* 描述是**每个会话**的常驻成本,不分模式。筛之前 RP 会话背着设计三件
|
|
128
|
+
* (deskskill/docx/site 合计 ~2.4KB)的描述,而它们要用的工具在 RP 下压根没注册。
|
|
129
|
+
* 对账跟 assertModeProfileNames 一样狠:表里的名字没装上就当场炸,别静默空转。
|
|
130
|
+
*/
|
|
131
|
+
export function modeSkillsFor(installedNames, mode) {
|
|
132
|
+
assertSkillModeNames(installedNames);
|
|
133
|
+
const out = filterSkillsForMode(installedNames, mode);
|
|
134
|
+
if (out.length !== installedNames.length) {
|
|
135
|
+
const dropped = installedNames.filter((n) => !out.includes(n));
|
|
136
|
+
console.log(`[session-loop] skills 按 mode=${mode} 筛掉 ${dropped.length}: [${dropped.join(', ')}]`);
|
|
137
|
+
}
|
|
138
|
+
return out;
|
|
139
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcp/server-name.js —— MCP 服务名的唯一真相源(2026-08-25)
|
|
3
|
+
*
|
|
4
|
+
* 这个名字有两个读者,而且**改错了不会报错,只会静默失效**:
|
|
5
|
+
* 1. session-loop.js 的 `mcpServers: { [MCP_SERVER_NAME]: server }` —— 决定
|
|
6
|
+
* 工具在模型眼里叫 `mcp__<名>__<工具>`
|
|
7
|
+
* 2. isolation.js 的 `permissions.allow: ['mcp__<名>']` —— 决定这些工具跳不跳
|
|
8
|
+
* auto 模式分类器
|
|
9
|
+
* 两处对不上时:工具照常能用,只是每一次调用又开始过分类器,没有任何报错。
|
|
10
|
+
* 所以名字收在这里一份,两边都 import,并由 isolation.test.js 钉住。
|
|
11
|
+
*
|
|
12
|
+
* 单独一个文件而不是挂在 mcp/index.js:isolation.js 只要这一个字符串,
|
|
13
|
+
* 不该为此把整棵工具树(连带 DB 模块)拖进来。
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export const MCP_SERVER_NAME = 'nodesign';
|
|
17
|
+
|
|
18
|
+
/** 给 permissions.allow 用的整服务放行规则 */
|
|
19
|
+
export const MCP_ALLOW_RULE = `mcp__${MCP_SERVER_NAME}`;
|
|
@@ -257,11 +257,12 @@ export const ARTIFACT_BATCHABLE = [
|
|
|
257
257
|
'screenshot_canvas', 'trace_motion', 'get_computed_styles', 'explain_style', 'query_elements',
|
|
258
258
|
];
|
|
259
259
|
|
|
260
|
-
export function makeArtifactBatchTool({ tools }) {
|
|
260
|
+
export function makeArtifactBatchTool({ tools, resolve = null }) {
|
|
261
261
|
const names = ARTIFACT_BATCHABLE.filter(n => tools.some(t => t.name === n));
|
|
262
262
|
return makeBatchTool({
|
|
263
263
|
name: 'artifact_batch',
|
|
264
264
|
tools,
|
|
265
|
+
resolve,
|
|
265
266
|
batchable: ARTIFACT_BATCHABLE,
|
|
266
267
|
finalShot: { name: 'artifact_computer', input: { action: 'screenshot' } },
|
|
267
268
|
description: `Run several artifact-session steps in ONE round trip: open → click → type →
|
|
@@ -179,7 +179,8 @@ async function zoomShot(page, region, frame, lead) {
|
|
|
179
179
|
}
|
|
180
180
|
const [x0, y0, x1, y1] = region.map(Math.round);
|
|
181
181
|
if (x0 < 0 || y0 < 0 || x1 > frame.w || y1 > frame.h || x1 - x0 < 8 || y1 - y0 < 8) {
|
|
182
|
-
return asText(`Error: zoom region [${region.join(', ')}] must lie inside the ${frame.w}×${frame.h}
|
|
182
|
+
return asText(`Error: zoom region [${region.join(', ')}] must lie inside the ${frame.w}×${frame.h} LIVE VIEWPORT and be at least 8×8. `
|
|
183
|
+
+ 'zoom takes viewport pixels — coordinates from a fullPage screenshot are in page space and do NOT work here; scroll the target into view first, or subtract the scroll offset.', true);
|
|
183
184
|
}
|
|
184
185
|
const clip = { x: toPage(x0, frame), y: toPage(y0, frame), width: toPage(x1 - x0, frame), height: toPage(y1 - y0, frame) };
|
|
185
186
|
const buf = await page.screenshot({ type: 'png', clip });
|
|
@@ -85,41 +85,102 @@ as an error telling you to find again.`,
|
|
|
85
85
|
* @param {string[]} o.batchable 允许的名字
|
|
86
86
|
* @param {{name:string, input:object}} [o.finalShot] 结尾补的那张"当前状态";不传就不补
|
|
87
87
|
*/
|
|
88
|
-
export function makeBatchTool({ name, description, tools, batchable, finalShot }) {
|
|
88
|
+
export function makeBatchTool({ name, description, tools = [], batchable, resolve = null, finalShot }) {
|
|
89
|
+
// resolve(2026-08-27 重置,清 08-26 那条「batch 绕闸」挂账):传了它,子工具在
|
|
90
|
+
// **运行时**从装配完成后的注册表取(index.js 在包装管线跑完后回填 wrappedByName),
|
|
91
|
+
// 能力闸 / 参数消毒 / 模式过滤对 batch 内的调用照常生效。batchable 仍是**政策名单**
|
|
92
|
+
// (哪些名字许进 batch);resolve 查不到 = 这台机器/该模式把它下架了,如实报。
|
|
93
|
+
// 不传 resolve 走旧的实例表(单测直连用 —— 但生产装配一律传 resolve)。
|
|
89
94
|
const byName = new Map(tools.filter(t => batchable.includes(t.name)).map(t => [t.name, t]));
|
|
90
|
-
const
|
|
95
|
+
const lookup = (n) => (resolve ? (batchable.includes(n) ? resolve(n) : undefined) : byName.get(n));
|
|
96
|
+
const names = resolve ? [...batchable] : [...byName.keys()];
|
|
97
|
+
const shotDefault = finalShot ? finalShot.default !== false : false;
|
|
91
98
|
return tool(
|
|
92
99
|
name,
|
|
93
100
|
description,
|
|
94
101
|
{
|
|
95
|
-
|
|
102
|
+
// looseObject(2026-08-29):**放错层的参数不许静默消失**。模型很自然会写
|
|
103
|
+
// {name, chain:true, input:{…}} —— chain 是 write_on_board 的参数,写在了
|
|
104
|
+
// action 这一层。z.object 默认剥掉未知键,于是那一步照跑、只是丢了半个意图
|
|
105
|
+
// (真会话 proj_mtdr2xpa:两章的 chain:true 都这么没的,章节不接线程、
|
|
106
|
+
// 落到兜底位,正文列当场散架,用户看到的是"摆位乱了")。收下它们,在
|
|
107
|
+
// handler 里按子工具的 schema 归位,并如实报一句。
|
|
108
|
+
actions: z.array(z.looseObject({
|
|
96
109
|
name: z.string().describe(`Tool name: one of ${names.join(' | ')}.`),
|
|
97
|
-
input: z.record(z.string(), z.unknown()).optional().describe("That tool's input, same shape as calling it directly."),
|
|
110
|
+
input: z.record(z.string(), z.unknown()).optional().describe("That tool's input, same shape as calling it directly. Put the tool's OWN parameters in here — a parameter written beside `name` instead of inside `input` is folded in for you and reported."),
|
|
98
111
|
})).min(1).max(MAX_ITEMS)
|
|
99
112
|
.describe(`1-${MAX_ITEMS} items, run in order. Each item: {"name": <tool>, "input": {...}}.`),
|
|
100
|
-
|
|
101
|
-
|
|
113
|
+
// 没有 finalShot 就不放这个参数 —— 写一个永远无效的旋钮是在骗模型
|
|
114
|
+
...(finalShot ? { screenshotAfter: z.boolean().optional()
|
|
115
|
+
.describe(shotDefault
|
|
116
|
+
? 'Append a look at the resulting state at the end (default true). Set false for text-only sequences to save tokens.'
|
|
117
|
+
: 'Pass true to append a look at the resulting state at the end (default false — most board upkeep is text work; ask for eyes when looks matter).') } : {}),
|
|
102
118
|
},
|
|
103
119
|
async ({ actions, screenshotAfter }, extra) => {
|
|
104
120
|
const out = [];
|
|
105
121
|
const n = actions.length;
|
|
106
122
|
let failedAt = -1;
|
|
123
|
+
let failText = '';
|
|
107
124
|
let lastHadImage = false;
|
|
125
|
+
let shotLifted = false;
|
|
108
126
|
for (let i = 0; i < n; i += 1) {
|
|
109
|
-
const { name: toolName, input } = actions[i];
|
|
127
|
+
const { name: toolName, input, ...stray } = actions[i];
|
|
110
128
|
const label = `[${i + 1}/${n}] ${toolName}${input?.action ? ` ${input.action}` : ''}`;
|
|
111
129
|
if (failedAt >= 0) { out.push({ type: 'text', text: `${label}: ${HALT_TEXT}` }); continue; }
|
|
112
|
-
const def =
|
|
130
|
+
const def = lookup(toolName);
|
|
113
131
|
if (!def) {
|
|
114
132
|
failedAt = i;
|
|
115
|
-
|
|
133
|
+
failText = batchable.includes(toolName)
|
|
134
|
+
? `"${toolName}" 在这台机器/该项目模式下没有注册(能力或模式闸下架了它)——这一步换别的路。`
|
|
135
|
+
: `"${toolName}" is not batchable here (use one of ${names.join(', ')}).`;
|
|
136
|
+
out.push({ type: 'text', text: `${label}: Error: ${failText}` });
|
|
116
137
|
continue;
|
|
117
138
|
}
|
|
118
|
-
|
|
139
|
+
// 归位(08-29):action 这一层的多余键按子工具的 schema 收进 input;
|
|
140
|
+
// screenshotAfter 是 batch 自己的旋钮,抬到 batch 层。都如实报 —— 静默
|
|
141
|
+
// 修正会让下一次还写错,静默丢弃会让这一次就出错。
|
|
142
|
+
let folded = input || {};
|
|
143
|
+
const notes = [];
|
|
144
|
+
const own = new Set(Object.keys(def.inputSchema || {}));
|
|
145
|
+
const strayKeys = Object.keys(stray);
|
|
146
|
+
if (strayKeys.length) {
|
|
147
|
+
const patch = {};
|
|
148
|
+
for (const k of strayKeys) {
|
|
149
|
+
if (k === 'screenshotAfter') { shotLifted = shotLifted || stray[k] === true; notes.push('screenshotAfter 是整批的旋钮,已抬到 batch 层'); continue; }
|
|
150
|
+
if (own.has(k) && !(k in folded)) { patch[k] = stray[k]; continue; }
|
|
151
|
+
notes.push(`${k} 不是 ${toolName} 的参数,忽略了`);
|
|
152
|
+
}
|
|
153
|
+
if (Object.keys(patch).length) {
|
|
154
|
+
folded = { ...folded, ...patch };
|
|
155
|
+
notes.push(`${Object.keys(patch).join('/')} 本该写在 input 里(已收进去,下次直接写 input 内)`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// 双层信封(2026-08-30):{"input":{"input":{…},"op":"x"}} 真实发生过 ——
|
|
159
|
+
// 模型要拼两级嵌套,多包一层不出声。里层不是这个工具的参数、而里面的键是,
|
|
160
|
+
// 就摊平上来。
|
|
161
|
+
if (!own.has('input') && folded.input && typeof folded.input === 'object' && !Array.isArray(folded.input)) {
|
|
162
|
+
const inner = folded.input;
|
|
163
|
+
if (Object.keys(inner).some((k) => own.has(k))) {
|
|
164
|
+
const { input: _drop, ...rest } = folded;
|
|
165
|
+
folded = { ...inner, ...rest };
|
|
166
|
+
notes.push('input 里又套了一层 input,已摊平(下次一层就够)');
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// ⛔ input **内部**的未知键:z.object 静默 strip,不报错不留痕。08-29 那把
|
|
170
|
+
// looseObject 只盖住了写在 name 旁边的(action 这一层),差一层没盖到 ——
|
|
171
|
+
// 真会话里 write_on_board 收到过整份 `facts`(一长串剧情事实),一个字没落、
|
|
172
|
+
// 一句话没报。归不了位就点名,别静默丢。
|
|
173
|
+
const unknownIn = Object.keys(folded).filter((k) => !own.has(k));
|
|
174
|
+
if (unknownIn.length) {
|
|
175
|
+
notes.push(`⛔ ${unknownIn.join('/')} 不是 ${toolName} 的参数,这次**整个丢掉了**(内容没落盘)`
|
|
176
|
+
+ `—— ${toolName} 收的是:${[...own].join('/')}`);
|
|
177
|
+
}
|
|
178
|
+
const parsed = z.object(def.inputSchema).safeParse(folded);
|
|
119
179
|
if (!parsed.success) {
|
|
120
180
|
failedAt = i;
|
|
121
181
|
const why = parsed.error.issues.map(is => `${is.path.join('.') || '(root)'}: ${is.message}`).join('; ');
|
|
122
|
-
|
|
182
|
+
failText = `invalid input — ${why}`;
|
|
183
|
+
out.push({ type: 'text', text: `${label}: Error: ${failText}` });
|
|
123
184
|
continue;
|
|
124
185
|
}
|
|
125
186
|
let r;
|
|
@@ -131,14 +192,31 @@ export function makeBatchTool({ name, description, tools, batchable, finalShot }
|
|
|
131
192
|
// 第一块文本前面挂上 [i/n] 标签;没有文本块(纯图)就补一行标签再放图
|
|
132
193
|
if (!blocks.some(b => b.type === 'text')) out.push({ type: 'text', text: `${label}: done` });
|
|
133
194
|
let prefixed = false;
|
|
195
|
+
const tail = notes.length ? `\n⚠ ${notes.join(';')}` : '';
|
|
134
196
|
for (const b of blocks) {
|
|
135
|
-
if (b.type === 'text' && !prefixed) { out.push({ type: 'text', text: `${label}: ${b.text}` }); prefixed = true; }
|
|
197
|
+
if (b.type === 'text' && !prefixed) { out.push({ type: 'text', text: `${label}: ${b.text}${tail}` }); prefixed = true; }
|
|
136
198
|
else out.push(b);
|
|
137
199
|
}
|
|
138
|
-
if (
|
|
200
|
+
if (!prefixed && tail) out.push({ type: 'text', text: `${label}:${tail}` });
|
|
201
|
+
if (r?.isError) {
|
|
202
|
+
failedAt = i;
|
|
203
|
+
failText = blocks.find(b => b.type === 'text')?.text || '(no error text)';
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// 失败时把错误行提到最前面:下游(记账层截 120/500 字符、模型扫返回)都先看到
|
|
207
|
+
// 真正的报错,而不是前面成功步骤的输出。同时钉死"别整批重跑"——前面的步骤
|
|
208
|
+
// (click/type 这类非幂等动作)已经执行过了。
|
|
209
|
+
if (failedAt >= 0) {
|
|
210
|
+
const step = actions[failedAt];
|
|
211
|
+
out.unshift({
|
|
212
|
+
type: 'text',
|
|
213
|
+
text: `FAILED at step ${failedAt + 1}/${n} (${step.name}${step.input?.action ? ` ${step.input.action}` : ''}): ${String(failText).split('\n')[0]}\n`
|
|
214
|
+
+ `Steps 1-${failedAt} already ran — do NOT re-run the whole batch; continue from the failed step.`,
|
|
215
|
+
});
|
|
139
216
|
}
|
|
140
|
-
|
|
141
|
-
|
|
217
|
+
const wantShot = screenshotAfter === undefined ? (shotLifted || shotDefault) : screenshotAfter;
|
|
218
|
+
if (finalShot && wantShot && !lastHadImage) {
|
|
219
|
+
const shotDef = lookup(finalShot.name);
|
|
142
220
|
if (shotDef) {
|
|
143
221
|
try {
|
|
144
222
|
const s = await shotDef.handler(finalShot.input || {}, extra);
|
|
@@ -154,11 +232,12 @@ export function makeBatchTool({ name, description, tools, batchable, finalShot }
|
|
|
154
232
|
);
|
|
155
233
|
}
|
|
156
234
|
|
|
157
|
-
export function makeBrowserBatchTool({ tools }) {
|
|
235
|
+
export function makeBrowserBatchTool({ tools, resolve = null }) {
|
|
158
236
|
const names = BATCHABLE.filter(n => tools.some(t => t.name === n));
|
|
159
237
|
return makeBatchTool({
|
|
160
238
|
name: 'browser_batch',
|
|
161
239
|
tools,
|
|
240
|
+
resolve,
|
|
162
241
|
batchable: BATCHABLE,
|
|
163
242
|
finalShot: { name: 'browser_screenshot', input: {} },
|
|
164
243
|
description: `Run a sequence of browser tool calls in ONE round trip. Each item is
|