@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.
Files changed (358) 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 +42 -22
  9. package/server/api/assets/notes.js +194 -144
  10. package/server/api/assets.js +891 -896
  11. package/server/api/board.js +134 -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 +465 -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 +258 -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 +388 -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 +1035 -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 +351 -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 +152 -155
  118. package/server/engine/mcp/tools/crystallize-skill.js +168 -168
  119. package/server/engine/mcp/tools/edit-sketch.js +167 -0
  120. package/server/engine/mcp/tools/explain-style.js +237 -237
  121. package/server/engine/mcp/tools/export-handoff.js +133 -133
  122. package/server/engine/mcp/tools/expose-tweaks.js +149 -149
  123. package/server/engine/mcp/tools/generate-image.js +842 -842
  124. package/server/engine/mcp/tools/get-computed-styles.js +164 -164
  125. package/server/engine/mcp/tools/get-pending-changes.js +205 -205
  126. package/server/engine/mcp/tools/h3box-ssh.js +84 -84
  127. package/server/engine/mcp/tools/helpers/acquire-page.js +82 -82
  128. package/server/engine/mcp/tools/helpers/motion-lab.js +554 -554
  129. package/server/engine/mcp/tools/helpers/motion-scroll.js +112 -112
  130. package/server/engine/mcp/tools/helpers/perception-page.js +215 -215
  131. package/server/engine/mcp/tools/helpers/reference-download.js +103 -103
  132. package/server/engine/mcp/tools/helpers/rembg-bridge.py +80 -80
  133. package/server/engine/mcp/tools/helpers/shot-pipeline.js +280 -280
  134. package/server/engine/mcp/tools/highlight.js +68 -68
  135. package/server/engine/mcp/tools/list-pages.js +222 -222
  136. package/server/engine/mcp/tools/look-at-board.js +124 -0
  137. package/server/engine/mcp/tools/lookup-tags.js +59 -59
  138. package/server/engine/mcp/tools/navigate-to-page.js +60 -60
  139. package/server/engine/mcp/tools/organize-board.js +64 -64
  140. package/server/engine/mcp/tools/paint-still.js +434 -434
  141. package/server/engine/mcp/tools/pin-to-board.js +130 -130
  142. package/server/engine/mcp/tools/preview-deck.js +130 -130
  143. package/server/engine/mcp/tools/profile-scroll.js +305 -305
  144. package/server/engine/mcp/tools/publish-site.js +102 -102
  145. package/server/engine/mcp/tools/query-elements.js +195 -195
  146. package/server/engine/mcp/tools/read-board.js +190 -103
  147. package/server/engine/mcp/tools/read-document.js +93 -93
  148. package/server/engine/mcp/tools/read-page.js +264 -264
  149. package/server/engine/mcp/tools/read-tavern-json.js +143 -143
  150. package/server/engine/mcp/tools/read-user-view.js +59 -0
  151. package/server/engine/mcp/tools/record-decision.js +140 -140
  152. package/server/engine/mcp/tools/relate-on-board.js +112 -110
  153. package/server/engine/mcp/tools/report-issue.js +115 -115
  154. package/server/engine/mcp/tools/roll-film.js +266 -266
  155. package/server/engine/mcp/tools/screenshot-docx.js +138 -138
  156. package/server/engine/mcp/tools/screenshot-url.js +195 -195
  157. package/server/engine/mcp/tools/screenshot.js +583 -583
  158. package/server/engine/mcp/tools/sketch-on-board.js +337 -0
  159. package/server/engine/mcp/tools/tier-gate.js +96 -96
  160. package/server/engine/mcp/tools/trace-motion.js +215 -215
  161. package/server/engine/mcp/tools/web-search.js +548 -548
  162. package/server/engine/mcp/tools/write-on-board.js +130 -0
  163. package/server/engine/motion/inventory.js +349 -349
  164. package/server/engine/perception/session.js +235 -235
  165. package/server/engine/plugins/nodesign/.claude-plugin/plugin.json +5 -5
  166. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/SKILL.md +199 -192
  167. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/canvas.template.html +667 -667
  168. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/hybrid-grid.md +22 -22
  169. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/image-led-cover.md +25 -25
  170. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/portrait.md +23 -23
  171. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/quote-backdrop.md +21 -21
  172. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/section-divider.md +23 -23
  173. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/text-led.md +21 -21
  174. package/server/engine/plugins/nodesign/skills/docx-craft/SKILL.md +169 -162
  175. package/server/engine/plugins/nodesign/skills/docx-craft/references/token-schema.md +407 -407
  176. package/server/engine/plugins/nodesign/skills/docx-craft//346/226/207/346/241/243.template.json +80 -80
  177. package/server/engine/plugins/nodesign/skills/rp-craft/SKILL.md +235 -228
  178. 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
  179. package/server/engine/plugins/nodesign/skills/rp-craft//346/274/224/345/207/272.template.js +268 -268
  180. package/server/engine/plugins/nodesign/skills/site-craft/SKILL.md +330 -323
  181. package/server/engine/plugins/nodesign/skills/site-craft/patterns/build-lane.md +134 -134
  182. package/server/engine/plugins/nodesign/skills/site-craft/patterns/cutout-collage.md +61 -61
  183. package/server/engine/plugins/nodesign/skills/site-craft/patterns/mock-app.md +163 -163
  184. package/server/engine/plugins/nodesign/skills/site-craft/patterns/page-transitions.md +86 -86
  185. package/server/engine/runs/active-runs.js +698 -698
  186. package/server/engine/runs/board-tasklist.js +130 -0
  187. package/server/engine/runs/live-turn.js +252 -252
  188. package/server/engine/runs/store.js +364 -364
  189. package/server/engine/runs/turn-relay.js +217 -217
  190. package/server/engine/runtime/workspace.js +164 -164
  191. package/server/index.js +3 -0
  192. package/server/lib/artifact-file-path.js +80 -80
  193. package/server/lib/artifact-target.js +284 -284
  194. package/server/lib/asset-refs.js +239 -239
  195. package/server/lib/async-queue.js +104 -104
  196. package/server/lib/auto-relations.js +130 -130
  197. package/server/lib/binding-types.js +72 -60
  198. package/server/lib/board-graph-export.js +191 -0
  199. package/server/lib/board-groups.js +167 -0
  200. package/server/lib/board-hero.js +76 -0
  201. package/server/lib/board-kind-sizes.js +85 -62
  202. package/server/lib/board-relations.js +133 -133
  203. package/server/lib/browse-proxy.js +180 -180
  204. package/server/lib/canvas-id.js +36 -36
  205. package/server/lib/chalk.js +121 -0
  206. package/server/lib/cover.js +227 -227
  207. package/server/lib/danbooru-tags.js +291 -291
  208. package/server/lib/doc-extract.js +156 -156
  209. package/server/lib/docx/build-from-source.js +260 -260
  210. package/server/lib/docx/build.js +490 -490
  211. package/server/lib/docx/dump-styles.js +287 -287
  212. package/server/lib/docx/fonts/nodesign-cjk.conf +164 -164
  213. package/server/lib/docx/merge-runs.js +129 -129
  214. package/server/lib/docx/numbering.js +218 -218
  215. package/server/lib/docx/order.js +152 -152
  216. package/server/lib/docx/rawzip.js +172 -172
  217. package/server/lib/docx/render.js +92 -92
  218. package/server/lib/docx/text-lint.js +225 -225
  219. package/server/lib/docx/tokens.js +335 -335
  220. package/server/lib/docx/units.js +29 -29
  221. package/server/lib/docx/xml.js +291 -291
  222. package/server/lib/docx-pages.js +187 -187
  223. package/server/lib/export-collect.js +289 -289
  224. package/server/lib/export-package.js +210 -210
  225. package/server/lib/html-srcset.js +145 -145
  226. package/server/lib/image-variant.js +460 -460
  227. package/server/lib/ingress/forward-openai-chat.js +305 -305
  228. package/server/lib/ingress/openai-chat.js +491 -491
  229. package/server/lib/ingress/session-notice.js +66 -66
  230. package/server/lib/ingress/session-routes.js +68 -68
  231. package/server/lib/ingress/slot-probe.js +130 -130
  232. package/server/lib/ingress/upstream-billing.js +52 -52
  233. package/server/lib/ingress/upstream-fail-streak.js +72 -72
  234. package/server/lib/ingress/upstream-truncation.js +48 -48
  235. package/server/lib/issues-store.js +182 -182
  236. package/server/lib/kinds/deck.js +72 -72
  237. package/server/lib/kinds/docx.js +283 -283
  238. package/server/lib/kinds/file-kinds.js +113 -113
  239. package/server/lib/kinds/index.js +202 -202
  240. package/server/lib/kinds/site.js +161 -161
  241. package/server/lib/model-ingress.js +543 -543
  242. package/server/lib/moderation.js +255 -255
  243. package/server/lib/notice-store.js +103 -103
  244. package/server/lib/plugin-install.js +104 -104
  245. package/server/lib/plugin-validator.js +721 -721
  246. package/server/lib/publish-store.js +115 -115
  247. package/server/lib/quick-summary.js +52 -52
  248. package/server/lib/quota.js +270 -270
  249. package/server/lib/rate-window.js +29 -29
  250. package/server/lib/reference-assets.js +92 -92
  251. package/server/lib/region-shot.js +135 -135
  252. package/server/lib/safe-path.js +73 -73
  253. package/server/lib/sdk-session.js +33 -33
  254. package/server/lib/showcase-store.js +92 -92
  255. package/server/lib/site-publish.js +465 -465
  256. package/server/lib/sketch-layout.js +277 -0
  257. package/server/lib/ssrf-guard.js +432 -432
  258. package/server/lib/task-scan.js +158 -158
  259. package/server/lib/tavern-json.js +154 -154
  260. package/server/lib/video-variant.js +237 -237
  261. package/server/lib/workspace-path.js +33 -33
  262. package/server/ops/fix-sdk-musl.mjs +40 -40
  263. package/server/ops/install-macos-fonts.sh +114 -114
  264. package/server/ops/macos-fonts.conf +336 -336
  265. package/server/ops/sandbox-shim/bwrap +57 -57
  266. package/server/projects/assets-summary.js +119 -119
  267. package/server/projects/auto-name.js +53 -53
  268. package/server/projects/board-limits.js +12 -0
  269. package/server/projects/board-sanitize.js +252 -0
  270. package/server/projects/board-store.js +507 -640
  271. package/server/projects/move-entry.js +103 -103
  272. package/server/projects/store.js +270 -270
  273. package/server/projects/ui-config.js +60 -54
  274. package/server/projects/viewpoint-store.js +78 -0
  275. package/server/projects/workspace-templates.js +53 -53
  276. package/server/projects/workspace.js +1025 -1025
  277. package/server/runtime/local-config.js +177 -177
  278. package/server/runtime/profile.js +72 -72
  279. package/server/services/rembg-service.py +334 -334
  280. package/server/shared/README.md +25 -25
  281. package/server/shared/deck.js +54 -54
  282. package/server/shared/time.js +49 -49
  283. package/server/style-pipeline/README.md +53 -53
  284. package/server/ws/broker.js +39 -36
  285. package/server/ws/browse-channel.js +177 -177
  286. package/server/ws/index.js +386 -386
  287. package/web/README.md +89 -89
  288. package/web/dist/assets/BrowserWindow-P_vIdh-G.js +11 -0
  289. package/web/dist/assets/{DeckWindow-4G0xX7P3.js → DeckWindow-BpLv5082.js} +3 -3
  290. package/web/dist/assets/{DocxWindow-BXQsoPkh.js → DocxWindow-DSAU1-tD.js} +4 -4
  291. package/web/dist/assets/MermaidBlock-DR1GikCv.js +313 -0
  292. package/web/dist/assets/SiteWindow-92uBuRRR.js +18 -0
  293. package/web/dist/assets/abnfDiagram-VCTEODGH-uA8Esix4.js +1 -0
  294. package/web/dist/assets/arc-D_khH_xN.js +1 -0
  295. package/web/dist/assets/architectureDiagram-5GKGNRK7-DydJHqOt.js +36 -0
  296. package/web/dist/assets/blockDiagram-NRAW4CY4-B7wBbKiW.js +129 -0
  297. package/web/dist/assets/c4Diagram-UCG6FXSJ-6mrH0x7Y.js +38 -0
  298. package/web/dist/assets/channel-DGkccMO1.js +1 -0
  299. package/web/dist/assets/chunk-2Q5K7J3B-Cuikho5Q.js +1 -0
  300. package/web/dist/assets/chunk-5VM5RSS4-3-KZ5AUz.js +15 -0
  301. package/web/dist/assets/chunk-F27PBJKO-Bkwq2gGU.js +1 -0
  302. package/web/dist/assets/chunk-G27WJ6UU-BLyQzdGE.js +231 -0
  303. package/web/dist/assets/chunk-JWPE2WC7-B7HxxQds.js +1 -0
  304. package/web/dist/assets/chunk-LCL6LL3I-CtXrnUwF.js +206 -0
  305. package/web/dist/assets/chunk-POPQ4Y6H-dxddZlXt.js +1 -0
  306. package/web/dist/assets/chunk-SVP7TREG-DpkmrgHn.js +88 -0
  307. package/web/dist/assets/chunk-XXDRQBXY-BwZ7RbpQ.js +1 -0
  308. package/web/dist/assets/classDiagram-DTDB5LWJ-BGscw3OD.js +1 -0
  309. package/web/dist/assets/classDiagram-v2-JRS7N3AN-BGscw3OD.js +1 -0
  310. package/web/dist/assets/cose-bilkent-JH36ORCC-DGFOsMUt.js +1 -0
  311. package/web/dist/assets/cynefin-OW5HDTMX-DUwn3ehS.js +178 -0
  312. package/web/dist/assets/cynefinDiagram-5FMLGOSQ-DlLAOZ9x.js +62 -0
  313. package/web/dist/assets/cytoscape.esm-BjAbmLdb.js +331 -0
  314. package/web/dist/assets/dagre-3AP2YEHR-CyourLfz.js +4 -0
  315. package/web/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  316. package/web/dist/assets/diagram-S7CK7UJ4-BTMbx2np.js +30 -0
  317. package/web/dist/assets/diagram-UQ7AKVKN-UK94_1-P.js +41 -0
  318. package/web/dist/assets/diagram-VSXAHHWV-C7zS-v9v.js +3 -0
  319. package/web/dist/assets/diagram-VX7I27RA-DKJRa6CK.js +24 -0
  320. package/web/dist/assets/diagram-Z3DM3KII-kUbAfGAp.js +24 -0
  321. package/web/dist/assets/ebnfDiagram-PWID7BFC-CVW16_vb.js +1 -0
  322. package/web/dist/assets/erDiagram-SSCWMZ5O-BRQMFQ5y.js +99 -0
  323. package/web/dist/assets/flowDiagram-A5DVABFB-S34LpLtK.js +168 -0
  324. package/web/dist/assets/ganttDiagram-EL5Y4UJY-BFiqk1-G.js +292 -0
  325. package/web/dist/assets/gitGraphDiagram-WWUBYQGX-LZsrdyyv.js +106 -0
  326. package/web/dist/assets/index-GAamh1p4.js +2152 -0
  327. package/web/dist/assets/infoDiagram-RXCK75RN-0DvN6KIp.js +2 -0
  328. package/web/dist/assets/init-Gi6I4Gst.js +1 -0
  329. package/web/dist/assets/ishikawaDiagram-5VMMS53U-CaY3A-Bx.js +70 -0
  330. package/web/dist/assets/journeyDiagram-EYS64GPL-BBeiaCrj.js +139 -0
  331. package/web/dist/assets/kanban-definition-3QL26DDD-ux42DRXQ.js +89 -0
  332. package/web/dist/assets/layout-CnXiF_NB.js +1 -0
  333. package/web/dist/assets/linear-BMW0u6G6.js +1 -0
  334. package/web/dist/assets/mindmap-definition-FBJOCRG2-hUxSpdKn.js +96 -0
  335. package/web/dist/assets/ordinal-Cboi1Yqb.js +1 -0
  336. package/web/dist/assets/pegDiagram-XKGWAZYB-aCaQPH0w.js +1 -0
  337. package/web/dist/assets/{pending-edit-apply-DTjo2geW.js → pending-edit-apply-AcdOQ9Ij.js} +6 -6
  338. package/web/dist/assets/pieDiagram-E7YTZNPT-CmOEZ8zg.js +39 -0
  339. package/web/dist/assets/quadrantDiagram-AXDQQJYC-VW6fAhsV.js +7 -0
  340. package/web/dist/assets/railroadDiagram-O6MQD6OU-CKJ7Ba5K.js +1 -0
  341. package/web/dist/assets/requirementDiagram-EFPCY7ZU-pNGkq9Vw.js +84 -0
  342. package/web/dist/assets/{rotate-cw-LMT3x1Zj.js → rotate-cw-KAfChbGV.js} +1 -1
  343. package/web/dist/assets/sankeyDiagram-P5KCCOFB-BIMmDTfZ.js +40 -0
  344. package/web/dist/assets/sequenceDiagram-WJ2MYXX4-BBW7wzKY.js +162 -0
  345. package/web/dist/assets/sizeCapture-X5ZJPWSS-DdkXmLYR.js +1 -0
  346. package/web/dist/assets/{square-dashed-mouse-pointer-CBoAkfhi.js → square-dashed-mouse-pointer-CDUlhUP7.js} +1 -1
  347. package/web/dist/assets/stateDiagram-HBIQ2CUA-W313Uz16.js +1 -0
  348. package/web/dist/assets/stateDiagram-v2-4QOOHH4V-DDhJBZzf.js +1 -0
  349. package/web/dist/assets/swimlanes-XN3QIQJK-C29TL26K.js +1 -0
  350. package/web/dist/assets/swimlanesDiagram-VK2B7HYN-BfN-Xdmu.js +8 -0
  351. package/web/dist/assets/timeline-definition-24CTP7MA-CF0JMObX.js +120 -0
  352. package/web/dist/assets/vennDiagram-4TSXK5OY-DrDFsaH3.js +34 -0
  353. package/web/dist/assets/wardleyDiagram-VM6X3IG4-CVrnRIS_.js +78 -0
  354. package/web/dist/assets/xychartDiagram-S5SC5T6Z-BvkN1zsT.js +7 -0
  355. package/web/dist/index.html +17 -17
  356. package/web/dist/assets/BrowserWindow-Dc7J7CYc.js +0 -11
  357. package/web/dist/assets/SiteWindow-D6eS-2gM.js +0 -18
  358. package/web/dist/assets/index-Cbl3ATvp.js +0 -2125
