@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
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* engine/agent/subagent-flight.js —— 「这个会话还有后台角色在干活吗」(2026-08-28)
|
|
3
|
+
*
|
|
4
|
+
* ## 为什么需要这条路
|
|
5
|
+
*
|
|
6
|
+
* ws/index.js 的 grace 闸(07-27 建)只认 turn:用户关 tab / 切走后 turn 还在飞就
|
|
7
|
+
* 续命,等它干完再回收 SDK 进程。演员位范式造出了**第二种在飞工作** —— GM 的场务
|
|
8
|
+
* turn 几秒钟就结束,后台角色还要写好几分钟。闸不认识它,于是 08-28 泉此方场实录:
|
|
9
|
+
*
|
|
10
|
+
* 17:47:39 角色派出 → 17:48:17 GM turn 结束 → 17:49:29 grace 到期关会话
|
|
11
|
+
* → 角色被腰斩在第三个 Read 上,板上永远没有第二拍,日志里连个 warn 都没有。
|
|
12
|
+
*
|
|
13
|
+
* 从用户视角看就是「角色不写了」。这正是 07-27 那道闸要保住的东西("用户关 tab 时
|
|
14
|
+
* 后端应该把活干完"),只是当时在飞工作只有 turn 一种形态。
|
|
15
|
+
*
|
|
16
|
+
* ## 判据(2026-08-29 简化)
|
|
17
|
+
*
|
|
18
|
+
* **在飞 = SubagentStart 过且 SubagentStop 还没到**,就这一条。
|
|
19
|
+
*
|
|
20
|
+
* 08-29 之前它还要减掉「候场」——那时角色写完一段会挂在 await_user 上不收回合,
|
|
21
|
+
* 一个挂着的角色就能让会话永远关不掉(每个 SDK 进程 ~250MB 且 RSS 单调不减,
|
|
22
|
+
* 这台盒子 1vCPU/8G、swap=0)。新回路里角色写一段就结束这一轮,「永不收回合」这个
|
|
23
|
+
* 形态不存在了,减数也就跟着没了。
|
|
24
|
+
*
|
|
25
|
+
* 信号是 harness 在 spawn / 结束那一刻亲眼所见并盖的章,不是模型能写的东西。
|
|
26
|
+
*
|
|
27
|
+
* ## 生命周期
|
|
28
|
+
*
|
|
29
|
+
* 会话内存态,runSession 的 finally 里跟收件箱一起清。**这里不设时间上限** ——
|
|
30
|
+
* 兜底封顶在 ws/index.js 的续命次数上(一处判据一个真相源,别在两边各写一份)。
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { agentNameOf } from './actor-trail.js';
|
|
34
|
+
|
|
35
|
+
const flights = new Map(); // sessionId -> Map<agentId, { agentType, startedAt }>
|
|
36
|
+
|
|
37
|
+
/** 子代理起飞。agentId 来自 SubagentStart hook input,harness 盖的章 */
|
|
38
|
+
export function noteSubagentStart(sessionId, agentId, agentType = null) {
|
|
39
|
+
if (!sessionId || !agentId) return;
|
|
40
|
+
let m = flights.get(sessionId);
|
|
41
|
+
if (!m) { m = new Map(); flights.set(sessionId, m); }
|
|
42
|
+
m.set(agentId, { agentType, startedAt: Date.now() });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** 子代理落地 */
|
|
46
|
+
export function noteSubagentStop(sessionId, agentId) {
|
|
47
|
+
if (!sessionId || !agentId) return;
|
|
48
|
+
const m = flights.get(sessionId);
|
|
49
|
+
if (!m) return;
|
|
50
|
+
m.delete(agentId);
|
|
51
|
+
if (m.size === 0) flights.delete(sessionId);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 这个会话里还在飞的后台子代理。
|
|
56
|
+
*
|
|
57
|
+
* name 是实例名(角色)——翻不出来的(普通干活子代理)也照样算在飞,只是没名字。
|
|
58
|
+
*
|
|
59
|
+
* @param {string} sessionId
|
|
60
|
+
* @param {string|null} _projectId 旧签名的兼容位(候场判定退役后不再需要)
|
|
61
|
+
* @returns {Array<{ agentId, agentType, name, startedAt }>}
|
|
62
|
+
*/
|
|
63
|
+
export function workingSubagents(sessionId, _projectId = null) {
|
|
64
|
+
const m = flights.get(sessionId);
|
|
65
|
+
if (!m || m.size === 0) return [];
|
|
66
|
+
return [...m].map(([agentId, info]) => ({ agentId, name: agentNameOf(agentId), ...info }));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** 会话收摊 */
|
|
70
|
+
export function clearSessionFlights(sessionId) { flights.delete(sessionId); }
|
|
71
|
+
|
|
72
|
+
/** 测试用:清空全局态 */
|
|
73
|
+
export function _resetSubagentFlight() { flights.clear(); }
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import path from 'node:path';
|
|
15
15
|
import fs from 'node:fs';
|
|
16
16
|
import { fileURLToPath } from 'node:url';
|
|
17
|
+
import { DEFAULT_LOCALE } from '../../shared/locales.js';
|
|
17
18
|
|
|
18
19
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
19
20
|
|
|
@@ -40,6 +41,13 @@ const ADULT_POLICY = {
|
|
|
40
41
|
strict: '露骨的成人内容在这个账号档位下不写——涉及时收敛处理、用留白带过。',
|
|
41
42
|
};
|
|
42
43
|
|
|
44
|
+
// 界面语言的人话名(2026-08-26 i18n)。注给模型看的是「中文(zh-CN)」这种带 id 的写法:
|
|
45
|
+
// 光写「中文」模型不知道对应哪个 tag,光写 tag 又不如人话直白。
|
|
46
|
+
const UI_LOCALE_NAME = {
|
|
47
|
+
'zh-CN': '中文(zh-CN)',
|
|
48
|
+
en: 'English(en)',
|
|
49
|
+
};
|
|
50
|
+
|
|
43
51
|
/**
|
|
44
52
|
* 「底线」那一节在 prelude 里有**两份并排写着**的版本,标记块框起来:
|
|
45
53
|
* `nd:policy:full`(对外开放平台的完整产物政策)和 `nd:policy:min`。渲染时留一份、
|
|
@@ -51,6 +59,14 @@ const ADULT_POLICY = {
|
|
|
51
59
|
*/
|
|
52
60
|
const POLICY_BLOCK = /<!-- nd:policy:(full|min):start -->\n([\s\S]*?)<!-- nd:policy:\1:end -->\n/g;
|
|
53
61
|
|
|
62
|
+
/**
|
|
63
|
+
* 项目模式分区(2026-08-27):prelude 里设计道专属的节框在 `nd:mode:design` 块里,
|
|
64
|
+
* 演出(常驻角色)专属的节框在 `nd:mode:rp` 块里,渲染时按项目模式留一族、删一族。
|
|
65
|
+
* 没框的部分是共用骨架。同一个文件里可以有**多个**同名标记块(设计道的节不连续)。
|
|
66
|
+
* 为什么是标记块不是两份 md:见 POLICY_BLOCK 注释 —— 单一真相源 + 切错当场炸。
|
|
67
|
+
*/
|
|
68
|
+
const MODE_BLOCK = /<!-- nd:mode:(design|rp):start -->\n([\s\S]*?)<!-- nd:mode:\1:end -->\n/g;
|
|
69
|
+
|
|
54
70
|
// 加载期断言:两份都必须在。少一份说明有人编辑 prelude 时把标记删了,那时候
|
|
55
71
|
// 正则会静默退化成"一份都不删"(uncensored 路径拿到完整底线)或"整节消失"。
|
|
56
72
|
{
|
|
@@ -60,6 +76,23 @@ const POLICY_BLOCK = /<!-- nd:policy:(full|min):start -->\n([\s\S]*?)<!-- nd:pol
|
|
|
60
76
|
throw new Error(`[system-prompts] nodesign-prelude.md 缺少 nd:policy:${want} 标记块 —— 提示词渲染会静默走错版本`);
|
|
61
77
|
}
|
|
62
78
|
}
|
|
79
|
+
const modes = [...NODESIGN_PRELUDE.matchAll(MODE_BLOCK)].map((m) => m[1]);
|
|
80
|
+
for (const want of ['design', 'rp']) {
|
|
81
|
+
if (NODESIGN_PRELUDE && !modes.includes(want)) {
|
|
82
|
+
throw new Error(`[system-prompts] nodesign-prelude.md 缺少 nd:mode:${want} 标记块 —— 模式分区渲染会静默失效`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 占位符也要断言:`.replace('{{X}}', v)` 在占位符不存在时**静默什么都不做**,
|
|
88
|
+
// 于是线上会悄悄发出一份没有成人档、或者没有语言指令的提示词,不报错。
|
|
89
|
+
// 标记块那套已经这么防了,占位符这两个之前漏了(08-26 补)。
|
|
90
|
+
{
|
|
91
|
+
for (const ph of ['{{ADULT_POLICY}}', '{{UI_LOCALE}}']) {
|
|
92
|
+
if (NODESIGN_PRELUDE && !NODESIGN_PRELUDE.includes(ph)) {
|
|
93
|
+
throw new Error(`[system-prompts] nodesign-prelude.md 缺少 ${ph} 占位符 —— 渲染会静默少一段`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
63
96
|
}
|
|
64
97
|
|
|
65
98
|
/**
|
|
@@ -76,11 +109,19 @@ const POLICY_BLOCK = /<!-- nd:policy:(full|min):start -->\n([\s\S]*?)<!-- nd:pol
|
|
|
76
109
|
* 前提不成立。留下的一条不随档位变,也不随谁在用变。
|
|
77
110
|
*
|
|
78
111
|
* ⚠️ 默认 false。调用方拿不到模型名时落**完整**那份,绝不落 min。
|
|
112
|
+
*
|
|
113
|
+
* `mode`:项目模式(projects.mode)。'design'(默认)留设计道分区,'rp' 留
|
|
114
|
+
* 演出分区。认不出的值落 design —— 存量项目全是 design,猜错方向宁可多给不少给。
|
|
79
115
|
*/
|
|
80
116
|
export function renderPrelude(level = 'loose', opts = {}) {
|
|
81
117
|
const keep = opts.uncensored === true ? 'min' : 'full';
|
|
118
|
+
const keepMode = opts.mode === 'rp' ? 'rp' : 'design';
|
|
119
|
+
// 认不出的 locale 落中文:这个产品是中文优先的,拿不准时给中文不给英文。
|
|
120
|
+
const localeName = UI_LOCALE_NAME[opts.locale] || UI_LOCALE_NAME[DEFAULT_LOCALE];
|
|
82
121
|
return NODESIGN_PRELUDE
|
|
83
122
|
.replace(POLICY_BLOCK, (_all, which, body) => (which === keep ? body : ''))
|
|
123
|
+
.replace(MODE_BLOCK, (_all, which, body) => (which === keepMode ? body : ''))
|
|
84
124
|
.replace('{{ADULT_POLICY}}', ADULT_POLICY[level] || ADULT_POLICY.loose)
|
|
125
|
+
.replace('{{UI_LOCALE}}', localeName)
|
|
85
126
|
.trim();
|
|
86
127
|
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* server/engine/agent/tool-input-stream.js —— 真流式工具入参(2026-07-28 建,
|
|
3
|
+
* 2026-08-29 从 agent-shared.js 拆出:行数棘轮,胖了就拆别抬上限)
|
|
4
|
+
*
|
|
5
|
+
* input_json_delta 是半截 JSON 碎片。等拼完再发的话,模型逐 token 生成 new_string
|
|
6
|
+
* 的几十秒里前端只能干转圈。这里对点名的工具累积缓冲区,节流用 partial-json 容错
|
|
7
|
+
* 解析累积串,把目标字段相对上次的**纯文本增量**推给前端(run.delta.tool_input)。
|
|
8
|
+
*
|
|
9
|
+
* 转义符跨块断开由解析器兜住;字段单调增长,万一局部解析短暂回缩就跳过本拍
|
|
10
|
+
* (append 只在变长时发)。
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { Events } from './events.js';
|
|
14
|
+
import { toWorkspaceRel } from '../../lib/workspace-path.js';
|
|
15
|
+
import { parse as parsePartialJson, Allow as PartialAllow } from 'partial-json';
|
|
16
|
+
|
|
17
|
+
// ── 真流式工具入参(2026-07-28,工作台舞台层代码直播)──
|
|
18
|
+
// input_json_delta 是半截 JSON 碎片,等拼完再发一次的话,模型逐 token 生成
|
|
19
|
+
// new_string 的几十秒里前端只能干转圈。这里对写代码的工具累积缓冲区,节流用
|
|
20
|
+
// partial-json 容错解析累积串,把目标字段相对上次的纯文本增量推给前端
|
|
21
|
+
// (run.delta.tool_input)。转义符跨块断开由解析器兜住;字段单调增长,
|
|
22
|
+
// 万一局部解析短暂回缩就跳过本拍(append 只在变长时发)。
|
|
23
|
+
/**
|
|
24
|
+
* `spot`(2026-08-29 占位契约刀 C):跟 text 一起抽出来的**位置字段**。
|
|
25
|
+
*
|
|
26
|
+
* 在这之前流式板书的字画在"视口里一块空地"(BoardCanvas 的 liveChalkSpotFor),
|
|
27
|
+
* 跟 agent 给的 at 毫无关系 —— 写完淡出、真卡在真位置接棒,用户看到的是字从假
|
|
28
|
+
* 位置跳到真位置。站主要的是「先把位置选好,内容流到选定位置」。
|
|
29
|
+
*
|
|
30
|
+
* 时机不用另外等:判据跟 file_path 那套一样 —— **目标字段(text)的 key 一出现,
|
|
31
|
+
* 就说明排在它前面的字段都已闭合**(所以 write_on_board 的 schema 把 at/sheet/
|
|
32
|
+
* width 排到了 text 前面)。也就是说框在第一个字到达的那一刻立起来,正好。
|
|
33
|
+
*
|
|
34
|
+
* ⚠️ 不能只看 `at` 在不在:容错解析会把**没写完的数字**也交出来(`{"x": 123`
|
|
35
|
+
* 流到一半是 `{x:12}`,完全合法且看不出来),用它当坐标就是错的位置。
|
|
36
|
+
*/
|
|
37
|
+
export const TOOL_INPUT_STREAM_FIELDS = {
|
|
38
|
+
Edit: 'new_string',
|
|
39
|
+
Write: 'content',
|
|
40
|
+
// 板书直播(2026-08-25 流式路 A):write_on_board 的 text 逐 token 流到画布上
|
|
41
|
+
// 的舞台粉笔卡(StageLayer chalk 档)—— 粉笔字在用户眼前一行行长出来。
|
|
42
|
+
mcp__nodesign__write_on_board: { field: 'text', spot: ['slot', 'at', 'sheet', 'width', 'h', 'near', 'side', 'reply_to', 'chain'] },
|
|
43
|
+
// board_batch 批内嵌套(08-25 用户报「流式名存实亡」:skill 教的是一章一次
|
|
44
|
+
// batch,正文藏在 actions[].input.text 里,顶层字段抽取器抓不到 —— 等于亲手
|
|
45
|
+
// 教了大家绕开流式)。batch 档抽**最新一条** write_on_board 动作的 text,
|
|
46
|
+
// 换动作时发 reset 让前端另起一张。
|
|
47
|
+
mcp__nodesign__board_batch: { batch: 'write_on_board', field: 'text', spot: ['slot', 'at', 'sheet', 'width', 'h', 'near', 'side', 'reply_to', 'chain'] },
|
|
48
|
+
};
|
|
49
|
+
const TOOL_INPUT_THROTTLE_MS = 120;
|
|
50
|
+
|
|
51
|
+
export function toolInputStreams(ctx) {
|
|
52
|
+
if (!ctx._toolInputStreams) ctx._toolInputStreams = new Map();
|
|
53
|
+
return ctx._toolInputStreams;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
/** 批内嵌套抽取(纯函数好钉测试):最新一条 <tool> 动作的 <field> 字符串与它的序号 */
|
|
58
|
+
export function latestBatchField(obj, toolName, field) {
|
|
59
|
+
const actions = Array.isArray(obj?.actions) ? obj.actions : [];
|
|
60
|
+
for (let i = actions.length - 1; i >= 0; i -= 1) {
|
|
61
|
+
const a = actions[i];
|
|
62
|
+
const name = String(a?.name || '');
|
|
63
|
+
if ((name === toolName || name.endsWith(`__${toolName}`)) && typeof a?.input?.[field] === 'string') {
|
|
64
|
+
return { idx: i, text: a.input[field], input: a.input };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 位置字段抽取(占位契约刀 C)。只在**目标字段已经出现**时调用 —— 那时排在它
|
|
72
|
+
* 前面的位置字段都已闭合,数字不会是流到一半的半截值。
|
|
73
|
+
*
|
|
74
|
+
* ⚠️ 一个位置字段都没有时返回的是**空对象不是 null**(2026-08-29 刀 F):
|
|
75
|
+
* "什么都没点名" 本身就是一条位置信息 —— 那是**纸内顺排**,前端照服务端同一条
|
|
76
|
+
* 规则算得出落点。返回 null 的话这条事件根本不发,前端只能把字先写在视口一块
|
|
77
|
+
* 空地上、等落盘再跳过去(站主看到的"流式完毕之后再移动")。而顺排恰恰是最
|
|
78
|
+
* 常见的调用形态。
|
|
79
|
+
*
|
|
80
|
+
* @returns {object|null} null 只在入参根本不是对象时出现
|
|
81
|
+
*/
|
|
82
|
+
export function pickSpot(input, fields) {
|
|
83
|
+
if (!input || typeof input !== 'object') return null;
|
|
84
|
+
const out = {};
|
|
85
|
+
for (const k of fields) {
|
|
86
|
+
const v = input[k];
|
|
87
|
+
if (v === undefined || v === null) continue;
|
|
88
|
+
// at 是 {x,y}:两个坐标都得是有限数才算数(缺一个就是没写完)
|
|
89
|
+
if (k === 'at') {
|
|
90
|
+
if (typeof v === 'object' && Number.isFinite(v.x) && Number.isFinite(v.y)) {
|
|
91
|
+
out.at = { x: v.x, y: v.y };
|
|
92
|
+
}
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (typeof v === 'string' || Number.isFinite(v) || typeof v === 'boolean') out[k] = v;
|
|
96
|
+
}
|
|
97
|
+
return out;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function pumpToolInputStream(ctx, st, flush) {
|
|
101
|
+
const now = Date.now();
|
|
102
|
+
if (!flush && now - st.lastEmit < TOOL_INPUT_THROTTLE_MS) return;
|
|
103
|
+
let obj;
|
|
104
|
+
try { obj = parsePartialJson(st.buf, PartialAllow.ALL); } catch { return; }
|
|
105
|
+
if (!obj || typeof obj !== 'object') return;
|
|
106
|
+
let text = '';
|
|
107
|
+
let reset = false;
|
|
108
|
+
let host = obj; // 位置字段所在的对象(batch 档是那条动作的 input)
|
|
109
|
+
if (st.batch) {
|
|
110
|
+
const hit = latestBatchField(obj, st.batch, st.field);
|
|
111
|
+
if (hit) {
|
|
112
|
+
if (st.actionIdx !== hit.idx) { st.actionIdx = hit.idx; st.sent = 0; st.spotSent = false; reset = true; }
|
|
113
|
+
text = hit.text;
|
|
114
|
+
host = hit.input;
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
text = typeof obj[st.field] === 'string' ? obj[st.field] : '';
|
|
118
|
+
}
|
|
119
|
+
// 位置(刀 C):目标字段已出现 = 排在它前面的位置字段都闭合了,这一拍可以定框。
|
|
120
|
+
// 一条动作只发一次(batch 换动作时 spotSent 已随 reset 归位)。
|
|
121
|
+
const spot = (!st.spotSent && st.spot && host?.[st.field] !== undefined)
|
|
122
|
+
? { ...pickSpot(host, st.spot), ...(st.batch ? { batchIdx: st.actionIdx } : {}) } : null;
|
|
123
|
+
// 新纸预告(刀④ 2026-08-30):batch 的典型形状是 [open_sheet, write{slot}, …],
|
|
124
|
+
// 流式发生时**一个动作都没执行**、新纸还没登记 —— 前端只能退到「最新那张纸」
|
|
125
|
+
// (偏一整屏)或空地(叠一堆)。这里把「这条 write 排在一个 open_sheet 后面」
|
|
126
|
+
// 这件事随 spot 带出去,slot 的规划矩形也从流进来的 plan 里抠出来,
|
|
127
|
+
// 前端就能把框立在新纸将要出现的地方。
|
|
128
|
+
if (spot && st.batch && Array.isArray(obj.actions)) {
|
|
129
|
+
const opened = obj.actions.slice(0, st.actionIdx)
|
|
130
|
+
.filter((a) => typeof a?.name === 'string' && a.name.replace(/^mcp__\w+__/, '') === 'open_sheet')
|
|
131
|
+
.pop();
|
|
132
|
+
if (opened) {
|
|
133
|
+
spot.freshSheet = true;
|
|
134
|
+
const plan = Array.isArray(opened.input?.plan) ? opened.input.plan : [];
|
|
135
|
+
const sl = spot.slot ? plan.find((p) => p?.slot === spot.slot) : null;
|
|
136
|
+
if (sl && Number.isFinite(sl.at?.x) && Number.isFinite(sl.at?.y)
|
|
137
|
+
&& Number.isFinite(sl.w) && Number.isFinite(sl.h)) {
|
|
138
|
+
spot.planSlot = { x: sl.at.x, y: sl.at.y, w: sl.w, h: sl.h };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// file_path 只在确定流完后才取:容错解析会把半截字符串也带出来,第一拍常
|
|
143
|
+
// 截在路径中间(e2e 撞过:抽到项目目录名 → 前端物件寻址指错)。目标字段的
|
|
144
|
+
// key 出现(键序在 file_path 之后)或对象已有第二个键 = 路径已闭合。
|
|
145
|
+
const pathComplete = obj[st.field] !== undefined || Object.keys(obj).length >= 2;
|
|
146
|
+
// 发**工作区相对路径**(2026-08-13):前端拿它当画布物件 id 的路径部分,
|
|
147
|
+
// 而 id = 工作区相对路径。以前原样转发绝对路径,前端靠 `tasks/<任务>/`
|
|
148
|
+
// 这个特征段抠相对部分 —— 那一层拆掉后绝对路径里没有可锚定的标志了。
|
|
149
|
+
const rawFilePath = !st.filePathSent && pathComplete && typeof obj.file_path === 'string' ? obj.file_path : null;
|
|
150
|
+
const filePath = rawFilePath ? toWorkspaceRel(rawFilePath, ctx.workspace?.root?.()) : null;
|
|
151
|
+
const append = text.length > st.sent ? text.slice(st.sent) : '';
|
|
152
|
+
if (!append && !filePath && !spot && !flush && !reset) return;
|
|
153
|
+
st.lastEmit = now;
|
|
154
|
+
if (append) st.sent = text.length;
|
|
155
|
+
if (filePath) st.filePathSent = true;
|
|
156
|
+
if (spot) st.spotSent = true;
|
|
157
|
+
ctx.emit(Events.deltaToolInput(ctx.counters.turns, st.id, st.name, {
|
|
158
|
+
...(filePath ? { filePath } : {}),
|
|
159
|
+
...(spot ? { spot } : {}),
|
|
160
|
+
...(append ? { append } : {}),
|
|
161
|
+
...(reset ? { reset: true } : {}),
|
|
162
|
+
...(flush ? { done: true } : {}),
|
|
163
|
+
}));
|
|
164
|
+
}
|
|
165
|
+
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
- `Read` / `Glob` / `Grep` —— 看本地 `./assets/` 里的素材 / `./spec.json` 决策档案
|
|
45
45
|
- `TodoWrite` —— 3 步以上研究列计划
|
|
46
46
|
|
|
47
|
-
**工具集外的工具**(用了也无效,且打破子代理边界):Write / Edit / Bash / screenshot_canvas / export /
|
|
47
|
+
**工具集外的工具**(用了也无效,且打破子代理边界):Write / Edit / Bash / screenshot_canvas / export /
|
|
48
48
|
AskUserQuestion —— 你的产物是信息不是修改,跟用户对话由主 agent 负责。研究就是研究。
|
|
49
49
|
|
|
50
50
|
---
|
|
@@ -137,7 +137,7 @@ export function createAgents({ mainModel, sdkModel, fastModel } = {}) {
|
|
|
137
137
|
// - TodoWrite(多步研究列计划)
|
|
138
138
|
// 不给:Write/Edit(不写代码)/ Bash(不要 shell shenanigans)/
|
|
139
139
|
// AskUserQuestion(子代理不直接跟用户说话)/ screenshot/export/
|
|
140
|
-
//
|
|
140
|
+
// Task(不允许嵌套子代理)
|
|
141
141
|
// ⏸ explorer 研究员(2026-08-14 用户暂时停用:"有点没用")。定义与
|
|
142
142
|
// prompt(explorer.md)原样保留,恢复 = 取消注释 + prelude 补回子代理
|
|
143
143
|
// 清单那两行。停用期间搜索/读外链由主 agent 直接用 web_search / WebFetch。
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* engine/mcp/actor.js —— 板上写入的署名(2026-08-26)
|
|
3
|
+
*
|
|
4
|
+
* 板上每一样东西都带 `by`。在常驻角色之前它只有两个值('agent' / 'user'),
|
|
5
|
+
* 现在多了第三类:**具名角色**(叙事者、NPC),值是它的 slug(`rp-moli`)。
|
|
6
|
+
*
|
|
7
|
+
* 为什么署 slug 而不署展示名:slug 是 harness 在派发那一刻盖的章(见 actor-trail.js),
|
|
8
|
+
* 展示名住在角色文件里、而那个文件模型能改。署名要能当证据用,就不能取自被署名者
|
|
9
|
+
* 自己写的文本。展示名由读侧按 slug 查出来(role-card.js),查不到就显示 slug 本身。
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { callerOf, agentNameOf } from '../agent/actor-trail.js';
|
|
13
|
+
import { isResidentRole, isSlotType, safeRoleLabel } from '../agent/cast.js';
|
|
14
|
+
|
|
15
|
+
/** MCP handler 的 extra 里取本次 tool_use id(2026-08-26 实测就在这个键上) */
|
|
16
|
+
export function toolUseIdOf(extra) {
|
|
17
|
+
return extra?._meta?.['claudecode/toolUseId'] || null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 这次板上写入该署谁的名。
|
|
22
|
+
* @returns {'agent'|string} 主 agent → 'agent';常驻角色 → 它的 slug
|
|
23
|
+
*/
|
|
24
|
+
export function byOf(extra) {
|
|
25
|
+
const caller = callerOf(toolUseIdOf(extra));
|
|
26
|
+
const type = caller?.agentType;
|
|
27
|
+
// 落到**演员位**(rp-actor/rp-narrator)说明盖章那一刻别名还没学到实例名。
|
|
28
|
+
// 这里**当场再解一次** —— 别名可能在盖章之后才学到(08-28 真会话实录:
|
|
29
|
+
// 19:59 派发、20:10 角色调 jot_memory 被拒、20:10 GM 一发 SendMessage 别名补上、
|
|
30
|
+
// 20:21 同一个工具就成了。差的就是"用盖章那一刻的快照"还是"用此刻的表")。
|
|
31
|
+
if (isSlotType(type)) {
|
|
32
|
+
const nm = agentNameOf(caller?.agentId);
|
|
33
|
+
if (isResidentRole(nm) && !isSlotType(nm)) return nm;
|
|
34
|
+
}
|
|
35
|
+
return isResidentRole(type) ? type : 'agent';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 把一个 `by` 渲染成给**这个读者**看的称呼。
|
|
40
|
+
*
|
|
41
|
+
* read_board 的输出可能被主 agent 读,也可能被角色自己读 —— 同一句「你写的」对两个
|
|
42
|
+
* 读者含义相反。所以渲染要带视角:谁在读,就管谁叫「你」。
|
|
43
|
+
*
|
|
44
|
+
* @param by 板上那条东西的署名('user' / 'agent' / 'rp-*')
|
|
45
|
+
* @param viewer 当前读者(同上取值)
|
|
46
|
+
* @param names slug → 展示名(只当展示层,见 role-card.listRoleNames)
|
|
47
|
+
*/
|
|
48
|
+
export function describeBy(by, viewer, names) {
|
|
49
|
+
if (by === viewer) return '你';
|
|
50
|
+
if (by === 'user') return '用户';
|
|
51
|
+
if (by === 'agent') return '主控';
|
|
52
|
+
return safeRoleLabel(by, names?.get?.(by));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 保留字的第二道防线。真正的闸在源头(`listRoleNames` 出口,见 cast.js
|
|
57
|
+
* `safeRoleLabel` 的注释);这里留一层是给「名字没经过那条路」的调用点兜底。
|
|
58
|
+
*/
|
|
59
|
+
export { safeRoleLabel as roleLabel } from '../agent/cast.js';
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* engine/mcp/capability-gate.js — 工具 × 本机能力位(runtime/capabilities.js)的唯一对照表 + 闸。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* -
|
|
4
|
+
* 三种模式:
|
|
5
|
+
* - unregister:能力缺席时**整件工具不注册**(连名字都不进模型上下文)。给那种
|
|
6
|
+
* 「缺了就完全没有替代路径、而且短期内不会回来」的工具用——站主的本地
|
|
7
|
+
* GPU 盒子平时不开机,留着名字只会让 agent 反复去撞 SSH 拒连(08-24
|
|
8
|
+
* 信箱实证:paint_still 连撞两次,一次超时一次参数被拒才放弃)。
|
|
9
|
+
* - block:能力缺席时工具描述前缀「⛔ CURRENTLY UNAVAILABLE + 装法」,
|
|
6
10
|
* 真调了也在这里拦住,返回同一句话让它转告用户——不让裸的 ENOENT / 500 漏到 agent 面前
|
|
7
11
|
* - note :工具仍可用,只在描述末尾加一句降级说明(build_docx 没有 LibreOffice 时仍能出文件,只是没页图)
|
|
8
12
|
* 没探过(capabilityState 为 null:单测 / 脚本直接 import)→ 原样放行,这层不猜。
|
|
@@ -26,17 +30,32 @@ export const TOOL_CAPABILITIES = Object.freeze({
|
|
|
26
30
|
web_search: { cap: 'webSearch', mode: 'block' },
|
|
27
31
|
generate_image: { cap: 'imageGen', mode: 'block' },
|
|
28
32
|
publish_site: { cap: 'publish', mode: 'block' },
|
|
33
|
+
// 站主自己的 5090 盒子(NODESIGN_LOCAL_BOX + NODESIGN_H3BOX_SSH)。盒子是手动
|
|
34
|
+
// 开关的,平时关着,所以用 unregister:不在线时连工具名都不给 agent 看见。
|
|
35
|
+
// 通用生图仍有 generate_image 顶着,不存在能力真空。
|
|
36
|
+
paint_still: { cap: 'localBox', mode: 'unregister' },
|
|
37
|
+
roll_film: { cap: 'localBox', mode: 'unregister' },
|
|
29
38
|
});
|
|
30
39
|
|
|
31
40
|
export function unavailableMessage(c) {
|
|
32
41
|
return `本机缺 ${c.label}(${c.detail})。装法:${c.fix}`;
|
|
33
42
|
}
|
|
34
43
|
|
|
44
|
+
/** 这件工具在当前能力状态下该不该注册(false = 连名字都不给) */
|
|
45
|
+
export function shouldRegisterTool(toolDef) {
|
|
46
|
+
const spec = TOOL_CAPABILITIES[toolDef.name];
|
|
47
|
+
if (!spec || spec.mode !== 'unregister') return true;
|
|
48
|
+
const c = capabilityState(spec.cap);
|
|
49
|
+
// 没探过(单测 / 脚本直接 import)一律注册 —— 这层不猜,跟 withCapabilityGate 同纪律
|
|
50
|
+
return !c || c.available;
|
|
51
|
+
}
|
|
52
|
+
|
|
35
53
|
export function withCapabilityGate(toolDef) {
|
|
36
54
|
const spec = TOOL_CAPABILITIES[toolDef.name];
|
|
37
55
|
if (!spec) return toolDef;
|
|
38
56
|
const c = capabilityState(spec.cap);
|
|
39
57
|
if (!c || c.available) return toolDef;
|
|
58
|
+
// unregister 档走 shouldRegisterTool,走到这里说明调用方没过滤 —— 按 block 兜底
|
|
40
59
|
const msg = unavailableMessage(c);
|
|
41
60
|
if (spec.mode === 'note') {
|
|
42
61
|
return { ...toolDef, description: `${toolDef.description}\n\n⚠️ ${msg} 本工具仍可用,但依赖它的步骤(页图/体检)会缺席。` };
|