@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,277 +1,277 @@
1
- /**
2
- * PreToolUse 首调注入族 —— 各工具的 reference 文档 / 起手提醒,agent 首次调
3
- * 对应工具时才进 context(不放系统 prompt 恒驻,每 turn 拖累)。
4
- * (2026-08-14 可维护性行动:从 hooks.js 原样迁出,语义零改动)
5
- *
6
- * 共同模式:closure 里一个 alreadyInjected 布尔(或 per-kind Set),每 session
7
- * 只注一次;permissionDecision='allow' 不阻塞工具。
8
- */
9
- import path from 'node:path';
10
- import { toWorkspaceRel } from '../../../lib/workspace-path.js';
11
- import { kindOfPath, kindDef, KIND_DECK } from '../../../lib/artifact-target.js';
12
- import { loadToolPrompt } from './tool-prompts.js';
13
-
14
- /**
15
- * PreToolUse(get_pending_changes) — 第一次调用时注入 DirectEdit 逐 kind
16
- * 处理协议全文(字段结构 / pending-move 语义 / 邻居保护 / preDragLayout /
17
- * constraint anchor 表)。prelude 常驻部分只留流程骨架 + 语义底线三条,
18
- * ~90 行细则在 agent 真的要处理 pending changes 时才进 context。
19
- */
20
- export function makePreToolUseGetPendingChangesProtocolInjector() {
21
- let alreadyInjected = false;
22
- return async (_input, _toolUseId, _options) => {
23
- if (alreadyInjected) return {};
24
- alreadyInjected = true;
25
- const protocol = loadToolPrompt('direct-edit-protocol');
26
- return {
27
- hookSpecificOutput: {
28
- hookEventName: 'PreToolUse',
29
- permissionDecision: 'allow',
30
- additionalContext:
31
- '<system-reminder>\n[DirectEdit 逐 kind 处理协议 — 首次注入]\n\n'
32
- + protocol
33
- + '\n\n本协议每 session 只注入一次,后续处理 pending changes 直接按它做。\n'
34
- + '</system-reminder>',
35
- },
36
- };
37
- };
38
- }
39
-
40
- /**
41
- * PreToolUse(AskUserQuestion) — 第一次问用户时注入 NoDesign 的问法协议
42
- * (何时用卡片 vs chat、schema、写选项的诀窍、preview 字段的两种形态与限制)。
43
- * 常驻在 prelude 里是 1.2k tokens,但一次会话里可能一次都用不上。
44
- */
45
- export function makePreToolUseAskUserQuestionProtocolInjector() {
46
- let alreadyInjected = false;
47
- return async (_input, _toolUseId, _options) => {
48
- if (alreadyInjected) return {};
49
- alreadyInjected = true;
50
- const protocol = loadToolPrompt('ask-user-question-protocol');
51
- return {
52
- hookSpecificOutput: {
53
- hookEventName: 'PreToolUse',
54
- permissionDecision: 'allow',
55
- additionalContext:
56
- '<system-reminder>\n[AskUserQuestion 协议 — 首次注入]\n\n'
57
- + protocol
58
- + '\n\n本协议每 session 只注入一次,后续问用户直接按它写。\n'
59
- + '</system-reminder>',
60
- },
61
- };
62
- };
63
- }
64
-
65
- /**
66
- * PreToolUse(Write) — 第一次写 .html 时注入该形态的技术参考。
67
- *
68
- * 2026-07-28 加站点后按 kind 分流:以前是"任何 .html 都注入 hybrid deck 参考",
69
- * 于是 agent 写站点首页时会被塞一份讲 `data-page` / `__nd-deck-wrap` / babel 的
70
- * 文档 —— 文不对题,还会诱导它往站点里塞 deck 专属结构。
71
- *
72
- * 两种形态各注一次(一个会话理论上只做一种,但试作阶段可能先摸另一种)。
73
- */
74
- export function makePreToolUseHybridReferenceInjector({ workspaceRoot } = {}) {
75
- const injected = new Set();
76
- return async (input, _toolUseId, _options) => {
77
- const fp = input?.tool_input?.file_path;
78
- if (typeof fp !== 'string') return {};
79
- const rel = workspaceRoot ? toWorkspaceRel(fp, workspaceRoot) : fp;
80
- const kind = workspaceRoot ? await kindOfPath(workspaceRoot, rel) : KIND_DECK;
81
- // 触发条件从「写 .html」改成「写的文件跟这个形态的入口同类型」(2026-08-01)。
82
- // 写死 .html 的年代只有 deck 和 site,两者入口都是 html 所以恰好没错;非 html 入口的形态
83
- // 的入口不是 .html,于是它的技术参考**永远不会被注入**,agent 一辈子不知道
84
- // 目录结构该长什么样。扩展名从注册表的 entryFile 推,加形态不用再回来改。
85
- const wantExt = path.extname(kindDef(kind)?.entryFile || '.html').toLowerCase();
86
- if (path.extname(fp).toLowerCase() !== wantExt) return {};
87
- if (injected.has(kind)) return {};
88
- injected.add(kind);
89
- // 技术参考按注册表分发(kinds/<kind>.referenceDoc)—— 新形态自带自己那份
90
- const meta = kindDef(kind)?.referenceDoc || kindDef(KIND_DECK).referenceDoc;
91
- return {
92
- hookSpecificOutput: {
93
- hookEventName: 'PreToolUse',
94
- permissionDecision: 'allow',
95
- additionalContext:
96
- `<system-reminder>\n[${meta.title} — 首次注入]\n\n`
97
- + loadToolPrompt(meta.file)
98
- + '\n\n本参考每 session 每形态只注入一次。\n'
99
- + '</system-reminder>',
100
- },
101
- };
102
- };
103
- }
104
-
105
- // paint_still 首调注入本地生图手册:四模型选型 + noobai 标签流 + FLUX.2 官方
106
- // 提示词实践(BFL prompting guide 摘要)+ 装卸税排序纪律。
107
- export function makePreToolUsePaintStillCookbookInjector() {
108
- let alreadyInjected = false;
109
- return async (_input, _toolUseId, _options) => {
110
- if (alreadyInjected) return {};
111
- alreadyInjected = true;
112
- const cookbook = loadToolPrompt('paint-still-cookbook');
113
- return {
114
- hookSpecificOutput: {
115
- hookEventName: 'PreToolUse',
116
- permissionDecision: 'allow',
117
- additionalContext:
118
- '<system-reminder>\n[paint_still 本地生图手册 — 首次注入]\n\n'
119
- + cookbook
120
- + '\n\n本手册每 session 只注入一次,后续调用直接照用。\n'
121
- + '</system-reminder>',
122
- },
123
- };
124
- };
125
- }
126
-
127
- // roll_film 首调注入 H3 提示词手册:三字段格式 + 多镜纪律(逐字角色块/同种子)
128
- // + 禁视觉检查。模式与 generate_image cookbook 完全同款。
129
- export function makePreToolUseRollFilmCookbookInjector() {
130
- let alreadyInjected = false;
131
- return async (_input, _toolUseId, _options) => {
132
- if (alreadyInjected) return {};
133
- alreadyInjected = true;
134
- const cookbook = loadToolPrompt('roll-film-cookbook');
135
- return {
136
- hookSpecificOutput: {
137
- hookEventName: 'PreToolUse',
138
- permissionDecision: 'allow',
139
- additionalContext:
140
- '<system-reminder>\n[roll_film H3 提示词手册 — 首次注入]\n\n'
141
- + cookbook
142
- + '\n\n本手册每 session 只注入一次,后续调用直接照用。\n'
143
- + '</system-reminder>',
144
- },
145
- };
146
- };
147
- }
148
-
149
- /**
150
- * PreToolUse(generate_image) — 第一次调用时注 完整 cookbook(A-J 段)。
151
- *
152
- * 配套 SKILL.md 里的精简版 cookbook(5 元素公式 + 渲文字铁律 + 反例正例)保第一张
153
- * 图质量底线;本 hook 注入完整深度内容,让第二张起 agent 拿出更稳的 prompt。
154
- *
155
- * 触发:本 session 第 1 次调 generate_image;后续不再注入(避免 spam)。
156
- * 文件源:prompts/tools/generate-image-cookbook.md(模块加载时缓存)。
157
- */
158
- export function makePreToolUseGenerateImageCookbookInjector() {
159
- let alreadyInjected = false;
160
- return async (_input, _toolUseId, _options) => {
161
- if (alreadyInjected) return {};
162
- alreadyInjected = true;
163
- const cookbook = loadToolPrompt('generate-image-cookbook');
164
- return {
165
- hookSpecificOutput: {
166
- hookEventName: 'PreToolUse',
167
- permissionDecision: 'allow',
168
- additionalContext:
169
- '<system-reminder>\n[generate_image 完整 cookbook — 首次注入]\n\n'
170
- + cookbook
171
- + '\n\n本 cookbook 每 session 只注入一次,已读完后续生图调用直接用即可。\n'
172
- + '</system-reminder>',
173
- },
174
- };
175
- };
176
- }
177
-
178
- /**
179
- * PreToolUse(generate_image) — 第一次调用时提醒 agent 先 Read 目标页面。
180
- *
181
- * 设计原则 metadata-not-content:不预解析 canvas.html 注入页面 HTML,
182
- * 而是提醒 agent 自己 Read。避免"被注入摘要后反而不主动读"的反模式。
183
- *
184
- * 触发:本 session(hook 工厂调用一次 → closure 一份 alreadyReminded)内
185
- * 第 1 次调用 generate_image;后续不再注入。
186
- *
187
- * 不阻塞工具调用,permissionDecision='allow' 直接放行。
188
- */
189
- export function makePreToolUseGenerateImageReadPageReminder() {
190
- let alreadyReminded = false;
191
- return async (_input, _toolUseId, _options) => {
192
- if (alreadyReminded) return {};
193
- alreadyReminded = true;
194
- return {
195
- hookSpecificOutput: {
196
- hookEventName: 'PreToolUse',
197
- permissionDecision: 'allow',
198
- additionalContext:
199
- '<system-reminder>\n[generate_image 目标页提醒]\n\n'
200
- + '即将生成图片。如果还没看过目标页(deck 里对应的 <section data-page="N"> / 站点的那一页),建议先 Read 一下:\n'
201
- + ' - 页面尺寸(多少行 / 多大留给图)\n'
202
- + ' - 主色(design-tokens 里的 --bg / --accent / --hero)\n'
203
- + ' - 已有视觉风格(hybrid 范式有无 React 组件 / 已有图片调性)\n\n'
204
- + '多数情况下第一张图会被当 referenceImages 种子用于全 deck,看一眼能避免后续违和(暖色页塞冷调插图这类)。本提醒每 session 只触发一次。\n'
205
- + '</system-reminder>',
206
- },
207
- };
208
- };
209
- }
210
-
211
- /**
212
- * PreToolUse(expose_tweaks) — 第一次调用时注 完整控件 schema 语法。
213
- *
214
- * SKILL.md 已有"何时暴露 / 暴露什么"哲学(5-8 个核心维度即可);本 hook 注入完整
215
- * 控件类型 / target_var vs target_class_on / target_scope / Tailwind 桥接 / 常坑
216
- * 等参考语法,让 agent 写 controls JSON 时一次到位。
217
- *
218
- * 触发:本 session 第 1 次调 expose_tweaks;后续不再注入。
219
- * 文件源:prompts/tools/tweaks-syntax.md(模块加载时缓存)。
220
- */
221
- export function makePreToolUseExposeTweaksSyntaxInjector() {
222
- let alreadyInjected = false;
223
- return async (_input, _toolUseId, _options) => {
224
- if (alreadyInjected) return {};
225
- alreadyInjected = true;
226
- const syntax = loadToolPrompt('tweaks-syntax');
227
- return {
228
- hookSpecificOutput: {
229
- hookEventName: 'PreToolUse',
230
- permissionDecision: 'allow',
231
- additionalContext:
232
- '<system-reminder>\n[expose_tweaks 完整语法 — 首次注入]\n\n'
233
- + syntax
234
- + '\n\n本语法每 session 只注入一次。\n'
235
- + '</system-reminder>',
236
- },
237
- };
238
- };
239
- }
240
-
241
- /**
242
- * PreToolUse(Agent) — subagent_type='vision-checker' 时首次注 派遣 prompt 模板。
243
- *
244
- * 注:跟 makePreToolUseAgentForceForegroundHandler 共存于同一 'Task|Agent' matcher
245
- * 下,SDK 按数组顺序串行执行多个 hook。本 hook 仅在 subagent_type==='vision-checker'
246
- * 命中时注 dispatch 模板(含全 deck 自检 / 有 plan 时按计划 critique / 单页评审 3 模板)。
247
- *
248
- * ⚠️ 2026-08-03 修:原来读的是 `input.subagent_type`,而 PreToolUse 的 hook input
249
- * 形状是 `{ tool_name, tool_input, tool_use_id, ... }`(sdk.d.ts PreToolUseHookInput),
250
- * 工具入参在 **tool_input** 里 —— 顶层那个字段永远是 undefined,条件永远不成立。
251
- * 结果:历史上 6 次 vision-checker 派遣,模板一次都没注进去(jsonl 全量 grep 0 命中)。
252
- * 同文件的 force-foreground handler 一直读的是 `input?.tool_input`,是对的,
253
- * 这里当初抄漏了一层。
254
- *
255
- * 触发:本 session 第 1 次派 vision-checker;后续不再注入。
256
- * 文件源:prompts/tools/vision-checker-dispatch.md(模块加载时缓存)。
257
- */
258
- export function makePreToolUseTaskVisionCheckerDispatchInjector() {
259
- let alreadyInjected = false;
260
- return async (input, _toolUseId, _options) => {
261
- if (alreadyInjected) return {};
262
- if (input?.tool_input?.subagent_type !== 'vision-checker') return {};
263
- alreadyInjected = true;
264
- const dispatch = loadToolPrompt('vision-checker-dispatch');
265
- return {
266
- hookSpecificOutput: {
267
- hookEventName: 'PreToolUse',
268
- permissionDecision: 'allow',
269
- additionalContext:
270
- '<system-reminder>\n[vision-checker 派遣 prompt 模板 — 首次注入]\n\n'
271
- + dispatch
272
- + '\n\n本模板每 session 只注入一次。后续派遣按这套结构写 prompt 即可。\n'
273
- + '</system-reminder>',
274
- },
275
- };
276
- };
277
- }
1
+ /**
2
+ * PreToolUse 首调注入族 —— 各工具的 reference 文档 / 起手提醒,agent 首次调
3
+ * 对应工具时才进 context(不放系统 prompt 恒驻,每 turn 拖累)。
4
+ * (2026-08-14 可维护性行动:从 hooks.js 原样迁出,语义零改动)
5
+ *
6
+ * 共同模式:closure 里一个 alreadyInjected 布尔(或 per-kind Set),每 session
7
+ * 只注一次;permissionDecision='allow' 不阻塞工具。
8
+ */
9
+ import path from 'node:path';
10
+ import { toWorkspaceRel } from '../../../lib/workspace-path.js';
11
+ import { kindOfPath, kindDef, KIND_DECK } from '../../../lib/artifact-target.js';
12
+ import { loadToolPrompt } from './tool-prompts.js';
13
+
14
+ /**
15
+ * PreToolUse(get_pending_changes) — 第一次调用时注入 DirectEdit 逐 kind
16
+ * 处理协议全文(字段结构 / pending-move 语义 / 邻居保护 / preDragLayout /
17
+ * constraint anchor 表)。prelude 常驻部分只留流程骨架 + 语义底线三条,
18
+ * ~90 行细则在 agent 真的要处理 pending changes 时才进 context。
19
+ */
20
+ export function makePreToolUseGetPendingChangesProtocolInjector() {
21
+ let alreadyInjected = false;
22
+ return async (_input, _toolUseId, _options) => {
23
+ if (alreadyInjected) return {};
24
+ alreadyInjected = true;
25
+ const protocol = loadToolPrompt('direct-edit-protocol');
26
+ return {
27
+ hookSpecificOutput: {
28
+ hookEventName: 'PreToolUse',
29
+ permissionDecision: 'allow',
30
+ additionalContext:
31
+ '<system-reminder>\n[DirectEdit 逐 kind 处理协议 — 首次注入]\n\n'
32
+ + protocol
33
+ + '\n\n本协议每 session 只注入一次,后续处理 pending changes 直接按它做。\n'
34
+ + '</system-reminder>',
35
+ },
36
+ };
37
+ };
38
+ }
39
+
40
+ /**
41
+ * PreToolUse(AskUserQuestion) — 第一次问用户时注入 NoDesign 的问法协议
42
+ * (何时用卡片 vs chat、schema、写选项的诀窍、preview 字段的两种形态与限制)。
43
+ * 常驻在 prelude 里是 1.2k tokens,但一次会话里可能一次都用不上。
44
+ */
45
+ export function makePreToolUseAskUserQuestionProtocolInjector() {
46
+ let alreadyInjected = false;
47
+ return async (_input, _toolUseId, _options) => {
48
+ if (alreadyInjected) return {};
49
+ alreadyInjected = true;
50
+ const protocol = loadToolPrompt('ask-user-question-protocol');
51
+ return {
52
+ hookSpecificOutput: {
53
+ hookEventName: 'PreToolUse',
54
+ permissionDecision: 'allow',
55
+ additionalContext:
56
+ '<system-reminder>\n[AskUserQuestion 协议 — 首次注入]\n\n'
57
+ + protocol
58
+ + '\n\n本协议每 session 只注入一次,后续问用户直接按它写。\n'
59
+ + '</system-reminder>',
60
+ },
61
+ };
62
+ };
63
+ }
64
+
65
+ /**
66
+ * PreToolUse(Write) — 第一次写 .html 时注入该形态的技术参考。
67
+ *
68
+ * 2026-07-28 加站点后按 kind 分流:以前是"任何 .html 都注入 hybrid deck 参考",
69
+ * 于是 agent 写站点首页时会被塞一份讲 `data-page` / `__nd-deck-wrap` / babel 的
70
+ * 文档 —— 文不对题,还会诱导它往站点里塞 deck 专属结构。
71
+ *
72
+ * 两种形态各注一次(一个会话理论上只做一种,但试作阶段可能先摸另一种)。
73
+ */
74
+ export function makePreToolUseHybridReferenceInjector({ workspaceRoot } = {}) {
75
+ const injected = new Set();
76
+ return async (input, _toolUseId, _options) => {
77
+ const fp = input?.tool_input?.file_path;
78
+ if (typeof fp !== 'string') return {};
79
+ const rel = workspaceRoot ? toWorkspaceRel(fp, workspaceRoot) : fp;
80
+ const kind = workspaceRoot ? await kindOfPath(workspaceRoot, rel) : KIND_DECK;
81
+ // 触发条件从「写 .html」改成「写的文件跟这个形态的入口同类型」(2026-08-01)。
82
+ // 写死 .html 的年代只有 deck 和 site,两者入口都是 html 所以恰好没错;非 html 入口的形态
83
+ // 的入口不是 .html,于是它的技术参考**永远不会被注入**,agent 一辈子不知道
84
+ // 目录结构该长什么样。扩展名从注册表的 entryFile 推,加形态不用再回来改。
85
+ const wantExt = path.extname(kindDef(kind)?.entryFile || '.html').toLowerCase();
86
+ if (path.extname(fp).toLowerCase() !== wantExt) return {};
87
+ if (injected.has(kind)) return {};
88
+ injected.add(kind);
89
+ // 技术参考按注册表分发(kinds/<kind>.referenceDoc)—— 新形态自带自己那份
90
+ const meta = kindDef(kind)?.referenceDoc || kindDef(KIND_DECK).referenceDoc;
91
+ return {
92
+ hookSpecificOutput: {
93
+ hookEventName: 'PreToolUse',
94
+ permissionDecision: 'allow',
95
+ additionalContext:
96
+ `<system-reminder>\n[${meta.title} — 首次注入]\n\n`
97
+ + loadToolPrompt(meta.file)
98
+ + '\n\n本参考每 session 每形态只注入一次。\n'
99
+ + '</system-reminder>',
100
+ },
101
+ };
102
+ };
103
+ }
104
+
105
+ // paint_still 首调注入本地生图手册:四模型选型 + noobai 标签流 + FLUX.2 官方
106
+ // 提示词实践(BFL prompting guide 摘要)+ 装卸税排序纪律。
107
+ export function makePreToolUsePaintStillCookbookInjector() {
108
+ let alreadyInjected = false;
109
+ return async (_input, _toolUseId, _options) => {
110
+ if (alreadyInjected) return {};
111
+ alreadyInjected = true;
112
+ const cookbook = loadToolPrompt('paint-still-cookbook');
113
+ return {
114
+ hookSpecificOutput: {
115
+ hookEventName: 'PreToolUse',
116
+ permissionDecision: 'allow',
117
+ additionalContext:
118
+ '<system-reminder>\n[paint_still 本地生图手册 — 首次注入]\n\n'
119
+ + cookbook
120
+ + '\n\n本手册每 session 只注入一次,后续调用直接照用。\n'
121
+ + '</system-reminder>',
122
+ },
123
+ };
124
+ };
125
+ }
126
+
127
+ // roll_film 首调注入 H3 提示词手册:三字段格式 + 多镜纪律(逐字角色块/同种子)
128
+ // + 禁视觉检查。模式与 generate_image cookbook 完全同款。
129
+ export function makePreToolUseRollFilmCookbookInjector() {
130
+ let alreadyInjected = false;
131
+ return async (_input, _toolUseId, _options) => {
132
+ if (alreadyInjected) return {};
133
+ alreadyInjected = true;
134
+ const cookbook = loadToolPrompt('roll-film-cookbook');
135
+ return {
136
+ hookSpecificOutput: {
137
+ hookEventName: 'PreToolUse',
138
+ permissionDecision: 'allow',
139
+ additionalContext:
140
+ '<system-reminder>\n[roll_film H3 提示词手册 — 首次注入]\n\n'
141
+ + cookbook
142
+ + '\n\n本手册每 session 只注入一次,后续调用直接照用。\n'
143
+ + '</system-reminder>',
144
+ },
145
+ };
146
+ };
147
+ }
148
+
149
+ /**
150
+ * PreToolUse(generate_image) — 第一次调用时注 完整 cookbook(A-J 段)。
151
+ *
152
+ * 配套 SKILL.md 里的精简版 cookbook(5 元素公式 + 渲文字铁律 + 反例正例)保第一张
153
+ * 图质量底线;本 hook 注入完整深度内容,让第二张起 agent 拿出更稳的 prompt。
154
+ *
155
+ * 触发:本 session 第 1 次调 generate_image;后续不再注入(避免 spam)。
156
+ * 文件源:prompts/tools/generate-image-cookbook.md(模块加载时缓存)。
157
+ */
158
+ export function makePreToolUseGenerateImageCookbookInjector() {
159
+ let alreadyInjected = false;
160
+ return async (_input, _toolUseId, _options) => {
161
+ if (alreadyInjected) return {};
162
+ alreadyInjected = true;
163
+ const cookbook = loadToolPrompt('generate-image-cookbook');
164
+ return {
165
+ hookSpecificOutput: {
166
+ hookEventName: 'PreToolUse',
167
+ permissionDecision: 'allow',
168
+ additionalContext:
169
+ '<system-reminder>\n[generate_image 完整 cookbook — 首次注入]\n\n'
170
+ + cookbook
171
+ + '\n\n本 cookbook 每 session 只注入一次,已读完后续生图调用直接用即可。\n'
172
+ + '</system-reminder>',
173
+ },
174
+ };
175
+ };
176
+ }
177
+
178
+ /**
179
+ * PreToolUse(generate_image) — 第一次调用时提醒 agent 先 Read 目标页面。
180
+ *
181
+ * 设计原则 metadata-not-content:不预解析 canvas.html 注入页面 HTML,
182
+ * 而是提醒 agent 自己 Read。避免"被注入摘要后反而不主动读"的反模式。
183
+ *
184
+ * 触发:本 session(hook 工厂调用一次 → closure 一份 alreadyReminded)内
185
+ * 第 1 次调用 generate_image;后续不再注入。
186
+ *
187
+ * 不阻塞工具调用,permissionDecision='allow' 直接放行。
188
+ */
189
+ export function makePreToolUseGenerateImageReadPageReminder() {
190
+ let alreadyReminded = false;
191
+ return async (_input, _toolUseId, _options) => {
192
+ if (alreadyReminded) return {};
193
+ alreadyReminded = true;
194
+ return {
195
+ hookSpecificOutput: {
196
+ hookEventName: 'PreToolUse',
197
+ permissionDecision: 'allow',
198
+ additionalContext:
199
+ '<system-reminder>\n[generate_image 目标页提醒]\n\n'
200
+ + '即将生成图片。如果还没看过目标页(deck 里对应的 <section data-page="N"> / 站点的那一页),建议先 Read 一下:\n'
201
+ + ' - 页面尺寸(多少行 / 多大留给图)\n'
202
+ + ' - 主色(design-tokens 里的 --bg / --accent / --hero)\n'
203
+ + ' - 已有视觉风格(hybrid 范式有无 React 组件 / 已有图片调性)\n\n'
204
+ + '多数情况下第一张图会被当 referenceImages 种子用于全 deck,看一眼能避免后续违和(暖色页塞冷调插图这类)。本提醒每 session 只触发一次。\n'
205
+ + '</system-reminder>',
206
+ },
207
+ };
208
+ };
209
+ }
210
+
211
+ /**
212
+ * PreToolUse(expose_tweaks) — 第一次调用时注 完整控件 schema 语法。
213
+ *
214
+ * SKILL.md 已有"何时暴露 / 暴露什么"哲学(5-8 个核心维度即可);本 hook 注入完整
215
+ * 控件类型 / target_var vs target_class_on / target_scope / Tailwind 桥接 / 常坑
216
+ * 等参考语法,让 agent 写 controls JSON 时一次到位。
217
+ *
218
+ * 触发:本 session 第 1 次调 expose_tweaks;后续不再注入。
219
+ * 文件源:prompts/tools/tweaks-syntax.md(模块加载时缓存)。
220
+ */
221
+ export function makePreToolUseExposeTweaksSyntaxInjector() {
222
+ let alreadyInjected = false;
223
+ return async (_input, _toolUseId, _options) => {
224
+ if (alreadyInjected) return {};
225
+ alreadyInjected = true;
226
+ const syntax = loadToolPrompt('tweaks-syntax');
227
+ return {
228
+ hookSpecificOutput: {
229
+ hookEventName: 'PreToolUse',
230
+ permissionDecision: 'allow',
231
+ additionalContext:
232
+ '<system-reminder>\n[expose_tweaks 完整语法 — 首次注入]\n\n'
233
+ + syntax
234
+ + '\n\n本语法每 session 只注入一次。\n'
235
+ + '</system-reminder>',
236
+ },
237
+ };
238
+ };
239
+ }
240
+
241
+ /**
242
+ * PreToolUse(Agent) — subagent_type='vision-checker' 时首次注 派遣 prompt 模板。
243
+ *
244
+ * 注:跟 makePreToolUseAgentForceForegroundHandler 共存于同一 'Task|Agent' matcher
245
+ * 下,SDK 按数组顺序串行执行多个 hook。本 hook 仅在 subagent_type==='vision-checker'
246
+ * 命中时注 dispatch 模板(含全 deck 自检 / 有 plan 时按计划 critique / 单页评审 3 模板)。
247
+ *
248
+ * ⚠️ 2026-08-03 修:原来读的是 `input.subagent_type`,而 PreToolUse 的 hook input
249
+ * 形状是 `{ tool_name, tool_input, tool_use_id, ... }`(sdk.d.ts PreToolUseHookInput),
250
+ * 工具入参在 **tool_input** 里 —— 顶层那个字段永远是 undefined,条件永远不成立。
251
+ * 结果:历史上 6 次 vision-checker 派遣,模板一次都没注进去(jsonl 全量 grep 0 命中)。
252
+ * 同文件的 force-foreground handler 一直读的是 `input?.tool_input`,是对的,
253
+ * 这里当初抄漏了一层。
254
+ *
255
+ * 触发:本 session 第 1 次派 vision-checker;后续不再注入。
256
+ * 文件源:prompts/tools/vision-checker-dispatch.md(模块加载时缓存)。
257
+ */
258
+ export function makePreToolUseTaskVisionCheckerDispatchInjector() {
259
+ let alreadyInjected = false;
260
+ return async (input, _toolUseId, _options) => {
261
+ if (alreadyInjected) return {};
262
+ if (input?.tool_input?.subagent_type !== 'vision-checker') return {};
263
+ alreadyInjected = true;
264
+ const dispatch = loadToolPrompt('vision-checker-dispatch');
265
+ return {
266
+ hookSpecificOutput: {
267
+ hookEventName: 'PreToolUse',
268
+ permissionDecision: 'allow',
269
+ additionalContext:
270
+ '<system-reminder>\n[vision-checker 派遣 prompt 模板 — 首次注入]\n\n'
271
+ + dispatch
272
+ + '\n\n本模板每 session 只注入一次。后续派遣按这套结构写 prompt 即可。\n'
273
+ + '</system-reminder>',
274
+ },
275
+ };
276
+ };
277
+ }