@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,79 +1,79 @@
1
- /**
2
- * chat-log.js —— 演出的对话记录与摘要落盘。
3
- *
4
- * 对话记录(默认 `对话.jsonl`,可在 编排.yaml 的 历史.文件 改):
5
- * 一行一条 { seq, role: 'user'|'assistant', text, at }。
6
- * ⭐ 只存双方真实发言,永远只追加、永远不删——摘要折叠掉的轮次仍然留在
7
- * 文件里(编译时靠 摘要.json 的 `至` 跳过),全量记录随时可重放、可导出。
8
- *
9
- * 摘要(固定名 `摘要.json`,派生态不给改名旋钮):
10
- * { 至, 内容, 时, 模型, 用量, 花费 } —— `至` 是被折叠的最后一条记录的 seq,
11
- * 滚动覆盖写(旧摘要在生成新摘要时被并入,不单独存档)。
12
- */
13
-
14
- import path from 'node:path';
15
- import fs from 'node:fs/promises';
16
-
17
- export const SUMMARY_FILE = '摘要.json';
18
-
19
- function logPath(dir, config) {
20
- const rel = config?.历史?.文件 || '对话.jsonl';
21
- const abs = path.resolve(dir, rel);
22
- if (abs !== path.resolve(dir) && !abs.startsWith(path.resolve(dir) + path.sep)) {
23
- throw Object.assign(new Error(`历史.文件「${rel}」跑出了演出文件夹`), { code: 'ORCH_INVALID' });
24
- }
25
- return abs;
26
- }
27
-
28
- /** 读全量记录。文件不存在 = 空场;坏行跳过不炸(记录是追加型文件,尾行可能残缺)。 */
29
- export async function readLog(dir, config) {
30
- let raw;
31
- try { raw = await fs.readFile(logPath(dir, config), 'utf8'); } catch { return []; }
32
- const out = [];
33
- for (const line of raw.split('\n')) {
34
- const s = line.trim();
35
- if (!s) continue;
36
- try {
37
- const r = JSON.parse(s);
38
- if (Number.isInteger(r.seq) && (r.role === 'user' || r.role === 'assistant') && typeof r.text === 'string') {
39
- out.push(r);
40
- }
41
- } catch { /* 残行跳过 */ }
42
- }
43
- return out;
44
- }
45
-
46
- /**
47
- * 追加一轮(user + assistant 成对写入,调用成功之后才落盘——失败的调用
48
- * 不留半条记录,重试不会双写)。
49
- */
50
- export async function appendTurn(dir, config, userText, assistantText) {
51
- const records = await readLog(dir, config);
52
- const last = records.length ? records[records.length - 1].seq : 0;
53
- const at = new Date().toISOString();
54
- const lines = [
55
- { seq: last + 1, role: 'user', text: String(userText), at },
56
- { seq: last + 2, role: 'assistant', text: String(assistantText), at },
57
- ];
58
- await fs.appendFile(
59
- logPath(dir, config),
60
- lines.map(r => JSON.stringify(r)).join('\n') + '\n',
61
- 'utf8',
62
- );
63
- return lines;
64
- }
65
-
66
- export async function readSummary(dir) {
67
- try {
68
- const s = JSON.parse(await fs.readFile(path.join(dir, SUMMARY_FILE), 'utf8'));
69
- return (s && Number.isInteger(s.至) && typeof s.内容 === 'string') ? s : null;
70
- } catch { return null; }
71
- }
72
-
73
- /** 原子写(tmp + rename):摘要生成要花一次真调用,别让并发读读到半个文件。 */
74
- export async function writeSummary(dir, summary) {
75
- const target = path.join(dir, SUMMARY_FILE);
76
- const tmp = `${target}.tmp`;
77
- await fs.writeFile(tmp, JSON.stringify(summary, null, 2), 'utf8');
78
- await fs.rename(tmp, target);
79
- }
1
+ /**
2
+ * chat-log.js —— 演出的对话记录与摘要落盘。
3
+ *
4
+ * 对话记录(默认 `对话.jsonl`,可在 编排.yaml 的 历史.文件 改):
5
+ * 一行一条 { seq, role: 'user'|'assistant', text, at }。
6
+ * ⭐ 只存双方真实发言,永远只追加、永远不删——摘要折叠掉的轮次仍然留在
7
+ * 文件里(编译时靠 摘要.json 的 `至` 跳过),全量记录随时可重放、可导出。
8
+ *
9
+ * 摘要(固定名 `摘要.json`,派生态不给改名旋钮):
10
+ * { 至, 内容, 时, 模型, 用量, 花费 } —— `至` 是被折叠的最后一条记录的 seq,
11
+ * 滚动覆盖写(旧摘要在生成新摘要时被并入,不单独存档)。
12
+ */
13
+
14
+ import path from 'node:path';
15
+ import fs from 'node:fs/promises';
16
+
17
+ export const SUMMARY_FILE = '摘要.json';
18
+
19
+ function logPath(dir, config) {
20
+ const rel = config?.历史?.文件 || '对话.jsonl';
21
+ const abs = path.resolve(dir, rel);
22
+ if (abs !== path.resolve(dir) && !abs.startsWith(path.resolve(dir) + path.sep)) {
23
+ throw Object.assign(new Error(`历史.文件「${rel}」跑出了演出文件夹`), { code: 'ORCH_INVALID' });
24
+ }
25
+ return abs;
26
+ }
27
+
28
+ /** 读全量记录。文件不存在 = 空场;坏行跳过不炸(记录是追加型文件,尾行可能残缺)。 */
29
+ export async function readLog(dir, config) {
30
+ let raw;
31
+ try { raw = await fs.readFile(logPath(dir, config), 'utf8'); } catch { return []; }
32
+ const out = [];
33
+ for (const line of raw.split('\n')) {
34
+ const s = line.trim();
35
+ if (!s) continue;
36
+ try {
37
+ const r = JSON.parse(s);
38
+ if (Number.isInteger(r.seq) && (r.role === 'user' || r.role === 'assistant') && typeof r.text === 'string') {
39
+ out.push(r);
40
+ }
41
+ } catch { /* 残行跳过 */ }
42
+ }
43
+ return out;
44
+ }
45
+
46
+ /**
47
+ * 追加一轮(user + assistant 成对写入,调用成功之后才落盘——失败的调用
48
+ * 不留半条记录,重试不会双写)。
49
+ */
50
+ export async function appendTurn(dir, config, userText, assistantText) {
51
+ const records = await readLog(dir, config);
52
+ const last = records.length ? records[records.length - 1].seq : 0;
53
+ const at = new Date().toISOString();
54
+ const lines = [
55
+ { seq: last + 1, role: 'user', text: String(userText), at },
56
+ { seq: last + 2, role: 'assistant', text: String(assistantText), at },
57
+ ];
58
+ await fs.appendFile(
59
+ logPath(dir, config),
60
+ lines.map(r => JSON.stringify(r)).join('\n') + '\n',
61
+ 'utf8',
62
+ );
63
+ return lines;
64
+ }
65
+
66
+ export async function readSummary(dir) {
67
+ try {
68
+ const s = JSON.parse(await fs.readFile(path.join(dir, SUMMARY_FILE), 'utf8'));
69
+ return (s && Number.isInteger(s.至) && typeof s.内容 === 'string') ? s : null;
70
+ } catch { return null; }
71
+ }
72
+
73
+ /** 原子写(tmp + rename):摘要生成要花一次真调用,别让并发读读到半个文件。 */
74
+ export async function writeSummary(dir, summary) {
75
+ const target = path.join(dir, SUMMARY_FILE);
76
+ const tmp = `${target}.tmp`;
77
+ await fs.writeFile(tmp, JSON.stringify(summary, null, 2), 'utf8');
78
+ await fs.rename(tmp, target);
79
+ }
@@ -1,193 +1,193 @@
1
- /**
2
- * chatai —— 第二条模型通路(跟 agent 会话完全无关)
3
- *
4
- * agent 走 Claude Agent SDK、有工具、会改文件;**chatai 只是一次补全调用**:
5
- * 传进去 system + messages,回来一段文本和用量。它没有工具、没有会话、
6
- * 改不了任何东西。
7
- *
8
- * 存在的理由不是省钱,是**别让高频生成挤掉设计会话**:订阅通路是全站共享的一个
9
- * OAuth 额度加并发上限,而生成类动作频次高,一跑起来能把正经设计会话挤没。
10
- *
11
- * 通路配置走 env(`CHATAI_BASE_URL` / `CHATAI_API_KEY` / `CHATAI_MODEL`),
12
- * 密钥不进代码不进 git。
13
- *
14
- * 计价:上游中转站的计量口径不透明,所以金额一律按**我们自己的单价表**算,
15
- * 谁要拿它进配额闸门就用这个数。
16
- */
17
-
18
- import { callOpenAICompat } from './openai-compat.js';
19
-
20
- /**
21
- * 模型表 —— 单价、思考档位、中转站实名,一张表说完(2026-08-15 加思考档)。
22
- *
23
- * 单价 USD / 1M token。gemini-3.7-flash 是促销价,2027-01-01 起翻倍到 1.5 / 7.5。
24
- * 思考 token 按输出计价(Gemini 的口径;Claude 的思考量直接混在 completion_tokens 里)。
25
- *
26
- * ⭐ **思考等级在中转站是模型名的一部分,不是请求参数**(2026-08-15 实测它家 100 个
27
- * 模型:gemini 系是 -low/-medium/-high 三个独立模型名,claude 系是 base 与 -thinking
28
- * 两个)。所以「档」不发 reasoning_effort,而是换实名。用户那边只看见标准名 + 一个
29
- * 档位旋钮,换渠道时改这张表就行。
30
- *
31
- * 思耗 = 粗估的「思考 token ÷ 正文 token」倍数,只给设置页算预演帐目用,不进计费。
32
- * 实测(演出类提示,2026-08-15):gemini flash 正文 234 / 思考 785 ≈ 3.4 倍,且
33
- * 低/中/高 三档的思考量差异淹在噪声里(785/587/601),别把它当精确旋钮;
34
- * claude 开思考后正文 363→408、输入 115→144(中转站往提示里塞了东西)。
35
- */
36
- export const MODEL_SPECS = Object.freeze({
37
- 'gemini-3.7-flash': {
38
- 价: { in: 0.75, out: 3.75 }, 思耗: 3.4,
39
- 注: '$0.75 / $3.75 每百万 · 促销价,思考计入输出',
40
- 默认档: '低',
41
- 档: {
42
- 低: { 名: '反重力-流式抗截断/gemini-3.7-flash-low', 注: '最省,中转站的常规档' },
43
- 中: { 名: '反重力-流式抗截断/gemini-3.7-flash-medium', 注: '中档' },
44
- 高: { 名: '反重力-流式抗截断/gemini-3.7-flash-high', 注: '让它多想一会儿(实测三档差异有限,别指望它是精确旋钮)' },
45
- },
46
- },
47
- 'gemini-3.6-flash': {
48
- 价: { in: 0.75, out: 3.75 }, 思耗: 3.4,
49
- 注: '$0.75 / $3.75 每百万 · 上一版,行文更收敛',
50
- 默认档: '低',
51
- 档: {
52
- 低: { 名: '反重力-流式抗截断/gemini-3.6-flash-low', 注: '最省,中转站的常规档' },
53
- 中: { 名: '反重力-流式抗截断/gemini-3.6-flash-medium', 注: '中档' },
54
- 高: { 名: '反重力-流式抗截断/gemini-3.6-flash-high', 注: '让它多想一会儿' },
55
- },
56
- },
57
- 'gemini-3-flash': {
58
- 价: { in: 0.50, out: 2.50 }, 思耗: 3.0,
59
- 注: '$0.50 / $2.50 每百万 · 更便宜,思考档不可调',
60
- 实名: '反重力-流式抗截断/gemini-3-flash',
61
- 档: null,
62
- },
63
- 'claude-sonnet-4-6': {
64
- 价: { in: 3.00, out: 15.00 }, 思耗: 1,
65
- 注: '$3 / $15 每百万 · 文笔更稳,一轮贵一个量级',
66
- 默认档: '关',
67
- 档: {
68
- 关: { 名: '反重力-流式抗截断/claude-sonnet-4-6', 思耗: 1, 注: '不开扩展思考' },
69
- 高: { 名: '反重力-流式抗截断/claude-sonnet-4-6-thinking', 思耗: 1.3, 注: '开扩展思考:思考走单独通道不进台词,但按输出计价' },
70
- },
71
- },
72
- 'claude-opus-4-6': {
73
- 价: { in: 15.00, out: 75.00 }, 思耗: 1,
74
- 注: '$15 / $75 每百万 · 只在真的在乎的场合;中转站常报没容量',
75
- 默认档: '关',
76
- 档: {
77
- 关: { 名: '反重力-claude-opus-4-6', 思耗: 1, 注: '不开扩展思考' },
78
- 高: { 名: '反重力-claude-opus-4-6-thinking', 思耗: 1.3, 注: '开扩展思考:思考不进台词,但按输出计价' },
79
- },
80
- },
81
- });
82
-
83
- /** 档位词表 —— 编排.yaml 只认这四个词,设置页只画模型支持的那几档 */
84
- export const LEVELS = Object.freeze(['关', '低', '中', '高']);
85
-
86
- /** 单价表(USD / 1M token),从模型表派生 —— 价格只有一处定义 */
87
- export const PRICES = Object.freeze({
88
- ...Object.fromEntries(Object.entries(MODEL_SPECS).map(([k, v]) => [k, v.价])),
89
- _default: { in: 1.00, out: 5.00 },
90
- });
91
-
92
- /** 从中转站的花式模型名里认出计价用的底模(`反重力-流式抗截断/gemini-3.7-flash-low`) */
93
- export function priceKeyOf(model) {
94
- const s = String(model || '').toLowerCase();
95
- for (const k of Object.keys(PRICES)) {
96
- if (k !== '_default' && s.includes(k)) return k;
97
- }
98
- return '_default';
99
- }
100
-
101
- /** 按单价表估这次调用多少钱。缓存读按输入价一折(隐式缓存的通行口径) */
102
- export function costOf(model, usage) {
103
- const p = PRICES[priceKeyOf(model)];
104
- const inTok = Math.max(0, (usage.inputTokens || 0) - (usage.cacheReadTokens || 0));
105
- const cached = usage.cacheReadTokens || 0;
106
- const outTok = (usage.outputTokens || 0) + (usage.reasoningTokens || 0);
107
- return (inTok * p.in + cached * p.in * 0.1 + outTok * p.out) / 1e6;
108
- }
109
-
110
- export function chataiConfig() {
111
- const base = (process.env.CHATAI_BASE_URL || '').replace(/\/+$/, '');
112
- const key = process.env.CHATAI_API_KEY || '';
113
- const model = process.env.CHATAI_MODEL || '';
114
- return { base, key, model, ok: !!(base && key && model) };
115
- }
116
-
117
- /** 简写 → 标准名(历史遗留的手写值,别再往里加) */
118
- const SHORTHAND = Object.freeze({ 'claude-sonnet': 'claude-sonnet-4-6' });
119
-
120
- /**
121
- * 标准模型名 + 思考档 → 中转站实名(2026-08-15 时停之城 503 案 + 思考档)。
122
- *
123
- * 中转站的 100 个模型**没有一个裸标准名**,全是「反重力-流式抗截断/xxx」这类
124
- * 前缀变体,思考等级也编在名字里。而 编排.yaml / 设置页 / skill 教的都是标准名
125
- * (用户不该学中转站的命名黑话,换渠道也不用改配置)。这层在发请求前换成实名。
126
- *
127
- * 档给空或者这个模型不支持这档 → 落到模型的默认档(每个模型的默认档都是最便宜
128
- * 那档),并把降级理由报回去:设置页只画支持的档,但 编排.yaml 是 agent 和人手写的,
129
- * 写岔了不该拒开演出,只该说清楚跑的是哪档。
130
- * 表里没有的模型名原样放行(直接写实名也合法)。env `CHATAI_MODEL_ALIASES`(JSON)
131
- * 覆盖标准名→实名,写了就绕开档位(中转站哪天改名,改 env 不用动代码)。
132
- *
133
- * @returns {{ 名: string, 档: string|null, 降级: string|null, 思耗: number }}
134
- */
135
- export function resolveModelVariant(model, 档) {
136
- const empty = { 名: model, 档: null, 降级: null, 思耗: 1 };
137
- if (!model) return empty;
138
- let extra = {};
139
- try { extra = JSON.parse(process.env.CHATAI_MODEL_ALIASES || '{}'); } catch { /* 坏 JSON 当没配 */ }
140
- if (extra[model]) return { ...empty, 名: extra[model] };
141
-
142
- const canonical = SHORTHAND[model] || model;
143
- const spec = MODEL_SPECS[canonical];
144
- if (!spec) return empty;
145
- if (!spec.档) {
146
- return {
147
- 名: spec.实名, 档: null, 思耗: spec.思耗,
148
- 降级: 档 ? `${canonical} 的思考档不可调,「${档}」没生效` : null,
149
- };
150
- }
151
- const 生效 = spec.档[档] ? 档 : spec.默认档;
152
- const v = spec.档[生效];
153
- return {
154
- 名: v.名, 档: 生效, 思耗: v.思耗 ?? spec.思耗,
155
- 降级: 档 && 生效 !== 档 ? `${canonical} 没有「${档}」档,按默认档「${生效}」跑` : null,
156
- };
157
- }
158
-
159
- /** 只要实名的老口径(默认档) */
160
- export function resolveModelAlias(model) {
161
- return resolveModelVariant(model).名;
162
- }
163
-
164
- /** 给设置页的模型目录:单价、档位、注释都从这一张表来,前端不再各存一份 */
165
- export function modelCatalog() {
166
- return Object.entries(MODEL_SPECS).map(([id, s]) => ({
167
- id, 入: s.价.in, 出: s.价.out, 注: s.注, 思耗: s.思耗,
168
- 档: s.档 ? Object.entries(s.档).map(([名, v]) => ({ 名, 思耗: v.思耗 ?? s.思耗, 注: v.注 ?? null })) : [],
169
- 默认档: s.默认档 ?? null,
170
- }));
171
- }
172
-
173
- /**
174
- * 跑一次 chatai。
175
- * @param {object} opts system / messages / model / 思考 / maxTokens / signal / onDelta
176
- */
177
- export async function runChatai({
178
- system = '', messages = [], model, 思考 = null, maxTokens = 2000, signal, onDelta,
179
- } = {}) {
180
- const cfg = chataiConfig();
181
- if (!cfg.ok) {
182
- throw Object.assign(
183
- new Error('chatai 通路没配置(CHATAI_BASE_URL / CHATAI_API_KEY / CHATAI_MODEL)'),
184
- { code: 'CHATAI_UNCONFIGURED' },
185
- );
186
- }
187
- const v = resolveModelVariant(model || cfg.model, 思考);
188
- const out = await callOpenAICompat({
189
- base: cfg.base, key: cfg.key, model: v.名,
190
- system, messages, maxTokens, signal, onDelta,
191
- });
192
- return { ...out, model: v.名, 档: v.档, 降级: v.降级, costUsd: costOf(v.名, out.usage) };
193
- }
1
+ /**
2
+ * chatai —— 第二条模型通路(跟 agent 会话完全无关)
3
+ *
4
+ * agent 走 Claude Agent SDK、有工具、会改文件;**chatai 只是一次补全调用**:
5
+ * 传进去 system + messages,回来一段文本和用量。它没有工具、没有会话、
6
+ * 改不了任何东西。
7
+ *
8
+ * 存在的理由不是省钱,是**别让高频生成挤掉设计会话**:订阅通路是全站共享的一个
9
+ * OAuth 额度加并发上限,而生成类动作频次高,一跑起来能把正经设计会话挤没。
10
+ *
11
+ * 通路配置走 env(`CHATAI_BASE_URL` / `CHATAI_API_KEY` / `CHATAI_MODEL`),
12
+ * 密钥不进代码不进 git。
13
+ *
14
+ * 计价:上游中转站的计量口径不透明,所以金额一律按**我们自己的单价表**算,
15
+ * 谁要拿它进配额闸门就用这个数。
16
+ */
17
+
18
+ import { callOpenAICompat } from './openai-compat.js';
19
+
20
+ /**
21
+ * 模型表 —— 单价、思考档位、中转站实名,一张表说完(2026-08-15 加思考档)。
22
+ *
23
+ * 单价 USD / 1M token。gemini-3.7-flash 是促销价,2027-01-01 起翻倍到 1.5 / 7.5。
24
+ * 思考 token 按输出计价(Gemini 的口径;Claude 的思考量直接混在 completion_tokens 里)。
25
+ *
26
+ * ⭐ **思考等级在中转站是模型名的一部分,不是请求参数**(2026-08-15 实测它家 100 个
27
+ * 模型:gemini 系是 -low/-medium/-high 三个独立模型名,claude 系是 base 与 -thinking
28
+ * 两个)。所以「档」不发 reasoning_effort,而是换实名。用户那边只看见标准名 + 一个
29
+ * 档位旋钮,换渠道时改这张表就行。
30
+ *
31
+ * 思耗 = 粗估的「思考 token ÷ 正文 token」倍数,只给设置页算预演帐目用,不进计费。
32
+ * 实测(演出类提示,2026-08-15):gemini flash 正文 234 / 思考 785 ≈ 3.4 倍,且
33
+ * 低/中/高 三档的思考量差异淹在噪声里(785/587/601),别把它当精确旋钮;
34
+ * claude 开思考后正文 363→408、输入 115→144(中转站往提示里塞了东西)。
35
+ */
36
+ export const MODEL_SPECS = Object.freeze({
37
+ 'gemini-3.7-flash': {
38
+ 价: { in: 0.75, out: 3.75 }, 思耗: 3.4,
39
+ 注: '$0.75 / $3.75 每百万 · 促销价,思考计入输出',
40
+ 默认档: '低',
41
+ 档: {
42
+ 低: { 名: '反重力-流式抗截断/gemini-3.7-flash-low', 注: '最省,中转站的常规档' },
43
+ 中: { 名: '反重力-流式抗截断/gemini-3.7-flash-medium', 注: '中档' },
44
+ 高: { 名: '反重力-流式抗截断/gemini-3.7-flash-high', 注: '让它多想一会儿(实测三档差异有限,别指望它是精确旋钮)' },
45
+ },
46
+ },
47
+ 'gemini-3.6-flash': {
48
+ 价: { in: 0.75, out: 3.75 }, 思耗: 3.4,
49
+ 注: '$0.75 / $3.75 每百万 · 上一版,行文更收敛',
50
+ 默认档: '低',
51
+ 档: {
52
+ 低: { 名: '反重力-流式抗截断/gemini-3.6-flash-low', 注: '最省,中转站的常规档' },
53
+ 中: { 名: '反重力-流式抗截断/gemini-3.6-flash-medium', 注: '中档' },
54
+ 高: { 名: '反重力-流式抗截断/gemini-3.6-flash-high', 注: '让它多想一会儿' },
55
+ },
56
+ },
57
+ 'gemini-3-flash': {
58
+ 价: { in: 0.50, out: 2.50 }, 思耗: 3.0,
59
+ 注: '$0.50 / $2.50 每百万 · 更便宜,思考档不可调',
60
+ 实名: '反重力-流式抗截断/gemini-3-flash',
61
+ 档: null,
62
+ },
63
+ 'claude-sonnet-4-6': {
64
+ 价: { in: 3.00, out: 15.00 }, 思耗: 1,
65
+ 注: '$3 / $15 每百万 · 文笔更稳,一轮贵一个量级',
66
+ 默认档: '关',
67
+ 档: {
68
+ 关: { 名: '反重力-流式抗截断/claude-sonnet-4-6', 思耗: 1, 注: '不开扩展思考' },
69
+ 高: { 名: '反重力-流式抗截断/claude-sonnet-4-6-thinking', 思耗: 1.3, 注: '开扩展思考:思考走单独通道不进台词,但按输出计价' },
70
+ },
71
+ },
72
+ 'claude-opus-4-6': {
73
+ 价: { in: 15.00, out: 75.00 }, 思耗: 1,
74
+ 注: '$15 / $75 每百万 · 只在真的在乎的场合;中转站常报没容量',
75
+ 默认档: '关',
76
+ 档: {
77
+ 关: { 名: '反重力-claude-opus-4-6', 思耗: 1, 注: '不开扩展思考' },
78
+ 高: { 名: '反重力-claude-opus-4-6-thinking', 思耗: 1.3, 注: '开扩展思考:思考不进台词,但按输出计价' },
79
+ },
80
+ },
81
+ });
82
+
83
+ /** 档位词表 —— 编排.yaml 只认这四个词,设置页只画模型支持的那几档 */
84
+ export const LEVELS = Object.freeze(['关', '低', '中', '高']);
85
+
86
+ /** 单价表(USD / 1M token),从模型表派生 —— 价格只有一处定义 */
87
+ export const PRICES = Object.freeze({
88
+ ...Object.fromEntries(Object.entries(MODEL_SPECS).map(([k, v]) => [k, v.价])),
89
+ _default: { in: 1.00, out: 5.00 },
90
+ });
91
+
92
+ /** 从中转站的花式模型名里认出计价用的底模(`反重力-流式抗截断/gemini-3.7-flash-low`) */
93
+ export function priceKeyOf(model) {
94
+ const s = String(model || '').toLowerCase();
95
+ for (const k of Object.keys(PRICES)) {
96
+ if (k !== '_default' && s.includes(k)) return k;
97
+ }
98
+ return '_default';
99
+ }
100
+
101
+ /** 按单价表估这次调用多少钱。缓存读按输入价一折(隐式缓存的通行口径) */
102
+ export function costOf(model, usage) {
103
+ const p = PRICES[priceKeyOf(model)];
104
+ const inTok = Math.max(0, (usage.inputTokens || 0) - (usage.cacheReadTokens || 0));
105
+ const cached = usage.cacheReadTokens || 0;
106
+ const outTok = (usage.outputTokens || 0) + (usage.reasoningTokens || 0);
107
+ return (inTok * p.in + cached * p.in * 0.1 + outTok * p.out) / 1e6;
108
+ }
109
+
110
+ export function chataiConfig() {
111
+ const base = (process.env.CHATAI_BASE_URL || '').replace(/\/+$/, '');
112
+ const key = process.env.CHATAI_API_KEY || '';
113
+ const model = process.env.CHATAI_MODEL || '';
114
+ return { base, key, model, ok: !!(base && key && model) };
115
+ }
116
+
117
+ /** 简写 → 标准名(历史遗留的手写值,别再往里加) */
118
+ const SHORTHAND = Object.freeze({ 'claude-sonnet': 'claude-sonnet-4-6' });
119
+
120
+ /**
121
+ * 标准模型名 + 思考档 → 中转站实名(2026-08-15 时停之城 503 案 + 思考档)。
122
+ *
123
+ * 中转站的 100 个模型**没有一个裸标准名**,全是「反重力-流式抗截断/xxx」这类
124
+ * 前缀变体,思考等级也编在名字里。而 编排.yaml / 设置页 / skill 教的都是标准名
125
+ * (用户不该学中转站的命名黑话,换渠道也不用改配置)。这层在发请求前换成实名。
126
+ *
127
+ * 档给空或者这个模型不支持这档 → 落到模型的默认档(每个模型的默认档都是最便宜
128
+ * 那档),并把降级理由报回去:设置页只画支持的档,但 编排.yaml 是 agent 和人手写的,
129
+ * 写岔了不该拒开演出,只该说清楚跑的是哪档。
130
+ * 表里没有的模型名原样放行(直接写实名也合法)。env `CHATAI_MODEL_ALIASES`(JSON)
131
+ * 覆盖标准名→实名,写了就绕开档位(中转站哪天改名,改 env 不用动代码)。
132
+ *
133
+ * @returns {{ 名: string, 档: string|null, 降级: string|null, 思耗: number }}
134
+ */
135
+ export function resolveModelVariant(model, 档) {
136
+ const empty = { 名: model, 档: null, 降级: null, 思耗: 1 };
137
+ if (!model) return empty;
138
+ let extra = {};
139
+ try { extra = JSON.parse(process.env.CHATAI_MODEL_ALIASES || '{}'); } catch { /* 坏 JSON 当没配 */ }
140
+ if (extra[model]) return { ...empty, 名: extra[model] };
141
+
142
+ const canonical = SHORTHAND[model] || model;
143
+ const spec = MODEL_SPECS[canonical];
144
+ if (!spec) return empty;
145
+ if (!spec.档) {
146
+ return {
147
+ 名: spec.实名, 档: null, 思耗: spec.思耗,
148
+ 降级: 档 ? `${canonical} 的思考档不可调,「${档}」没生效` : null,
149
+ };
150
+ }
151
+ const 生效 = spec.档[档] ? 档 : spec.默认档;
152
+ const v = spec.档[生效];
153
+ return {
154
+ 名: v.名, 档: 生效, 思耗: v.思耗 ?? spec.思耗,
155
+ 降级: 档 && 生效 !== 档 ? `${canonical} 没有「${档}」档,按默认档「${生效}」跑` : null,
156
+ };
157
+ }
158
+
159
+ /** 只要实名的老口径(默认档) */
160
+ export function resolveModelAlias(model) {
161
+ return resolveModelVariant(model).名;
162
+ }
163
+
164
+ /** 给设置页的模型目录:单价、档位、注释都从这一张表来,前端不再各存一份 */
165
+ export function modelCatalog() {
166
+ return Object.entries(MODEL_SPECS).map(([id, s]) => ({
167
+ id, 入: s.价.in, 出: s.价.out, 注: s.注, 思耗: s.思耗,
168
+ 档: s.档 ? Object.entries(s.档).map(([名, v]) => ({ 名, 思耗: v.思耗 ?? s.思耗, 注: v.注 ?? null })) : [],
169
+ 默认档: s.默认档 ?? null,
170
+ }));
171
+ }
172
+
173
+ /**
174
+ * 跑一次 chatai。
175
+ * @param {object} opts system / messages / model / 思考 / maxTokens / signal / onDelta
176
+ */
177
+ export async function runChatai({
178
+ system = '', messages = [], model, 思考 = null, maxTokens = 2000, signal, onDelta,
179
+ } = {}) {
180
+ const cfg = chataiConfig();
181
+ if (!cfg.ok) {
182
+ throw Object.assign(
183
+ new Error('chatai 通路没配置(CHATAI_BASE_URL / CHATAI_API_KEY / CHATAI_MODEL)'),
184
+ { code: 'CHATAI_UNCONFIGURED' },
185
+ );
186
+ }
187
+ const v = resolveModelVariant(model || cfg.model, 思考);
188
+ const out = await callOpenAICompat({
189
+ base: cfg.base, key: cfg.key, model: v.名,
190
+ system, messages, maxTokens, signal, onDelta,
191
+ });
192
+ return { ...out, model: v.名, 档: v.档, 降级: v.降级, costUsd: costOf(v.名, out.usage) };
193
+ }