@xiaobuyu/nodesign 0.0.1 → 0.0.3
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 +156 -106
- package/bin/nodesign.js +0 -0
- package/package.json +1 -1
- package/server/api/README.md +45 -45
- package/server/api/_guard.js +75 -75
- package/server/api/admin.js +187 -187
- package/server/api/assets/docx-page.js +103 -103
- package/server/api/assets/helpers.js +42 -22
- package/server/api/assets/notes.js +194 -144
- package/server/api/assets.js +891 -896
- package/server/api/board.js +134 -57
- package/server/api/browse.js +138 -138
- package/server/api/canvas.js +444 -444
- package/server/api/chatai.js +324 -324
- package/server/api/exports/build-standalone.js +980 -980
- package/server/api/exports/cards.js +118 -118
- package/server/api/exports/docx-pdf.js +46 -46
- package/server/api/exports/export-page.js +142 -142
- package/server/api/exports/handoff.js +147 -147
- package/server/api/exports.js +690 -690
- package/server/api/instruction.js +75 -75
- package/server/api/me.js +116 -116
- package/server/api/memory.js +185 -185
- package/server/api/pending-changes.js +366 -366
- package/server/api/plugins.js +164 -164
- package/server/api/projects.js +220 -220
- package/server/api/publish.js +64 -64
- package/server/api/recent.js +73 -73
- package/server/api/sessions.js +589 -589
- package/server/api/skills.js +77 -77
- package/server/api/standalone-fit.js +168 -168
- package/server/api/turn-compose.js +180 -180
- package/server/api/turn-inflight.js +44 -44
- package/server/auth/README.md +17 -17
- package/server/auth/middleware.js +138 -138
- package/server/auth/origin-guard.js +71 -71
- package/server/auth/session.js +108 -108
- package/server/auth/tier.js +113 -113
- package/server/auth/users-store.js +348 -348
- package/server/edit/README.md +29 -29
- package/server/engine/README.md +113 -113
- package/server/engine/agent/agent-shared.js +550 -550
- package/server/engine/agent/auto-mode-default-hard-deny.txt +4 -4
- package/server/engine/agent/auto-mode-rules.js +78 -78
- package/server/engine/agent/context.js +418 -418
- package/server/engine/agent/events.js +465 -464
- package/server/engine/agent/hooks/canvas-validate.js +199 -199
- package/server/engine/agent/hooks/failure.js +120 -120
- package/server/engine/agent/hooks/file-events.js +75 -75
- package/server/engine/agent/hooks/lifecycle.js +233 -233
- package/server/engine/agent/hooks/post-canvas-focus.js +80 -80
- package/server/engine/agent/hooks/post-guidance.js +206 -206
- package/server/engine/agent/hooks/post-subagent-report.js +104 -104
- package/server/engine/agent/hooks/post-trim.js +58 -58
- package/server/engine/agent/hooks/pre-board-neighborhood.js +34 -34
- package/server/engine/agent/hooks/pre-defaults.js +84 -84
- package/server/engine/agent/hooks/pre-injectors.js +277 -277
- package/server/engine/agent/hooks/pre-performance-log-guard.js +78 -78
- package/server/engine/agent/hooks/pre-starter-files.js +61 -61
- package/server/engine/agent/hooks/pre-workspace-scope-guard.js +78 -78
- package/server/engine/agent/hooks/site-validate.js +94 -94
- package/server/engine/agent/hooks/tool-prompts.js +31 -31
- package/server/engine/agent/hooks/turn-state-memory.js +56 -56
- package/server/engine/agent/hooks/user-prompt-submit.js +258 -215
- package/server/engine/agent/hooks.js +354 -354
- package/server/engine/agent/init-contract.js +69 -69
- package/server/engine/agent/isolation.js +159 -159
- package/server/engine/agent/model-table.js +292 -292
- package/server/engine/agent/plugin-loader.js +266 -266
- package/server/engine/agent/prompts/nodesign-prelude.md +388 -336
- package/server/engine/agent/prompts/tools/ask-user-question-protocol.md +71 -71
- package/server/engine/agent/prompts/tools/direct-edit-protocol.md +98 -98
- package/server/engine/agent/prompts/tools/generate-image-cookbook.gemini-gateway.md +583 -583
- package/server/engine/agent/prompts/tools/generate-image-cookbook.md +483 -483
- package/server/engine/agent/prompts/tools/hybrid-reference.md +100 -100
- package/server/engine/agent/prompts/tools/paint-still-cookbook.md +270 -270
- package/server/engine/agent/prompts/tools/roll-film-cookbook.md +70 -70
- package/server/engine/agent/prompts/tools/site-reference.md +106 -106
- package/server/engine/agent/prompts/tools/tweaks-syntax.md +125 -125
- package/server/engine/agent/prompts/tools/vision-checker-dispatch.md +48 -48
- package/server/engine/agent/session-loop.js +1035 -1024
- package/server/engine/agent/session-model.js +164 -164
- package/server/engine/agent/skill.js +204 -204
- package/server/engine/agent/task-events.js +78 -78
- package/server/engine/agents/ds-extractor.md +132 -132
- package/server/engine/agents/explorer.md +190 -190
- package/server/engine/agents/index.js +230 -230
- package/server/engine/agents/schemas/design-system.json +156 -156
- package/server/engine/agents/schemas/tweak-schema.json +113 -113
- package/server/engine/agents/tweak-proposer.md +127 -127
- package/server/engine/agents/vision-checker.md +254 -254
- package/server/engine/browse/capture.js +422 -422
- package/server/engine/browse/card.js +137 -137
- package/server/engine/browse/handover.js +59 -59
- package/server/engine/browse/page-digest.js +119 -119
- package/server/engine/browse/refs.js +196 -196
- package/server/engine/browse/registry.js +307 -307
- package/server/engine/browse/screencast.js +170 -170
- package/server/engine/browse/state.js +121 -121
- package/server/engine/chatai/chat-log.js +79 -79
- package/server/engine/chatai/index.js +193 -193
- package/server/engine/chatai/openai-compat.js +152 -152
- package/server/engine/chatai/orchestrate.js +309 -309
- package/server/engine/chatai/perform.js +40 -40
- package/server/engine/chatai/summarize.js +79 -79
- package/server/engine/mcp/capability-gate.js +52 -52
- package/server/engine/mcp/index.js +351 -339
- package/server/engine/mcp/param-sanitizer.js +142 -142
- package/server/engine/mcp/tools/arrange-on-board.js +124 -124
- package/server/engine/mcp/tools/artifact-session.js +278 -278
- package/server/engine/mcp/tools/browse-computer.js +421 -421
- package/server/engine/mcp/tools/browse-find-batch.js +183 -183
- package/server/engine/mcp/tools/browse-screenshot.js +157 -157
- package/server/engine/mcp/tools/browse.js +480 -480
- package/server/engine/mcp/tools/build-docx.js +101 -101
- package/server/engine/mcp/tools/clear-pending-changes.js +99 -99
- package/server/engine/mcp/tools/create-on-board.js +152 -155
- package/server/engine/mcp/tools/crystallize-skill.js +168 -168
- package/server/engine/mcp/tools/edit-sketch.js +167 -0
- package/server/engine/mcp/tools/explain-style.js +237 -237
- package/server/engine/mcp/tools/export-handoff.js +133 -133
- package/server/engine/mcp/tools/expose-tweaks.js +149 -149
- package/server/engine/mcp/tools/generate-image.js +842 -842
- package/server/engine/mcp/tools/get-computed-styles.js +164 -164
- package/server/engine/mcp/tools/get-pending-changes.js +205 -205
- package/server/engine/mcp/tools/h3box-ssh.js +84 -84
- package/server/engine/mcp/tools/helpers/acquire-page.js +82 -82
- package/server/engine/mcp/tools/helpers/motion-lab.js +554 -554
- package/server/engine/mcp/tools/helpers/motion-scroll.js +112 -112
- package/server/engine/mcp/tools/helpers/perception-page.js +215 -215
- package/server/engine/mcp/tools/helpers/reference-download.js +103 -103
- package/server/engine/mcp/tools/helpers/rembg-bridge.py +80 -80
- package/server/engine/mcp/tools/helpers/shot-pipeline.js +280 -280
- package/server/engine/mcp/tools/highlight.js +68 -68
- package/server/engine/mcp/tools/list-pages.js +222 -222
- package/server/engine/mcp/tools/look-at-board.js +124 -0
- package/server/engine/mcp/tools/lookup-tags.js +59 -59
- package/server/engine/mcp/tools/navigate-to-page.js +60 -60
- package/server/engine/mcp/tools/organize-board.js +64 -64
- package/server/engine/mcp/tools/paint-still.js +434 -434
- package/server/engine/mcp/tools/pin-to-board.js +130 -130
- package/server/engine/mcp/tools/preview-deck.js +130 -130
- package/server/engine/mcp/tools/profile-scroll.js +305 -305
- package/server/engine/mcp/tools/publish-site.js +102 -102
- package/server/engine/mcp/tools/query-elements.js +195 -195
- package/server/engine/mcp/tools/read-board.js +190 -103
- package/server/engine/mcp/tools/read-document.js +93 -93
- package/server/engine/mcp/tools/read-page.js +264 -264
- package/server/engine/mcp/tools/read-tavern-json.js +143 -143
- package/server/engine/mcp/tools/read-user-view.js +59 -0
- package/server/engine/mcp/tools/record-decision.js +140 -140
- package/server/engine/mcp/tools/relate-on-board.js +112 -110
- package/server/engine/mcp/tools/report-issue.js +115 -115
- package/server/engine/mcp/tools/roll-film.js +266 -266
- package/server/engine/mcp/tools/screenshot-docx.js +138 -138
- package/server/engine/mcp/tools/screenshot-url.js +195 -195
- package/server/engine/mcp/tools/screenshot.js +583 -583
- package/server/engine/mcp/tools/sketch-on-board.js +337 -0
- package/server/engine/mcp/tools/tier-gate.js +96 -96
- package/server/engine/mcp/tools/trace-motion.js +215 -215
- package/server/engine/mcp/tools/web-search.js +548 -548
- package/server/engine/mcp/tools/write-on-board.js +130 -0
- package/server/engine/motion/inventory.js +349 -349
- package/server/engine/perception/session.js +235 -235
- package/server/engine/plugins/nodesign/.claude-plugin/plugin.json +5 -5
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/SKILL.md +199 -192
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/canvas.template.html +667 -667
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/hybrid-grid.md +22 -22
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/image-led-cover.md +25 -25
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/portrait.md +23 -23
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/quote-backdrop.md +21 -21
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/section-divider.md +23 -23
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/text-led.md +21 -21
- package/server/engine/plugins/nodesign/skills/docx-craft/SKILL.md +169 -162
- package/server/engine/plugins/nodesign/skills/docx-craft/references/token-schema.md +407 -407
- package/server/engine/plugins/nodesign/skills/docx-craft//346/226/207/346/241/243.template.json +80 -80
- package/server/engine/plugins/nodesign/skills/rp-craft/SKILL.md +235 -228
- 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 +78 -78
- package/server/engine/plugins/nodesign/skills/rp-craft//346/274/224/345/207/272.template.js +268 -268
- package/server/engine/plugins/nodesign/skills/site-craft/SKILL.md +330 -323
- package/server/engine/plugins/nodesign/skills/site-craft/patterns/build-lane.md +134 -134
- package/server/engine/plugins/nodesign/skills/site-craft/patterns/cutout-collage.md +61 -61
- package/server/engine/plugins/nodesign/skills/site-craft/patterns/mock-app.md +163 -163
- package/server/engine/plugins/nodesign/skills/site-craft/patterns/page-transitions.md +86 -86
- package/server/engine/runs/active-runs.js +698 -698
- package/server/engine/runs/board-tasklist.js +130 -0
- package/server/engine/runs/live-turn.js +252 -252
- package/server/engine/runs/store.js +364 -364
- package/server/engine/runs/turn-relay.js +217 -217
- package/server/engine/runtime/workspace.js +164 -164
- package/server/index.js +3 -0
- package/server/lib/artifact-file-path.js +80 -80
- package/server/lib/artifact-target.js +284 -284
- package/server/lib/asset-refs.js +239 -239
- package/server/lib/async-queue.js +104 -104
- package/server/lib/auto-relations.js +130 -130
- package/server/lib/binding-types.js +72 -60
- package/server/lib/board-graph-export.js +191 -0
- package/server/lib/board-groups.js +167 -0
- package/server/lib/board-hero.js +76 -0
- package/server/lib/board-kind-sizes.js +85 -62
- package/server/lib/board-relations.js +133 -133
- package/server/lib/browse-proxy.js +180 -180
- package/server/lib/canvas-id.js +36 -36
- package/server/lib/chalk.js +121 -0
- package/server/lib/cover.js +227 -227
- package/server/lib/danbooru-tags.js +291 -291
- package/server/lib/doc-extract.js +156 -156
- package/server/lib/docx/build-from-source.js +260 -260
- package/server/lib/docx/build.js +490 -490
- package/server/lib/docx/dump-styles.js +287 -287
- package/server/lib/docx/fonts/nodesign-cjk.conf +164 -164
- package/server/lib/docx/merge-runs.js +129 -129
- package/server/lib/docx/numbering.js +218 -218
- package/server/lib/docx/order.js +152 -152
- package/server/lib/docx/rawzip.js +172 -172
- package/server/lib/docx/render.js +92 -92
- package/server/lib/docx/text-lint.js +225 -225
- package/server/lib/docx/tokens.js +335 -335
- package/server/lib/docx/units.js +29 -29
- package/server/lib/docx/xml.js +291 -291
- package/server/lib/docx-pages.js +187 -187
- package/server/lib/export-collect.js +289 -289
- package/server/lib/export-package.js +210 -210
- package/server/lib/html-srcset.js +145 -145
- package/server/lib/image-variant.js +460 -460
- package/server/lib/ingress/forward-openai-chat.js +305 -305
- package/server/lib/ingress/openai-chat.js +491 -491
- package/server/lib/ingress/session-notice.js +66 -66
- package/server/lib/ingress/session-routes.js +68 -68
- package/server/lib/ingress/slot-probe.js +130 -130
- package/server/lib/ingress/upstream-billing.js +52 -52
- package/server/lib/ingress/upstream-fail-streak.js +72 -72
- package/server/lib/ingress/upstream-truncation.js +48 -48
- package/server/lib/issues-store.js +182 -182
- package/server/lib/kinds/deck.js +72 -72
- package/server/lib/kinds/docx.js +283 -283
- package/server/lib/kinds/file-kinds.js +113 -113
- package/server/lib/kinds/index.js +202 -202
- package/server/lib/kinds/site.js +161 -161
- package/server/lib/model-ingress.js +543 -543
- package/server/lib/moderation.js +255 -255
- package/server/lib/notice-store.js +103 -103
- package/server/lib/plugin-install.js +104 -104
- package/server/lib/plugin-validator.js +721 -721
- package/server/lib/publish-store.js +115 -115
- package/server/lib/quick-summary.js +52 -52
- package/server/lib/quota.js +270 -270
- package/server/lib/rate-window.js +29 -29
- package/server/lib/reference-assets.js +92 -92
- package/server/lib/region-shot.js +135 -135
- package/server/lib/safe-path.js +73 -73
- package/server/lib/sdk-session.js +33 -33
- package/server/lib/showcase-store.js +92 -92
- package/server/lib/site-publish.js +465 -465
- package/server/lib/sketch-layout.js +277 -0
- package/server/lib/ssrf-guard.js +432 -432
- package/server/lib/task-scan.js +158 -158
- package/server/lib/tavern-json.js +154 -154
- package/server/lib/video-variant.js +237 -237
- package/server/lib/workspace-path.js +33 -33
- package/server/ops/fix-sdk-musl.mjs +40 -40
- package/server/ops/install-macos-fonts.sh +114 -114
- package/server/ops/macos-fonts.conf +336 -336
- package/server/ops/sandbox-shim/bwrap +57 -57
- package/server/projects/assets-summary.js +119 -119
- package/server/projects/auto-name.js +53 -53
- package/server/projects/board-limits.js +12 -0
- package/server/projects/board-sanitize.js +252 -0
- package/server/projects/board-store.js +507 -640
- package/server/projects/move-entry.js +103 -103
- package/server/projects/store.js +270 -270
- package/server/projects/ui-config.js +60 -54
- package/server/projects/viewpoint-store.js +78 -0
- package/server/projects/workspace-templates.js +53 -53
- package/server/projects/workspace.js +1025 -1025
- package/server/runtime/local-config.js +177 -177
- package/server/runtime/profile.js +72 -72
- package/server/services/rembg-service.py +334 -334
- package/server/shared/README.md +25 -25
- package/server/shared/deck.js +54 -54
- package/server/shared/time.js +49 -49
- package/server/style-pipeline/README.md +53 -53
- package/server/ws/broker.js +39 -36
- package/server/ws/browse-channel.js +177 -177
- package/server/ws/index.js +386 -386
- package/web/README.md +89 -89
- package/web/dist/assets/BrowserWindow-P_vIdh-G.js +11 -0
- package/web/dist/assets/{DeckWindow-4G0xX7P3.js → DeckWindow-BpLv5082.js} +3 -3
- package/web/dist/assets/{DocxWindow-BXQsoPkh.js → DocxWindow-DSAU1-tD.js} +4 -4
- package/web/dist/assets/MermaidBlock-DR1GikCv.js +313 -0
- package/web/dist/assets/SiteWindow-92uBuRRR.js +18 -0
- package/web/dist/assets/abnfDiagram-VCTEODGH-uA8Esix4.js +1 -0
- package/web/dist/assets/arc-D_khH_xN.js +1 -0
- package/web/dist/assets/architectureDiagram-5GKGNRK7-DydJHqOt.js +36 -0
- package/web/dist/assets/blockDiagram-NRAW4CY4-B7wBbKiW.js +129 -0
- package/web/dist/assets/c4Diagram-UCG6FXSJ-6mrH0x7Y.js +38 -0
- package/web/dist/assets/channel-DGkccMO1.js +1 -0
- package/web/dist/assets/chunk-2Q5K7J3B-Cuikho5Q.js +1 -0
- package/web/dist/assets/chunk-5VM5RSS4-3-KZ5AUz.js +15 -0
- package/web/dist/assets/chunk-F27PBJKO-Bkwq2gGU.js +1 -0
- package/web/dist/assets/chunk-G27WJ6UU-BLyQzdGE.js +231 -0
- package/web/dist/assets/chunk-JWPE2WC7-B7HxxQds.js +1 -0
- package/web/dist/assets/chunk-LCL6LL3I-CtXrnUwF.js +206 -0
- package/web/dist/assets/chunk-POPQ4Y6H-dxddZlXt.js +1 -0
- package/web/dist/assets/chunk-SVP7TREG-DpkmrgHn.js +88 -0
- package/web/dist/assets/chunk-XXDRQBXY-BwZ7RbpQ.js +1 -0
- package/web/dist/assets/classDiagram-DTDB5LWJ-BGscw3OD.js +1 -0
- package/web/dist/assets/classDiagram-v2-JRS7N3AN-BGscw3OD.js +1 -0
- package/web/dist/assets/cose-bilkent-JH36ORCC-DGFOsMUt.js +1 -0
- package/web/dist/assets/cynefin-OW5HDTMX-DUwn3ehS.js +178 -0
- package/web/dist/assets/cynefinDiagram-5FMLGOSQ-DlLAOZ9x.js +62 -0
- package/web/dist/assets/cytoscape.esm-BjAbmLdb.js +331 -0
- package/web/dist/assets/dagre-3AP2YEHR-CyourLfz.js +4 -0
- package/web/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/web/dist/assets/diagram-S7CK7UJ4-BTMbx2np.js +30 -0
- package/web/dist/assets/diagram-UQ7AKVKN-UK94_1-P.js +41 -0
- package/web/dist/assets/diagram-VSXAHHWV-C7zS-v9v.js +3 -0
- package/web/dist/assets/diagram-VX7I27RA-DKJRa6CK.js +24 -0
- package/web/dist/assets/diagram-Z3DM3KII-kUbAfGAp.js +24 -0
- package/web/dist/assets/ebnfDiagram-PWID7BFC-CVW16_vb.js +1 -0
- package/web/dist/assets/erDiagram-SSCWMZ5O-BRQMFQ5y.js +99 -0
- package/web/dist/assets/flowDiagram-A5DVABFB-S34LpLtK.js +168 -0
- package/web/dist/assets/ganttDiagram-EL5Y4UJY-BFiqk1-G.js +292 -0
- package/web/dist/assets/gitGraphDiagram-WWUBYQGX-LZsrdyyv.js +106 -0
- package/web/dist/assets/index-GAamh1p4.js +2152 -0
- package/web/dist/assets/infoDiagram-RXCK75RN-0DvN6KIp.js +2 -0
- package/web/dist/assets/init-Gi6I4Gst.js +1 -0
- package/web/dist/assets/ishikawaDiagram-5VMMS53U-CaY3A-Bx.js +70 -0
- package/web/dist/assets/journeyDiagram-EYS64GPL-BBeiaCrj.js +139 -0
- package/web/dist/assets/kanban-definition-3QL26DDD-ux42DRXQ.js +89 -0
- package/web/dist/assets/layout-CnXiF_NB.js +1 -0
- package/web/dist/assets/linear-BMW0u6G6.js +1 -0
- package/web/dist/assets/mindmap-definition-FBJOCRG2-hUxSpdKn.js +96 -0
- package/web/dist/assets/ordinal-Cboi1Yqb.js +1 -0
- package/web/dist/assets/pegDiagram-XKGWAZYB-aCaQPH0w.js +1 -0
- package/web/dist/assets/{pending-edit-apply-DTjo2geW.js → pending-edit-apply-AcdOQ9Ij.js} +6 -6
- package/web/dist/assets/pieDiagram-E7YTZNPT-CmOEZ8zg.js +39 -0
- package/web/dist/assets/quadrantDiagram-AXDQQJYC-VW6fAhsV.js +7 -0
- package/web/dist/assets/railroadDiagram-O6MQD6OU-CKJ7Ba5K.js +1 -0
- package/web/dist/assets/requirementDiagram-EFPCY7ZU-pNGkq9Vw.js +84 -0
- package/web/dist/assets/{rotate-cw-LMT3x1Zj.js → rotate-cw-KAfChbGV.js} +1 -1
- package/web/dist/assets/sankeyDiagram-P5KCCOFB-BIMmDTfZ.js +40 -0
- package/web/dist/assets/sequenceDiagram-WJ2MYXX4-BBW7wzKY.js +162 -0
- package/web/dist/assets/sizeCapture-X5ZJPWSS-DdkXmLYR.js +1 -0
- package/web/dist/assets/{square-dashed-mouse-pointer-CBoAkfhi.js → square-dashed-mouse-pointer-CDUlhUP7.js} +1 -1
- package/web/dist/assets/stateDiagram-HBIQ2CUA-W313Uz16.js +1 -0
- package/web/dist/assets/stateDiagram-v2-4QOOHH4V-DDhJBZzf.js +1 -0
- package/web/dist/assets/swimlanes-XN3QIQJK-C29TL26K.js +1 -0
- package/web/dist/assets/swimlanesDiagram-VK2B7HYN-BfN-Xdmu.js +8 -0
- package/web/dist/assets/timeline-definition-24CTP7MA-CF0JMObX.js +120 -0
- package/web/dist/assets/vennDiagram-4TSXK5OY-DrDFsaH3.js +34 -0
- package/web/dist/assets/wardleyDiagram-VM6X3IG4-CVrnRIS_.js +78 -0
- package/web/dist/assets/xychartDiagram-S5SC5T6Z-BvkN1zsT.js +7 -0
- package/web/dist/index.html +17 -17
- package/web/dist/assets/BrowserWindow-Dc7J7CYc.js +0 -11
- package/web/dist/assets/SiteWindow-D6eS-2gM.js +0 -18
- package/web/dist/assets/index-Cbl3ATvp.js +0 -2125
|
@@ -1,204 +1,204 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* skill.js — Skill 加载器(YAML frontmatter + Markdown body)
|
|
3
|
-
*
|
|
4
|
-
* 目录结构(2026-05-18 起,对齐 Claude Code plugin convention):
|
|
5
|
-
* server/engine/plugins/nodesign/
|
|
6
|
-
* .claude-plugin/plugin.json — plugin 元数据
|
|
7
|
-
* skills/<skill-id>/SKILL.md — 各 skill
|
|
8
|
-
* skills/<skill-id>/<其他起手文件>
|
|
9
|
-
*
|
|
10
|
-
* SKILL.md 格式(YAML frontmatter + body):
|
|
11
|
-
* ---
|
|
12
|
-
* name: deskskill-engine-mini
|
|
13
|
-
* version: 0.0.1
|
|
14
|
-
* description: 给 LLM 看的"什么时候用我"的描述
|
|
15
|
-
* ---
|
|
16
|
-
*
|
|
17
|
-
* # System Prompt
|
|
18
|
-
*
|
|
19
|
-
* 你是一个 deck 设计 agent...(任意 markdown)
|
|
20
|
-
*
|
|
21
|
-
* 本模块职责:
|
|
22
|
-
* - 解析 SKILL.md 的 YAML frontmatter + body(loadSkill)
|
|
23
|
-
* - 把 skill 起手文件(canvas.template.html 等)拷进 session cwd(ensureSkillStarterFiles)
|
|
24
|
-
*
|
|
25
|
-
* 注:批量扫 plugin 下所有 skill 走 plugin-loader.js `listInstalledPluginsDetailed`,
|
|
26
|
-
* 不在本模块(API 层 server/api/skills.js 用那个)。
|
|
27
|
-
*
|
|
28
|
-
* SDK 集成(在 session-loop.js):
|
|
29
|
-
* - plugins: [{ type: 'local', path: PLUGIN_ROOT }] → 让 SDK 识别本 plugin
|
|
30
|
-
* - skills: [<skill-id>] → 让 SDK 把 description 注入 system prompt
|
|
31
|
-
* - SKILL.md body 通过 SDK 内置 Skill 工具按需加载(不再走 systemPrompt.append 恒驻)
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
import { promises as fs } from 'fs';
|
|
35
|
-
import path from 'path';
|
|
36
|
-
import { fileURLToPath } from 'url';
|
|
37
|
-
|
|
38
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
39
|
-
|
|
40
|
-
/** Plugin 根目录(含 .claude-plugin/plugin.json + skills/)*/
|
|
41
|
-
export const PLUGIN_ROOT = path.resolve(
|
|
42
|
-
process.env.NODESIGN_PLUGIN_DIR || path.join(__dirname, '../plugins/nodesign')
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
/** Skills 子目录(plugin convention:<plugin>/skills/<skill-id>/SKILL.md)*/
|
|
46
|
-
export const SKILLS_ROOT = path.resolve(
|
|
47
|
-
process.env.NODESIGN_SKILLS_DIR || path.join(PLUGIN_ROOT, 'skills')
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 加载一个 skill。返回 { id, name, version, description, systemPrompt, raw }。
|
|
52
|
-
* 找不到时抛 Error(code='SKILL_NOT_FOUND')。
|
|
53
|
-
*/
|
|
54
|
-
export async function loadSkill(skillId) {
|
|
55
|
-
if (!skillId || typeof skillId !== 'string') {
|
|
56
|
-
throw Object.assign(new Error('loadSkill: skillId required'), { code: 'INVALID_SKILL_ID' });
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const skillDir = path.join(SKILLS_ROOT, skillId);
|
|
60
|
-
const skillFile = path.join(skillDir, 'SKILL.md');
|
|
61
|
-
|
|
62
|
-
let raw;
|
|
63
|
-
try {
|
|
64
|
-
raw = await fs.readFile(skillFile, 'utf8');
|
|
65
|
-
} catch (err) {
|
|
66
|
-
if (err.code === 'ENOENT') {
|
|
67
|
-
throw Object.assign(
|
|
68
|
-
new Error(`skill not found: ${skillId} (expected at ${skillFile})`),
|
|
69
|
-
{ code: 'SKILL_NOT_FOUND' }
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
throw err;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const { frontmatter, body } = parseFrontmatter(raw);
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
id: skillId,
|
|
79
|
-
name: frontmatter.name || skillId,
|
|
80
|
-
version: frontmatter.version || '0.0.0',
|
|
81
|
-
description: frontmatter.description || '',
|
|
82
|
-
systemPrompt: body.trim(),
|
|
83
|
-
frontmatter,
|
|
84
|
-
raw,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* 把 skill 自带的工作区起手文件(目前主要是 canvas.template.html)拷贝
|
|
90
|
-
* 进 session cwd,让 agent 能直接 `Read canvas.template.html` 而不必去
|
|
91
|
-
* 仓库相对路径找(agent 看不到 server/engine/plugins/nodesign/skills/)。
|
|
92
|
-
*
|
|
93
|
-
* **拷贝不软链**:
|
|
94
|
-
* - 跨平台稳(Windows symlink 要 admin / Linux bwrap 不解析 symlink)
|
|
95
|
-
* - 防 agent 误 Edit 改源模板(影响其他 session)
|
|
96
|
-
* - session 是一次性沙盒,拷贝快照语义合理
|
|
97
|
-
*
|
|
98
|
-
* **幂等**:文件已存在就不覆盖(agent 改过的、或上次 session init 拷过的不动)。
|
|
99
|
-
*
|
|
100
|
-
* **起手文件是自动发现的**(2026-07-28 从硬编码 `['canvas.template.html']` 改来):
|
|
101
|
-
* skill 目录里凡是文件名带 `.template.` 的都算起手文件。加第二个 skill
|
|
102
|
-
* (站点)时不必再回来改这里 —— 硬编码一个文件名意味着新 skill 的模板永远
|
|
103
|
-
* 拷不出来,而且是静默的:agent 只会 `Read` 失败然后凭空写。
|
|
104
|
-
*
|
|
105
|
-
* @param {string} sessionRoot - sessions/<sid>/ 绝对路径
|
|
106
|
-
* @param {string} skillId - 同 loadSkill 的 skillId
|
|
107
|
-
* @returns {Promise<{ copied: string[], skipped: string[] }>}
|
|
108
|
-
*/
|
|
109
|
-
/** 内置 plugin 里现有的 skill id(目录名即 id) */
|
|
110
|
-
export async function listSkillIds() {
|
|
111
|
-
try {
|
|
112
|
-
const entries = await fs.readdir(SKILLS_ROOT, { withFileTypes: true });
|
|
113
|
-
return entries.filter(e => e.isDirectory() && !e.name.startsWith('.')).map(e => e.name);
|
|
114
|
-
} catch { return []; }
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export async function listSkillStarterFiles(skillId) {
|
|
118
|
-
if (!skillId) return [];
|
|
119
|
-
try {
|
|
120
|
-
const entries = await fs.readdir(path.join(SKILLS_ROOT, skillId), { withFileTypes: true });
|
|
121
|
-
return entries
|
|
122
|
-
.filter(e => e.isFile() && e.name.includes('.template.'))
|
|
123
|
-
.map(e => e.name)
|
|
124
|
-
.sort();
|
|
125
|
-
} catch { return []; }
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export async function ensureSkillStarterFiles(sessionRoot, skillId) {
|
|
129
|
-
const result = { copied: [], skipped: [] };
|
|
130
|
-
if (!sessionRoot || !skillId) return result;
|
|
131
|
-
|
|
132
|
-
const skillDir = path.join(SKILLS_ROOT, skillId);
|
|
133
|
-
const starterFiles = await listSkillStarterFiles(skillId);
|
|
134
|
-
|
|
135
|
-
for (const name of starterFiles) {
|
|
136
|
-
const src = path.join(skillDir, name);
|
|
137
|
-
const dst = path.join(sessionRoot, name);
|
|
138
|
-
|
|
139
|
-
let srcExists = false;
|
|
140
|
-
try {
|
|
141
|
-
await fs.access(src);
|
|
142
|
-
srcExists = true;
|
|
143
|
-
} catch { /* skill 没这个起手文件 */ }
|
|
144
|
-
if (!srcExists) continue;
|
|
145
|
-
|
|
146
|
-
let dstExists = false;
|
|
147
|
-
try {
|
|
148
|
-
await fs.access(dst);
|
|
149
|
-
dstExists = true;
|
|
150
|
-
} catch { /* dst 不存在,需要拷 */ }
|
|
151
|
-
if (dstExists) {
|
|
152
|
-
result.skipped.push(name);
|
|
153
|
-
continue;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
try {
|
|
157
|
-
await fs.copyFile(src, dst);
|
|
158
|
-
result.copied.push(name);
|
|
159
|
-
} catch (err) {
|
|
160
|
-
console.warn(
|
|
161
|
-
`[skill] copy ${name} failed (${err.code || err.message}); `
|
|
162
|
-
+ `agent will not have it in cwd`,
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return result;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// ── frontmatter 解析(极简 YAML:只支持 key: value)──
|
|
171
|
-
|
|
172
|
-
const FRONTMATTER_RE = /^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/;
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* 解析 SKILL.md 的 frontmatter + body。
|
|
176
|
-
* 不支持嵌套 / 多行 / list — 只接受 `key: value` 形态。
|
|
177
|
-
*
|
|
178
|
-
* 没 frontmatter 的文件:返回 { frontmatter: {}, body: <整个文件> }
|
|
179
|
-
*/
|
|
180
|
-
function parseFrontmatter(raw) {
|
|
181
|
-
const m = FRONTMATTER_RE.exec(raw);
|
|
182
|
-
if (!m) return { frontmatter: {}, body: raw };
|
|
183
|
-
|
|
184
|
-
const [, yamlText, body] = m;
|
|
185
|
-
const frontmatter = {};
|
|
186
|
-
for (const line of yamlText.split('\n')) {
|
|
187
|
-
const trimmed = line.trim();
|
|
188
|
-
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
189
|
-
const colonIdx = trimmed.indexOf(':');
|
|
190
|
-
if (colonIdx < 1) continue;
|
|
191
|
-
const key = trimmed.slice(0, colonIdx).trim();
|
|
192
|
-
let value = trimmed.slice(colonIdx + 1).trim();
|
|
193
|
-
// 去掉成对引号
|
|
194
|
-
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
195
|
-
(value.startsWith("'") && value.endsWith("'"))) {
|
|
196
|
-
value = value.slice(1, -1);
|
|
197
|
-
}
|
|
198
|
-
frontmatter[key] = value;
|
|
199
|
-
}
|
|
200
|
-
return { frontmatter, body: body || '' };
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// 暴露供单测
|
|
204
|
-
export { parseFrontmatter };
|
|
1
|
+
/**
|
|
2
|
+
* skill.js — Skill 加载器(YAML frontmatter + Markdown body)
|
|
3
|
+
*
|
|
4
|
+
* 目录结构(2026-05-18 起,对齐 Claude Code plugin convention):
|
|
5
|
+
* server/engine/plugins/nodesign/
|
|
6
|
+
* .claude-plugin/plugin.json — plugin 元数据
|
|
7
|
+
* skills/<skill-id>/SKILL.md — 各 skill
|
|
8
|
+
* skills/<skill-id>/<其他起手文件>
|
|
9
|
+
*
|
|
10
|
+
* SKILL.md 格式(YAML frontmatter + body):
|
|
11
|
+
* ---
|
|
12
|
+
* name: deskskill-engine-mini
|
|
13
|
+
* version: 0.0.1
|
|
14
|
+
* description: 给 LLM 看的"什么时候用我"的描述
|
|
15
|
+
* ---
|
|
16
|
+
*
|
|
17
|
+
* # System Prompt
|
|
18
|
+
*
|
|
19
|
+
* 你是一个 deck 设计 agent...(任意 markdown)
|
|
20
|
+
*
|
|
21
|
+
* 本模块职责:
|
|
22
|
+
* - 解析 SKILL.md 的 YAML frontmatter + body(loadSkill)
|
|
23
|
+
* - 把 skill 起手文件(canvas.template.html 等)拷进 session cwd(ensureSkillStarterFiles)
|
|
24
|
+
*
|
|
25
|
+
* 注:批量扫 plugin 下所有 skill 走 plugin-loader.js `listInstalledPluginsDetailed`,
|
|
26
|
+
* 不在本模块(API 层 server/api/skills.js 用那个)。
|
|
27
|
+
*
|
|
28
|
+
* SDK 集成(在 session-loop.js):
|
|
29
|
+
* - plugins: [{ type: 'local', path: PLUGIN_ROOT }] → 让 SDK 识别本 plugin
|
|
30
|
+
* - skills: [<skill-id>] → 让 SDK 把 description 注入 system prompt
|
|
31
|
+
* - SKILL.md body 通过 SDK 内置 Skill 工具按需加载(不再走 systemPrompt.append 恒驻)
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { promises as fs } from 'fs';
|
|
35
|
+
import path from 'path';
|
|
36
|
+
import { fileURLToPath } from 'url';
|
|
37
|
+
|
|
38
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
39
|
+
|
|
40
|
+
/** Plugin 根目录(含 .claude-plugin/plugin.json + skills/)*/
|
|
41
|
+
export const PLUGIN_ROOT = path.resolve(
|
|
42
|
+
process.env.NODESIGN_PLUGIN_DIR || path.join(__dirname, '../plugins/nodesign')
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
/** Skills 子目录(plugin convention:<plugin>/skills/<skill-id>/SKILL.md)*/
|
|
46
|
+
export const SKILLS_ROOT = path.resolve(
|
|
47
|
+
process.env.NODESIGN_SKILLS_DIR || path.join(PLUGIN_ROOT, 'skills')
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 加载一个 skill。返回 { id, name, version, description, systemPrompt, raw }。
|
|
52
|
+
* 找不到时抛 Error(code='SKILL_NOT_FOUND')。
|
|
53
|
+
*/
|
|
54
|
+
export async function loadSkill(skillId) {
|
|
55
|
+
if (!skillId || typeof skillId !== 'string') {
|
|
56
|
+
throw Object.assign(new Error('loadSkill: skillId required'), { code: 'INVALID_SKILL_ID' });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const skillDir = path.join(SKILLS_ROOT, skillId);
|
|
60
|
+
const skillFile = path.join(skillDir, 'SKILL.md');
|
|
61
|
+
|
|
62
|
+
let raw;
|
|
63
|
+
try {
|
|
64
|
+
raw = await fs.readFile(skillFile, 'utf8');
|
|
65
|
+
} catch (err) {
|
|
66
|
+
if (err.code === 'ENOENT') {
|
|
67
|
+
throw Object.assign(
|
|
68
|
+
new Error(`skill not found: ${skillId} (expected at ${skillFile})`),
|
|
69
|
+
{ code: 'SKILL_NOT_FOUND' }
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
throw err;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const { frontmatter, body } = parseFrontmatter(raw);
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
id: skillId,
|
|
79
|
+
name: frontmatter.name || skillId,
|
|
80
|
+
version: frontmatter.version || '0.0.0',
|
|
81
|
+
description: frontmatter.description || '',
|
|
82
|
+
systemPrompt: body.trim(),
|
|
83
|
+
frontmatter,
|
|
84
|
+
raw,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 把 skill 自带的工作区起手文件(目前主要是 canvas.template.html)拷贝
|
|
90
|
+
* 进 session cwd,让 agent 能直接 `Read canvas.template.html` 而不必去
|
|
91
|
+
* 仓库相对路径找(agent 看不到 server/engine/plugins/nodesign/skills/)。
|
|
92
|
+
*
|
|
93
|
+
* **拷贝不软链**:
|
|
94
|
+
* - 跨平台稳(Windows symlink 要 admin / Linux bwrap 不解析 symlink)
|
|
95
|
+
* - 防 agent 误 Edit 改源模板(影响其他 session)
|
|
96
|
+
* - session 是一次性沙盒,拷贝快照语义合理
|
|
97
|
+
*
|
|
98
|
+
* **幂等**:文件已存在就不覆盖(agent 改过的、或上次 session init 拷过的不动)。
|
|
99
|
+
*
|
|
100
|
+
* **起手文件是自动发现的**(2026-07-28 从硬编码 `['canvas.template.html']` 改来):
|
|
101
|
+
* skill 目录里凡是文件名带 `.template.` 的都算起手文件。加第二个 skill
|
|
102
|
+
* (站点)时不必再回来改这里 —— 硬编码一个文件名意味着新 skill 的模板永远
|
|
103
|
+
* 拷不出来,而且是静默的:agent 只会 `Read` 失败然后凭空写。
|
|
104
|
+
*
|
|
105
|
+
* @param {string} sessionRoot - sessions/<sid>/ 绝对路径
|
|
106
|
+
* @param {string} skillId - 同 loadSkill 的 skillId
|
|
107
|
+
* @returns {Promise<{ copied: string[], skipped: string[] }>}
|
|
108
|
+
*/
|
|
109
|
+
/** 内置 plugin 里现有的 skill id(目录名即 id) */
|
|
110
|
+
export async function listSkillIds() {
|
|
111
|
+
try {
|
|
112
|
+
const entries = await fs.readdir(SKILLS_ROOT, { withFileTypes: true });
|
|
113
|
+
return entries.filter(e => e.isDirectory() && !e.name.startsWith('.')).map(e => e.name);
|
|
114
|
+
} catch { return []; }
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export async function listSkillStarterFiles(skillId) {
|
|
118
|
+
if (!skillId) return [];
|
|
119
|
+
try {
|
|
120
|
+
const entries = await fs.readdir(path.join(SKILLS_ROOT, skillId), { withFileTypes: true });
|
|
121
|
+
return entries
|
|
122
|
+
.filter(e => e.isFile() && e.name.includes('.template.'))
|
|
123
|
+
.map(e => e.name)
|
|
124
|
+
.sort();
|
|
125
|
+
} catch { return []; }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export async function ensureSkillStarterFiles(sessionRoot, skillId) {
|
|
129
|
+
const result = { copied: [], skipped: [] };
|
|
130
|
+
if (!sessionRoot || !skillId) return result;
|
|
131
|
+
|
|
132
|
+
const skillDir = path.join(SKILLS_ROOT, skillId);
|
|
133
|
+
const starterFiles = await listSkillStarterFiles(skillId);
|
|
134
|
+
|
|
135
|
+
for (const name of starterFiles) {
|
|
136
|
+
const src = path.join(skillDir, name);
|
|
137
|
+
const dst = path.join(sessionRoot, name);
|
|
138
|
+
|
|
139
|
+
let srcExists = false;
|
|
140
|
+
try {
|
|
141
|
+
await fs.access(src);
|
|
142
|
+
srcExists = true;
|
|
143
|
+
} catch { /* skill 没这个起手文件 */ }
|
|
144
|
+
if (!srcExists) continue;
|
|
145
|
+
|
|
146
|
+
let dstExists = false;
|
|
147
|
+
try {
|
|
148
|
+
await fs.access(dst);
|
|
149
|
+
dstExists = true;
|
|
150
|
+
} catch { /* dst 不存在,需要拷 */ }
|
|
151
|
+
if (dstExists) {
|
|
152
|
+
result.skipped.push(name);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
await fs.copyFile(src, dst);
|
|
158
|
+
result.copied.push(name);
|
|
159
|
+
} catch (err) {
|
|
160
|
+
console.warn(
|
|
161
|
+
`[skill] copy ${name} failed (${err.code || err.message}); `
|
|
162
|
+
+ `agent will not have it in cwd`,
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ── frontmatter 解析(极简 YAML:只支持 key: value)──
|
|
171
|
+
|
|
172
|
+
const FRONTMATTER_RE = /^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* 解析 SKILL.md 的 frontmatter + body。
|
|
176
|
+
* 不支持嵌套 / 多行 / list — 只接受 `key: value` 形态。
|
|
177
|
+
*
|
|
178
|
+
* 没 frontmatter 的文件:返回 { frontmatter: {}, body: <整个文件> }
|
|
179
|
+
*/
|
|
180
|
+
function parseFrontmatter(raw) {
|
|
181
|
+
const m = FRONTMATTER_RE.exec(raw);
|
|
182
|
+
if (!m) return { frontmatter: {}, body: raw };
|
|
183
|
+
|
|
184
|
+
const [, yamlText, body] = m;
|
|
185
|
+
const frontmatter = {};
|
|
186
|
+
for (const line of yamlText.split('\n')) {
|
|
187
|
+
const trimmed = line.trim();
|
|
188
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
189
|
+
const colonIdx = trimmed.indexOf(':');
|
|
190
|
+
if (colonIdx < 1) continue;
|
|
191
|
+
const key = trimmed.slice(0, colonIdx).trim();
|
|
192
|
+
let value = trimmed.slice(colonIdx + 1).trim();
|
|
193
|
+
// 去掉成对引号
|
|
194
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
195
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
196
|
+
value = value.slice(1, -1);
|
|
197
|
+
}
|
|
198
|
+
frontmatter[key] = value;
|
|
199
|
+
}
|
|
200
|
+
return { frontmatter, body: body || '' };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// 暴露供单测
|
|
204
|
+
export { parseFrontmatter };
|
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* task-events.js — SDK 统一任务消息族(task_*)的收口翻译(2026-08-18,
|
|
3
|
-
* 从 agent-shared.js handleSystemMessage 拆出)
|
|
4
|
-
*
|
|
5
|
-
* SDK 0.3.x 起「任务」统一化:task_* 消息不再只代表 Task 子代理 —— 后台
|
|
6
|
-
* Bash(task_type 'local_bash')、Workflow('local_workflow')等也走同一条。
|
|
7
|
-
* 我们 run.task.* 事件的语义是「子代理」,在这个咽喉点收口:只放真子代理
|
|
8
|
-
* 过去,其余不进事件流。不收口的话每条 bash 命令都会在前端顶着「子代理」
|
|
9
|
-
* 的名头出现(舞台便利贴/在场徽记/侧栏状态位全线噪音,2026-08-18 事故)。
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { Events } from './events.js';
|
|
13
|
-
import { recordTaskNotification } from './hooks/post-subagent-report.js';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* 这条 task_* 消息说的是不是真子代理(Task 工具)。靠 subagent_type /
|
|
17
|
-
* task_type 区分;skip_transcript 是 SDK 标的 ambient/housekeeping 任务,
|
|
18
|
-
* 按 SDK 约定对用户隐藏。
|
|
19
|
-
*/
|
|
20
|
-
export function isSubagentTask(msg) {
|
|
21
|
-
if (msg.skip_transcript) return false;
|
|
22
|
-
return !!msg.subagent_type || msg.task_type === 'local_agent';
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* 本轮已放行的子代理 task_id —— task_progress / task_notification 不带
|
|
27
|
-
* subagent_type,靠它过滤非子代理任务。挂在 ctx 上惰性建:task_* 消息
|
|
28
|
-
* 不带 parent_tool_use_id,进来的恒是真 ctx(不是子代理的派生 ctx),
|
|
29
|
-
* own property 不会写丢。
|
|
30
|
-
*/
|
|
31
|
-
function subagentTaskIds(ctx) {
|
|
32
|
-
if (!ctx._subagentTaskIds) ctx._subagentTaskIds = new Set();
|
|
33
|
-
return ctx._subagentTaskIds;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** handleSystemMessage 的 task_* 四兄弟统一入口 */
|
|
37
|
-
export function handleTaskMessage(ctx, msg) {
|
|
38
|
-
switch (msg.subtype) {
|
|
39
|
-
case 'task_started':
|
|
40
|
-
if (!isSubagentTask(msg)) return;
|
|
41
|
-
subagentTaskIds(ctx).add(msg.task_id);
|
|
42
|
-
ctx.emit(Events.taskStarted(
|
|
43
|
-
msg.task_id, msg.description, msg.subagent_type, msg.task_type, msg.prompt, msg.tool_use_id,
|
|
44
|
-
));
|
|
45
|
-
return;
|
|
46
|
-
|
|
47
|
-
case 'task_progress':
|
|
48
|
-
// agentProgressSummaries: true 时每 ~30s 一次:"正在调整字号节奏" 之类
|
|
49
|
-
if (!subagentTaskIds(ctx).has(msg.task_id)) return;
|
|
50
|
-
ctx.emit(Events.taskProgress(
|
|
51
|
-
msg.task_id, msg.description, msg.summary, msg.last_tool_name, msg.usage, msg.tool_use_id,
|
|
52
|
-
));
|
|
53
|
-
return;
|
|
54
|
-
|
|
55
|
-
case 'task_updated':
|
|
56
|
-
if (!subagentTaskIds(ctx).has(msg.task_id)) return;
|
|
57
|
-
ctx.emit(Events.taskUpdated(msg.task_id, msg.patch, msg.tool_use_id));
|
|
58
|
-
return;
|
|
59
|
-
|
|
60
|
-
case 'task_notification':
|
|
61
|
-
// 收尾用量记账不分任务类型(进 metadata 可观测,不进主 token 列 ——
|
|
62
|
-
// 防止与 result.usage 双重计数,详见 context.absorbSubagentUsage):
|
|
63
|
-
// 将来若接 workflow 之类带真用量的本地任务,账也不能漏。
|
|
64
|
-
ctx.absorbSubagentUsage?.(msg.usage);
|
|
65
|
-
// 报告丢失的兜底也在闸**前**:把 output_file 记下来,PostToolUse(Agent)
|
|
66
|
-
// 的 handler 在报告看起来是空的时候把转录路径递给主 agent(见
|
|
67
|
-
// hooks/post-subagent-report.js)。它按 tool_use_id 查、只被 Agent 工具
|
|
68
|
-
// 问到,多记非子代理任务无害;安全网不该依赖过滤闸的状态(存储有界 200 条)。
|
|
69
|
-
recordTaskNotification(msg);
|
|
70
|
-
if (!subagentTaskIds(ctx).has(msg.task_id)) return;
|
|
71
|
-
ctx.emit(Events.taskNotification(
|
|
72
|
-
msg.task_id, msg.status, msg.summary, msg.usage, msg.tool_use_id,
|
|
73
|
-
));
|
|
74
|
-
return;
|
|
75
|
-
|
|
76
|
-
default:
|
|
77
|
-
}
|
|
78
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* task-events.js — SDK 统一任务消息族(task_*)的收口翻译(2026-08-18,
|
|
3
|
+
* 从 agent-shared.js handleSystemMessage 拆出)
|
|
4
|
+
*
|
|
5
|
+
* SDK 0.3.x 起「任务」统一化:task_* 消息不再只代表 Task 子代理 —— 后台
|
|
6
|
+
* Bash(task_type 'local_bash')、Workflow('local_workflow')等也走同一条。
|
|
7
|
+
* 我们 run.task.* 事件的语义是「子代理」,在这个咽喉点收口:只放真子代理
|
|
8
|
+
* 过去,其余不进事件流。不收口的话每条 bash 命令都会在前端顶着「子代理」
|
|
9
|
+
* 的名头出现(舞台便利贴/在场徽记/侧栏状态位全线噪音,2026-08-18 事故)。
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { Events } from './events.js';
|
|
13
|
+
import { recordTaskNotification } from './hooks/post-subagent-report.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 这条 task_* 消息说的是不是真子代理(Task 工具)。靠 subagent_type /
|
|
17
|
+
* task_type 区分;skip_transcript 是 SDK 标的 ambient/housekeeping 任务,
|
|
18
|
+
* 按 SDK 约定对用户隐藏。
|
|
19
|
+
*/
|
|
20
|
+
export function isSubagentTask(msg) {
|
|
21
|
+
if (msg.skip_transcript) return false;
|
|
22
|
+
return !!msg.subagent_type || msg.task_type === 'local_agent';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 本轮已放行的子代理 task_id —— task_progress / task_notification 不带
|
|
27
|
+
* subagent_type,靠它过滤非子代理任务。挂在 ctx 上惰性建:task_* 消息
|
|
28
|
+
* 不带 parent_tool_use_id,进来的恒是真 ctx(不是子代理的派生 ctx),
|
|
29
|
+
* own property 不会写丢。
|
|
30
|
+
*/
|
|
31
|
+
function subagentTaskIds(ctx) {
|
|
32
|
+
if (!ctx._subagentTaskIds) ctx._subagentTaskIds = new Set();
|
|
33
|
+
return ctx._subagentTaskIds;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** handleSystemMessage 的 task_* 四兄弟统一入口 */
|
|
37
|
+
export function handleTaskMessage(ctx, msg) {
|
|
38
|
+
switch (msg.subtype) {
|
|
39
|
+
case 'task_started':
|
|
40
|
+
if (!isSubagentTask(msg)) return;
|
|
41
|
+
subagentTaskIds(ctx).add(msg.task_id);
|
|
42
|
+
ctx.emit(Events.taskStarted(
|
|
43
|
+
msg.task_id, msg.description, msg.subagent_type, msg.task_type, msg.prompt, msg.tool_use_id,
|
|
44
|
+
));
|
|
45
|
+
return;
|
|
46
|
+
|
|
47
|
+
case 'task_progress':
|
|
48
|
+
// agentProgressSummaries: true 时每 ~30s 一次:"正在调整字号节奏" 之类
|
|
49
|
+
if (!subagentTaskIds(ctx).has(msg.task_id)) return;
|
|
50
|
+
ctx.emit(Events.taskProgress(
|
|
51
|
+
msg.task_id, msg.description, msg.summary, msg.last_tool_name, msg.usage, msg.tool_use_id,
|
|
52
|
+
));
|
|
53
|
+
return;
|
|
54
|
+
|
|
55
|
+
case 'task_updated':
|
|
56
|
+
if (!subagentTaskIds(ctx).has(msg.task_id)) return;
|
|
57
|
+
ctx.emit(Events.taskUpdated(msg.task_id, msg.patch, msg.tool_use_id));
|
|
58
|
+
return;
|
|
59
|
+
|
|
60
|
+
case 'task_notification':
|
|
61
|
+
// 收尾用量记账不分任务类型(进 metadata 可观测,不进主 token 列 ——
|
|
62
|
+
// 防止与 result.usage 双重计数,详见 context.absorbSubagentUsage):
|
|
63
|
+
// 将来若接 workflow 之类带真用量的本地任务,账也不能漏。
|
|
64
|
+
ctx.absorbSubagentUsage?.(msg.usage);
|
|
65
|
+
// 报告丢失的兜底也在闸**前**:把 output_file 记下来,PostToolUse(Agent)
|
|
66
|
+
// 的 handler 在报告看起来是空的时候把转录路径递给主 agent(见
|
|
67
|
+
// hooks/post-subagent-report.js)。它按 tool_use_id 查、只被 Agent 工具
|
|
68
|
+
// 问到,多记非子代理任务无害;安全网不该依赖过滤闸的状态(存储有界 200 条)。
|
|
69
|
+
recordTaskNotification(msg);
|
|
70
|
+
if (!subagentTaskIds(ctx).has(msg.task_id)) return;
|
|
71
|
+
ctx.emit(Events.taskNotification(
|
|
72
|
+
msg.task_id, msg.status, msg.summary, msg.usage, msg.tool_use_id,
|
|
73
|
+
));
|
|
74
|
+
return;
|
|
75
|
+
|
|
76
|
+
default:
|
|
77
|
+
}
|
|
78
|
+
}
|