@xiaobuyu/nodesign 0.0.1

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 (372) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +140 -0
  3. package/bin/nodesign.js +176 -0
  4. package/package.json +104 -0
  5. package/server/api/README.md +45 -0
  6. package/server/api/_guard.js +75 -0
  7. package/server/api/admin.js +187 -0
  8. package/server/api/assets/docx-page.js +103 -0
  9. package/server/api/assets/helpers.js +22 -0
  10. package/server/api/assets/notes.js +144 -0
  11. package/server/api/assets.js +896 -0
  12. package/server/api/board.js +57 -0
  13. package/server/api/browse.js +138 -0
  14. package/server/api/canvas.js +444 -0
  15. package/server/api/chatai.js +324 -0
  16. package/server/api/exports/build-standalone.js +980 -0
  17. package/server/api/exports/cards.js +118 -0
  18. package/server/api/exports/docx-pdf.js +46 -0
  19. package/server/api/exports/export-page.js +142 -0
  20. package/server/api/exports/handoff.js +147 -0
  21. package/server/api/exports.js +690 -0
  22. package/server/api/instruction.js +75 -0
  23. package/server/api/local.js +115 -0
  24. package/server/api/me.js +116 -0
  25. package/server/api/memory.js +185 -0
  26. package/server/api/pending-changes.js +366 -0
  27. package/server/api/plugins.js +164 -0
  28. package/server/api/projects.js +220 -0
  29. package/server/api/publish.js +64 -0
  30. package/server/api/recent.js +73 -0
  31. package/server/api/sessions.js +589 -0
  32. package/server/api/skills.js +77 -0
  33. package/server/api/standalone-fit.js +168 -0
  34. package/server/api/turn-compose.js +180 -0
  35. package/server/api/turn-inflight.js +44 -0
  36. package/server/api/turn.js +669 -0
  37. package/server/auth/README.md +17 -0
  38. package/server/auth/middleware.js +138 -0
  39. package/server/auth/origin-guard.js +71 -0
  40. package/server/auth/session.js +108 -0
  41. package/server/auth/tier.js +113 -0
  42. package/server/auth/users-store.js +348 -0
  43. package/server/edit/README.md +29 -0
  44. package/server/engine/README.md +113 -0
  45. package/server/engine/agent/agent-shared.js +550 -0
  46. package/server/engine/agent/auto-mode-default-hard-deny.txt +4 -0
  47. package/server/engine/agent/auto-mode-rules.js +78 -0
  48. package/server/engine/agent/context.js +418 -0
  49. package/server/engine/agent/events.js +464 -0
  50. package/server/engine/agent/hooks/canvas-validate.js +199 -0
  51. package/server/engine/agent/hooks/failure.js +120 -0
  52. package/server/engine/agent/hooks/file-events.js +75 -0
  53. package/server/engine/agent/hooks/lifecycle.js +233 -0
  54. package/server/engine/agent/hooks/post-canvas-focus.js +80 -0
  55. package/server/engine/agent/hooks/post-guidance.js +206 -0
  56. package/server/engine/agent/hooks/post-subagent-report.js +104 -0
  57. package/server/engine/agent/hooks/post-trim.js +58 -0
  58. package/server/engine/agent/hooks/pre-board-neighborhood.js +34 -0
  59. package/server/engine/agent/hooks/pre-defaults.js +84 -0
  60. package/server/engine/agent/hooks/pre-injectors.js +277 -0
  61. package/server/engine/agent/hooks/pre-performance-log-guard.js +78 -0
  62. package/server/engine/agent/hooks/pre-starter-files.js +61 -0
  63. package/server/engine/agent/hooks/pre-workspace-scope-guard.js +78 -0
  64. package/server/engine/agent/hooks/site-validate.js +94 -0
  65. package/server/engine/agent/hooks/tool-prompts.js +31 -0
  66. package/server/engine/agent/hooks/turn-state-memory.js +56 -0
  67. package/server/engine/agent/hooks/user-prompt-submit.js +215 -0
  68. package/server/engine/agent/hooks.js +354 -0
  69. package/server/engine/agent/init-contract.js +69 -0
  70. package/server/engine/agent/isolation.js +159 -0
  71. package/server/engine/agent/model-context.js +359 -0
  72. package/server/engine/agent/model-table.js +292 -0
  73. package/server/engine/agent/plugin-loader.js +266 -0
  74. package/server/engine/agent/prompts/nodesign-prelude.md +336 -0
  75. package/server/engine/agent/prompts/tools/ask-user-question-protocol.md +71 -0
  76. package/server/engine/agent/prompts/tools/direct-edit-protocol.md +98 -0
  77. package/server/engine/agent/prompts/tools/generate-image-cookbook.gemini-gateway.md +583 -0
  78. package/server/engine/agent/prompts/tools/generate-image-cookbook.md +483 -0
  79. package/server/engine/agent/prompts/tools/hybrid-reference.md +100 -0
  80. package/server/engine/agent/prompts/tools/paint-still-cookbook.md +270 -0
  81. package/server/engine/agent/prompts/tools/roll-film-cookbook.md +70 -0
  82. package/server/engine/agent/prompts/tools/site-reference.md +106 -0
  83. package/server/engine/agent/prompts/tools/tweaks-syntax.md +125 -0
  84. package/server/engine/agent/prompts/tools/vision-checker-dispatch.md +48 -0
  85. package/server/engine/agent/session-loop.js +1024 -0
  86. package/server/engine/agent/session-model.js +164 -0
  87. package/server/engine/agent/skill.js +204 -0
  88. package/server/engine/agent/system-prompts.js +86 -0
  89. package/server/engine/agent/task-events.js +78 -0
  90. package/server/engine/agents/ds-extractor.md +132 -0
  91. package/server/engine/agents/explorer.md +190 -0
  92. package/server/engine/agents/index.js +230 -0
  93. package/server/engine/agents/schemas/design-system.json +156 -0
  94. package/server/engine/agents/schemas/tweak-schema.json +113 -0
  95. package/server/engine/agents/tweak-proposer.md +127 -0
  96. package/server/engine/agents/vision-checker.md +254 -0
  97. package/server/engine/browse/capture.js +422 -0
  98. package/server/engine/browse/card.js +137 -0
  99. package/server/engine/browse/handover.js +59 -0
  100. package/server/engine/browse/page-digest.js +119 -0
  101. package/server/engine/browse/refs.js +196 -0
  102. package/server/engine/browse/registry.js +307 -0
  103. package/server/engine/browse/screencast.js +170 -0
  104. package/server/engine/browse/state.js +121 -0
  105. package/server/engine/chatai/chat-log.js +79 -0
  106. package/server/engine/chatai/index.js +193 -0
  107. package/server/engine/chatai/openai-compat.js +152 -0
  108. package/server/engine/chatai/orchestrate.js +309 -0
  109. package/server/engine/chatai/perform.js +40 -0
  110. package/server/engine/chatai/summarize.js +79 -0
  111. package/server/engine/mcp/capability-gate.js +52 -0
  112. package/server/engine/mcp/index.js +339 -0
  113. package/server/engine/mcp/param-sanitizer.js +142 -0
  114. package/server/engine/mcp/tools/arrange-on-board.js +124 -0
  115. package/server/engine/mcp/tools/artifact-session.js +278 -0
  116. package/server/engine/mcp/tools/browse-computer.js +421 -0
  117. package/server/engine/mcp/tools/browse-find-batch.js +183 -0
  118. package/server/engine/mcp/tools/browse-screenshot.js +157 -0
  119. package/server/engine/mcp/tools/browse.js +480 -0
  120. package/server/engine/mcp/tools/build-docx.js +101 -0
  121. package/server/engine/mcp/tools/clear-pending-changes.js +99 -0
  122. package/server/engine/mcp/tools/create-on-board.js +155 -0
  123. package/server/engine/mcp/tools/crystallize-skill.js +168 -0
  124. package/server/engine/mcp/tools/deliver-files.js +0 -0
  125. package/server/engine/mcp/tools/explain-style.js +237 -0
  126. package/server/engine/mcp/tools/export-handoff.js +133 -0
  127. package/server/engine/mcp/tools/expose-tweaks.js +149 -0
  128. package/server/engine/mcp/tools/generate-image.js +842 -0
  129. package/server/engine/mcp/tools/get-computed-styles.js +164 -0
  130. package/server/engine/mcp/tools/get-pending-changes.js +205 -0
  131. package/server/engine/mcp/tools/h3box-ssh.js +84 -0
  132. package/server/engine/mcp/tools/helpers/acquire-page.js +82 -0
  133. package/server/engine/mcp/tools/helpers/motion-lab.js +554 -0
  134. package/server/engine/mcp/tools/helpers/motion-scroll.js +112 -0
  135. package/server/engine/mcp/tools/helpers/perception-page.js +215 -0
  136. package/server/engine/mcp/tools/helpers/reference-download.js +103 -0
  137. package/server/engine/mcp/tools/helpers/rembg-bridge.py +80 -0
  138. package/server/engine/mcp/tools/helpers/rembg.js +273 -0
  139. package/server/engine/mcp/tools/helpers/shot-pipeline.js +280 -0
  140. package/server/engine/mcp/tools/highlight.js +68 -0
  141. package/server/engine/mcp/tools/list-pages.js +222 -0
  142. package/server/engine/mcp/tools/lookup-tags.js +59 -0
  143. package/server/engine/mcp/tools/navigate-to-page.js +60 -0
  144. package/server/engine/mcp/tools/organize-board.js +64 -0
  145. package/server/engine/mcp/tools/paint-still.js +434 -0
  146. package/server/engine/mcp/tools/pin-to-board.js +130 -0
  147. package/server/engine/mcp/tools/preview-deck.js +130 -0
  148. package/server/engine/mcp/tools/profile-scroll.js +305 -0
  149. package/server/engine/mcp/tools/publish-site.js +102 -0
  150. package/server/engine/mcp/tools/query-elements.js +195 -0
  151. package/server/engine/mcp/tools/read-board.js +103 -0
  152. package/server/engine/mcp/tools/read-document.js +93 -0
  153. package/server/engine/mcp/tools/read-page.js +264 -0
  154. package/server/engine/mcp/tools/read-tavern-json.js +143 -0
  155. package/server/engine/mcp/tools/record-decision.js +140 -0
  156. package/server/engine/mcp/tools/relate-on-board.js +110 -0
  157. package/server/engine/mcp/tools/remove-background.js +391 -0
  158. package/server/engine/mcp/tools/report-issue.js +115 -0
  159. package/server/engine/mcp/tools/roll-film.js +266 -0
  160. package/server/engine/mcp/tools/screenshot-docx.js +138 -0
  161. package/server/engine/mcp/tools/screenshot-url.js +195 -0
  162. package/server/engine/mcp/tools/screenshot.js +583 -0
  163. package/server/engine/mcp/tools/tier-gate.js +96 -0
  164. package/server/engine/mcp/tools/trace-motion.js +215 -0
  165. package/server/engine/mcp/tools/web-search.js +548 -0
  166. package/server/engine/motion/inventory.js +349 -0
  167. package/server/engine/perception/session.js +235 -0
  168. package/server/engine/plugins/nodesign/.claude-plugin/plugin.json +5 -0
  169. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/SKILL.md +192 -0
  170. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/canvas.template.html +667 -0
  171. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/hybrid-grid.md +22 -0
  172. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/image-led-cover.md +25 -0
  173. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/portrait.md +23 -0
  174. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/quote-backdrop.md +21 -0
  175. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/section-divider.md +23 -0
  176. package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/text-led.md +21 -0
  177. package/server/engine/plugins/nodesign/skills/docx-craft/SKILL.md +162 -0
  178. package/server/engine/plugins/nodesign/skills/docx-craft/references/token-schema.md +407 -0
  179. package/server/engine/plugins/nodesign/skills/docx-craft//346/226/207/346/241/243.template.json +80 -0
  180. package/server/engine/plugins/nodesign/skills/rp-craft/SKILL.md +228 -0
  181. 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 -0
  182. package/server/engine/plugins/nodesign/skills/rp-craft//346/274/224/345/207/272.template.js +268 -0
  183. package/server/engine/plugins/nodesign/skills/site-craft/SKILL.md +323 -0
  184. package/server/engine/plugins/nodesign/skills/site-craft/patterns/build-lane.md +134 -0
  185. package/server/engine/plugins/nodesign/skills/site-craft/patterns/cutout-collage.md +61 -0
  186. package/server/engine/plugins/nodesign/skills/site-craft/patterns/mock-app.md +163 -0
  187. package/server/engine/plugins/nodesign/skills/site-craft/patterns/page-transitions.md +86 -0
  188. package/server/engine/runs/active-runs.js +698 -0
  189. package/server/engine/runs/live-turn.js +252 -0
  190. package/server/engine/runs/store.js +364 -0
  191. package/server/engine/runs/turn-relay.js +217 -0
  192. package/server/engine/runtime/workspace.js +164 -0
  193. package/server/index.js +235 -0
  194. package/server/lib/artifact-file-path.js +80 -0
  195. package/server/lib/artifact-target.js +284 -0
  196. package/server/lib/asset-refs.js +239 -0
  197. package/server/lib/async-queue.js +104 -0
  198. package/server/lib/auto-relations.js +130 -0
  199. package/server/lib/binding-types.js +60 -0
  200. package/server/lib/board-kind-sizes.js +62 -0
  201. package/server/lib/board-relations.js +133 -0
  202. package/server/lib/browse-proxy.js +180 -0
  203. package/server/lib/canvas-id.js +36 -0
  204. package/server/lib/cover.js +227 -0
  205. package/server/lib/danbooru-tags.js +291 -0
  206. package/server/lib/doc-extract.js +156 -0
  207. package/server/lib/docx/build-from-source.js +260 -0
  208. package/server/lib/docx/build.js +490 -0
  209. package/server/lib/docx/dump-styles.js +287 -0
  210. package/server/lib/docx/fonts/nodesign-cjk.conf +164 -0
  211. package/server/lib/docx/merge-runs.js +129 -0
  212. package/server/lib/docx/numbering.js +218 -0
  213. package/server/lib/docx/order.js +152 -0
  214. package/server/lib/docx/rawzip.js +172 -0
  215. package/server/lib/docx/render.js +92 -0
  216. package/server/lib/docx/text-lint.js +225 -0
  217. package/server/lib/docx/tokens.js +335 -0
  218. package/server/lib/docx/units.js +29 -0
  219. package/server/lib/docx/xml.js +291 -0
  220. package/server/lib/docx-pages.js +187 -0
  221. package/server/lib/export-collect.js +289 -0
  222. package/server/lib/export-package.js +210 -0
  223. package/server/lib/html-srcset.js +145 -0
  224. package/server/lib/image-variant.js +460 -0
  225. package/server/lib/ingress/forward-openai-chat.js +305 -0
  226. package/server/lib/ingress/openai-chat.js +491 -0
  227. package/server/lib/ingress/session-notice.js +66 -0
  228. package/server/lib/ingress/session-routes.js +68 -0
  229. package/server/lib/ingress/slot-probe.js +130 -0
  230. package/server/lib/ingress/upstream-billing.js +52 -0
  231. package/server/lib/ingress/upstream-fail-streak.js +72 -0
  232. package/server/lib/ingress/upstream-truncation.js +48 -0
  233. package/server/lib/issues-store.js +182 -0
  234. package/server/lib/kinds/deck.js +72 -0
  235. package/server/lib/kinds/docx.js +283 -0
  236. package/server/lib/kinds/file-kinds.js +113 -0
  237. package/server/lib/kinds/index.js +202 -0
  238. package/server/lib/kinds/site.js +161 -0
  239. package/server/lib/model-ingress.js +543 -0
  240. package/server/lib/moderation.js +255 -0
  241. package/server/lib/notice-store.js +103 -0
  242. package/server/lib/plugin-install.js +104 -0
  243. package/server/lib/plugin-validator.js +721 -0
  244. package/server/lib/publish-store.js +115 -0
  245. package/server/lib/quick-summary.js +52 -0
  246. package/server/lib/quota.js +270 -0
  247. package/server/lib/rate-window.js +29 -0
  248. package/server/lib/reference-assets.js +92 -0
  249. package/server/lib/region-shot.js +135 -0
  250. package/server/lib/safe-path.js +73 -0
  251. package/server/lib/sdk-session.js +33 -0
  252. package/server/lib/showcase-store.js +92 -0
  253. package/server/lib/site-publish.js +465 -0
  254. package/server/lib/ssrf-guard.js +432 -0
  255. package/server/lib/task-scan.js +158 -0
  256. package/server/lib/tavern-json.js +154 -0
  257. package/server/lib/video-variant.js +237 -0
  258. package/server/lib/workspace-path.js +33 -0
  259. package/server/ops/fix-sdk-musl.mjs +40 -0
  260. package/server/ops/install-macos-fonts.sh +114 -0
  261. package/server/ops/macos-fonts.conf +336 -0
  262. package/server/ops/sandbox-shim/bwrap +57 -0
  263. package/server/projects/assets-summary.js +119 -0
  264. package/server/projects/auto-name.js +53 -0
  265. package/server/projects/board-store.js +640 -0
  266. package/server/projects/move-entry.js +103 -0
  267. package/server/projects/store.js +270 -0
  268. package/server/projects/ui-config.js +54 -0
  269. package/server/projects/workspace-templates.js +53 -0
  270. package/server/projects/workspace.js +1025 -0
  271. package/server/runtime/capabilities.js +153 -0
  272. package/server/runtime/local-config.js +177 -0
  273. package/server/runtime/local-env.js +88 -0
  274. package/server/runtime/platform.js +342 -0
  275. package/server/runtime/profile.js +72 -0
  276. package/server/services/rembg-launcher.js +313 -0
  277. package/server/services/rembg-service.py +334 -0
  278. package/server/shared/README.md +25 -0
  279. package/server/shared/deck.js +54 -0
  280. package/server/shared/time.js +49 -0
  281. package/server/style-pipeline/README.md +53 -0
  282. package/server/ws/broker.js +36 -0
  283. package/server/ws/browse-channel.js +177 -0
  284. package/server/ws/index.js +386 -0
  285. package/web/README.md +89 -0
  286. package/web/dist/assets/BrowserWindow-Dc7J7CYc.js +11 -0
  287. package/web/dist/assets/DeckWindow-4G0xX7P3.js +16 -0
  288. package/web/dist/assets/DocxWindow-BXQsoPkh.js +16 -0
  289. package/web/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  290. package/web/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  291. package/web/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  292. package/web/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  293. package/web/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  294. package/web/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  295. package/web/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  296. package/web/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  297. package/web/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  298. package/web/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  299. package/web/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  300. package/web/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  301. package/web/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  302. package/web/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  303. package/web/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  304. package/web/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  305. package/web/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  306. package/web/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  307. package/web/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  308. package/web/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  309. package/web/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  310. package/web/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  311. package/web/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  312. package/web/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  313. package/web/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  314. package/web/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  315. package/web/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  316. package/web/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  317. package/web/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  318. package/web/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  319. package/web/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  320. package/web/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  321. package/web/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  322. package/web/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  323. package/web/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  324. package/web/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  325. package/web/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  326. package/web/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  327. package/web/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  328. package/web/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  329. package/web/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  330. package/web/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  331. package/web/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  332. package/web/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  333. package/web/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  334. package/web/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  335. package/web/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  336. package/web/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  337. package/web/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  338. package/web/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  339. package/web/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  340. package/web/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  341. package/web/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  342. package/web/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  343. package/web/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  344. package/web/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  345. package/web/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  346. package/web/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  347. package/web/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  348. package/web/dist/assets/SiteWindow-D6eS-2gM.js +18 -0
  349. package/web/dist/assets/again-D8tfgKKO.webp +0 -0
  350. package/web/dist/assets/caveat-nd-CP6HlsNg.woff2 +0 -0
  351. package/web/dist/assets/clock-xJhvfYpS.webp +0 -0
  352. package/web/dist/assets/film-cut-BBKMwH7q.webp +0 -0
  353. package/web/dist/assets/film-still-BZ_DL9Tt.webp +0 -0
  354. package/web/dist/assets/index-C0KUf6Wd.css +1 -0
  355. package/web/dist/assets/index-Cbl3ATvp.js +2125 -0
  356. package/web/dist/assets/ink-desk-BRbxeDsR.webp +0 -0
  357. package/web/dist/assets/ink-night-Bz4BT3XH.webp +0 -0
  358. package/web/dist/assets/ink-portrait-C0DM4V8Q.webp +0 -0
  359. package/web/dist/assets/longcang-regular-C0uvTuKa.woff2 +0 -0
  360. package/web/dist/assets/lxgw-nd-bold-DbRfiTgo.woff2 +0 -0
  361. package/web/dist/assets/lxgw-nd-regular-CpMw9Ehg.woff2 +0 -0
  362. package/web/dist/assets/pending-edit-apply-DTjo2geW.js +31 -0
  363. package/web/dist/assets/question-8H4HSqxh.webp +0 -0
  364. package/web/dist/assets/reject-BaPJqElj.webp +0 -0
  365. package/web/dist/assets/rotate-cw-LMT3x1Zj.js +11 -0
  366. package/web/dist/assets/rp-portrait-CbrGpew2.webp +0 -0
  367. package/web/dist/assets/rp-street-C4jVKjxx.webp +0 -0
  368. package/web/dist/assets/square-dashed-mouse-pointer-CBoAkfhi.js +11 -0
  369. package/web/dist/assets/tangle-DIxHVNuT.webp +0 -0
  370. package/web/dist/assets/thisone-BylZKglV.webp +0 -0
  371. package/web/dist/assets/thumb-DO1wfK1I.webp +0 -0
  372. package/web/dist/index.html +18 -0