@@ -1,69 +1,69 @@
1
- /**
2
- * server/engine/agent/init-contract.js — 开局契约自检(2026-08-20 从 session-loop.js
3
- * 拆出,行数棘轮;逻辑原样)。session-loop 在每条 system:init 到达时调一次。
4
- */
5
-
6
- import { recordIssue, signatureOf } from '../../lib/issues-store.js';
7
-
8
- // ── 开局契约自检(2026-08-14 空壳钩子灭门案第 3 层,真正治本)──
9
- //
10
- // 背景:一个 `{ matcher: 'Bash' }` 空壳钩子条目让 SDK initialize 的大 try 吞掉
11
- // TypeError → 全部程序化钩子 + 全部 in-process MCP server 无声蒸发,mcp_servers
12
- // 里连 failed 都不留,会话照常跑 —— 潜伏六天。能静默这么久的结构性原因是这里
13
- // 从来不消费 system:init:SDK 开局就把「会话里实际有哪些 server / 工具」告诉了
14
- // 我们,但没人看。
15
- //
16
- // 现在对账:nodesign 必须 connected,且 server 实例声明的每个工具(探针实测
17
- // deferred 工具也在 init.tools 里,27/27)都必须出现。不满足 → recordIssue 进
18
- // 自动层 + throw 杀会话(外层 catch 走真错路径:markRunFailed + run.error 前端
19
- // 显式可见)。已知代价:SDK 改 init 形状会误杀会话 —— 但误杀 5 分钟定位,
20
- // 静默降级是 6 天暗账;工具残废的会话产出是负价值还烧钱,杀掉比放行仁慈。
21
- export function assertInitContract(init, { sessionId, projectId, isResume, initialPermissionMode, platform, sdkModel, nodesignServer }) {
22
- const problems = [];
23
- const nd = (init.mcp_servers || []).find((s) => s.name === 'nodesign');
24
- if (!nd) {
25
- problems.push('mcp_servers 里没有 nodesign(in-process MCP server 蒸发,连 failed 状态都不留)');
26
- } else if (nd.status !== 'connected') {
27
- problems.push(`nodesign server status=${nd.status}(预期 connected)`);
28
- }
29
- const registered = new Set(init.tools || []);
30
- const expected = (nodesignServer.toolNames || []).map((n) => `mcp__nodesign__${n}`);
31
- const missing = expected.filter((n) => !registered.has(n));
32
- if (missing.length) {
33
- problems.push(`nodesign 工具缺 ${missing.length}/${expected.length}:${missing.join(', ')}`);
34
- }
35
- // 权限模式对账(2026-08-15):**要的和拿到的可能不一样,而且是静默的**。
36
- // 实测:会话模型是 haiku 时 `permissionMode:'auto'` 会被无声降级成 'default',
37
- // init 里照报 default,没有任何报错 —— 分类器一次都不跑,我们却以为它在把关。
38
- // 只警告不杀:降级后的会话还能干活,杀掉代价大于收益;但必须在日志里喊出来。
39
- const wantMode = isResume ? null : (initialPermissionMode === 'plan' ? 'plan' : platform.permissionModeDefault);
40
- if (wantMode && init.permissionMode && init.permissionMode !== wantMode) {
41
- console.warn(
42
- `[session-loop] ⚠️ sid=${sessionId.slice(0, 8)} 权限模式被降级:要 ${wantMode},`
43
- + `实际 ${init.permissionMode}(模型 ${sdkModel} 可能不支持该模式)`,
44
- );
45
- }
46
- if (!problems.length) {
47
- console.info(
48
- `[session-loop] sid=${sessionId.slice(0, 8)} init 契约自检 ✓ `
49
- + `(nodesign connected, ${expected.length}/${expected.length} tools, `
50
- + `mode=${init.permissionMode ?? '未报'})`,
51
- );
52
- return;
53
- }
54
- const detail = problems.join(';');
55
- // 自动层留案底(fail-soft:记录本身不能变成新故障源)。signature 只含缺失
56
- // 集合不含 sessionId —— 同一种蒸发聚成一行计数。
57
- try {
58
- recordIssue({
59
- source: 'auto',
60
- toolName: 'session_init_contract',
61
- summary: `开局契约自检失败:${detail.slice(0, 120)}`,
62
- detail,
63
- projectId,
64
- sessionId,
65
- signature: signatureOf(`session_init_contract|${missing.join(',')}|${nd ? nd.status : 'absent'}`),
66
- });
67
- } catch { /* ignore */ }
68
- throw new Error(`开局契约自检失败(杀会话):${detail}`);
69
- }
1
+ /**
2
+ * server/engine/agent/init-contract.js — 开局契约自检(2026-08-20 从 session-loop.js
3
+ * 拆出,行数棘轮;逻辑原样)。session-loop 在每条 system:init 到达时调一次。
4
+ */
5
+
6
+ import { recordIssue, signatureOf } from '../../lib/issues-store.js';
7
+
8
+ // ── 开局契约自检(2026-08-14 空壳钩子灭门案第 3 层,真正治本)──
9
+ //
10
+ // 背景:一个 `{ matcher: 'Bash' }` 空壳钩子条目让 SDK initialize 的大 try 吞掉
11
+ // TypeError → 全部程序化钩子 + 全部 in-process MCP server 无声蒸发,mcp_servers
12
+ // 里连 failed 都不留,会话照常跑 —— 潜伏六天。能静默这么久的结构性原因是这里
13
+ // 从来不消费 system:init:SDK 开局就把「会话里实际有哪些 server / 工具」告诉了
14
+ // 我们,但没人看。
15
+ //
16
+ // 现在对账:nodesign 必须 connected,且 server 实例声明的每个工具(探针实测
17
+ // deferred 工具也在 init.tools 里,27/27)都必须出现。不满足 → recordIssue 进
18
+ // 自动层 + throw 杀会话(外层 catch 走真错路径:markRunFailed + run.error 前端
19
+ // 显式可见)。已知代价:SDK 改 init 形状会误杀会话 —— 但误杀 5 分钟定位,
20
+ // 静默降级是 6 天暗账;工具残废的会话产出是负价值还烧钱,杀掉比放行仁慈。
21
+ export function assertInitContract(init, { sessionId, projectId, isResume, initialPermissionMode, platform, sdkModel, nodesignServer }) {
22
+ const problems = [];
23
+ const nd = (init.mcp_servers || []).find((s) => s.name === 'nodesign');
24
+ if (!nd) {
25
+ problems.push('mcp_servers 里没有 nodesign(in-process MCP server 蒸发,连 failed 状态都不留)');
26
+ } else if (nd.status !== 'connected') {
27
+ problems.push(`nodesign server status=${nd.status}(预期 connected)`);
28
+ }
29
+ const registered = new Set(init.tools || []);
30
+ const expected = (nodesignServer.toolNames || []).map((n) => `mcp__nodesign__${n}`);
31
+ const missing = expected.filter((n) => !registered.has(n));
32
+ if (missing.length) {
33
+ problems.push(`nodesign 工具缺 ${missing.length}/${expected.length}:${missing.join(', ')}`);
34
+ }
35
+ // 权限模式对账(2026-08-15):**要的和拿到的可能不一样,而且是静默的**。
36
+ // 实测:会话模型是 haiku 时 `permissionMode:'auto'` 会被无声降级成 'default',
37
+ // init 里照报 default,没有任何报错 —— 分类器一次都不跑,我们却以为它在把关。
38
+ // 只警告不杀:降级后的会话还能干活,杀掉代价大于收益;但必须在日志里喊出来。
39
+ const wantMode = isResume ? null : (initialPermissionMode === 'plan' ? 'plan' : platform.permissionModeDefault);
40
+ if (wantMode && init.permissionMode && init.permissionMode !== wantMode) {
41
+ console.warn(
42
+ `[session-loop] ⚠️ sid=${sessionId.slice(0, 8)} 权限模式被降级:要 ${wantMode},`
43
+ + `实际 ${init.permissionMode}(模型 ${sdkModel} 可能不支持该模式)`,
44
+ );
45
+ }
46
+ if (!problems.length) {
47
+ console.info(
48
+ `[session-loop] sid=${sessionId.slice(0, 8)} init 契约自检 ✓ `
49
+ + `(nodesign connected, ${expected.length}/${expected.length} tools, `
50
+ + `mode=${init.permissionMode ?? '未报'})`,
51
+ );
52
+ return;
53
+ }
54
+ const detail = problems.join(';');
55
+ // 自动层留案底(fail-soft:记录本身不能变成新故障源)。signature 只含缺失
56
+ // 集合不含 sessionId —— 同一种蒸发聚成一行计数。
57
+ try {
58
+ recordIssue({
59
+ source: 'auto',
60
+ toolName: 'session_init_contract',
61
+ summary: `开局契约自检失败:${detail.slice(0, 120)}`,
62
+ detail,
63
+ projectId,
64
+ sessionId,
65
+ signature: signatureOf(`session_init_contract|${missing.join(',')}|${nd ? nd.status : 'absent'}`),
66
+ });
67
+ } catch { /* ignore */ }
68
+ throw new Error(`开局契约自检失败(杀会话):${detail}`);
69
+ }
@@ -1,159 +1,159 @@
1
- /**
2
- * agent/isolation.js —— 会话隔离配置的单一来源(2026-08-15)
3
- *
4
- * 一件事被拆成两道闸,因为 SDK 的工具分两拨跑:
5
- *
6
- * ① sandbox → **只管 Bash**。bwrap 起独立 mount/net namespace:写只落工作区、
7
- * 凭据读不到、env 里的 key 被 unset、AF_UNIX 与回环被切断、
8
- * 外网走代理。开关在 runtime/platform.js(NODESIGN_SANDBOX=on)。
9
- * ② settings.permissions.deny → 管 **Read / Grep / Glob / Write / Edit**。
10
- * 这些是 SDK 进程内工具,根本不进 bwrap,沙盒对它们零作用。
11
- *
12
- * 缺一半等于没关。第三块(跨项目边界)在 hooks/pre-workspace-scope-guard.js ——
13
- * deny 规则写不出"除了自己这个项目"(deny 压过 allow,项目又是动态新建的)。
14
- *
15
- * 08-15 开这套时真跑出来的四件事,改之前先读:
16
- * 1. `dangerouslyDisableSandbox` 默认允许,agent 撞到偶发失败会自己拿它关沙盒
17
- * —— 必须 allowUnsandboxedCommands:false 焊死。
18
- * 2. deny 规则的路径必须是**双斜杠**绝对形式,单斜杠静默失效。
19
- * 3. npm 默认缓存在 ~/.npm,沙盒里 HOME 不可写 → `npm i` EROFS,构建道整条断。
20
- * 4. 目录级 denyRead 拦得住读文件,拦不住 `ls` 看文件名(接受:名字不是秘密)。
21
- */
22
-
23
- import path from 'node:path';
24
- import os from 'node:os';
25
- import fs from 'node:fs/promises';
26
- import { platform } from '../../runtime/platform.js';
27
- import { autoModeSettings } from './auto-mode-rules.js';
28
-
29
- /**
30
- * 会话要用的缓存/临时目录一次备齐(2026-08-19 从 session-loop 下沉)。
31
- *
32
- * - npmCacheDir:共用 npm 缓存(数据根下;内容寻址 + 完整性校验,跨会话共用
33
- * 不构成投毒面)。沙盒里 HOME 不可写,不给它 `npm i` 直接 EROFS。
34
- * - agentTmpDir:沙盒里 Bash 的 $TMPDIR。SDK 按 CLAUDE_CODE_TMPDIR 派生沙盒
35
- * tmp(没设就 os.tmpdir()),而派生出来的 /tmp/claude 在 bwrap 里只读 ——
36
- * agent 装个 py7zr 连撞四堵墙、venv 静默失败(iss_msz25m5p_v5so)。
37
- * ⚠️ 必须短:SDK 二进制里有条 warn —— 这个路径超 ~30 字节时 AF_UNIX socket
38
- * 放不下,子进程 $TMPDIR **静默回退**默认值(= 白配)。所以挂 /tmp/nd 下、
39
- * 按项目分目录;沙盒里遮兄弟目录见 buildIsolationOptions。
40
- * - pip 缓存指进 agentTmpDir/pip,不然每条 pip 命令先吐一段
41
- * ~/.cache/pip 不可写的 WARNING 噪音。
42
- *
43
- * 目录必须先存在 —— bwrap 绑一个不存在的路径会起不来;建不出来也不拦会话。
44
- * envPatch 直接摊进 sdkEnv。
45
- */
46
- export async function prepareAgentDirs({ dataRoot, projectId, sessionId }) {
47
- const npmCacheDir = path.join(dataRoot, '.npm-cache');
48
- const agentTmpRoot = path.join(os.tmpdir(), 'nd');
49
- const agentTmpDir = path.join(agentTmpRoot, projectId || String(sessionId || 'anon').slice(0, 12));
50
- for (const d of [npmCacheDir, path.join(agentTmpDir, 'pip')]) {
51
- try { await fs.mkdir(d, { recursive: true }); } catch { /* 起不来也不该拦会话 */ }
52
- }
53
- return {
54
- npmCacheDir,
55
- agentTmpRoot,
56
- agentTmpDir,
57
- envPatch: {
58
- npm_config_cache: npmCacheDir,
59
- CLAUDE_CODE_TMPDIR: agentTmpDir,
60
- PIP_CACHE_DIR: path.join(agentTmpDir, 'pip'),
61
- },
62
- };
63
- }
64
-
65
- /**
66
- * bwrap 垫片的 env(PATH 前插一个目录,里面的 `bwrap` 是我们的包装脚本)
67
- *
68
- * 治的是 `apply-seccomp: unshare(CLONE_NEWUSER): Invalid argument` 这个偶发
69
- * —— 内核级竞态,机器越闲越容易撞,实测每十几次 Bash 调用炸一次,而且会把
70
- * agent 带进错误推断(有一次它干脆自己拿 `dangerouslyDisableSandbox` 绕过去)。
71
- * 原理与安全不变量写在 server/ops/sandbox-shim/bwrap 里。
72
- *
73
- * 📮 上游 issue:https://github.com/anthropics/claude-code/issues/86928
74
- * ⏳ **临时设施**:垫片认的是 SDK 内部的命令前缀,**SDK 一升级前缀变了就静默
75
- * 失效**(原样透传 = 悄悄退回那个偶发,不报错)。升级后查
76
- * `<数据根>/.sandbox-shim.log` 里 `rewrote=1` 的计数还在不在涨;
77
- * 上游修好之后连这个函数带 ops/sandbox-shim/ 一起删掉。
78
- * 关掉:`NODESIGN_SANDBOX_SHIM=off`。
79
- */
80
- export function sandboxShimEnv({ baseEnv = process.env, dataRoot } = {}) {
81
- if (!platform.sandboxEnabled) return {};
82
- if (process.env.NODESIGN_SANDBOX_SHIM === 'off') return {};
83
- const dir = path.join(platform.repoRoot, 'server', 'ops', 'sandbox-shim');
84
- return {
85
- PATH: `${dir}${path.delimiter}${baseEnv.PATH || ''}`,
86
- // 改写次数记一笔:SDK 升级后 pattern 变了会静默退回现状,靠这个计数发现
87
- ...(dataRoot ? { NODESIGN_SHIM_LOG: path.join(dataRoot, '.sandbox-shim.log') } : {}),
88
- };
89
- }
90
-
91
- /**
92
- * @param {object} o
93
- * @param {string} o.cwdRoot 会话工作区(= sharedRoot,扁平化之后同一个目录)
94
- * @param {string} o.sharedRoot 项目共享根
95
- * @param {string} o.npmCacheDir 共用 npm 缓存(在数据根下,必须可写可读)
96
- * @param {string} [o.agentTmpRoot] 所有项目沙盒 tmp 的根(/tmp/nd)—— 整体遮读
97
- * @param {string} [o.agentTmpDir] 本项目的沙盒 tmp(CLAUDE_CODE_TMPDIR 指它)——
98
- * 开可写可读天窗。两个一起传或都不传。
99
- * @param {string} o.dataRoot PROJECTS_DATA_ROOT
100
- * @param {object} o.env 传给 SDK 的 env(凭据抹除按它的键名算)
101
- * @returns {{ sandbox: object, settings: object }} 直接摊进 query options
102
- */
103
- export function buildIsolationOptions({ cwdRoot, sharedRoot, npmCacheDir, agentTmpRoot, agentTmpDir, dataRoot, env }) {
104
- return {
105
- sandbox: {
106
- enabled: platform.sandboxEnabled,
107
- failIfUnavailable: false,
108
- // ⭐ 逃生门焊死:SDK 给 Bash 留了 `dangerouslyDisableSandbox` 参数,**默认允许**。
109
- // 08-15 开沙盒当天就被 agent 自发用上了 —— 它撞到 apply-seccomp 偶发失败,
110
- // 第三次自己带上这个参数关掉沙盒,然后读到了隔壁项目的文件(它老实汇报了,
111
- // 所以我们看见了)。一个能被工具参数关掉的沙盒等于没有沙盒。
112
- allowUnsandboxedCommands: false,
113
- network: {
114
- allowLocalBinding: false,
115
- // 全域允许:这层留着不是为了管出口,是为了 Linux 上顺带切断 unix socket
116
- // —— pm2 的 rpc.sock 就在家目录里,通了的话 `pm2 start` 能起一个沙盒外的
117
- // 进程(完整逃逸)。只读挂载拦不住 socket 连接,实测过。
118
- allowedDomains: ['*'],
119
- },
120
- filesystem: {
121
- allowWrite: [
122
- cwdRoot,
123
- ...(sharedRoot ? [
124
- path.join(sharedRoot, '.claude', 'agent-memory'),
125
- path.join(sharedRoot, 'assets'),
126
- ] : []),
127
- npmCacheDir,
128
- // 本项目的沙盒 tmp(CLAUDE_CODE_TMPDIR / $TMPDIR / pip 缓存都指这里)。
129
- // 没有它 Bash 的 tmp 只读:venv 静默失败、pip --user EROFS、npm 装不上
130
- ...(agentTmpDir ? [agentTmpDir] : []),
131
- ],
132
- denyWrite: ['/etc', '/usr', '/bin', '/sbin', '/private/etc'],
133
- // 数据根整个盖住、再用 allowRead 给自己的工作区开天窗。
134
- // ⚠️ 口径要准(08-18 上生产时实测纠正):`ls 数据根` **看得见别的项目的
135
- // 目录名**(沙盒里实测列出了另一个 pid),拦住的是**进去读**——
136
- // `cat <别人的>/board.json` 与 `ls <别人的>/` 都空。
137
- // 原注释写的"连 ls 数据根都只看得见自己那一个条目"过强,是错的;
138
- // platform.js 那边的说法才对:「目录级 denyRead 拦得住 cat,拦不住 ls
139
- // 看文件名 —— 文件名不是秘密,接受」。
140
- // agentTmpRoot(/tmp/nd)同 dataRoot 一个待遇:根整个遮住、自己的子目录
141
- // 开天窗 —— 不遮的话 /tmp/nd/<别的项目>/ 就是跨项目读通道
142
- denyRead: [...platform.credentialBlacklist(), dataRoot, ...(agentTmpRoot ? [agentTmpRoot] : [])],
143
- allowRead: [cwdRoot, npmCacheDir, ...(agentTmpDir ? [agentTmpDir] : [])],
144
- },
145
- credentials: {
146
- // filesystem 那层拦得住 `cat .env`,拦不住 `env` —— 服务端 process.env
147
- // 原样继承给了 Bash 子进程,key 就明晃晃躺着。按名字在沙盒内 unset。
148
- envVars: platform.secretEnvVarNames(env).map(name => ({ name, mode: 'deny' })),
149
- },
150
- },
151
- settings: {
152
- permissions: { deny: platform.protectedPathRules({ dataRoot }) },
153
- // auto 模式的分类器规则(只在开了 auto 时注入,省得白占 settings)。
154
- // ⚠️ 按节替换不是追加 —— 为什么只覆盖 environment / hard_deny 两节,
155
- // 见 auto-mode-rules.js 文件头。
156
- ...(platform.autoModeEnabled ? { autoMode: autoModeSettings() } : {}),
157
- },
158
- };
159
- }
1
+ /**
2
+ * agent/isolation.js —— 会话隔离配置的单一来源(2026-08-15)
3
+ *
4
+ * 一件事被拆成两道闸,因为 SDK 的工具分两拨跑:
5
+ *
6
+ * ① sandbox → **只管 Bash**。bwrap 起独立 mount/net namespace:写只落工作区、
7
+ * 凭据读不到、env 里的 key 被 unset、AF_UNIX 与回环被切断、
8
+ * 外网走代理。开关在 runtime/platform.js(NODESIGN_SANDBOX=on)。
9
+ * ② settings.permissions.deny → 管 **Read / Grep / Glob / Write / Edit**。
10
+ * 这些是 SDK 进程内工具,根本不进 bwrap,沙盒对它们零作用。
11
+ *
12
+ * 缺一半等于没关。第三块(跨项目边界)在 hooks/pre-workspace-scope-guard.js ——
13
+ * deny 规则写不出"除了自己这个项目"(deny 压过 allow,项目又是动态新建的)。
14
+ *
15
+ * 08-15 开这套时真跑出来的四件事,改之前先读:
16
+ * 1. `dangerouslyDisableSandbox` 默认允许,agent 撞到偶发失败会自己拿它关沙盒
17
+ * —— 必须 allowUnsandboxedCommands:false 焊死。
18
+ * 2. deny 规则的路径必须是**双斜杠**绝对形式,单斜杠静默失效。
19
+ * 3. npm 默认缓存在 ~/.npm,沙盒里 HOME 不可写 → `npm i` EROFS,构建道整条断。
20
+ * 4. 目录级 denyRead 拦得住读文件,拦不住 `ls` 看文件名(接受:名字不是秘密)。
21
+ */
22
+
23
+ import path from 'node:path';
24
+ import os from 'node:os';
25
+ import fs from 'node:fs/promises';
26
+ import { platform } from '../../runtime/platform.js';
27
+ import { autoModeSettings } from './auto-mode-rules.js';
28
+
29
+ /**
30
+ * 会话要用的缓存/临时目录一次备齐(2026-08-19 从 session-loop 下沉)。
31
+ *
32
+ * - npmCacheDir:共用 npm 缓存(数据根下;内容寻址 + 完整性校验,跨会话共用
33
+ * 不构成投毒面)。沙盒里 HOME 不可写,不给它 `npm i` 直接 EROFS。
34
+ * - agentTmpDir:沙盒里 Bash 的 $TMPDIR。SDK 按 CLAUDE_CODE_TMPDIR 派生沙盒
35
+ * tmp(没设就 os.tmpdir()),而派生出来的 /tmp/claude 在 bwrap 里只读 ——
36
+ * agent 装个 py7zr 连撞四堵墙、venv 静默失败(iss_msz25m5p_v5so)。
37
+ * ⚠️ 必须短:SDK 二进制里有条 warn —— 这个路径超 ~30 字节时 AF_UNIX socket
38
+ * 放不下,子进程 $TMPDIR **静默回退**默认值(= 白配)。所以挂 /tmp/nd 下、
39
+ * 按项目分目录;沙盒里遮兄弟目录见 buildIsolationOptions。
40
+ * - pip 缓存指进 agentTmpDir/pip,不然每条 pip 命令先吐一段
41
+ * ~/.cache/pip 不可写的 WARNING 噪音。
42
+ *
43
+ * 目录必须先存在 —— bwrap 绑一个不存在的路径会起不来;建不出来也不拦会话。
44
+ * envPatch 直接摊进 sdkEnv。
45
+ */
46
+ export async function prepareAgentDirs({ dataRoot, projectId, sessionId }) {
47
+ const npmCacheDir = path.join(dataRoot, '.npm-cache');
48
+ const agentTmpRoot = path.join(os.tmpdir(), 'nd');
49
+ const agentTmpDir = path.join(agentTmpRoot, projectId || String(sessionId || 'anon').slice(0, 12));
50
+ for (const d of [npmCacheDir, path.join(agentTmpDir, 'pip')]) {
51
+ try { await fs.mkdir(d, { recursive: true }); } catch { /* 起不来也不该拦会话 */ }
52
+ }
53
+ return {
54
+ npmCacheDir,
55
+ agentTmpRoot,
56
+ agentTmpDir,
57
+ envPatch: {
58
+ npm_config_cache: npmCacheDir,
59
+ CLAUDE_CODE_TMPDIR: agentTmpDir,
60
+ PIP_CACHE_DIR: path.join(agentTmpDir, 'pip'),
61
+ },
62
+ };
63
+ }
64
+
65
+ /**
66
+ * bwrap 垫片的 env(PATH 前插一个目录,里面的 `bwrap` 是我们的包装脚本)
67
+ *
68
+ * 治的是 `apply-seccomp: unshare(CLONE_NEWUSER): Invalid argument` 这个偶发
69
+ * —— 内核级竞态,机器越闲越容易撞,实测每十几次 Bash 调用炸一次,而且会把
70
+ * agent 带进错误推断(有一次它干脆自己拿 `dangerouslyDisableSandbox` 绕过去)。
71
+ * 原理与安全不变量写在 server/ops/sandbox-shim/bwrap 里。
72
+ *
73
+ * 📮 上游 issue:https://github.com/anthropics/claude-code/issues/86928
74
+ * ⏳ **临时设施**:垫片认的是 SDK 内部的命令前缀,**SDK 一升级前缀变了就静默
75
+ * 失效**(原样透传 = 悄悄退回那个偶发,不报错)。升级后查
76
+ * `<数据根>/.sandbox-shim.log` 里 `rewrote=1` 的计数还在不在涨;
77
+ * 上游修好之后连这个函数带 ops/sandbox-shim/ 一起删掉。
78
+ * 关掉:`NODESIGN_SANDBOX_SHIM=off`。
79
+ */
80
+ export function sandboxShimEnv({ baseEnv = process.env, dataRoot } = {}) {
81
+ if (!platform.sandboxEnabled) return {};
82
+ if (process.env.NODESIGN_SANDBOX_SHIM === 'off') return {};
83
+ const dir = path.join(platform.repoRoot, 'server', 'ops', 'sandbox-shim');
84
+ return {
85
+ PATH: `${dir}${path.delimiter}${baseEnv.PATH || ''}`,
86
+ // 改写次数记一笔:SDK 升级后 pattern 变了会静默退回现状,靠这个计数发现
87
+ ...(dataRoot ? { NODESIGN_SHIM_LOG: path.join(dataRoot, '.sandbox-shim.log') } : {}),
88
+ };
89
+ }
90
+
91
+ /**
92
+ * @param {object} o
93
+ * @param {string} o.cwdRoot 会话工作区(= sharedRoot,扁平化之后同一个目录)
94
+ * @param {string} o.sharedRoot 项目共享根
95
+ * @param {string} o.npmCacheDir 共用 npm 缓存(在数据根下,必须可写可读)
96
+ * @param {string} [o.agentTmpRoot] 所有项目沙盒 tmp 的根(/tmp/nd)—— 整体遮读
97
+ * @param {string} [o.agentTmpDir] 本项目的沙盒 tmp(CLAUDE_CODE_TMPDIR 指它)——
98
+ * 开可写可读天窗。两个一起传或都不传。
99
+ * @param {string} o.dataRoot PROJECTS_DATA_ROOT
100
+ * @param {object} o.env 传给 SDK 的 env(凭据抹除按它的键名算)
101
+ * @returns {{ sandbox: object, settings: object }} 直接摊进 query options
102
+ */
103
+ export function buildIsolationOptions({ cwdRoot, sharedRoot, npmCacheDir, agentTmpRoot, agentTmpDir, dataRoot, env }) {
104
+ return {
105
+ sandbox: {
106
+ enabled: platform.sandboxEnabled,
107
+ failIfUnavailable: false,
108
+ // ⭐ 逃生门焊死:SDK 给 Bash 留了 `dangerouslyDisableSandbox` 参数,**默认允许**。
109
+ // 08-15 开沙盒当天就被 agent 自发用上了 —— 它撞到 apply-seccomp 偶发失败,
110
+ // 第三次自己带上这个参数关掉沙盒,然后读到了隔壁项目的文件(它老实汇报了,
111
+ // 所以我们看见了)。一个能被工具参数关掉的沙盒等于没有沙盒。
112
+ allowUnsandboxedCommands: false,
113
+ network: {
114
+ allowLocalBinding: false,
115
+ // 全域允许:这层留着不是为了管出口,是为了 Linux 上顺带切断 unix socket
116
+ // —— pm2 的 rpc.sock 就在家目录里,通了的话 `pm2 start` 能起一个沙盒外的
117
+ // 进程(完整逃逸)。只读挂载拦不住 socket 连接,实测过。
118
+ allowedDomains: ['*'],
119
+ },
120
+ filesystem: {
121
+ allowWrite: [
122
+ cwdRoot,
123
+ ...(sharedRoot ? [
124
+ path.join(sharedRoot, '.claude', 'agent-memory'),
125
+ path.join(sharedRoot, 'assets'),
126
+ ] : []),
127
+ npmCacheDir,
128
+ // 本项目的沙盒 tmp(CLAUDE_CODE_TMPDIR / $TMPDIR / pip 缓存都指这里)。
129
+ // 没有它 Bash 的 tmp 只读:venv 静默失败、pip --user EROFS、npm 装不上
130
+ ...(agentTmpDir ? [agentTmpDir] : []),
131
+ ],
132
+ denyWrite: ['/etc', '/usr', '/bin', '/sbin', '/private/etc'],
133
+ // 数据根整个盖住、再用 allowRead 给自己的工作区开天窗。
134
+ // ⚠️ 口径要准(08-18 上生产时实测纠正):`ls 数据根` **看得见别的项目的
135
+ // 目录名**(沙盒里实测列出了另一个 pid),拦住的是**进去读**——
136
+ // `cat <别人的>/board.json` 与 `ls <别人的>/` 都空。
137
+ // 原注释写的"连 ls 数据根都只看得见自己那一个条目"过强,是错的;
138
+ // platform.js 那边的说法才对:「目录级 denyRead 拦得住 cat,拦不住 ls
139
+ // 看文件名 —— 文件名不是秘密,接受」。
140
+ // agentTmpRoot(/tmp/nd)同 dataRoot 一个待遇:根整个遮住、自己的子目录
141
+ // 开天窗 —— 不遮的话 /tmp/nd/<别的项目>/ 就是跨项目读通道
142
+ denyRead: [...platform.credentialBlacklist(), dataRoot, ...(agentTmpRoot ? [agentTmpRoot] : [])],
143
+ allowRead: [cwdRoot, npmCacheDir, ...(agentTmpDir ? [agentTmpDir] : [])],
144
+ },
145
+ credentials: {
146
+ // filesystem 那层拦得住 `cat .env`,拦不住 `env` —— 服务端 process.env
147
+ // 原样继承给了 Bash 子进程,key 就明晃晃躺着。按名字在沙盒内 unset。
148
+ envVars: platform.secretEnvVarNames(env).map(name => ({ name, mode: 'deny' })),
149
+ },
150
+ },
151
+ settings: {
152
+ permissions: { deny: platform.protectedPathRules({ dataRoot }) },
153
+ // auto 模式的分类器规则(只在开了 auto 时注入,省得白占 settings)。
154
+ // ⚠️ 按节替换不是追加 —— 为什么只覆盖 environment / hard_deny 两节,
155
+ // 见 auto-mode-rules.js 文件头。
156
+ ...(platform.autoModeEnabled ? { autoMode: autoModeSettings() } : {}),
157
+ },
158
+ };
159
+ }