@xiaobuyu/nodesign 0.0.1 → 0.0.2

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.
Files changed (282) hide show
  1. package/README.md +156 -106
  2. package/bin/nodesign.js +0 -0
  3. package/package.json +1 -1
  4. package/server/api/README.md +45 -45
  5. package/server/api/_guard.js +75 -75
  6. package/server/api/admin.js +187 -187
  7. package/server/api/assets/docx-page.js +103 -103
  8. package/server/api/assets/helpers.js +22 -22
  9. package/server/api/assets/notes.js +144 -144
  10. package/server/api/assets.js +896 -896
  11. package/server/api/board.js +57 -57
  12. package/server/api/browse.js +138 -138
  13. package/server/api/canvas.js +444 -444
  14. package/server/api/chatai.js +324 -324
  15. package/server/api/exports/build-standalone.js +980 -980
  16. package/server/api/exports/cards.js +118 -118
  17. package/server/api/exports/docx-pdf.js +46 -46
  18. package/server/api/exports/export-page.js +142 -142
  19. package/server/api/exports/handoff.js +147 -147
  20. package/server/api/exports.js +690 -690
  21. package/server/api/instruction.js +75 -75
  22. package/server/api/me.js +116 -116
  23. package/server/api/memory.js +185 -185
  24. package/server/api/pending-changes.js +366 -366
  25. package/server/api/plugins.js +164 -164
  26. package/server/api/projects.js +220 -220
  27. package/server/api/publish.js +64 -64
  28. package/server/api/recent.js +73 -73
  29. package/server/api/sessions.js +589 -589
  30. package/server/api/skills.js +77 -77
  31. package/server/api/standalone-fit.js +168 -168
  32. package/server/api/turn-compose.js +180 -180
  33. package/server/api/turn-inflight.js +44 -44
  34. package/server/auth/README.md +17 -17
  35. package/server/auth/middleware.js +138 -138
  36. package/server/auth/origin-guard.js +71 -71
  37. package/server/auth/session.js +108 -108
  38. package/server/auth/tier.js +113 -113
  39. package/server/auth/users-store.js +348 -348
  40. package/server/edit/README.md +29 -29
  41. package/server/engine/README.md +113 -113
  42. package/server/engine/agent/agent-shared.js +550 -550
  43. package/server/engine/agent/auto-mode-default-hard-deny.txt +4 -4
  44. package/server/engine/agent/auto-mode-rules.js +78 -78
  45. package/server/engine/agent/context.js +418 -418
  46. package/server/engine/agent/events.js +464 -464
  47. package/server/engine/agent/hooks/canvas-validate.js +199 -199
  48. package/server/engine/agent/hooks/failure.js +120 -120
  49. package/server/engine/agent/hooks/file-events.js +75 -75
  50. package/server/engine/agent/hooks/lifecycle.js +233 -233
  51. package/server/engine/agent/hooks/post-canvas-focus.js +80 -80
  52. package/server/engine/agent/hooks/post-guidance.js +206 -206
  53. package/server/engine/agent/hooks/post-subagent-report.js +104 -104
  54. package/server/engine/agent/hooks/post-trim.js +58 -58
  55. package/server/engine/agent/hooks/pre-board-neighborhood.js +34 -34
  56. package/server/engine/agent/hooks/pre-defaults.js +84 -84
  57. package/server/engine/agent/hooks/pre-injectors.js +277 -277
  58. package/server/engine/agent/hooks/pre-performance-log-guard.js +78 -78
  59. package/server/engine/agent/hooks/pre-starter-files.js +61 -61
  60. package/server/engine/agent/hooks/pre-workspace-scope-guard.js +78 -78
  61. package/server/engine/agent/hooks/site-validate.js +94 -94
  62. package/server/engine/agent/hooks/tool-prompts.js +31 -31
  63. package/server/engine/agent/hooks/turn-state-memory.js +56 -56
  64. package/server/engine/agent/hooks/user-prompt-submit.js +215 -215
  65. package/server/engine/agent/hooks.js +354 -354
  66. package/server/engine/agent/init-contract.js +69 -69
  67. package/server/engine/agent/isolation.js +159 -159
  68. package/server/engine/agent/model-table.js +292 -292
  69. package/server/engine/agent/plugin-loader.js +266 -266
  70. package/server/engine/agent/prompts/nodesign-prelude.md +336 -336
  71. package/server/engine/agent/prompts/tools/ask-user-question-protocol.md +71 -71
  72. package/server/engine/agent/prompts/tools/direct-edit-protocol.md +98 -98
  73. package/server/engine/agent/prompts/tools/generate-image-cookbook.gemini-gateway.md +583 -583
  74. package/server/engine/agent/prompts/tools/generate-image-cookbook.md +483 -483
  75. package/server/engine/agent/prompts/tools/hybrid-reference.md +100 -100
  76. package/server/engine/agent/prompts/tools/paint-still-cookbook.md +270 -270
  77. package/server/engine/agent/prompts/tools/roll-film-cookbook.md +70 -70
  78. package/server/engine/agent/prompts/tools/site-reference.md +106 -106
  79. package/server/engine/agent/prompts/tools/tweaks-syntax.md +125 -125
  80. package/server/engine/agent/prompts/tools/vision-checker-dispatch.md +48 -48
  81. package/server/engine/agent/session-loop.js +1024 -1024
  82. package/server/engine/agent/session-model.js +164 -164
  83. package/server/engine/agent/skill.js +204 -204
  84. package/server/engine/agent/task-events.js +78 -78
  85. package/server/engine/agents/ds-extractor.md +132 -132
  86. package/server/engine/agents/explorer.md +190 -190
  87. package/server/engine/agents/index.js +230 -230
  88. package/server/engine/agents/schemas/design-system.json +156 -156
  89. package/server/engine/agents/schemas/tweak-schema.json +113 -113
  90. package/server/engine/agents/tweak-proposer.md +127 -127
  91. package/server/engine/agents/vision-checker.md +254 -254
  92. package/server/engine/browse/capture.js +422 -422
  93. package/server/engine/browse/card.js +137 -137
  94. package/server/engine/browse/handover.js +59 -59
  95. package/server/engine/browse/page-digest.js +119 -119
  96. package/server/engine/browse/refs.js +196 -196
  97. package/server/engine/browse/registry.js +307 -307
  98. package/server/engine/browse/screencast.js +170 -170
  99. package/server/engine/browse/state.js +121 -121
  100. package/server/engine/chatai/chat-log.js +79 -79
  101. package/server/engine/chatai/index.js +193 -193
  102. package/server/engine/chatai/openai-compat.js +152 -152
  103. package/server/engine/chatai/orchestrate.js +309 -309
  104. package/server/engine/chatai/perform.js +40 -40
  105. package/server/engine/chatai/summarize.js +79 -79
  106. package/server/engine/mcp/capability-gate.js +52 -52
  107. package/server/engine/mcp/index.js +339 -339
  108. package/server/engine/mcp/param-sanitizer.js +142 -142
  109. package/server/engine/mcp/tools/arrange-on-board.js +124 -124
  110. package/server/engine/mcp/tools/artifact-session.js +278 -278
  111. package/server/engine/mcp/tools/browse-computer.js +421 -421
  112. package/server/engine/mcp/tools/browse-find-batch.js +183 -183
  113. package/server/engine/mcp/tools/browse-screenshot.js +157 -157
  114. package/server/engine/mcp/tools/browse.js +480 -480
  115. package/server/engine/mcp/tools/build-docx.js +101 -101
  116. package/server/engine/mcp/tools/clear-pending-changes.js +99 -99
  117. package/server/engine/mcp/tools/create-on-board.js +155 -155
  118. package/server/engine/mcp/tools/crystallize-skill.js +168 -168
  119. package/server/engine/mcp/tools/explain-style.js +237 -237
  120. package/server/engine/mcp/tools/export-handoff.js +133 -133
  121. package/server/engine/mcp/tools/expose-tweaks.js +149 -149
  122. package/server/engine/mcp/tools/generate-image.js +842 -842
  123. package/server/engine/mcp/tools/get-computed-styles.js +164 -164
  124. package/server/engine/mcp/tools/get-pending-changes.js +205 -205
  125. package/server/engine/mcp/tools/h3box-ssh.js +84 -84
  126. package/server/engine/mcp/tools/helpers/acquire-page.js +82 -82
  127. package/server/engine/mcp/tools/helpers/motion-lab.js +554 -554
  128. package/server/engine/mcp/tools/helpers/motion-scroll.js +112 -112
  129. package/server/engine/mcp/tools/helpers/perception-page.js +215 -215
  130. package/server/engine/mcp/tools/helpers/reference-download.js +103 -103
  131. package/server/engine/mcp/tools/helpers/rembg-bridge.py +80 -80
  132. package/server/engine/mcp/tools/helpers/shot-pipeline.js +280 -280
  133. package/server/engine/mcp/tools/highlight.js +68 -68
  134. package/server/engine/mcp/tools/list-pages.js +222 -222
  135. package/server/engine/mcp/tools/lookup-tags.js +59 -59
  136. package/server/engine/mcp/tools/navigate-to-page.js +60 -60
  137. package/server/engine/mcp/tools/organize-board.js +64 -64
  138. package/server/engine/mcp/tools/paint-still.js +434 -434
  139. package/server/engine/mcp/tools/pin-to-board.js +130 -130
  140. package/server/engine/mcp/tools/preview-deck.js +130 -130
  141. package/server/engine/mcp/tools/profile-scroll.js +305 -305
  142. package/server/engine/mcp/tools/publish-site.js +102 -102
  143. package/server/engine/mcp/tools/query-elements.js +195 -195
  144. package/server/engine/mcp/tools/read-board.js +103 -103
  145. package/server/engine/mcp/tools/read-document.js +93 -93
  146. package/server/engine/mcp/tools/read-page.js +264 -264
  147. package/server/engine/mcp/tools/read-tavern-json.js +143 -143
  148. package/server/engine/mcp/tools/record-decision.js +140 -140
  149. package/server/engine/mcp/tools/relate-on-board.js +110 -110
  150. package/server/engine/mcp/tools/report-issue.js +115 -115
  151. package/server/engine/mcp/tools/roll-film.js +266 -266
  152. package/server/engine/mcp/tools/screenshot-docx.js +138 -138
  153. package/server/engine/mcp/tools/screenshot-url.js +195 -195
  154. package/server/engine/mcp/tools/screenshot.js +583 -583
  155. package/server/engine/mcp/tools/tier-gate.js +96 -96
  156. package/server/engine/mcp/tools/trace-motion.js +215 -215
  157. package/server/engine/mcp/tools/web-search.js +548 -548
  158. package/server/engine/motion/inventory.js +349 -349
  159. package/server/engine/perception/session.js +235 -235
  160. package/server/engine/plugins/nodesign/.claude-plugin/plugin.json +5 -5
  161. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/SKILL.md +192 -192
  162. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/canvas.template.html +667 -667
  163. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/hybrid-grid.md +22 -22
  164. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/image-led-cover.md +25 -25
  165. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/portrait.md +23 -23
  166. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/quote-backdrop.md +21 -21
  167. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/section-divider.md +23 -23
  168. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/text-led.md +21 -21
  169. package/server/engine/plugins/nodesign/skills/docx-craft/SKILL.md +162 -162
  170. package/server/engine/plugins/nodesign/skills/docx-craft/references/token-schema.md +407 -407
  171. package/server/engine/plugins/nodesign/skills/docx-craft//346/226/207/346/241/243.template.json +80 -80
  172. package/server/engine/plugins/nodesign/skills/rp-craft/SKILL.md +228 -228
  173. 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
  174. package/server/engine/plugins/nodesign/skills/rp-craft//346/274/224/345/207/272.template.js +268 -268
  175. package/server/engine/plugins/nodesign/skills/site-craft/SKILL.md +323 -323
  176. package/server/engine/plugins/nodesign/skills/site-craft/patterns/build-lane.md +134 -134
  177. package/server/engine/plugins/nodesign/skills/site-craft/patterns/cutout-collage.md +61 -61
  178. package/server/engine/plugins/nodesign/skills/site-craft/patterns/mock-app.md +163 -163
  179. package/server/engine/plugins/nodesign/skills/site-craft/patterns/page-transitions.md +86 -86
  180. package/server/engine/runs/active-runs.js +698 -698
  181. package/server/engine/runs/live-turn.js +252 -252
  182. package/server/engine/runs/store.js +364 -364
  183. package/server/engine/runs/turn-relay.js +217 -217
  184. package/server/engine/runtime/workspace.js +164 -164
  185. package/server/lib/artifact-file-path.js +80 -80
  186. package/server/lib/artifact-target.js +284 -284
  187. package/server/lib/asset-refs.js +239 -239
  188. package/server/lib/async-queue.js +104 -104
  189. package/server/lib/auto-relations.js +130 -130
  190. package/server/lib/binding-types.js +60 -60
  191. package/server/lib/board-kind-sizes.js +62 -62
  192. package/server/lib/board-relations.js +133 -133
  193. package/server/lib/browse-proxy.js +180 -180
  194. package/server/lib/canvas-id.js +36 -36
  195. package/server/lib/cover.js +227 -227
  196. package/server/lib/danbooru-tags.js +291 -291
  197. package/server/lib/doc-extract.js +156 -156
  198. package/server/lib/docx/build-from-source.js +260 -260
  199. package/server/lib/docx/build.js +490 -490
  200. package/server/lib/docx/dump-styles.js +287 -287
  201. package/server/lib/docx/fonts/nodesign-cjk.conf +164 -164
  202. package/server/lib/docx/merge-runs.js +129 -129
  203. package/server/lib/docx/numbering.js +218 -218
  204. package/server/lib/docx/order.js +152 -152
  205. package/server/lib/docx/rawzip.js +172 -172
  206. package/server/lib/docx/render.js +92 -92
  207. package/server/lib/docx/text-lint.js +225 -225
  208. package/server/lib/docx/tokens.js +335 -335
  209. package/server/lib/docx/units.js +29 -29
  210. package/server/lib/docx/xml.js +291 -291
  211. package/server/lib/docx-pages.js +187 -187
  212. package/server/lib/export-collect.js +289 -289
  213. package/server/lib/export-package.js +210 -210
  214. package/server/lib/html-srcset.js +145 -145
  215. package/server/lib/image-variant.js +460 -460
  216. package/server/lib/ingress/forward-openai-chat.js +305 -305
  217. package/server/lib/ingress/openai-chat.js +491 -491
  218. package/server/lib/ingress/session-notice.js +66 -66
  219. package/server/lib/ingress/session-routes.js +68 -68
  220. package/server/lib/ingress/slot-probe.js +130 -130
  221. package/server/lib/ingress/upstream-billing.js +52 -52
  222. package/server/lib/ingress/upstream-fail-streak.js +72 -72
  223. package/server/lib/ingress/upstream-truncation.js +48 -48
  224. package/server/lib/issues-store.js +182 -182
  225. package/server/lib/kinds/deck.js +72 -72
  226. package/server/lib/kinds/docx.js +283 -283
  227. package/server/lib/kinds/file-kinds.js +113 -113
  228. package/server/lib/kinds/index.js +202 -202
  229. package/server/lib/kinds/site.js +161 -161
  230. package/server/lib/model-ingress.js +543 -543
  231. package/server/lib/moderation.js +255 -255
  232. package/server/lib/notice-store.js +103 -103
  233. package/server/lib/plugin-install.js +104 -104
  234. package/server/lib/plugin-validator.js +721 -721
  235. package/server/lib/publish-store.js +115 -115
  236. package/server/lib/quick-summary.js +52 -52
  237. package/server/lib/quota.js +270 -270
  238. package/server/lib/rate-window.js +29 -29
  239. package/server/lib/reference-assets.js +92 -92
  240. package/server/lib/region-shot.js +135 -135
  241. package/server/lib/safe-path.js +73 -73
  242. package/server/lib/sdk-session.js +33 -33
  243. package/server/lib/showcase-store.js +92 -92
  244. package/server/lib/site-publish.js +465 -465
  245. package/server/lib/ssrf-guard.js +432 -432
  246. package/server/lib/task-scan.js +158 -158
  247. package/server/lib/tavern-json.js +154 -154
  248. package/server/lib/video-variant.js +237 -237
  249. package/server/lib/workspace-path.js +33 -33
  250. package/server/ops/fix-sdk-musl.mjs +40 -40
  251. package/server/ops/install-macos-fonts.sh +114 -114
  252. package/server/ops/macos-fonts.conf +336 -336
  253. package/server/ops/sandbox-shim/bwrap +57 -57
  254. package/server/projects/assets-summary.js +119 -119
  255. package/server/projects/auto-name.js +53 -53
  256. package/server/projects/board-store.js +640 -640
  257. package/server/projects/move-entry.js +103 -103
  258. package/server/projects/store.js +270 -270
  259. package/server/projects/ui-config.js +54 -54
  260. package/server/projects/workspace-templates.js +53 -53
  261. package/server/projects/workspace.js +1025 -1025
  262. package/server/runtime/local-config.js +177 -177
  263. package/server/runtime/profile.js +72 -72
  264. package/server/services/rembg-service.py +334 -334
  265. package/server/shared/README.md +25 -25
  266. package/server/shared/deck.js +54 -54
  267. package/server/shared/time.js +49 -49
  268. package/server/style-pipeline/README.md +53 -53
  269. package/server/ws/broker.js +36 -36
  270. package/server/ws/browse-channel.js +177 -177
  271. package/server/ws/index.js +386 -386
  272. package/web/README.md +89 -89
  273. package/web/dist/assets/BrowserWindow-BYCgizHw.js +11 -0
  274. package/web/dist/assets/{DeckWindow-4G0xX7P3.js → DeckWindow-pNydEM4L.js} +1 -1
  275. package/web/dist/assets/{DocxWindow-BXQsoPkh.js → DocxWindow-PPgzh3Gq.js} +1 -1
  276. package/web/dist/assets/{SiteWindow-D6eS-2gM.js → SiteWindow-DM0LQPCO.js} +1 -1
  277. package/web/dist/assets/{index-Cbl3ATvp.js → index-BHTBJlpY.js} +32 -32
  278. package/web/dist/assets/{pending-edit-apply-DTjo2geW.js → pending-edit-apply-C0I13CbD.js} +1 -1
  279. package/web/dist/assets/{rotate-cw-LMT3x1Zj.js → rotate-cw-B1UQ8Hld.js} +1 -1
  280. package/web/dist/assets/{square-dashed-mouse-pointer-CBoAkfhi.js → square-dashed-mouse-pointer-8lrgqmfv.js} +1 -1
  281. package/web/dist/index.html +17 -17
  282. package/web/dist/assets/BrowserWindow-Dc7J7CYc.js +0 -11