package/README.md ADDED
@@ -0,0 +1,140 @@
1
+ # NoDesign
2
+
3
+ 面向独立创作者的 agent 创作工作台。一张无限画布就是你的桌面,说一句想做什么,
4
+ agent 在真实文件上做出网站、演示稿、图像和视频,过程实时演在画布上;你直接在
5
+ 产物上改字、圈选、留评论、拖拽整理,agent 接着你的动作继续做。
6
+
7
+ 线上实例(内测,邀请制):`nodesign.xiaobuyu.trade`
8
+
9
+ ## 它长什么样
10
+
11
+ - **画布即桌面**:项目就是一张空间画布,画布上的一切与磁盘一一对应。文件夹是
12
+ 真目录,卡片 id 就是文件路径,拖一张卡进文件夹等于真的 `mv`。
13
+ - **产物即文件**:形态由文件证据认定,不用声明。写出 `<名字>.html` 是一份
14
+ deck;建一个带 `index.html` 的文件夹是一个站点,配响应式取景的显示器窗;
15
+ 普通文件各自成卡,图片、视频、Office 文档、Markdown 都读得开。
16
+ - **agent 是在场的**:一枚铅笔定格风格的 Claude 星芒住在画布上。干活时贴着
17
+ 它正在写的那张卡,代码直播框跟在身边;空闲时停在你的视野里,写一句刚才
18
+ 干了什么。点它可以直接搭话。
19
+ - **关系是一等公民**:六类关系线(改自、批注、接着、取材、对照、自定义
20
+ label)。你画的线 agent 读得到,agent 也会在收尾时主动把产物之间的关系画
21
+ 出来;HTML 里真实引用的素材由服务端自动对账成取材边。版面排布按关系走:
22
+ 相关的凑近、对照的成行、现役主角放大。
23
+
24
+ ## agent 能做什么
25
+
26
+ | 能力 | 说明 |
27
+ |---|---|
28
+ | 建站 / 做 deck | 手写或构建型站点(Astro、11ty 均可,产物根自动认定);deck 固定比例分页 |
29
+ | 看得见 | 截图自检(回传 console 错误与加载失败资源)、DOM 查询、真机移动端取景 |
30
+ | 画布语言 | `read_board` 看座次、`arrange_on_board` 语义摆位、`create_on_board` 手写便签、`organize_board` 归纳收纳、`relate_on_board` 画关系线 |
31
+ | 图像 | `generate_image` 生图、`remove_background` 抠图;可接自部署 GPU 产线(多模型生图、文生视频,按账号开通) |
32
+ | 发布 | `publish_site` 一键发布到四级子域名(Cloudflare Pages);下线即回收 |
33
+ | 导出 | PDF / PPTX / 整站 zip / 工程交付包,浏览器直接下载 |
34
+ | 记忆 | 项目级风格档案与用户偏好档,跨会话不忘;共享便利贴层与决策记录 |
35
+
36
+ 用户侧的直接操作全部会回到 agent 手里:双击改字写回源文件,元素评论与圈选
37
+ 截图进 pending buffer 下一轮自动带上,拖拽移动、样式调整、删除都以结构化意图
38
+ 落地。
39
+
40
+ ## 架构
41
+
42
+ ```
43
+ web/ React + Vite 前端。无限画布为自研:相机、命中、形态能力表、关系
44
+ 排布、在场归约全部是带单测的纯函数(web/src/lib,30+ 模块)。
45
+ server/ Node ESM 服务端。Claude Agent SDK 驱动 agent 会话(每会话独立
46
+ cwd 指向项目工作区);in-process MCP 提供 31 件业务工具;hooks
47
+ 做注入与守卫;WS 采用快照加尾随协议,断线重连不丢流。
48
+ ```
49
+
50
+ 几个关键设计:
51
+
52
+ - **形态注册表**(`server/lib/kinds/`):一种产物形态一个条目,寻址、预览、
53
+ 导出、发布都从注册表读。加新形态不改散落的 if。
54
+ - **单一真相源**:会话指针在服务端,多标签页不分叉;搬家语义一份实现,用户
55
+ 拖拽与 agent 工具共用;改名是一等动词,三层传播(画布身份、关系线端点、
56
+ 转发表)保证 agent 背着画布 `mv` 之后版面不散。
57
+ - **事件三管线**:一条 WS 进来分流为舞台旁路(画布演出)、聊天流折叠、控制
58
+ 帧。分流名单与过期判据抽成纯函数并有钉子测试。
59
+ - **多用户**:邀请码注册、按用户隔离、用量计费闸门、内容外审档位。
60
+
61
+ ## 本地运行(单机版)
62
+
63
+ 同一份代码有两种形态:线上多用户站(hosted)和本地单机版(local,`NODESIGN_PROFILE=local`)。
64
+ 本地版默认单租户:没有登录墙、没有账号和额度,服务只绑 `127.0.0.1`,数据都在 `~/.nodesign/`
65
+ (`.env` 钥匙 / `config.json` 模型插槽 / 数据库 / 项目 / 缓存)。
66
+
67
+ 一条命令(要先装好 Node ≥ 20):
68
+
69
+ ```bash
70
+ npx @xiaobuyu/nodesign # 首次会下载约 470MB(含 Claude CLI 本体),起来后自动开浏览器
71
+ npx @xiaobuyu/nodesign login # 用 Claude 订阅的话登录一次(不用另装 claude CLI);用 API Key 的话在设置页填
72
+ # 或者装成全局命令:npm i -g @xiaobuyu/nodesign,之后直接 nodesign / nodesign login
73
+ ```
74
+
75
+ 常用参数:`--port N`(默认 4001,被占会自动往上找)、`--data-dir DIR`、`--no-open`。
76
+
77
+ 从仓库跑(开发):
78
+
79
+ ```bash
80
+ npm install && cd web && npm install && cd ..
81
+ npm run build:web # 前端构建产物由 Node 直接托管
82
+ npm run local # = node bin/nodesign.js --no-open
83
+ ```
84
+
85
+ 第一次起来后打开右上角齿轮(`/settings`):
86
+
87
+ - **本机能力**:git / Chromium(playwright) / LibreOffice / poppler / ffmpeg / rembg 等探测结果与装法。
88
+ 截图自检要 `npx playwright install chromium`;Word 形态要装 LibreOffice。缺的能力对应的工具
89
+ 会在 agent 面前标「不可用 + 装法」,不会静默失败
90
+ - **模型**:「Claude 官方」(API Key 或 `nodesign login` 的订阅登录态)与「自定义接入」(DeepSeek / OpenAI /
91
+ 智谱 / 通义 / OpenRouter / 中转站 / 本机 Ollama…,选服务商预设填钥匙和模型名即可)两张并列的卡;
92
+ 没配任何一种时模型选择器是空的
93
+ - **其他钥匙与开关**:四家搜索 / 生图通道 / Cloudflare 发布 / 沙盒与权限模式,写进
94
+ `~/.nodesign/.env`,钥匙类保存即生效
95
+ - 模型插槽细节:自己的上游(Anthropic 或 OpenAI-chat 协议的任何端点)+ 模型行,保存后重启生效;
96
+ 每行可「体检」(非流式 / 流式 / 工具调用 / 看图 / count_tokens 五项红绿)
97
+
98
+ Claude 本身二选一:本机 `claude login` 过(订阅),什么都不用填;或在钥匙页填 `ANTHROPIC_API_KEY`。
99
+
100
+ Windows 没有沙盒(bwrap/sandbox-exec),本地版默认不开沙盒,靠 CLI 自己的权限模式;
101
+ `NODESIGN_SANDBOX=on` 只在 Linux/macOS 有效。
102
+
103
+ ## 开发
104
+
105
+ ```bash
106
+ npm install && cd web && npm install && cd ..
107
+
108
+ # 服务端(读 .env;需要 Claude 订阅登录态或 API key)
109
+ npm run dev
110
+
111
+ # 前端
112
+ cd web && npm run dev
113
+ ```
114
+
115
+ 测试与守门:
116
+
117
+ ```bash
118
+ npm test # server 单测 + web 单测(含 lint 型测试)
119
+ npm run test:server # 仅服务端
120
+ node web/src/components/canvas/_hook-order-check.mjs # TDZ 依赖顺序体检
121
+ ```
122
+
123
+ lint 型测试是这个仓库的护栏(没有 CI,vitest 就是部署链的闸门):
124
+
125
+ - `loc-ratchet.lint`:源文件不超过 600 行,存量超标文件按现状冻结上限,只降不升
126
+ - `legacy-shape.lint`:旧任务模型的路径形状不许回到代码里
127
+ - `path-compose.lint`:路径拼接必须走统一入口
128
+ - parity 系列:前端消费的事件形状必须在服务端源码里逐字存在,reducer 消费的
129
+ 事件必须在转发名单里
130
+
131
+ 前端上线用 `web/scripts/deploy.sh`:构建到旁路目录后原子换入,旧分片保留,
132
+ 开着的页面不断链。服务端改动记得重启进程,Node 不热重载。
133
+
134
+ 真渲染验证有两条通道:`web/scripts/inspect.mjs`(拦截 API 喂固定数据,纯 UI
135
+ 回归)与 `web/scripts/shot-live.mjs`(登录真服务端截图加探针,查真问题用)。
136
+
137
+ ## 现状
138
+
139
+ 个人项目,内测运行中。近期完成画布与 agent 交互的整体重做:扁平桌面模型、
140
+ 连线范式、铅笔精灵、agent 摆位与归纳工具、根站治理。方向与记录见提交历史。
@@ -0,0 +1,176 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * bin/nodesign.js — 本地分发版入口(`npx nodesign` / `nodesign`)。
4
+ *
5
+ * 它是一个很薄的 supervisor:把 profile 钉成 local、把命令行参数翻译成 env、拉起 server/index.js 子进程、
6
+ * health 通了开一次浏览器;子进程以 RESTART_EXIT_CODE(75,见 server/api/local.js)退出就重新拉起——
7
+ * 配置页「保存并重启」走的就是这条路。所有真正的决策都在 server/runtime/profile.js,这里不复制一份。
8
+ *
9
+ * nodesign # 数据在 ~/.nodesign,http://127.0.0.1:4001
10
+ * nodesign --port 5000 # 换端口
11
+ * nodesign --data-dir ./mydata # 换数据目录(.env / config.json / 数据库 / 项目都在里面)
12
+ * nodesign --no-open # 不自动开浏览器
13
+ * nodesign login # 用 Claude 订阅:登录一次(转发给 SDK 自带的 claude auth login)
14
+ *
15
+ * 钥匙放 <数据目录>/.env:ANTHROPIC_API_KEY=...(或者本机 `claude login` 过,什么都不用填);
16
+ * 自己的模型插槽放 <数据目录>/config.json(形状见 server/runtime/local-config.js)。
17
+ */
18
+
19
+ import { spawn } from 'node:child_process';
20
+ import { createRequire } from 'node:module';
21
+ import http from 'node:http';
22
+ import net from 'node:net';
23
+ import path from 'node:path';
24
+ import { fileURLToPath } from 'node:url';
25
+
26
+ const RESTART_EXIT_CODE = 75;
27
+ const serverEntry = path.join(path.dirname(fileURLToPath(import.meta.url)), '../server/index.js');
28
+
29
+ const args = process.argv.slice(2);
30
+
31
+ // 子命令:`nodesign login` / `logout` / `auth status` —— 转发给 SDK 自带的 Claude CLI(用户不用再全局装一份 claude)。
32
+ // 配置目录与服务端同一个(server/runtime/platform.js 的 claudeConfigDir:NODESIGN_CONFIG_DIR 或 ~/.claude),
33
+ // 登录态落在那里,服务端的 claudeAuthPresent() 才看得见。
34
+ if (['login', 'logout', 'auth'].includes(args[0])) {
35
+ const sub = args[0] === 'auth' ? args.slice(1) : [args[0], ...args.slice(1)];
36
+ const code = await runBundledClaude(['auth', ...sub]);
37
+ process.exit(code);
38
+ }
39
+
40
+ const flags = {};
41
+ for (let i = 0; i < args.length; i++) {
42
+ const a = args[i];
43
+ if (a === '--help' || a === '-h') { flags.help = true; continue; }
44
+ if (a === '--no-open') { flags.noOpen = true; continue; }
45
+ if (a === '--open') { flags.noOpen = false; continue; }
46
+ const m = /^--(port|data-dir|host)(?:=(.*))?$/.exec(a);
47
+ if (m) {
48
+ const v = m[2] !== undefined ? m[2] : args[++i];
49
+ if (v === undefined) { console.error(`--${m[1]} 需要一个值`); process.exit(2); }
50
+ flags[m[1]] = v;
51
+ continue;
52
+ }
53
+ console.error(`不认识的参数:${a}(--help 看用法)`);
54
+ process.exit(2);
55
+ }
56
+
57
+ if (flags.help) {
58
+ console.log(`用法:nodesign [--port N] [--data-dir DIR] [--host H] [--no-open]
59
+ --port N 监听端口(默认 4001;env PORT)
60
+ --data-dir DIR 数据目录:.env / config.json / 数据库 / 项目 / 缓存(默认 ~/.nodesign;env NODESIGN_DATA_DIR)
61
+ --host H 监听地址(默认 127.0.0.1;没有登录墙,别改成 0.0.0.0)
62
+ --no-open 启动后不自动打开浏览器
63
+ login / logout / auth status Claude 订阅登录态(不用另装 claude CLI)
64
+ 钥匙:<数据目录>/.env 里写 ANTHROPIC_API_KEY=...;或本机已 \`claude login\` 则不用填。`);
65
+ process.exit(0);
66
+ }
67
+
68
+ const env = { ...process.env };
69
+ env.NODESIGN_PROFILE = env.NODESIGN_PROFILE || 'local';
70
+ if (flags.port) env.PORT = String(flags.port);
71
+ if (flags['data-dir']) env.NODESIGN_DATA_DIR = flags['data-dir'];
72
+ if (flags.host) env.NODESIGN_HOST = flags.host;
73
+
74
+ const host = env.NODESIGN_HOST || '127.0.0.1';
75
+ // 端口:用户指定了(--port / PORT)就用它,被占就报错退出;没指定则从 4001 往上找第一个空的
76
+ // (4001 在别人机器上常有主——Cursor、QQ 都见过——让用户自己换端口不如自己让一步)
77
+ const port = await pickPort(env.PORT ? Number(env.PORT) : null);
78
+ env.PORT = String(port);
79
+ const url = `http://${host}:${port}/`;
80
+
81
+ async function pickPort(wanted) {
82
+ const free = (p) => new Promise((resolve) => {
83
+ const srv = net.createServer();
84
+ srv.once('error', () => resolve(false));
85
+ srv.listen(p, host, () => srv.close(() => resolve(true)));
86
+ });
87
+ if (wanted) {
88
+ if (await free(wanted)) return wanted;
89
+ console.error(`[nodesign] 端口 ${wanted} 已被占用(查占用:${process.platform === 'win32' ? `netstat -ano | findstr :${wanted}` : `lsof -i :${wanted}`})`);
90
+ process.exit(1);
91
+ }
92
+ for (let p = 4001; p < 4001 + 50; p++) {
93
+ if (await free(p)) {
94
+ if (p !== 4001) console.log(`[nodesign] 4001 被占用,改用端口 ${p}`);
95
+ return p;
96
+ }
97
+ }
98
+ console.error('[nodesign] 4001~4050 全被占用,用 --port 指定一个');
99
+ process.exit(1);
100
+ }
101
+ let opened = false;
102
+ let child = null;
103
+ let stopping = false;
104
+
105
+ /** SDK 平台包里的 claude 可执行:@anthropic-ai/claude-agent-sdk-<platform>-<arch>[-musl]/claude[.exe] */
106
+ function bundledClaudePath() {
107
+ const require = createRequire(import.meta.url);
108
+ const musl = process.platform === 'linux' && (() => { try { return require('node:fs').readFileSync('/usr/bin/ldd', 'utf8').includes('musl'); } catch { return false; } })();
109
+ const pkg = `@anthropic-ai/claude-agent-sdk-${process.platform}-${process.arch}${musl ? '-musl' : ''}`;
110
+ const dir = path.dirname(require.resolve(`${pkg}/package.json`));
111
+ return path.join(dir, process.platform === 'win32' ? 'claude.exe' : 'claude');
112
+ }
113
+ function runBundledClaude(cliArgs) {
114
+ return new Promise((resolve) => {
115
+ let bin;
116
+ try { bin = bundledClaudePath(); } catch (e) { console.error(`[nodesign] 找不到 SDK 自带的 claude 可执行:${e.message}`); resolve(1); return; }
117
+ const cfgDir = process.env.NODESIGN_CONFIG_DIR || path.join(process.env.HOME || process.env.USERPROFILE || '', '.claude');
118
+ const p = spawn(bin, cliArgs, { stdio: 'inherit', env: { ...process.env, CLAUDE_CONFIG_DIR: cfgDir } });
119
+ p.on('error', (e) => { console.error(`[nodesign] 起不来 claude:${e.message}`); resolve(1); });
120
+ p.on('exit', (c) => resolve(c ?? 1));
121
+ });
122
+ }
123
+
124
+ function start() {
125
+ child = spawn(process.execPath, [serverEntry], { env, stdio: 'inherit' });
126
+ child.on('exit', (code, signal) => {
127
+ child = null;
128
+ if (stopping) process.exit(code ?? 0);
129
+ if (code === RESTART_EXIT_CODE) {
130
+ console.log('[nodesign] 服务端请求重启,重新拉起…');
131
+ start();
132
+ return;
133
+ }
134
+ process.exit(code ?? (signal ? 1 : 0));
135
+ });
136
+ if (!opened && !flags.noOpen && env.NODESIGN_OPEN !== '0') waitHealthThenOpen();
137
+ }
138
+
139
+ // 等 /api/health 通了再开浏览器(开早了是一页「无法连接」)。只开一次:重启后页面自己会刷新
140
+ function waitHealthThenOpen() {
141
+ const deadline = Date.now() + 20_000;
142
+ const tick = () => {
143
+ if (opened || !child) return;
144
+ const req = http.get(`${url}api/health`, (res) => {
145
+ res.resume();
146
+ if (res.statusCode === 200) { opened = true; openBrowser(url); return; }
147
+ retry();
148
+ });
149
+ req.on('error', retry);
150
+ req.setTimeout(1000, () => { req.destroy(); });
151
+ };
152
+ const retry = () => { if (Date.now() < deadline) setTimeout(tick, 300).unref(); };
153
+ tick();
154
+ }
155
+
156
+ function openBrowser(target) {
157
+ const cmd = process.platform === 'darwin' ? ['open', [target]]
158
+ : process.platform === 'win32' ? ['cmd', ['/c', 'start', '', target]]
159
+ : ['xdg-open', [target]];
160
+ try {
161
+ const p = spawn(cmd[0], cmd[1], { stdio: 'ignore', detached: true });
162
+ p.on('error', () => { console.log(`[nodesign] 打不开浏览器,请手动访问 ${target}`); });
163
+ p.unref();
164
+ } catch {
165
+ console.log(`[nodesign] 打不开浏览器,请手动访问 ${target}`);
166
+ }
167
+ }
168
+
169
+ for (const sig of ['SIGINT', 'SIGTERM']) {
170
+ process.on(sig, () => {
171
+ stopping = true;
172
+ if (child) child.kill(sig); else process.exit(0);
173
+ });
174
+ }
175
+
176
+ start();
package/package.json ADDED
@@ -0,0 +1,104 @@
1
+ {
2
+ "name": "@xiaobuyu/nodesign",
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "type": "module",
6
+ "description": "NoDesign — 面向独立创作者的 agent 创作工作台(本地分发版:npx nodesign)",
7
+ "bin": {
8
+ "nodesign": "bin/nodesign.js"
9
+ },
10
+ "files": [
11
+ "bin/",
12
+ "server/",
13
+ "web/dist/",
14
+ "README.md",
15
+ "LICENSE",
16
+ "!server/**/*.test.js",
17
+ "!server/**/_probe-*",
18
+ "!server/**/_*-check.mjs",
19
+ "!server/**/_smoke.js",
20
+ "!server/server/",
21
+ "!server/db/",
22
+ "!server/node_modules/",
23
+ "!server/runs/",
24
+ "!server/skills/installed/",
25
+ "!server/lib/docx/lab/",
26
+ "!server/lib/ssrf-lab/",
27
+ "!server/scripts/",
28
+ "!web/dist/mock/"
29
+ ],
30
+ "scripts": {
31
+ "postinstall": "node server/ops/fix-sdk-musl.mjs",
32
+ "start": "node --env-file-if-exists=.env server/index.js",
33
+ "dev": "node --env-file-if-exists=.env --watch server/index.js",
34
+ "smoke:engine": "node --env-file-if-exists=.env server/engine/_smoke.js",
35
+ "smoke:agent": "node --env-file-if-exists=.env server/engine/agent/_smoke.js",
36
+ "test:server": "nice -n 15 vitest run -c vitest.server.config.js",
37
+ "test": "npm run test:server && cd web && nice -n 15 npx vitest run",
38
+ "local": "node bin/nodesign.js --no-open",
39
+ "build:web": "cd web && npx vite build",
40
+ "prepack": "npm run build:web"
41
+ },
42
+ "dependencies": {
43
+ "@anthropic-ai/claude-agent-sdk": "^0.3.237",
44
+ "async-mutex-lite": "^1.0.0",
45
+ "better-sqlite3": "^12.8.0",
46
+ "cors": "^2.8.5",
47
+ "esbuild": "^0.28.0",
48
+ "express": "^5.1.0",
49
+ "fflate": "^0.8.3",
50
+ "jszip": "^3.10.1",
51
+ "mammoth": "^1.12.0",
52
+ "multer": "^2.1.1",
53
+ "partial-json": "^0.1.7",
54
+ "playwright": "^1.50.0",
55
+ "pptxgenjs": "^4.0.1",
56
+ "sharp": "^0.34.0",
57
+ "tailwindcss": "^3.4.19",
58
+ "ws": "^8.18.0",
59
+ "yaml": "^2.9.0",
60
+ "zod": "^4.3.6"
61
+ },
62
+ "comments": {
63
+ "_intentionally_omitted": [
64
+ "@anthropic-ai/sdk — Phase 4 删了;agent SDK 已包 LLM 通信,server/ 生产代码 0 直连用法。回退见 git revert(同 commit 删了 _probe-*.js)",
65
+ "@larksuiteoapi/node-sdk — 飞书入口走小合 → 调 Nodesign HTTP API;本服务不直接连飞书",
66
+ "@modelcontextprotocol/sdk — MCP 是 dev/ 工作台的事;Nodesign 暴露的是 REST/SSE",
67
+ "bcryptjs / jsonwebtoken — 鉴权方案待组长确认('已有平台'是什么),先不锁",
68
+ "react / vite — 前端在 Nodesign/web/(待建);server 是纯后端"
69
+ ],
70
+ "_pending_decisions": [
71
+ "playwright vs puppeteer — playwright 更现代但带 chromium ~150MB,部署环境吃得消?",
72
+ "better-sqlite3 vs pg — SaaS 数据规模会涨,可能要切 PostgreSQL;MVP 先 SQLite 起步"
73
+ ]
74
+ },
75
+ "allowScripts": {
76
+ "better-sqlite3@12.9.0": true,
77
+ "esbuild@0.28.0": true,
78
+ "sharp@0.34.5": true
79
+ },
80
+ "devDependencies": {
81
+ "happy-dom": "^20.11.2",
82
+ "vitest": "^4.1.10"
83
+ },
84
+ "repository": {
85
+ "type": "git",
86
+ "url": "git+https://github.com/Xiaokebuyu/Nodesign.git"
87
+ },
88
+ "homepage": "https://github.com/Xiaokebuyu/Nodesign#readme",
89
+ "bugs": {
90
+ "url": "https://github.com/Xiaokebuyu/Nodesign/issues"
91
+ },
92
+ "engines": {
93
+ "node": ">=20"
94
+ },
95
+ "keywords": [
96
+ "agent",
97
+ "canvas",
98
+ "creative",
99
+ "claude",
100
+ "deepseek",
101
+ "local-first"
102
+ ],
103
+ "license": "AGPL-3.0-only"
104
+ }
@@ -0,0 +1,45 @@
1
+ # server/api/ — HTTP API 入口
2
+
3
+ Nodesign 对外的公网 / 内网 HTTP 接口层。
4
+
5
+ ## 计划路由(待实现)
6
+
7
+ ```
8
+ POST /engine/runs 启动一个 skill run
9
+ body: { skill, brief, style_reference?, tools?, options? }
10
+ → 201 { run_id, status, stream_url }
11
+
12
+ GET /engine/runs/:id 查 run 状态
13
+ GET /engine/runs/:id/stream SSE 实时进度(text/thinking/tool_call/screenshot/done)
14
+ GET /engine/runs/:id/artifacts 列产物
15
+ GET /engine/runs/:id/artifacts/:filename 下载/打开(deck.html 直接可看)
16
+ POST /engine/runs/:id/cancel 取消
17
+
18
+ POST /style/extract 上传素材 → 提 style tokens
19
+ body: multipart (file) | { url }
20
+ → { task_id }
21
+ GET /style/tasks/:id 提取结果
22
+
23
+ POST /edit/sessions 启动 edit 会话(绑定一个 deck)
24
+ POST /edit/sessions/:id/messages 发指令
25
+ GET /edit/sessions/:id/stream SSE
26
+ ```
27
+
28
+ ## 鉴权(待组长确认)
29
+
30
+ 7 个待对齐问题里有"已有平台具体指什么" → 决定鉴权方式:
31
+ - 平台 SSO:复用平台的 token / cookie
32
+ - 自建:JWT + bcrypt
33
+ - 内部测试期:仅 `INTERNAL_API_TOKEN` Bearer
34
+
35
+ 外部 API 必加:rate limit、CORS、CSRF(如有 cookie 鉴权)。
36
+
37
+ ## 调用方
38
+
39
+ - **Web 前端**([Nodesign/web/](../../web/),待建)—— 主入口
40
+ - **小合**([dev/server/bot/](../../../dev/server/bot/))—— 内部 fn call,复用 `INTERNAL_API_TOKEN`
41
+ - **第三方 / CLI**(远期)
42
+
43
+ ## 框架选择
44
+
45
+ Express 5(与 dev/ 一致,复用度高)。如果未来 SSE 量大可换 Fastify。
@@ -0,0 +1,75 @@
1
+ /**
2
+ * server/api/_guard.js — 项目路由统一守卫(2026-07-30 多用户内测)
3
+ *
4
+ * 老范式是每个 handler 开头两行 `validateProjectId` + `getProject`(4 个文件
5
+ * 各有局部 guard()、其余 ~40 处内联)。多用户后归属校验必须只有一个实现,
6
+ * 全部收敛到这里。
7
+ *
8
+ * 语义:项目不存在、或存在但不属于当前用户(admin 例外)→ 一律 404,
9
+ * 不区分两种情况 —— 别让外人靠状态码枚举 pid 空间。
10
+ *
11
+ * req.user 由 auth/middleware.js authGuard 挂(登录墙关闭时是匿名 admin,
12
+ * 单机开发行为不变)。
13
+ */
14
+
15
+ import { validateProjectId, getProject } from '../projects/store.js';
16
+ import { getRun } from '../engine/runs/store.js';
17
+ import { getUserById } from '../auth/users-store.js';
18
+
19
+ /**
20
+ * 模型资格按谁算:**项目 owner**(08-21 晚)。非 admin 只能进自己的项目(guardProject),
21
+ * 所以对他们 owner 就是自己;差别只在 admin 代看别人的项目 —— 那时选模型/默认模型/锁行
22
+ * 都得按 owner 的档位(auth/tier.js),否则 admin 选了订阅 Claude 行、session-loop 按 owner
23
+ * 断言 OAuth 资格时再打回 INIT_FAILED。owner 查不到时退回请求者(不放大权限:admin 本就全开)。
24
+ */
25
+ export function modelUserFor(req, project) {
26
+ const ownerId = project?.ownerId;
27
+ if (!ownerId || ownerId === req.user?.id) return req.user;
28
+ return getUserById(ownerId) || req.user;
29
+ }
30
+
31
+ /**
32
+ * @returns {object|null} project;null 时响应已发出,caller 直接 return
33
+ */
34
+ export function guardProject(req, res) {
35
+ try {
36
+ validateProjectId(req.params.pid);
37
+ } catch (err) {
38
+ res.status(400).json({ error: err.message || 'invalid projectId' });
39
+ return null;
40
+ }
41
+ const project = getProject(req.params.pid);
42
+ const user = req.user;
43
+ const allowed = project && (user?.role === 'admin' || (user && project.ownerId === user.id));
44
+ if (!allowed) {
45
+ res.status(404).json({ error: 'project not found' });
46
+ return null;
47
+ }
48
+ return project;
49
+ }
50
+
51
+ /** 归属判断(不发响应)—— WS upgrade 等非 express 场景用 */
52
+ export function userOwnsProject(user, project) {
53
+ if (!project || !user) return false;
54
+ if (user.role === 'admin') return true;
55
+ // ⚠️ `project.ownerId === user.id` 在**两边都 undefined** 时是 true。今天不可达
56
+ // (每行都有 owner,bootstrapAuth 每次启动回填 NULL),但离"通配放行"只差一个
57
+ // 缺列或一个改了形状的调用方。归属判断上宁可写死。
58
+ return typeof user.id === 'string' && user.id !== ''
59
+ && typeof project.ownerId === 'string' && project.ownerId === user.id;
60
+ }
61
+
62
+ /**
63
+ * /:pid/runs/:runId/* 路由的第二道锁:runId 必须真属于这个 pid。
64
+ * cancel/rewind/answer 走的是全局内存 Map(key 只有 runId),没有这道校验
65
+ * 就是"拿自己的 pid + 别人的 runId"的跨租户控制通道。
66
+ * guardProject 通过之后调;不通过时已响应 404。
67
+ */
68
+ export function guardRunInProject(req, res) {
69
+ const run = getRun(req.params.runId);
70
+ if (!run || run.projectId !== req.params.pid) {
71
+ res.status(404).json({ error: 'run not found' });
72
+ return null;
73
+ }
74
+ return run;
75
+ }