@@ -1,339 +1,339 @@
1
- /**
2
- * server/engine/mcp/index.js — Nodesign 内置 MCP server
3
- *
4
- * 暴露给 agent 的自定义工具集(in-process,via SDK 的 createSdkMcpServer):
5
- *
6
- * 感知层(playwright headless 跑出真实渲染元数据):
7
- * screenshot_canvas / list_pages / read_page / query_elements / get_computed_styles
8
- * 控制层(emit 事件让前端同步):
9
- * navigate_to_page / highlight / preview_deck
10
- * 反馈层(用户在 canvas 上的直接编辑 + 评论 buffer):
11
- * get_pending_changes / clear_pending_changes
12
- * 产物层(NoDesign 差异化能力):
13
- * expose_tweaks / export_handoff / record_decision
14
- * 研究层:
15
- * web_search(4 provider,CJK auto baidu)
16
- *
17
- * 调用约定(SDK 自动给 tool name 加前缀):
18
- * tool 名在 agent 端是 mcp__nodesign__<tool>,比如 mcp__nodesign__screenshot_canvas
19
- *
20
- * 实例化策略:
21
- * 每个 runAgent 创建一个新的 MCP server 实例(through createNodesignMcpServer)。
22
- * 开销小(in-process,没起 process),但能让 deps(workspaceRoot / projectId / ctx)
23
- * 绑死到当前 turn 的上下文,避免 cross-talk。
24
- *
25
- * 安全:
26
- * tool handler 在 SDK 进程内(本服务器进程)跑,不通过 stdio/sse/http。
27
- * handler 自己不做沙盒,由 PreToolUse hook + workspace cwd 隔离兜底。
28
- */
29
-
30
- import { createSdkMcpServer } from '@anthropic-ai/claude-agent-sdk';
31
- import { withParamSanitizer } from './param-sanitizer.js';
32
- import { withCapabilityGate } from './capability-gate.js';
33
- import { makeScreenshotCanvasTool } from './tools/screenshot.js';
34
- import { makeScreenshotUrlTool } from './tools/screenshot-url.js';
35
- import { makeExportHandoffTool } from './tools/export-handoff.js';
36
- import { makeRecordDecisionTool } from './tools/record-decision.js';
37
- import { makeWebSearchTool } from './tools/web-search.js';
38
- import { withTierGate } from './tools/tier-gate.js'; // 档位闸包装器(auth/tier.js;按项目 owner)
39
- import { makeReadPageTool } from './tools/read-page.js';
40
- import { makeListPagesTool } from './tools/list-pages.js';
41
- import { makeQueryElementsTool } from './tools/query-elements.js';
42
- import { makeProfileScrollTool } from './tools/profile-scroll.js';
43
- import { makeExplainStyleTool } from './tools/explain-style.js';
44
- import { makeTraceMotionTool } from './tools/trace-motion.js';
45
- import {
46
- makeBrowserNavigateTool, makeBrowserReadTool, makeBrowserClickTool,
47
- makeBrowserRequestHelpTool, makeBrowserCaptureTool,
48
- } from './tools/browse.js';
49
- import { makeBrowserScreenshotTool } from './tools/browse-screenshot.js';
50
- import { makeBrowserComputerTool } from './tools/browse-computer.js';
51
- import { makeBrowserFindTool, makeBrowserBatchTool } from './tools/browse-find-batch.js';
52
- import { makeArtifactOpenTool, makeArtifactComputerTool, makeArtifactFindTool, makeArtifactMotionTool, makeArtifactBatchTool } from './tools/artifact-session.js';
53
- import { makeGetComputedStylesTool } from './tools/get-computed-styles.js';
54
- import { makeNavigateToPageTool } from './tools/navigate-to-page.js';
55
- import { makeHighlightTool } from './tools/highlight.js';
56
- import { makePreviewDeckTool } from './tools/preview-deck.js';
57
- import { makeBuildDocxTool } from './tools/build-docx.js';
58
- import { makeExposeTweaksTool } from './tools/expose-tweaks.js';
59
- import { makeGetPendingChangesTool } from './tools/get-pending-changes.js';
60
- import { makeClearPendingChangesTool } from './tools/clear-pending-changes.js';
61
- import { makeGenerateImageTool } from './tools/generate-image.js';
62
- import { makeRemoveBackgroundTool } from './tools/remove-background.js';
63
- import { makePinToBoardTool } from './tools/pin-to-board.js';
64
- import { makeRelateOnBoardTool } from './tools/relate-on-board.js';
65
- 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 { makeOrganizeBoardTool } from './tools/organize-board.js';
69
- import { makeReadDocumentTool } from './tools/read-document.js';
70
- import { makeReadTavernJsonTool } from './tools/read-tavern-json.js';
71
- import { makeDeliverFilesTool } from './tools/deliver-files.js';
72
- import { makeCrystallizeSkillTool } from './tools/crystallize-skill.js';
73
- import { makePublishSiteTool } from './tools/publish-site.js';
74
- import { makeReportIssueTool } from './tools/report-issue.js';
75
- import { makeRollFilmTool } from './tools/roll-film.js';
76
- import { makePaintStillTool } from './tools/paint-still.js';
77
- import { makeLookupTagsTool } from './tools/lookup-tags.js';
78
-
79
- /**
80
- * 创建 Nodesign 的 MCP server,绑定当前 run 的依赖。
81
- *
82
- * @param {object} deps
83
- * @param {string} deps.workspaceRoot 绝对路径,project workspace(sessions/<sid>/)
84
- * @param {string} [deps.sharedRoot] project shared/ 根(跨 session 共享 assets / .claude)
85
- * @param {string} [deps.projectId]
86
- * @param {string} [deps.sessionId] NoDesign sessionId(活跃产物指针 / 会话级锁 / 出处记账用)
87
- * @param {import('../agent/context.js').AgentContext} [deps.ctx] EventBus 入口
88
- * @returns SDK MCP server config(喂给 query options.mcpServers)
89
- */
90
- // 常驻 schema 白名单(2026-07-23 订阅模式 token 瘦身):
91
- // 高频 + schema 小的工具第一 turn 就注入 prompt;不在名单里的走 SDK 默认
92
- // deferred —— system prompt 只留工具名,agent 用 ToolSearch 按需拉 schema
93
- // (需要 ENABLE_TOOL_SEARCH=true + allowlist 含 ToolSearch,见 session-loop)。
94
- // 实测 defer 掉 generate_image/web_search/remove_background 等 6 个胖工具
95
- // 省 ~80k 字符常驻 schema。prelude 的工具速查表仍列全部工具名 + 一句话用途,
96
- // agent 知道存在什么、需要时先 ToolSearch("select:mcp__nodesign__<tool>")。
97
- // (kimi 时代曾全局 alwaysLoad —— kimi 不认 ToolSearch;claude 系模型原生受训,可放心 defer)
98
- const ALWAYS_LOAD_TOOLS = new Set([
99
- 'screenshot_canvas', 'read_page', 'list_pages', 'query_elements',
100
- 'get_computed_styles', 'navigate_to_page', 'highlight', 'preview_deck',
101
- 'record_decision', 'get_pending_changes', 'clear_pending_changes',
102
- // screenshot_url 常驻:explorer 显式 tools 列表没有 ToolSearch,defer 了它就
103
- // 永远拉不到 schema;schema 本身很小(4 字段),常驻成本可忽略
104
- 'screenshot_url',
105
- // ⭐ 浏览通道六件(2026-08-18 当天从 deferred 改常驻;08-21 加到九件,见下)。
106
- //
107
- // 它们最初跟着「新工具默认 deferred」的习惯走,而那条习惯的依据是**成本**:
108
- // defer 掉的是 expose_tweaks / paint_still / roll_film 那种十万字符级的胖子。
109
- // 这六个实测 description 合计 4980 字符、连参数区 ≈ 6.9k —— 比那几个小
110
- // 30~100 倍,塞进被缓存的 system prompt 每轮增量约等于零。
111
- //
112
- // 而 deferred 的代价是具体的:agent 只看得到**名字**。`browser_capture`
113
- // 这个名字一个字都没说它能带回调色板、字体、命中的 CSS 规则和结构三数 ——
114
- // 于是它不会去搜这个 schema,做 deck / 做文档的会话里整条浏览通道等于不存在
115
- // (只有加载了 site-craft skill 才会被点名)。**名字自解释的工具可以 defer,
116
- // 卖点藏在描述里的不能。**
117
- 'browser_navigate', 'browser_read', 'browser_click', 'browser_screenshot',
118
- 'browser_request_help', 'browser_capture',
119
- // 08-21 加的三件(坐标/引用级操作 + 词法找元 + 一次往返跑一串)。同一条理由:
120
- // browser_batch 的卖点"省掉模型往返"和 browser_find 的"ref 比像素稳"都在描述里,
121
- // 名字本身不卖;三件描述合计 ≈ 5.5k 字符,缓存里每轮增量约等于零。
122
- 'browser_computer', 'browser_find', 'browser_batch',
123
- // 08-21 产物会话五件:成品检查的交互半边(状态跨调用留着)。artifact_batch 的卖点
124
- // "一趟跑完 + 结尾截图"和 live:true 的存在都只在描述里说,常驻。
125
- 'artifact_open', 'artifact_computer', 'artifact_find', 'artifact_batch', 'artifact_motion',
126
- ]);
127
-
128
- export function createNodesignMcpServer({ workspaceRoot, sharedRoot, projectId, sessionId, ctx } = {}) {
129
- // 浏览通道里能被 browser_batch 串起来的七件:先建一次,batch 拿**同一批实例**
130
- // (projectId/ctx 绑在 handler 里,不能再造第二份)。只有 request_help 不进
131
- // batch(它阻塞等人);capture 在里面 —— 逐页采 token 正是 batch 要省的那种回合。
132
- const browseBatchable = [
133
- makeBrowserNavigateTool({ projectId, ctx }),
134
- makeBrowserReadTool({ projectId }),
135
- makeBrowserClickTool({ projectId }),
136
- makeBrowserScreenshotTool({ projectId, workspaceRoot }),
137
- // 采集:把可复用的东西(调色板/字体/CSS/结构骨架/截图)落进
138
- // assets/references/web/ + 出处 sidecar —— 下个会话还在
139
- makeBrowserCaptureTool({ projectId, workspaceRoot, sessionId, ctx }),
140
- // 坐标/引用级指针与键盘 + 词法找元(08-21,形状照 browser_toolset_20260801)
141
- makeBrowserComputerTool({ projectId, ctx }),
142
- makeBrowserFindTool({ projectId }),
143
- ];
144
- // 五个能骑到产物会话上(live:true)的量具:先建一次,artifact_batch 拿同一批实例
145
- const screenshotCanvas = makeScreenshotCanvasTool({ workspaceRoot, projectId, sessionId, ctx });
146
- const queryElements = makeQueryElementsTool({ workspaceRoot, projectId, sessionId, ctx });
147
- const getComputedStyles = makeGetComputedStylesTool({ workspaceRoot, projectId, sessionId, ctx });
148
- const explainStyle = makeExplainStyleTool({ workspaceRoot, projectId, sessionId });
149
- const traceMotion = makeTraceMotionTool({ workspaceRoot, projectId, sessionId });
150
- // 产物会话四件(engine/perception/session.js):artifact_open / computer / find / motion
151
- const artifactSessionTools = [
152
- makeArtifactOpenTool({ projectId, workspaceRoot, sessionId }),
153
- makeArtifactComputerTool({ projectId }),
154
- makeArtifactFindTool({ projectId }),
155
- // 自己的产物靠什么在动:跟 browser_capture motion 同一份引擎(engine/motion/inventory.js)
156
- makeArtifactMotionTool({ projectId, workspaceRoot, sessionId }),
157
- ];
158
- const tools = [
159
- // C9 screenshot_canvas — playwright headless 截图 → image content block
160
- screenshotCanvas,
161
-
162
- // screenshot_url — 外部 URL 截图(2026-07-29)。explorer 找视觉参考不再
163
- // 只能 WebFetch 文本转述;主 agent 也能直接看参考站。http/https only。
164
- makeScreenshotUrlTool({ projectId, ctx }),
165
-
166
- // deliver_files — agent 挑好的产物直接进用户浏览器下载列表(emit run.download_ready)
167
- makeDeliverFilesTool({ workspaceRoot, projectId, sessionId, ctx }),
168
-
169
- // read_document — Word / Excel / PowerPoint 的读取口(2026-08-07)。
170
- // 普通 Read 读这三种只会拿到二进制乱码**而且不报错**,agent 会拿着空气
171
- // 往下干。PDF 不在此列:Read 原生支持,真跑验过。
172
- makeReadDocumentTool({ workspaceRoot, sharedRoot }),
173
-
174
- // 酒馆 JSON 读取口:预设/角色卡/世界书先摘要再取正文(Read 会被 460KB 预设撑爆)
175
- makeReadTavernJsonTool({ workspaceRoot, sharedRoot }),
176
-
177
- // C10 export_handoff — 复用 exports.js 的 buildHandoffZip,写到 workspace/exports/
178
- makeExportHandoffTool({ workspaceRoot, sharedRoot, projectId, sessionId, ctx }),
179
-
180
- // C11 record_decision — 写入 spec.json decisions[] 设计意图档案
181
- makeRecordDecisionTool({ workspaceRoot, sessionId, ctx }),
182
-
183
- // crystallize_skill — 把探索出来的方法论固化成用户自己的 skill + 作品进橱窗
184
- // (2026-07-30)。用户明确要求才调;写的是判断依据不是成品 HTML。
185
- makeCrystallizeSkillTool({ projectId, sessionId, ctx }),
186
-
187
- // publish_site — 站点一键上线 Cloudflare Pages(2026-08-02)。用户明确要求
188
- // 才调(发公网是外发动作);额度按项目 owner 算,与站点窗按钮共用一套闸门。
189
- makePublishSiteTool({ projectId }),
190
-
191
- // roll_film — 自部署 MiniMax-H3 视频产线(2026-08-08)。默认走站主 5090
192
- // 盒子(h3box over SSH;Modal 余额告急降备用档,NODESIGN_FILM_BACKEND=modal
193
- // 显式才走,绝不自动回退烧余额);配方恒定 Turbo8步 ≤12.25s;试用号拒
194
- // (owner 闸门同 publish_site)。视觉 QC 归用户,工具只回文本路径。
195
- makeRollFilmTool({ workspaceRoot, sharedRoot, projectId, sessionId, ctx }),
196
-
197
- // paint_still — 站主本地 GPU 盒子生图(NoobAI/Anima,2026-08-08)。盒子
198
- // 在线才可用(NODESIGN_H3BOX_SSH);动漫向/视频关键帧首选,通用生图仍走
199
- // generate_image。视觉 QC 归用户。
200
- makePaintStillTool({ workspaceRoot, sharedRoot, projectId, sessionId, ctx }),
201
-
202
- // lookup_tags — danbooru 标签画前查询(2026-08-20)。paint_still 画完的体检
203
- // 只能事后说"这批图别信";这个把查的动作挪到画前,配手册的起手纪律
204
- // (先理解用户要什么 → 想候选标签 → 查 → 再画)。薄壳,逻辑与体检共用
205
- // lib/danbooru-tags.js。deferred:名字自解释,且 paint_still 描述里点了名。
206
- makeLookupTagsTool(),
207
-
208
- // report_issue — agent 给维护者写信(08-02 由 report_friction 扩容改名):
209
- // bug / friction / idea 三类走同一张 issues 表。跟 PostToolUseFailure 的
210
- // 自动记录分工:自动层记"发生了什么",这层补"为什么难受、期望怎样"。
211
- makeReportIssueTool({ projectId, sessionId, ctx }),
212
-
213
- // web_search — 4 provider 联网搜索(baidu/tavily/exa/zhipu,CJK auto route to baidu)
214
- // 移植自 ~/.deskclaw/skills/deskclaw-search-pro/scripts/search.py,0 外部依赖。
215
- // WebFetch 不在这里 — 用 SDK 内置(session-loop.js DEFAULT_TOOL_ALLOWLIST 启用),
216
- // 它自带 LLM summarize 能控制上下文,不需要自实现。
217
- withTierGate(makeWebSearchTool({ workspaceRoot, sharedRoot, ctx }), 'webSearch', projectId), // basic 档有日上限
218
-
219
- // S1c canvas 焕新升级 — read_page 让 agent 精确读 canvas.html 任意页
220
- // (`<section data-page="N">` 一段),不必 Read 整文件 + Grep + offset/limit。
221
- // 解 2026-05-02 用户观察"agent 只看第一页"痛点。
222
- makeReadPageTool({ workspaceRoot, sessionId, ctx }),
223
-
224
- // ── Canvas 焕新 C1(2026-05-02):完整 agent "感知 + 操作" 工具链 ──
225
- // 感知层:list_pages / query_elements / get_computed_styles —— playwright
226
- // headless 跑出来真实 render 后的元数据,agent 不再盲改
227
- makeListPagesTool({ workspaceRoot, projectId, sessionId, ctx }),
228
- queryElements,
229
-
230
- // profile_scroll — 滚动性能量具(2026-08-18)。用户说"一顿一顿"时 agent
231
- // 以前手里零工具,只能自己起 http server 手搓 rAF 采样。不进常驻工具表
232
- // (deferred,用得上时自然搜到),schema 不白占每轮上下文。
233
- makeProfileScrollTool({ workspaceRoot, projectId, sessionId }),
234
-
235
- // explain_style — CSS 级联诊断(2026-08-18)。computed 只给结果不给原因,
236
- // 而 agent 手里没有 devtools 的 Styles 面板。同样走 deferred。
237
- explainStyle,
238
-
239
- // trace_motion — 动画数值示波器(2026-08-19,iss_mszv782a_toab)。缓动/过冲/
240
- // 硬切从"看静帧猜"变成逐帧采样量出来。deferred:名字自解释,且常驻的
241
- // screenshot_canvas 描述里点了名(胶片条管看、这个管量)。
242
- traceMotion,
243
-
244
- // ── 浏览通道(2026-08-18):agent 真的会用浏览器 ──
245
- // 常驻一个 chromium(按项目键、带持久 profile),所以能点链接、翻子页、
246
- // 留住登录态。跟 screenshot_url 的分工:那个是一次性一张图,这组是有会话的逛。
247
- // ⭐ 每个请求都过 lib/ssrf-guard.js 的出网闸(含跳转每一跳、iframe、子资源),
248
- // 闸在工具实现体里,agent 关不掉。**全部常驻**(理由见 ALWAYS_LOAD_TOOLS)。
249
- //
250
- // ⚠️ 刻意**没给 explorer 子代理**:registry 按 projectId 键 = 主 agent 和
251
- // 子代理共用同一只浏览器、同一个 page。mutex 保证不撕裂,但保证不了不抢 ——
252
- // 子代理一导航就把主 agent 正在看的那一页带走了,症状是"我刚打开的页面
253
- // 自己变了"。要给的话得先有"借用后还原"(存 URL、用完 goto 回去),
254
- // 或者第二个常驻名额;1 vCPU 上后者不成立。
255
- ...browseBatchable,
256
- // 一次往返跑一串(串行、遇错即停、结尾补截图)—— 省的是模型回合数
257
- makeBrowserBatchTool({ tools: browseBatchable }),
258
- // ── 产物会话(2026-08-21):成品检查的交互半边 ──
259
- // artifact_open 把产物开进常驻会话,artifact_computer/find 对着它点、敲、找;
260
- // 五个量具 live:true 就量会话里现在这一页;artifact_batch 一趟跑一串。
261
- ...artifactSessionTools,
262
- makeArtifactBatchTool({ tools: [...artifactSessionTools, screenshotCanvas, queryElements, getComputedStyles, explainStyle, traceMotion] }),
263
- // 撞验证墙时举手叫人(阻塞等,默认 120 秒超时 —— 人可能就走了)
264
- makeBrowserRequestHelpTool({ projectId, ctx }),
265
- getComputedStyles,
266
-
267
- // 控制层:emit 反向事件给前端,server 主动操作 canvas UI
268
- makeNavigateToPageTool({ ctx }),
269
- makeHighlightTool({ ctx }),
270
- // 把 deck 摊到用户眼前(= 用户双击那张卡):收起态→内嵌渲染,展开态→最大化窗
271
- makePreviewDeckTool({ ctx, sessionId, workspaceRoot }),
272
-
273
- // word 形态的构建道:token JSON(真相源)→ .docx(产物)。
274
- // agent 拿到的是一条命令不是一个构建系统 —— 写 JSON、调它、再 screenshot 看。
275
- makeBuildDocxTool({ workspaceRoot, sessionId, ctx }),
276
-
277
- // 反馈层:用户在 canvas 上的直接编辑 + 评论 buffer
278
- // 前端在 chat 时由 turn.js 注入 system 提示,agent 主动调下面两个工具读 + 清
279
- makeGetPendingChangesTool({ workspaceRoot, ctx }),
280
- makeClearPendingChangesTool({ workspaceRoot, ctx }),
281
-
282
- // Tweaks 协议:agent 暴露 deck 专属可调参数 schema → 前端按 schema 渲染控件
283
- makeExposeTweaksTool({ workspaceRoot, ctx }),
284
-
285
- // 图片生成(gemini-3.1-flash-image-preview / Nano Banana 2,via NoDesk passthrough)
286
- // 落档优先 sharedRoot/assets/generated/,fallback workspaceRoot/assets/generated/。
287
- // 跨 session 共享靠 sessions/<sid>/assets softlink → shared/assets。
288
- withTierGate(makeGenerateImageTool({ workspaceRoot, sharedRoot, ctx }), 'imageGen', projectId, ctx), // 先过日限,出图记 $0.20/张
289
-
290
- // 抠图(rembg U²-Net,server 端 spawn .venv-rembg python subprocess)
291
- // 任何 workspace 里的图都能抠,输出 RGBA PNG 到 assets/generated/<name>.png。
292
- // 跟 generate_image 解耦:generate_image 只生图,想透明叠加单独调本工具。
293
- makeRemoveBackgroundTool({ workspaceRoot, sharedRoot, projectId, ctx }),
294
-
295
- // 工作台分区画布(2026-07-27):agent 协助摆放 —— 把产物/文档/deck 钉进
296
- // 某 session 的工作区。写 board.json(board-store 单锁)+ 广播 board.updated。
297
- makePinToBoardTool({ sharedRoot, projectId, ctx }),
298
-
299
- // 关系线(2026-08-07):agent 把「这版改自那版」「这两个是对照」这类
300
- // **只有它知道**的关系画到画布上。画布知道每个产物是什么,但不知道它们
301
- // 之间是什么关系 —— 那是北极星(排出有版面感的布局)真正缺的那一块。
302
- makeRelateOnBoardTool({ projectId, ctx }),
303
- // agent 摆位四件(2026-08-14):看版面 / 语义摆位·立主角 / 落手写便签 / 归纳收纳
304
- makeReadBoardTool({ projectId }),
305
- makeArrangeOnBoardTool({ projectId, ctx }),
306
- makeCreateOnBoardTool({ projectId, ctx }),
307
- makeOrganizeBoardTool({ projectId, ctx }),
308
-
309
- // 注:Phase Image-2 的 request_image_approval 工具已废弃(2026-05-06)。
310
- // generate_image 的 CallToolResult 已返 image content block,前端自动渲染;
311
- // agent 在 caption / 自然回话邀请反馈,下一轮用户 chat 即天然 gate。
312
- ].map((t) => (
313
- // SDK 用 _meta['anthropic/alwaysLoad'] 标记常驻(tool() 第 5 参的等价物,
314
- // 集中在这打标避免改 16 个工具文件)
315
- ALWAYS_LOAD_TOOLS.has(t.name)
316
- ? { ...t, _meta: { ...t._meta, 'anthropic/alwaysLoad': true } }
317
- : t
318
- )).map((t) => (
319
- // 本机能力闸(08-22):缺 chromium / LibreOffice / 钥匙 的工具,描述前缀「不可用 + 装法」、调用期拦住。
320
- // 对照表在 capability-gate.js 一份;没探过(单测)原样放行
321
- withCapabilityGate(t)
322
- )).map((t) => (
323
- // 参数标签泄漏消毒(2026-08-19):上游偶发把下一个参数吞进上一个字符串参数
324
- // (</rationale><parameter name="scope">… 原样落进 tool_use.input,会话
325
- // 008fe16c 4/4 实锤)。挂在出口包全部工具 —— 哪个工具中招看 recordIssue。
326
- withParamSanitizer(t, { projectId, sessionId })
327
- ));
328
-
329
- const server = createSdkMcpServer({
330
- name: 'nodesign',
331
- version: '0.1.0',
332
- tools,
333
- });
334
- // 开局契约自检用(2026-08-14 灭门案第 3 层):预期工具名从构造本 server 的
335
- // 同一份 tools 数组上取,不另立第二份清单 —— 第二真相源会漂移。session-loop
336
- // 收到 system:init 时拿它跟 SDK 实际注册进会话的工具对账。
337
- server.toolNames = tools.map((t) => t.name);
338
- return server;
339
- }
1
+ /**
2
+ * server/engine/mcp/index.js — Nodesign 内置 MCP server
3
+ *
4
+ * 暴露给 agent 的自定义工具集(in-process,via SDK 的 createSdkMcpServer):
5
+ *
6
+ * 感知层(playwright headless 跑出真实渲染元数据):
7
+ * screenshot_canvas / list_pages / read_page / query_elements / get_computed_styles
8
+ * 控制层(emit 事件让前端同步):
9
+ * navigate_to_page / highlight / preview_deck
10
+ * 反馈层(用户在 canvas 上的直接编辑 + 评论 buffer):
11
+ * get_pending_changes / clear_pending_changes
12
+ * 产物层(NoDesign 差异化能力):
13
+ * expose_tweaks / export_handoff / record_decision
14
+ * 研究层:
15
+ * web_search(4 provider,CJK auto baidu)
16
+ *
17
+ * 调用约定(SDK 自动给 tool name 加前缀):
18
+ * tool 名在 agent 端是 mcp__nodesign__<tool>,比如 mcp__nodesign__screenshot_canvas
19
+ *
20
+ * 实例化策略:
21
+ * 每个 runAgent 创建一个新的 MCP server 实例(through createNodesignMcpServer)。
22
+ * 开销小(in-process,没起 process),但能让 deps(workspaceRoot / projectId / ctx)
23
+ * 绑死到当前 turn 的上下文,避免 cross-talk。
24
+ *
25
+ * 安全:
26
+ * tool handler 在 SDK 进程内(本服务器进程)跑,不通过 stdio/sse/http。
27
+ * handler 自己不做沙盒,由 PreToolUse hook + workspace cwd 隔离兜底。
28
+ */
29
+
30
+ import { createSdkMcpServer } from '@anthropic-ai/claude-agent-sdk';
31
+ import { withParamSanitizer } from './param-sanitizer.js';
32
+ import { withCapabilityGate } from './capability-gate.js';
33
+ import { makeScreenshotCanvasTool } from './tools/screenshot.js';
34
+ import { makeScreenshotUrlTool } from './tools/screenshot-url.js';
35
+ import { makeExportHandoffTool } from './tools/export-handoff.js';
36
+ import { makeRecordDecisionTool } from './tools/record-decision.js';
37
+ import { makeWebSearchTool } from './tools/web-search.js';
38
+ import { withTierGate } from './tools/tier-gate.js'; // 档位闸包装器(auth/tier.js;按项目 owner)
39
+ import { makeReadPageTool } from './tools/read-page.js';
40
+ import { makeListPagesTool } from './tools/list-pages.js';
41
+ import { makeQueryElementsTool } from './tools/query-elements.js';
42
+ import { makeProfileScrollTool } from './tools/profile-scroll.js';
43
+ import { makeExplainStyleTool } from './tools/explain-style.js';
44
+ import { makeTraceMotionTool } from './tools/trace-motion.js';
45
+ import {
46
+ makeBrowserNavigateTool, makeBrowserReadTool, makeBrowserClickTool,
47
+ makeBrowserRequestHelpTool, makeBrowserCaptureTool,
48
+ } from './tools/browse.js';
49
+ import { makeBrowserScreenshotTool } from './tools/browse-screenshot.js';
50
+ import { makeBrowserComputerTool } from './tools/browse-computer.js';
51
+ import { makeBrowserFindTool, makeBrowserBatchTool } from './tools/browse-find-batch.js';
52
+ import { makeArtifactOpenTool, makeArtifactComputerTool, makeArtifactFindTool, makeArtifactMotionTool, makeArtifactBatchTool } from './tools/artifact-session.js';
53
+ import { makeGetComputedStylesTool } from './tools/get-computed-styles.js';
54
+ import { makeNavigateToPageTool } from './tools/navigate-to-page.js';
55
+ import { makeHighlightTool } from './tools/highlight.js';
56
+ import { makePreviewDeckTool } from './tools/preview-deck.js';
57
+ import { makeBuildDocxTool } from './tools/build-docx.js';
58
+ import { makeExposeTweaksTool } from './tools/expose-tweaks.js';
59
+ import { makeGetPendingChangesTool } from './tools/get-pending-changes.js';
60
+ import { makeClearPendingChangesTool } from './tools/clear-pending-changes.js';
61
+ import { makeGenerateImageTool } from './tools/generate-image.js';
62
+ import { makeRemoveBackgroundTool } from './tools/remove-background.js';
63
+ import { makePinToBoardTool } from './tools/pin-to-board.js';
64
+ import { makeRelateOnBoardTool } from './tools/relate-on-board.js';
65
+ 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 { makeOrganizeBoardTool } from './tools/organize-board.js';
69
+ import { makeReadDocumentTool } from './tools/read-document.js';
70
+ import { makeReadTavernJsonTool } from './tools/read-tavern-json.js';
71
+ import { makeDeliverFilesTool } from './tools/deliver-files.js';
72
+ import { makeCrystallizeSkillTool } from './tools/crystallize-skill.js';
73
+ import { makePublishSiteTool } from './tools/publish-site.js';
74
+ import { makeReportIssueTool } from './tools/report-issue.js';
75
+ import { makeRollFilmTool } from './tools/roll-film.js';
76
+ import { makePaintStillTool } from './tools/paint-still.js';
77
+ import { makeLookupTagsTool } from './tools/lookup-tags.js';
78
+
79
+ /**
80
+ * 创建 Nodesign 的 MCP server,绑定当前 run 的依赖。
81
+ *
82
+ * @param {object} deps
83
+ * @param {string} deps.workspaceRoot 绝对路径,project workspace(sessions/<sid>/)
84
+ * @param {string} [deps.sharedRoot] project shared/ 根(跨 session 共享 assets / .claude)
85
+ * @param {string} [deps.projectId]
86
+ * @param {string} [deps.sessionId] NoDesign sessionId(活跃产物指针 / 会话级锁 / 出处记账用)
87
+ * @param {import('../agent/context.js').AgentContext} [deps.ctx] EventBus 入口
88
+ * @returns SDK MCP server config(喂给 query options.mcpServers)
89
+ */
90
+ // 常驻 schema 白名单(2026-07-23 订阅模式 token 瘦身):
91
+ // 高频 + schema 小的工具第一 turn 就注入 prompt;不在名单里的走 SDK 默认
92
+ // deferred —— system prompt 只留工具名,agent 用 ToolSearch 按需拉 schema
93
+ // (需要 ENABLE_TOOL_SEARCH=true + allowlist 含 ToolSearch,见 session-loop)。
94
+ // 实测 defer 掉 generate_image/web_search/remove_background 等 6 个胖工具
95
+ // 省 ~80k 字符常驻 schema。prelude 的工具速查表仍列全部工具名 + 一句话用途,
96
+ // agent 知道存在什么、需要时先 ToolSearch("select:mcp__nodesign__<tool>")。
97
+ // (kimi 时代曾全局 alwaysLoad —— kimi 不认 ToolSearch;claude 系模型原生受训,可放心 defer)
98
+ const ALWAYS_LOAD_TOOLS = new Set([
99
+ 'screenshot_canvas', 'read_page', 'list_pages', 'query_elements',
100
+ 'get_computed_styles', 'navigate_to_page', 'highlight', 'preview_deck',
101
+ 'record_decision', 'get_pending_changes', 'clear_pending_changes',
102
+ // screenshot_url 常驻:explorer 显式 tools 列表没有 ToolSearch,defer 了它就
103
+ // 永远拉不到 schema;schema 本身很小(4 字段),常驻成本可忽略
104
+ 'screenshot_url',
105
+ // ⭐ 浏览通道六件(2026-08-18 当天从 deferred 改常驻;08-21 加到九件,见下)。
106
+ //
107
+ // 它们最初跟着「新工具默认 deferred」的习惯走,而那条习惯的依据是**成本**:
108
+ // defer 掉的是 expose_tweaks / paint_still / roll_film 那种十万字符级的胖子。
109
+ // 这六个实测 description 合计 4980 字符、连参数区 ≈ 6.9k —— 比那几个小
110
+ // 30~100 倍,塞进被缓存的 system prompt 每轮增量约等于零。
111
+ //
112
+ // 而 deferred 的代价是具体的:agent 只看得到**名字**。`browser_capture`
113
+ // 这个名字一个字都没说它能带回调色板、字体、命中的 CSS 规则和结构三数 ——
114
+ // 于是它不会去搜这个 schema,做 deck / 做文档的会话里整条浏览通道等于不存在
115
+ // (只有加载了 site-craft skill 才会被点名)。**名字自解释的工具可以 defer,
116
+ // 卖点藏在描述里的不能。**
117
+ 'browser_navigate', 'browser_read', 'browser_click', 'browser_screenshot',
118
+ 'browser_request_help', 'browser_capture',
119
+ // 08-21 加的三件(坐标/引用级操作 + 词法找元 + 一次往返跑一串)。同一条理由:
120
+ // browser_batch 的卖点"省掉模型往返"和 browser_find 的"ref 比像素稳"都在描述里,
121
+ // 名字本身不卖;三件描述合计 ≈ 5.5k 字符,缓存里每轮增量约等于零。
122
+ 'browser_computer', 'browser_find', 'browser_batch',
123
+ // 08-21 产物会话五件:成品检查的交互半边(状态跨调用留着)。artifact_batch 的卖点
124
+ // "一趟跑完 + 结尾截图"和 live:true 的存在都只在描述里说,常驻。
125
+ 'artifact_open', 'artifact_computer', 'artifact_find', 'artifact_batch', 'artifact_motion',
126
+ ]);
127
+
128
+ export function createNodesignMcpServer({ workspaceRoot, sharedRoot, projectId, sessionId, ctx } = {}) {
129
+ // 浏览通道里能被 browser_batch 串起来的七件:先建一次,batch 拿**同一批实例**
130
+ // (projectId/ctx 绑在 handler 里,不能再造第二份)。只有 request_help 不进
131
+ // batch(它阻塞等人);capture 在里面 —— 逐页采 token 正是 batch 要省的那种回合。
132
+ const browseBatchable = [
133
+ makeBrowserNavigateTool({ projectId, ctx }),
134
+ makeBrowserReadTool({ projectId }),
135
+ makeBrowserClickTool({ projectId }),
136
+ makeBrowserScreenshotTool({ projectId, workspaceRoot }),
137
+ // 采集:把可复用的东西(调色板/字体/CSS/结构骨架/截图)落进
138
+ // assets/references/web/ + 出处 sidecar —— 下个会话还在
139
+ makeBrowserCaptureTool({ projectId, workspaceRoot, sessionId, ctx }),
140
+ // 坐标/引用级指针与键盘 + 词法找元(08-21,形状照 browser_toolset_20260801)
141
+ makeBrowserComputerTool({ projectId, ctx }),
142
+ makeBrowserFindTool({ projectId }),
143
+ ];
144
+ // 五个能骑到产物会话上(live:true)的量具:先建一次,artifact_batch 拿同一批实例
145
+ const screenshotCanvas = makeScreenshotCanvasTool({ workspaceRoot, projectId, sessionId, ctx });
146
+ const queryElements = makeQueryElementsTool({ workspaceRoot, projectId, sessionId, ctx });
147
+ const getComputedStyles = makeGetComputedStylesTool({ workspaceRoot, projectId, sessionId, ctx });
148
+ const explainStyle = makeExplainStyleTool({ workspaceRoot, projectId, sessionId });
149
+ const traceMotion = makeTraceMotionTool({ workspaceRoot, projectId, sessionId });
150
+ // 产物会话四件(engine/perception/session.js):artifact_open / computer / find / motion
151
+ const artifactSessionTools = [
152
+ makeArtifactOpenTool({ projectId, workspaceRoot, sessionId }),
153
+ makeArtifactComputerTool({ projectId }),
154
+ makeArtifactFindTool({ projectId }),
155
+ // 自己的产物靠什么在动:跟 browser_capture motion 同一份引擎(engine/motion/inventory.js)
156
+ makeArtifactMotionTool({ projectId, workspaceRoot, sessionId }),
157
+ ];
158
+ const tools = [
159
+ // C9 screenshot_canvas — playwright headless 截图 → image content block
160
+ screenshotCanvas,
161
+
162
+ // screenshot_url — 外部 URL 截图(2026-07-29)。explorer 找视觉参考不再
163
+ // 只能 WebFetch 文本转述;主 agent 也能直接看参考站。http/https only。
164
+ makeScreenshotUrlTool({ projectId, ctx }),
165
+
166
+ // deliver_files — agent 挑好的产物直接进用户浏览器下载列表(emit run.download_ready)
167
+ makeDeliverFilesTool({ workspaceRoot, projectId, sessionId, ctx }),
168
+
169
+ // read_document — Word / Excel / PowerPoint 的读取口(2026-08-07)。
170
+ // 普通 Read 读这三种只会拿到二进制乱码**而且不报错**,agent 会拿着空气
171
+ // 往下干。PDF 不在此列:Read 原生支持,真跑验过。
172
+ makeReadDocumentTool({ workspaceRoot, sharedRoot }),
173
+
174
+ // 酒馆 JSON 读取口:预设/角色卡/世界书先摘要再取正文(Read 会被 460KB 预设撑爆)
175
+ makeReadTavernJsonTool({ workspaceRoot, sharedRoot }),
176
+
177
+ // C10 export_handoff — 复用 exports.js 的 buildHandoffZip,写到 workspace/exports/
178
+ makeExportHandoffTool({ workspaceRoot, sharedRoot, projectId, sessionId, ctx }),
179
+
180
+ // C11 record_decision — 写入 spec.json decisions[] 设计意图档案
181
+ makeRecordDecisionTool({ workspaceRoot, sessionId, ctx }),
182
+
183
+ // crystallize_skill — 把探索出来的方法论固化成用户自己的 skill + 作品进橱窗
184
+ // (2026-07-30)。用户明确要求才调;写的是判断依据不是成品 HTML。
185
+ makeCrystallizeSkillTool({ projectId, sessionId, ctx }),
186
+
187
+ // publish_site — 站点一键上线 Cloudflare Pages(2026-08-02)。用户明确要求
188
+ // 才调(发公网是外发动作);额度按项目 owner 算,与站点窗按钮共用一套闸门。
189
+ makePublishSiteTool({ projectId }),
190
+
191
+ // roll_film — 自部署 MiniMax-H3 视频产线(2026-08-08)。默认走站主 5090
192
+ // 盒子(h3box over SSH;Modal 余额告急降备用档,NODESIGN_FILM_BACKEND=modal
193
+ // 显式才走,绝不自动回退烧余额);配方恒定 Turbo8步 ≤12.25s;试用号拒
194
+ // (owner 闸门同 publish_site)。视觉 QC 归用户,工具只回文本路径。
195
+ makeRollFilmTool({ workspaceRoot, sharedRoot, projectId, sessionId, ctx }),
196
+
197
+ // paint_still — 站主本地 GPU 盒子生图(NoobAI/Anima,2026-08-08)。盒子
198
+ // 在线才可用(NODESIGN_H3BOX_SSH);动漫向/视频关键帧首选,通用生图仍走
199
+ // generate_image。视觉 QC 归用户。
200
+ makePaintStillTool({ workspaceRoot, sharedRoot, projectId, sessionId, ctx }),
201
+
202
+ // lookup_tags — danbooru 标签画前查询(2026-08-20)。paint_still 画完的体检
203
+ // 只能事后说"这批图别信";这个把查的动作挪到画前,配手册的起手纪律
204
+ // (先理解用户要什么 → 想候选标签 → 查 → 再画)。薄壳,逻辑与体检共用
205
+ // lib/danbooru-tags.js。deferred:名字自解释,且 paint_still 描述里点了名。
206
+ makeLookupTagsTool(),
207
+
208
+ // report_issue — agent 给维护者写信(08-02 由 report_friction 扩容改名):
209
+ // bug / friction / idea 三类走同一张 issues 表。跟 PostToolUseFailure 的
210
+ // 自动记录分工:自动层记"发生了什么",这层补"为什么难受、期望怎样"。
211
+ makeReportIssueTool({ projectId, sessionId, ctx }),
212
+
213
+ // web_search — 4 provider 联网搜索(baidu/tavily/exa/zhipu,CJK auto route to baidu)
214
+ // 移植自 ~/.deskclaw/skills/deskclaw-search-pro/scripts/search.py,0 外部依赖。
215
+ // WebFetch 不在这里 — 用 SDK 内置(session-loop.js DEFAULT_TOOL_ALLOWLIST 启用),
216
+ // 它自带 LLM summarize 能控制上下文,不需要自实现。
217
+ withTierGate(makeWebSearchTool({ workspaceRoot, sharedRoot, ctx }), 'webSearch', projectId), // basic 档有日上限
218
+
219
+ // S1c canvas 焕新升级 — read_page 让 agent 精确读 canvas.html 任意页
220
+ // (`<section data-page="N">` 一段),不必 Read 整文件 + Grep + offset/limit。
221
+ // 解 2026-05-02 用户观察"agent 只看第一页"痛点。
222
+ makeReadPageTool({ workspaceRoot, sessionId, ctx }),
223
+
224
+ // ── Canvas 焕新 C1(2026-05-02):完整 agent "感知 + 操作" 工具链 ──
225
+ // 感知层:list_pages / query_elements / get_computed_styles —— playwright
226
+ // headless 跑出来真实 render 后的元数据,agent 不再盲改
227
+ makeListPagesTool({ workspaceRoot, projectId, sessionId, ctx }),
228
+ queryElements,
229
+
230
+ // profile_scroll — 滚动性能量具(2026-08-18)。用户说"一顿一顿"时 agent
231
+ // 以前手里零工具,只能自己起 http server 手搓 rAF 采样。不进常驻工具表
232
+ // (deferred,用得上时自然搜到),schema 不白占每轮上下文。
233
+ makeProfileScrollTool({ workspaceRoot, projectId, sessionId }),
234
+
235
+ // explain_style — CSS 级联诊断(2026-08-18)。computed 只给结果不给原因,
236
+ // 而 agent 手里没有 devtools 的 Styles 面板。同样走 deferred。
237
+ explainStyle,
238
+
239
+ // trace_motion — 动画数值示波器(2026-08-19,iss_mszv782a_toab)。缓动/过冲/
240
+ // 硬切从"看静帧猜"变成逐帧采样量出来。deferred:名字自解释,且常驻的
241
+ // screenshot_canvas 描述里点了名(胶片条管看、这个管量)。
242
+ traceMotion,
243
+
244
+ // ── 浏览通道(2026-08-18):agent 真的会用浏览器 ──
245
+ // 常驻一个 chromium(按项目键、带持久 profile),所以能点链接、翻子页、
246
+ // 留住登录态。跟 screenshot_url 的分工:那个是一次性一张图,这组是有会话的逛。
247
+ // ⭐ 每个请求都过 lib/ssrf-guard.js 的出网闸(含跳转每一跳、iframe、子资源),
248
+ // 闸在工具实现体里,agent 关不掉。**全部常驻**(理由见 ALWAYS_LOAD_TOOLS)。
249
+ //
250
+ // ⚠️ 刻意**没给 explorer 子代理**:registry 按 projectId 键 = 主 agent 和
251
+ // 子代理共用同一只浏览器、同一个 page。mutex 保证不撕裂,但保证不了不抢 ——
252
+ // 子代理一导航就把主 agent 正在看的那一页带走了,症状是"我刚打开的页面
253
+ // 自己变了"。要给的话得先有"借用后还原"(存 URL、用完 goto 回去),
254
+ // 或者第二个常驻名额;1 vCPU 上后者不成立。
255
+ ...browseBatchable,
256
+ // 一次往返跑一串(串行、遇错即停、结尾补截图)—— 省的是模型回合数
257
+ makeBrowserBatchTool({ tools: browseBatchable }),
258
+ // ── 产物会话(2026-08-21):成品检查的交互半边 ──
259
+ // artifact_open 把产物开进常驻会话,artifact_computer/find 对着它点、敲、找;
260
+ // 五个量具 live:true 就量会话里现在这一页;artifact_batch 一趟跑一串。
261
+ ...artifactSessionTools,
262
+ makeArtifactBatchTool({ tools: [...artifactSessionTools, screenshotCanvas, queryElements, getComputedStyles, explainStyle, traceMotion] }),
263
+ // 撞验证墙时举手叫人(阻塞等,默认 120 秒超时 —— 人可能就走了)
264
+ makeBrowserRequestHelpTool({ projectId, ctx }),
265
+ getComputedStyles,
266
+
267
+ // 控制层:emit 反向事件给前端,server 主动操作 canvas UI
268
+ makeNavigateToPageTool({ ctx }),
269
+ makeHighlightTool({ ctx }),
270
+ // 把 deck 摊到用户眼前(= 用户双击那张卡):收起态→内嵌渲染,展开态→最大化窗
271
+ makePreviewDeckTool({ ctx, sessionId, workspaceRoot }),
272
+
273
+ // word 形态的构建道:token JSON(真相源)→ .docx(产物)。
274
+ // agent 拿到的是一条命令不是一个构建系统 —— 写 JSON、调它、再 screenshot 看。
275
+ makeBuildDocxTool({ workspaceRoot, sessionId, ctx }),
276
+
277
+ // 反馈层:用户在 canvas 上的直接编辑 + 评论 buffer
278
+ // 前端在 chat 时由 turn.js 注入 system 提示,agent 主动调下面两个工具读 + 清
279
+ makeGetPendingChangesTool({ workspaceRoot, ctx }),
280
+ makeClearPendingChangesTool({ workspaceRoot, ctx }),
281
+
282
+ // Tweaks 协议:agent 暴露 deck 专属可调参数 schema → 前端按 schema 渲染控件
283
+ makeExposeTweaksTool({ workspaceRoot, ctx }),
284
+
285
+ // 图片生成(gemini-3.1-flash-image-preview / Nano Banana 2,via NoDesk passthrough)
286
+ // 落档优先 sharedRoot/assets/generated/,fallback workspaceRoot/assets/generated/。
287
+ // 跨 session 共享靠 sessions/<sid>/assets softlink → shared/assets。
288
+ withTierGate(makeGenerateImageTool({ workspaceRoot, sharedRoot, ctx }), 'imageGen', projectId, ctx), // 先过日限,出图记 $0.20/张
289
+
290
+ // 抠图(rembg U²-Net,server 端 spawn .venv-rembg python subprocess)
291
+ // 任何 workspace 里的图都能抠,输出 RGBA PNG 到 assets/generated/<name>.png。
292
+ // 跟 generate_image 解耦:generate_image 只生图,想透明叠加单独调本工具。
293
+ makeRemoveBackgroundTool({ workspaceRoot, sharedRoot, projectId, ctx }),
294
+
295
+ // 工作台分区画布(2026-07-27):agent 协助摆放 —— 把产物/文档/deck 钉进
296
+ // 某 session 的工作区。写 board.json(board-store 单锁)+ 广播 board.updated。
297
+ makePinToBoardTool({ sharedRoot, projectId, ctx }),
298
+
299
+ // 关系线(2026-08-07):agent 把「这版改自那版」「这两个是对照」这类
300
+ // **只有它知道**的关系画到画布上。画布知道每个产物是什么,但不知道它们
301
+ // 之间是什么关系 —— 那是北极星(排出有版面感的布局)真正缺的那一块。
302
+ makeRelateOnBoardTool({ projectId, ctx }),
303
+ // agent 摆位四件(2026-08-14):看版面 / 语义摆位·立主角 / 落手写便签 / 归纳收纳
304
+ makeReadBoardTool({ projectId }),
305
+ makeArrangeOnBoardTool({ projectId, ctx }),
306
+ makeCreateOnBoardTool({ projectId, ctx }),
307
+ makeOrganizeBoardTool({ projectId, ctx }),
308
+
309
+ // 注:Phase Image-2 的 request_image_approval 工具已废弃(2026-05-06)。
310
+ // generate_image 的 CallToolResult 已返 image content block,前端自动渲染;
311
+ // agent 在 caption / 自然回话邀请反馈,下一轮用户 chat 即天然 gate。
312
+ ].map((t) => (
313
+ // SDK 用 _meta['anthropic/alwaysLoad'] 标记常驻(tool() 第 5 参的等价物,
314
+ // 集中在这打标避免改 16 个工具文件)
315
+ ALWAYS_LOAD_TOOLS.has(t.name)
316
+ ? { ...t, _meta: { ...t._meta, 'anthropic/alwaysLoad': true } }
317
+ : t
318
+ )).map((t) => (
319
+ // 本机能力闸(08-22):缺 chromium / LibreOffice / 钥匙 的工具,描述前缀「不可用 + 装法」、调用期拦住。
320
+ // 对照表在 capability-gate.js 一份;没探过(单测)原样放行
321
+ withCapabilityGate(t)
322
+ )).map((t) => (
323
+ // 参数标签泄漏消毒(2026-08-19):上游偶发把下一个参数吞进上一个字符串参数
324
+ // (</rationale><parameter name="scope">… 原样落进 tool_use.input,会话
325
+ // 008fe16c 4/4 实锤)。挂在出口包全部工具 —— 哪个工具中招看 recordIssue。
326
+ withParamSanitizer(t, { projectId, sessionId })
327
+ ));
328
+
329
+ const server = createSdkMcpServer({
330
+ name: 'nodesign',
331
+ version: '0.1.0',
332
+ tools,
333
+ });
334
+ // 开局契约自检用(2026-08-14 灭门案第 3 层):预期工具名从构造本 server 的
335
+ // 同一份 tools 数组上取,不另立第二份清单 —— 第二真相源会漂移。session-loop
336
+ // 收到 system:init 时拿它跟 SDK 实际注册进会话的工具对账。
337
+ server.toolNames = tools.map((t) => t.name);
338
+ return server;
339
+ }