create-windy 0.8.2 → 0.9.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 (574) hide show
  1. package/dist/cli.js +855 -560
  2. package/package.json +1 -1
  3. package/template/.windy-template.json +2 -2
  4. package/template/apps/agent-server/Dockerfile +92 -22
  5. package/template/apps/agent-server/README.md +47 -85
  6. package/template/apps/agent-server/documents/office.py +216 -0
  7. package/template/apps/agent-server/documents/query_report.py +136 -0
  8. package/template/apps/agent-server/documents/smoke.py +177 -0
  9. package/template/apps/agent-server/documents/test_boundaries.py +185 -0
  10. package/template/apps/agent-server/host-contracts.ts +56 -0
  11. package/template/apps/agent-server/install-native.ts +167 -0
  12. package/template/apps/agent-server/main.ts +179 -0
  13. package/template/apps/agent-server/native/EXTENSIONS.md +46 -0
  14. package/template/apps/agent-server/native/admission.ts +73 -0
  15. package/template/apps/agent-server/native/authorization.test.ts +176 -0
  16. package/template/apps/agent-server/native/authorization.ts +118 -0
  17. package/template/apps/agent-server/native/boundary-io.ts +93 -0
  18. package/template/apps/agent-server/native/boundary-product.ts +107 -0
  19. package/template/apps/agent-server/native/boundary-project.test.ts +247 -0
  20. package/template/apps/agent-server/native/boundary-project.ts +188 -0
  21. package/template/apps/agent-server/native/boundary.ts +188 -0
  22. package/template/apps/agent-server/native/compaction-policy.test.ts +175 -0
  23. package/template/apps/agent-server/native/config.ts +95 -0
  24. package/template/apps/agent-server/native/conversation-instructions.ts +9 -0
  25. package/template/apps/agent-server/native/extensions.test.ts +190 -0
  26. package/template/apps/agent-server/native/extensions.ts +31 -0
  27. package/template/apps/agent-server/native/host-profile.test.ts +91 -0
  28. package/template/apps/agent-server/native/host-profile.ts +33 -0
  29. package/template/apps/agent-server/native/host-test-fixture.ts +13 -0
  30. package/template/apps/agent-server/native/http.ts +129 -0
  31. package/template/apps/agent-server/native/lifecycle.test.ts +285 -0
  32. package/template/apps/agent-server/native/lifecycle.ts +136 -0
  33. package/template/apps/agent-server/native/manager.ts +292 -0
  34. package/template/apps/agent-server/native/native.test.ts +207 -0
  35. package/template/apps/agent-server/native/office-preview.test.ts +50 -0
  36. package/template/apps/agent-server/native/office-preview.ts +25 -0
  37. package/template/apps/agent-server/native/parallel-harness.ts +242 -0
  38. package/template/apps/agent-server/native/parallel-mcp-fixture.ts +97 -0
  39. package/template/apps/agent-server/native/parallel.test.ts +256 -0
  40. package/template/apps/agent-server/native/profile-composition.test.ts +147 -0
  41. package/template/apps/agent-server/native/profile.ts +307 -0
  42. package/template/apps/agent-server/native/request.ts +61 -0
  43. package/template/apps/agent-server/native/session-conflict.test.ts +235 -0
  44. package/template/apps/agent-server/native/session-conflict.ts +21 -0
  45. package/template/apps/agent-server/native/shared-skills.test.ts +128 -0
  46. package/template/apps/agent-server/native/shared-skills.ts +240 -0
  47. package/template/apps/agent-server/native/socket-lifecycle.test.ts +48 -0
  48. package/template/apps/agent-server/native/socket.ts +130 -0
  49. package/template/apps/agent-server/native/storage-lifecycle.test.ts +217 -0
  50. package/template/apps/agent-server/native/storage.ts +188 -0
  51. package/template/apps/agent-server/native/stream-authorization.test.ts +89 -0
  52. package/template/apps/agent-server/native/worker.ts +77 -0
  53. package/template/apps/agent-server/native-download.test.ts +119 -0
  54. package/template/apps/agent-server/native-download.ts +145 -0
  55. package/template/apps/agent-server/package.json +63 -0
  56. package/template/apps/agent-server/plugins/access.mjs +126 -0
  57. package/template/apps/agent-server/plugins/branding/README.md +9 -0
  58. package/template/apps/agent-server/plugins/branding/brand.css +85 -0
  59. package/template/apps/agent-server/plugins/branding/client.js +338 -0
  60. package/template/apps/agent-server/plugins/branding/index.mjs +35 -0
  61. package/template/apps/agent-server/plugins/branding/loading.d.mts +2 -0
  62. package/template/apps/agent-server/plugins/branding/loading.mjs +66 -0
  63. package/template/apps/agent-server/plugins/branding/loading.test.ts +89 -0
  64. package/template/apps/agent-server/plugins/branding/package.json +21 -0
  65. package/template/apps/agent-server/plugins/branding.test.ts +294 -0
  66. package/template/apps/agent-server/plugins/compaction.mjs +83 -0
  67. package/template/apps/agent-server/plugins/compaction.test.ts +91 -0
  68. package/template/apps/agent-server/plugins/confine-network.py +57 -0
  69. package/template/apps/agent-server/plugins/default-skills.test.ts +62 -0
  70. package/template/apps/agent-server/plugins/downloads/README.md +28 -0
  71. package/template/apps/agent-server/plugins/downloads/client.js +126 -0
  72. package/template/apps/agent-server/plugins/downloads/downloads.test.ts +222 -0
  73. package/template/apps/agent-server/plugins/downloads/index.d.mts +19 -0
  74. package/template/apps/agent-server/plugins/downloads/index.mjs +180 -0
  75. package/template/apps/agent-server/plugins/downloads/package.json +20 -0
  76. package/template/apps/agent-server/plugins/drop-overlay/README.md +24 -0
  77. package/template/apps/agent-server/plugins/drop-overlay/drop-overlay.test.ts +199 -0
  78. package/template/apps/agent-server/plugins/drop-overlay/index.d.mts +8 -0
  79. package/template/apps/agent-server/plugins/drop-overlay/index.mjs +12 -0
  80. package/template/apps/agent-server/plugins/drop-overlay/style.css +102 -0
  81. package/template/apps/agent-server/plugins/locale/client.js +61 -0
  82. package/template/apps/agent-server/plugins/locale/index.d.mts +9 -0
  83. package/template/apps/agent-server/plugins/locale/index.mjs +16 -0
  84. package/template/apps/agent-server/plugins/locale/locale.test.ts +217 -0
  85. package/template/apps/agent-server/plugins/locale/package.json +19 -0
  86. package/template/apps/agent-server/plugins/parallel.mjs +146 -0
  87. package/template/apps/agent-server/plugins/preset-registry.d.mts +2 -0
  88. package/template/apps/agent-server/plugins/preset-registry.mjs +41 -0
  89. package/template/apps/agent-server/plugins/preset-registry.test.ts +46 -0
  90. package/template/apps/agent-server/plugins/questions.d.mts +25 -0
  91. package/template/apps/agent-server/plugins/questions.mjs +142 -0
  92. package/template/apps/agent-server/plugins/questions.test.ts +105 -0
  93. package/template/apps/agent-server/plugins/settings/README.md +17 -0
  94. package/template/apps/agent-server/plugins/settings/client.js +102 -0
  95. package/template/apps/agent-server/plugins/settings/index.mjs +17 -0
  96. package/template/apps/agent-server/plugins/settings/package.json +19 -0
  97. package/template/apps/agent-server/plugins/settings/settings.test.ts +129 -0
  98. package/template/apps/agent-server/plugins/settings-controller.d.mts +4 -0
  99. package/template/apps/agent-server/plugins/settings-controller.mjs +31 -0
  100. package/template/apps/agent-server/plugins/settings-controller.test.ts +17 -0
  101. package/template/apps/agent-server/plugins/settings-dispatch.test.ts +34 -0
  102. package/template/apps/agent-server/plugins/shared-skills.d.mts +15 -0
  103. package/template/apps/agent-server/plugins/shared-skills.mjs +82 -0
  104. package/template/apps/agent-server/plugins/shared-skills.test.ts +51 -0
  105. package/template/apps/agent-server/plugins/skill-library/README.md +11 -0
  106. package/template/apps/agent-server/plugins/skill-library/archive.test.ts +43 -0
  107. package/template/apps/agent-server/plugins/skill-library/bundle.mjs +234 -0
  108. package/template/apps/agent-server/plugins/skill-library/client-chunks.test.ts +107 -0
  109. package/template/apps/agent-server/plugins/skill-library/client-form-mount.test.ts +139 -0
  110. package/template/apps/agent-server/plugins/skill-library/client-form.test.ts +261 -0
  111. package/template/apps/agent-server/plugins/skill-library/client-ui.test.ts +268 -0
  112. package/template/apps/agent-server/plugins/skill-library/client-use.test.ts +158 -0
  113. package/template/apps/agent-server/plugins/skill-library/client.editor.js +93 -0
  114. package/template/apps/agent-server/plugins/skill-library/client.form.js +316 -0
  115. package/template/apps/agent-server/plugins/skill-library/client.js +348 -0
  116. package/template/apps/agent-server/plugins/skill-library/client.request.js +52 -0
  117. package/template/apps/agent-server/plugins/skill-library/client.transfer.js +48 -0
  118. package/template/apps/agent-server/plugins/skill-library/client.use.js +46 -0
  119. package/template/apps/agent-server/plugins/skill-library/default-roots.test.ts +84 -0
  120. package/template/apps/agent-server/plugins/skill-library/draft.d.mts +17 -0
  121. package/template/apps/agent-server/plugins/skill-library/draft.mjs +152 -0
  122. package/template/apps/agent-server/plugins/skill-library/draft.test.ts +287 -0
  123. package/template/apps/agent-server/plugins/skill-library/index.d.mts +49 -0
  124. package/template/apps/agent-server/plugins/skill-library/index.mjs +226 -0
  125. package/template/apps/agent-server/plugins/skill-library/package.json +24 -0
  126. package/template/apps/agent-server/plugins/skill-library/presentation/README.md +27 -0
  127. package/template/apps/agent-server/plugins/skill-library/presentation/UPSTREAM.md +54 -0
  128. package/template/apps/agent-server/plugins/skill-library/presentation/boot.test.ts +150 -0
  129. package/template/apps/agent-server/plugins/skill-library/presentation/client.js +146 -0
  130. package/template/apps/agent-server/plugins/skill-library/presentation/client.test.ts +195 -0
  131. package/template/apps/agent-server/plugins/skill-library/presentation/index.d.mts +9 -0
  132. package/template/apps/agent-server/plugins/skill-library/presentation/index.mjs +30 -0
  133. package/template/apps/agent-server/plugins/skill-library/presentation/metadata.test.ts +82 -0
  134. package/template/apps/agent-server/plugins/skill-library/presentation/package.json +21 -0
  135. package/template/apps/agent-server/plugins/skill-library/presentation/react-boot.test.ts +162 -0
  136. package/template/apps/agent-server/plugins/skill-library/skills.test.ts +342 -0
  137. package/template/apps/agent-server/plugins/skill-library/storage.mjs +293 -0
  138. package/template/apps/agent-server/plugins/skill-library/style.css +229 -0
  139. package/template/apps/agent-server/plugins/skill-library/test-fixture.ts +77 -0
  140. package/template/apps/agent-server/plugins/skill-library/workflow.d.mts +18 -0
  141. package/template/apps/agent-server/plugins/skill-library/workflow.mjs +189 -0
  142. package/template/apps/agent-server/plugins/skill-library/workflow.test.ts +164 -0
  143. package/template/apps/agent-server/plugins/skills/README.md +5 -0
  144. package/template/apps/agent-server/plugins/skills/windy-data-summary/SKILL.md +14 -0
  145. package/template/apps/agent-server/plugins/skills/windy-extension-guide/SKILL.md +14 -0
  146. package/template/apps/agent-server/plugins/skills/windy-office/SKILL.md +14 -0
  147. package/template/apps/agent-server/plugins/skills/windy-skill-capture/SKILL.md +14 -0
  148. package/template/apps/agent-server/plugins/skills/windy-source-compare/SKILL.md +14 -0
  149. package/template/apps/agent-server/plugins/subprocess.mjs +40 -0
  150. package/template/apps/agent-server/plugins/theme/README.md +18 -0
  151. package/template/apps/agent-server/plugins/theme/client.js +18 -0
  152. package/template/apps/agent-server/plugins/theme/index.d.mts +9 -0
  153. package/template/apps/agent-server/plugins/theme/index.mjs +18 -0
  154. package/template/apps/agent-server/plugins/theme/package.json +19 -0
  155. package/template/apps/agent-server/plugins/theme/source-tokens.ts +82 -0
  156. package/template/apps/agent-server/plugins/theme/sync-tokens.ts +12 -0
  157. package/template/apps/agent-server/plugins/theme/theme.test.ts +193 -0
  158. package/template/apps/agent-server/plugins/theme/tokens.json +166 -0
  159. package/template/apps/agent-server/plugins/tool-catalog/README.md +79 -0
  160. package/template/apps/agent-server/plugins/tool-catalog/categories.mjs +111 -0
  161. package/template/apps/agent-server/plugins/tool-catalog/categories.test.ts +118 -0
  162. package/template/apps/agent-server/plugins/tool-catalog/client-cache.test.ts +264 -0
  163. package/template/apps/agent-server/plugins/tool-catalog/client.js +333 -0
  164. package/template/apps/agent-server/plugins/tool-catalog/client.test.ts +136 -0
  165. package/template/apps/agent-server/plugins/tool-catalog/discovery.d.mts +42 -0
  166. package/template/apps/agent-server/plugins/tool-catalog/discovery.mjs +242 -0
  167. package/template/apps/agent-server/plugins/tool-catalog/discovery.test.ts +229 -0
  168. package/template/apps/agent-server/plugins/tool-catalog/index.d.mts +5 -0
  169. package/template/apps/agent-server/plugins/tool-catalog/index.mjs +91 -0
  170. package/template/apps/agent-server/plugins/tool-catalog/package.json +23 -0
  171. package/template/apps/agent-server/plugins/tool-catalog/presentation.d.mts +21 -0
  172. package/template/apps/agent-server/plugins/tool-catalog/presentation.mjs +153 -0
  173. package/template/apps/agent-server/plugins/tool-catalog/presentation.test.ts +166 -0
  174. package/template/apps/agent-server/plugins/tool-catalog/routes.test.ts +209 -0
  175. package/template/apps/agent-server/plugins/tool-catalog/style.css +155 -0
  176. package/template/apps/agent-server/plugins/tool-catalog/use-tool.test.ts +160 -0
  177. package/template/apps/agent-server/plugins/tool-presentation/README.md +7 -0
  178. package/template/apps/agent-server/plugins/tool-presentation/build-client.ts +29 -0
  179. package/template/apps/agent-server/plugins/tool-presentation/client.js +312 -0
  180. package/template/apps/agent-server/plugins/tool-presentation/client.results.js +9 -0
  181. package/template/apps/agent-server/plugins/tool-presentation/client.test.ts +178 -0
  182. package/template/apps/agent-server/plugins/tool-presentation/index.mjs +10 -0
  183. package/template/apps/agent-server/plugins/tool-presentation/package.json +24 -0
  184. package/template/apps/agent-server/plugins/tool-presentation/result-discovery.mjs +43 -0
  185. package/template/apps/agent-server/plugins/tool-presentation/result-model.d.mts +51 -0
  186. package/template/apps/agent-server/plugins/tool-presentation/result-model.mjs +96 -0
  187. package/template/apps/agent-server/plugins/workspace/README.md +5 -0
  188. package/template/apps/agent-server/plugins/workspace/index.mjs +8 -0
  189. package/template/apps/agent-server/plugins/workspace/package.json +10 -0
  190. package/template/apps/agent-server/plugins/workspace/style.css +124 -0
  191. package/template/apps/agent-server/project/host.ts +13 -0
  192. package/template/apps/agent-server/runtime/artifacts.ts +115 -0
  193. package/template/apps/agent-server/runtime/audit.nodecheck.ts +60 -0
  194. package/template/apps/agent-server/runtime/capacity.ts +61 -0
  195. package/template/apps/agent-server/runtime/client-completion-budget.nodecheck.ts +92 -0
  196. package/template/apps/agent-server/runtime/compatibility.ts +33 -0
  197. package/template/apps/agent-server/runtime/completions.ts +320 -0
  198. package/template/apps/agent-server/runtime/config.ts +246 -0
  199. package/template/apps/agent-server/runtime/context-budget.ts +70 -0
  200. package/template/apps/agent-server/runtime/context-plugin.ts +306 -0
  201. package/template/apps/agent-server/runtime/context.nodecheck.ts +241 -0
  202. package/template/apps/agent-server/runtime/contracts.ts +201 -0
  203. package/template/apps/agent-server/runtime/dsh-engine.ts +196 -0
  204. package/template/apps/agent-server/runtime/evaluation-plugin.ts +115 -0
  205. package/template/apps/agent-server/runtime/evaluation.nodecheck.ts +194 -0
  206. package/template/apps/agent-server/runtime/events.ts +71 -0
  207. package/template/apps/agent-server/runtime/governance.ts +194 -0
  208. package/template/apps/agent-server/runtime/index.ts +339 -0
  209. package/template/apps/agent-server/runtime/internal-output.ts +37 -0
  210. package/template/apps/agent-server/runtime/isolation.nodecheck.ts +287 -0
  211. package/template/apps/agent-server/runtime/model-payload.ts +97 -0
  212. package/template/apps/agent-server/runtime/model-plugin.ts +308 -0
  213. package/template/apps/agent-server/runtime/model-route.ts +34 -0
  214. package/template/apps/agent-server/runtime/model-usage.ts +51 -0
  215. package/template/apps/agent-server/runtime/model-wire.ts +45 -0
  216. package/template/apps/agent-server/runtime/native-authorization.nodecheck.ts +126 -0
  217. package/template/apps/agent-server/runtime/native-completion.nodecheck.ts +81 -0
  218. package/template/apps/agent-server/runtime/output-validation.ts +66 -0
  219. package/template/apps/agent-server/runtime/production-capacity.nodecheck.ts +121 -0
  220. package/template/apps/agent-server/runtime/questions-workflow.nodecheck.ts +249 -0
  221. package/template/apps/agent-server/runtime/report-breakdown.ts +79 -0
  222. package/template/apps/agent-server/runtime/reporting.ts +219 -0
  223. package/template/apps/agent-server/runtime/run-completion.ts +39 -0
  224. package/template/apps/agent-server/runtime/run-request-digest.ts +18 -0
  225. package/template/apps/agent-server/runtime/runtime-test-fixtures.ts +264 -0
  226. package/template/apps/agent-server/runtime/runtime.nodecheck.ts +150 -0
  227. package/template/apps/agent-server/runtime/store-idempotency.nodecheck.ts +74 -0
  228. package/template/apps/agent-server/runtime/store.ts +324 -0
  229. package/template/apps/agent-server/runtime/structured-output-mode.nodecheck.ts +51 -0
  230. package/template/apps/agent-server/runtime/tool-name.ts +6 -0
  231. package/template/apps/agent-server/runtime/tool-plugin.ts +201 -0
  232. package/template/apps/agent-server/runtime/vision-readiness.ts +200 -0
  233. package/template/apps/agent-server/scripts/confinement-check.mjs +103 -0
  234. package/template/apps/agent-server/scripts/coordinator-check.mjs +344 -0
  235. package/template/apps/agent-server/scripts/documents-delivery-check.mjs +309 -0
  236. package/template/apps/agent-server/scripts/office-preview-check.mjs +92 -0
  237. package/template/apps/agent-server/scripts/test-confinement.ts +58 -0
  238. package/template/apps/agent-server/scripts/test-coordinator.ts +36 -0
  239. package/template/apps/agent-server/scripts/test-runtime.ts +46 -0
  240. package/template/apps/agent-server/tsconfig.json +21 -0
  241. package/template/apps/server/Dockerfile +3 -0
  242. package/template/apps/server/package.json +5 -1
  243. package/template/apps/server/scripts/check-dsh-platform-example.ts +251 -0
  244. package/template/apps/server/src/agent/admin-catalog-bootstrap.ts +25 -0
  245. package/template/apps/server/src/agent/agent-session-bootstrap.ts +7 -8
  246. package/template/apps/server/src/agent/agent-session-facade.ts +12 -0
  247. package/template/apps/server/src/agent/agent-session-validation.ts +43 -0
  248. package/template/apps/server/src/agent/dsh-runtime-wire.test.ts +33 -0
  249. package/template/apps/server/src/agent/governance-runtime.ts +41 -0
  250. package/template/apps/server/src/agent/operation-catalog.test.ts +202 -0
  251. package/template/apps/server/src/agent/operation-catalog.ts +135 -0
  252. package/template/apps/server/src/agent/remote-runtime-response.ts +1 -1
  253. package/template/apps/server/src/agent/run-browser-visibility.test.ts +59 -0
  254. package/template/apps/server/src/agent/run-browser-visibility.ts +11 -0
  255. package/template/apps/server/src/agent/run-contracts.ts +1 -0
  256. package/template/apps/server/src/agent/run-definition-support.ts +9 -0
  257. package/template/apps/server/src/agent/run-operation-policy.ts +1 -0
  258. package/template/apps/server/src/agent/run-route-response.ts +35 -0
  259. package/template/apps/server/src/agent/run-routes.ts +46 -43
  260. package/template/apps/server/src/agent/runtime-bootstrap.ts +21 -20
  261. package/template/apps/server/src/agent/runtime-disabled-composition.ts +28 -0
  262. package/template/apps/server/src/agent/runtime-tool-composition.ts +2 -0
  263. package/template/apps/server/src/agent/session-projection-facade.ts +8 -9
  264. package/template/apps/server/src/agent/session-projection-governance.ts +10 -0
  265. package/template/apps/server/src/agent/session-projection-view.ts +19 -16
  266. package/template/apps/server/src/agent/session-recording-reader.contract.test.ts +131 -0
  267. package/template/apps/server/src/agent/session-recording-reader.ts +62 -0
  268. package/template/apps/server/src/agent/tool-catalog-audit.ts +22 -0
  269. package/template/apps/server/src/agent/tool-catalog-availability.ts +21 -0
  270. package/template/apps/server/src/agent/tool-catalog-routes.test.ts +103 -0
  271. package/template/apps/server/src/agent/tool-catalog-routes.ts +62 -0
  272. package/template/apps/server/src/agent/tool-catalog.test.ts +122 -0
  273. package/template/apps/server/src/agent/tool-catalog.ts +44 -0
  274. package/template/apps/server/src/agent/tool-registry.ts +45 -14
  275. package/template/apps/server/src/agent/workbench-bootstrap.ts +39 -0
  276. package/template/apps/server/src/agent/workbench-event-projection.ts +115 -0
  277. package/template/apps/server/src/agent/workbench-facade.contract.test.ts +189 -0
  278. package/template/apps/server/src/agent/workbench-facade.ts +339 -0
  279. package/template/apps/server/src/agent/workbench-recording.contract.test.ts +328 -0
  280. package/template/apps/server/src/agent/workbench-routes.ts +97 -0
  281. package/template/apps/server/src/agent/workbench-run-integration.test.ts +231 -0
  282. package/template/apps/server/src/agent/workbench-run-reader.ts +187 -0
  283. package/template/apps/server/src/agent/workbench-safe-result.ts +61 -0
  284. package/template/apps/server/src/agent/workbench-sse.ts +50 -0
  285. package/template/apps/server/src/agent/workflow-runtime-bootstrap.ts +9 -0
  286. package/template/apps/server/src/agent-skills/access.ts +88 -0
  287. package/template/apps/server/src/agent-skills/bootstrap.ts +49 -0
  288. package/template/apps/server/src/agent-skills/builtin-registration.ts +83 -0
  289. package/template/apps/server/src/agent-skills/builtins.ts +19 -0
  290. package/template/apps/server/src/agent-skills/bundle-zip.ts +163 -0
  291. package/template/apps/server/src/agent-skills/bundle.test.ts +79 -0
  292. package/template/apps/server/src/agent-skills/bundle.ts +133 -0
  293. package/template/apps/server/src/agent-skills/contracts.ts +46 -0
  294. package/template/apps/server/src/agent-skills/drizzle-repository.ts +125 -0
  295. package/template/apps/server/src/agent-skills/input.ts +29 -0
  296. package/template/apps/server/src/agent-skills/postgres.integration.test.ts +348 -0
  297. package/template/apps/server/src/agent-skills/read-routes.test.ts +116 -0
  298. package/template/apps/server/src/agent-skills/reader.ts +108 -0
  299. package/template/apps/server/src/agent-skills/repository.ts +105 -0
  300. package/template/apps/server/src/agent-skills/routes.ts +176 -0
  301. package/template/apps/server/src/agent-skills/service.test.ts +295 -0
  302. package/template/apps/server/src/agent-skills/service.ts +301 -0
  303. package/template/apps/server/src/agent-workflow/preset-registry.test.ts +137 -0
  304. package/template/apps/server/src/agent-workflow/preset-registry.ts +191 -0
  305. package/template/apps/server/src/agent-workflow/preset-routes.test.ts +94 -0
  306. package/template/apps/server/src/agent-workflow/preset-routes.ts +45 -0
  307. package/template/apps/server/src/agent-workflow/query-service.ts +36 -0
  308. package/template/apps/server/src/agent-workflow/recording-projection.contract.test.ts +196 -0
  309. package/template/apps/server/src/agent-workflow/recording-projection.ts +86 -0
  310. package/template/apps/server/src/ai-runtime-report/service.test.ts +10 -7
  311. package/template/apps/server/src/ai-runtime-report/service.ts +1 -1
  312. package/template/apps/server/src/app/agent-workflow-presets.ts +4 -0
  313. package/template/apps/server/src/app/dsh-skill-draft-audit.test.ts +195 -0
  314. package/template/apps/server/src/app/dsh-skill-draft-audit.ts +115 -0
  315. package/template/apps/server/src/app/dsh-workbench-audit.test.ts +71 -0
  316. package/template/apps/server/src/app/dsh-workbench-audit.ts +34 -0
  317. package/template/apps/server/src/app/dsh-workbench-handshake.test.ts +63 -0
  318. package/template/apps/server/src/app/dsh-workbench-handshake.ts +48 -0
  319. package/template/apps/server/src/app/dsh-workbench-http.test.ts +96 -0
  320. package/template/apps/server/src/app/dsh-workbench-lan-origin.test.ts +114 -0
  321. package/template/apps/server/src/app/dsh-workbench-launch.test.ts +70 -0
  322. package/template/apps/server/src/app/dsh-workbench-origin.test.ts +54 -0
  323. package/template/apps/server/src/app/dsh-workbench-proxy.ts +205 -0
  324. package/template/apps/server/src/app/dsh-workbench-session-conflict.test.ts +61 -0
  325. package/template/apps/server/src/app/dsh-workbench-session.ts +59 -0
  326. package/template/apps/server/src/app/dsh-workbench-socket-audit.test.ts +115 -0
  327. package/template/apps/server/src/app/dsh-workbench-socket.test.ts +246 -0
  328. package/template/apps/server/src/app/dsh-workbench-socket.ts +272 -0
  329. package/template/apps/server/src/app/dsh-workbench-test-support.ts +158 -0
  330. package/template/apps/server/src/app/dsh-workbench.test.ts +213 -0
  331. package/template/apps/server/src/app/dsh-workbench.ts +279 -0
  332. package/template/apps/server/src/app/workbench-public-origin.ts +16 -0
  333. package/template/apps/server/src/data-governance/user-plaintext-routes.test.ts +3 -0
  334. package/template/apps/server/src/http-app.ts +31 -0
  335. package/template/apps/server/src/mcp/adapter.ts +1 -0
  336. package/template/apps/server/src/module-composition.test.ts +23 -0
  337. package/template/apps/server/src/module-composition.ts +9 -2
  338. package/template/apps/server/src/observability/bootstrap.ts +12 -0
  339. package/template/apps/server/src/observability/diagnostic-failure-recorder.ts +94 -0
  340. package/template/apps/server/src/observability/diagnostic-http-contract.test.ts +42 -0
  341. package/template/apps/server/src/observability/diagnostic-index.test.ts +89 -0
  342. package/template/apps/server/src/observability/diagnostic-index.ts +88 -0
  343. package/template/apps/server/src/observability/diagnostic-repository.ts +67 -0
  344. package/template/apps/server/src/platform-app-bootstrap.ts +42 -0
  345. package/template/apps/server/src/platform-http-runtime.ts +6 -0
  346. package/template/apps/server/src/runtime-development.test.ts +25 -0
  347. package/template/apps/server/src/runtime-development.ts +6 -44
  348. package/template/apps/server/src/system/diagnostic-routes.test.ts +78 -0
  349. package/template/apps/server/src/system/diagnostic-routes.ts +66 -0
  350. package/template/apps/web/Dockerfile +9 -1
  351. package/template/apps/web/dev/start.ts +21 -10
  352. package/template/apps/web/dsh-workbench-location.ts +21 -0
  353. package/template/apps/web/dsh-workbench-proxy.test.ts +121 -0
  354. package/template/apps/web/dsh-workbench-proxy.ts +194 -0
  355. package/template/apps/web/package.json +3 -1
  356. package/template/apps/web/server.ts +27 -6
  357. package/template/apps/web/src/composables/useLoginFlow.ts +13 -1
  358. package/template/apps/web/src/pages/errors/PlatformErrorPage.vue +6 -0
  359. package/template/apps/web/src/pages/errors/PlatformErrorPage.webtest.ts +14 -1
  360. package/template/apps/web/src/pages/errors/error-page-extension.ts +1 -0
  361. package/template/apps/web/src/pages/system/AgentDebugPage.vue +14 -0
  362. package/template/apps/web/src/pages/system/AgentNativePage.vue +44 -0
  363. package/template/apps/web/src/pages/system/AgentSessionPage.vue +29 -8
  364. package/template/apps/web/src/pages/system/AgentToolsPage.vue +76 -0
  365. package/template/apps/web/src/pages/system/AgentWorkflowPage.vue +20 -7
  366. package/template/apps/web/src/pages/system/DiagnosticLookupPage.vue +56 -0
  367. package/template/apps/web/src/pages/system/DiagnosticLookupPage.webtest.ts +99 -0
  368. package/template/apps/web/src/pages/system/SystemAgentSkillsPage.vue +88 -0
  369. package/template/apps/web/src/pages/system/components/DiagnosticRecordDetails.vue +52 -0
  370. package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillDetailDialog.vue +166 -0
  371. package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillGovernanceActionDialog.vue +51 -0
  372. package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillImportDialog.vue +320 -0
  373. package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillImportDialog.webtest.ts +96 -0
  374. package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillsTable.vue +69 -0
  375. package/template/apps/web/src/pages/system/components/agent-workbench/AgentWorkbench.vue +236 -0
  376. package/template/apps/web/src/pages/system/components/agent-workbench/DraftLeaveDialog.vue +34 -0
  377. package/template/apps/web/src/pages/system/components/agent-workbench/ReplayEventDetail.vue +175 -0
  378. package/template/apps/web/src/pages/system/components/agent-workbench/SessionReplayTimeline.vue +142 -0
  379. package/template/apps/web/src/pages/system/components/agent-workbench/SessionReplayTimeline.webtest.ts +242 -0
  380. package/template/apps/web/src/pages/system/components/agent-workbench/TestRunComposer.vue +97 -0
  381. package/template/apps/web/src/pages/system/components/agent-workbench/ToolCatalogPanel.vue +100 -0
  382. package/template/apps/web/src/pages/system/components/agent-workbench/ToolCatalogPanel.webtest.ts +55 -0
  383. package/template/apps/web/src/pages/system/components/agent-workbench/ToolRuleDetail.vue +81 -0
  384. package/template/apps/web/src/pages/system/components/agent-workbench/WorkbenchSessionList.vue +57 -0
  385. package/template/apps/web/src/pages/system/components/agent-workbench/catalog-presenter.ts +20 -0
  386. package/template/apps/web/src/pages/system/components/agent-workbench/replay-presenter.ts +94 -0
  387. package/template/apps/web/src/pages/system/components/agent-workflow/WorkflowPresetCatalog.vue +82 -0
  388. package/template/apps/web/src/pages/system/components/agent-workflow/WorkflowPresetCatalog.webtest.ts +57 -0
  389. package/template/apps/web/src/pages/system/composables/useAgentSkillsGovernance.ts +105 -0
  390. package/template/apps/web/src/pages/system/composables/useAgentWorkbench.ts +298 -0
  391. package/template/apps/web/src/pages/system/composables/useAgentWorkbench.webtest.ts +164 -0
  392. package/template/apps/web/src/pages/system/composables/useAgentWorkflowPresets.ts +44 -0
  393. package/template/apps/web/src/pages/system/composables/useDiagnosticLookup.ts +64 -0
  394. package/template/apps/web/src/pages/system/composables/useSessionReplay.ts +48 -0
  395. package/template/apps/web/src/router/error-navigation.ts +3 -1
  396. package/template/apps/web/src/router/error-navigation.webtest.ts +14 -2
  397. package/template/apps/web/src/router/index.ts +8 -45
  398. package/template/apps/web/src/router/platform-admin-pages.ts +79 -0
  399. package/template/apps/web/src/router/platform-admin-route-bindings.ts +12 -0
  400. package/template/apps/web/src/services/agent-admin-api.ts +155 -0
  401. package/template/apps/web/src/services/agent-admin-api.webtest.ts +120 -0
  402. package/template/apps/web/src/services/agent-skills-api.ts +55 -0
  403. package/template/apps/web/src/services/agent-workbench-event.ts +60 -0
  404. package/template/apps/web/src/services/agent-workflow-api.ts +12 -0
  405. package/template/apps/web/src/services/diagnostics-api.ts +12 -0
  406. package/template/apps/web/src/services/http.ts +18 -0
  407. package/template/apps/web/src/services/http.webtest.ts +51 -0
  408. package/template/apps/web/vite.config.ts +39 -0
  409. package/template/deploy/dsh/README.md +5 -0
  410. package/template/deploy/dsh/documents/README.md +9 -0
  411. package/template/deploy/dsh/documents/requirements.in +6 -0
  412. package/template/deploy/dsh/documents/requirements.lock +72 -0
  413. package/template/docker-compose.yml +24 -10
  414. package/template/docs/adr/0004-embedded-dsh-runtime.md +9 -0
  415. package/template/docs/architecture/agent-admin-workbench-implementation.md +73 -0
  416. package/template/docs/architecture/agent-admin-workbench-plan.md +41 -0
  417. package/template/docs/architecture/agent-harness.md +6 -0
  418. package/template/docs/architecture/agent-runtime-compatibility.md +2 -0
  419. package/template/docs/architecture/embedded-dsh-integration.md +44 -0
  420. package/template/docs/development/dsh-plugins.md +55 -0
  421. package/template/docs/operations/dsh-agent-migration.md +98 -0
  422. package/template/docs/platform/agent-production-store.md +5 -78
  423. package/template/docs/platform/agent-runtime-observability.md +2 -0
  424. package/template/docs/platform/agent-runtime.md +2 -0
  425. package/template/docs/platform/agent-skills.md +25 -0
  426. package/template/package.json +4 -3
  427. package/template/packages/database/drizzle/0064_dsh_skills_diagnostics.sql +42 -0
  428. package/template/packages/database/drizzle/meta/0064_snapshot.json +15349 -0
  429. package/template/packages/database/drizzle/meta/_journal.json +7 -0
  430. package/template/packages/database/package.json +2 -2
  431. package/template/packages/database/src/schema/agent-skills.ts +65 -0
  432. package/template/packages/database/src/schema/diagnostics.ts +27 -0
  433. package/template/packages/database/src/schema/index.ts +8 -0
  434. package/template/packages/modules/package.json +1 -1
  435. package/template/packages/modules/src/ai-operation-composition.ts +9 -0
  436. package/template/packages/modules/src/ai-operation-visibility.test.ts +33 -0
  437. package/template/packages/modules/src/manifest.ts +2 -0
  438. package/template/packages/modules/src/system-admin-routes.ts +40 -0
  439. package/template/packages/modules/src/system-admin-ui-catalog.ts +24 -11
  440. package/template/packages/modules/src/system-agent-admin-bindings.ts +44 -0
  441. package/template/packages/modules/src/system-agent-admin-menus.ts +46 -0
  442. package/template/packages/modules/src/system-agent-admin-registration.test.ts +52 -0
  443. package/template/packages/modules/src/system-agent-audit-actions.ts +8 -0
  444. package/template/packages/modules/src/system-agent-dsh.ts +119 -0
  445. package/template/packages/modules/src/system-ai-api-bindings.ts +2 -0
  446. package/template/packages/modules/src/system-api-permissions.ts +9 -0
  447. package/template/packages/modules/src/system-audit-actions.ts +36 -0
  448. package/template/packages/modules/src/system-features.ts +24 -0
  449. package/template/packages/modules/src/system-module-audit-selection.ts +25 -0
  450. package/template/packages/modules/src/system-module-catalog.ts +22 -40
  451. package/template/packages/modules/src/system-module-ownership.ts +12 -0
  452. package/template/packages/modules/src/system-modules.ts +16 -3
  453. package/template/packages/modules/src/system-permissions.ts +15 -0
  454. package/template/packages/server-sdk/index.ts +2 -0
  455. package/template/packages/server-sdk/package.json +2 -2
  456. package/template/packages/server-sdk/src/agent-session-provider.ts +19 -0
  457. package/template/packages/shared/index.ts +14 -0
  458. package/template/packages/shared/package.json +1 -1
  459. package/template/packages/shared/src/agent-admin-catalog.ts +73 -0
  460. package/template/packages/shared/src/agent-skills.ts +68 -0
  461. package/template/packages/shared/src/agent-workbench.ts +100 -0
  462. package/template/packages/shared/src/agent-workflow-presets.ts +26 -0
  463. package/template/packages/shared/src/diagnostics.ts +13 -0
  464. package/template/packages/shared/src/rbac.ts +1 -0
  465. package/template/apps/agent-server/install-python-dependencies.sh +0 -92
  466. package/template/apps/agent-server/pyproject.toml +0 -51
  467. package/template/apps/agent-server/src/southwind_agent_server/__init__.py +0 -5
  468. package/template/apps/agent-server/src/southwind_agent_server/app.py +0 -344
  469. package/template/apps/agent-server/src/southwind_agent_server/approval_resolution.py +0 -30
  470. package/template/apps/agent-server/src/southwind_agent_server/artifact_input.py +0 -153
  471. package/template/apps/agent-server/src/southwind_agent_server/asgi.py +0 -8
  472. package/template/apps/agent-server/src/southwind_agent_server/attempt_context.py +0 -199
  473. package/template/apps/agent-server/src/southwind_agent_server/attempt_context_projection.py +0 -203
  474. package/template/apps/agent-server/src/southwind_agent_server/client_completion_contracts.py +0 -61
  475. package/template/apps/agent-server/src/southwind_agent_server/client_completion_governance.py +0 -82
  476. package/template/apps/agent-server/src/southwind_agent_server/client_completion_routes.py +0 -121
  477. package/template/apps/agent-server/src/southwind_agent_server/client_completion_runtime.py +0 -158
  478. package/template/apps/agent-server/src/southwind_agent_server/config.py +0 -267
  479. package/template/apps/agent-server/src/southwind_agent_server/context_message_digest.py +0 -24
  480. package/template/apps/agent-server/src/southwind_agent_server/context_version_contracts.py +0 -71
  481. package/template/apps/agent-server/src/southwind_agent_server/context_version_port.py +0 -307
  482. package/template/apps/agent-server/src/southwind_agent_server/contracts.py +0 -297
  483. package/template/apps/agent-server/src/southwind_agent_server/deterministic.py +0 -63
  484. package/template/apps/agent-server/src/southwind_agent_server/engine.py +0 -134
  485. package/template/apps/agent-server/src/southwind_agent_server/engine_capacity.py +0 -31
  486. package/template/apps/agent-server/src/southwind_agent_server/engine_identity.py +0 -2
  487. package/template/apps/agent-server/src/southwind_agent_server/fingerprint.py +0 -61
  488. package/template/apps/agent-server/src/southwind_agent_server/health_routes.py +0 -93
  489. package/template/apps/agent-server/src/southwind_agent_server/http_helpers.py +0 -62
  490. package/template/apps/agent-server/src/southwind_agent_server/lease.py +0 -15
  491. package/template/apps/agent-server/src/southwind_agent_server/multimodal.py +0 -76
  492. package/template/apps/agent-server/src/southwind_agent_server/openai_engine.py +0 -329
  493. package/template/apps/agent-server/src/southwind_agent_server/openai_engine_validation.py +0 -165
  494. package/template/apps/agent-server/src/southwind_agent_server/openai_provider.py +0 -345
  495. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_insert.py +0 -37
  496. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_queries.py +0 -235
  497. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_replay.py +0 -44
  498. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_status.py +0 -83
  499. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_store.py +0 -336
  500. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_summary.py +0 -304
  501. package/template/apps/agent-server/src/southwind_agent_server/postgres_store.py +0 -335
  502. package/template/apps/agent-server/src/southwind_agent_server/postgres_store_backend.py +0 -333
  503. package/template/apps/agent-server/src/southwind_agent_server/provider_audit.py +0 -144
  504. package/template/apps/agent-server/src/southwind_agent_server/provider_governance.py +0 -309
  505. package/template/apps/agent-server/src/southwind_agent_server/provider_output_guidance.py +0 -34
  506. package/template/apps/agent-server/src/southwind_agent_server/readiness_pin.py +0 -37
  507. package/template/apps/agent-server/src/southwind_agent_server/report_lifecycle.py +0 -218
  508. package/template/apps/agent-server/src/southwind_agent_server/report_metrics.py +0 -149
  509. package/template/apps/agent-server/src/southwind_agent_server/report_presenter.py +0 -300
  510. package/template/apps/agent-server/src/southwind_agent_server/report_routes.py +0 -132
  511. package/template/apps/agent-server/src/southwind_agent_server/report_store.py +0 -298
  512. package/template/apps/agent-server/src/southwind_agent_server/report_store_protocol.py +0 -75
  513. package/template/apps/agent-server/src/southwind_agent_server/report_types.py +0 -118
  514. package/template/apps/agent-server/src/southwind_agent_server/run_admission.py +0 -64
  515. package/template/apps/agent-server/src/southwind_agent_server/run_capacity.py +0 -59
  516. package/template/apps/agent-server/src/southwind_agent_server/runtime_budget.py +0 -74
  517. package/template/apps/agent-server/src/southwind_agent_server/runtime_compatibility.py +0 -89
  518. package/template/apps/agent-server/src/southwind_agent_server/runtime_factory.py +0 -105
  519. package/template/apps/agent-server/src/southwind_agent_server/runtime_logging.py +0 -57
  520. package/template/apps/agent-server/src/southwind_agent_server/service.py +0 -325
  521. package/template/apps/agent-server/src/southwind_agent_server/service_control.py +0 -64
  522. package/template/apps/agent-server/src/southwind_agent_server/service_errors.py +0 -4
  523. package/template/apps/agent-server/src/southwind_agent_server/service_execution.py +0 -34
  524. package/template/apps/agent-server/src/southwind_agent_server/service_tasks.py +0 -34
  525. package/template/apps/agent-server/src/southwind_agent_server/signal_events.py +0 -53
  526. package/template/apps/agent-server/src/southwind_agent_server/sqlite_catalog.py +0 -118
  527. package/template/apps/agent-server/src/southwind_agent_server/sqlite_errors.py +0 -2
  528. package/template/apps/agent-server/src/southwind_agent_server/sqlite_schema.py +0 -73
  529. package/template/apps/agent-server/src/southwind_agent_server/sqlite_serialization.py +0 -16
  530. package/template/apps/agent-server/src/southwind_agent_server/sqlite_store.py +0 -350
  531. package/template/apps/agent-server/src/southwind_agent_server/sse.py +0 -41
  532. package/template/apps/agent-server/src/southwind_agent_server/store.py +0 -255
  533. package/template/apps/agent-server/src/southwind_agent_server/store_cipher.py +0 -40
  534. package/template/apps/agent-server/src/southwind_agent_server/structured_logging.py +0 -145
  535. package/template/apps/agent-server/src/southwind_agent_server/telemetry.py +0 -93
  536. package/template/apps/agent-server/src/southwind_agent_server/tool_host.py +0 -152
  537. package/template/apps/agent-server/src/southwind_agent_server/trajectory.py +0 -137
  538. package/template/apps/agent-server/src/southwind_agent_server/unavailable_engine.py +0 -58
  539. package/template/apps/agent-server/src/southwind_agent_server/vision_probe.py +0 -87
  540. package/template/apps/agent-server/src/southwind_agent_server/vision_requirement.py +0 -28
  541. package/template/apps/agent-server/src/southwind_agent_server/vlm_readiness.py +0 -247
  542. package/template/apps/agent-server/tests/__init__.py +0 -1
  543. package/template/apps/agent-server/tests/openai_provider_test_support.py +0 -131
  544. package/template/apps/agent-server/tests/test_api.py +0 -305
  545. package/template/apps/agent-server/tests/test_artifact_input.py +0 -110
  546. package/template/apps/agent-server/tests/test_client_completion.py +0 -230
  547. package/template/apps/agent-server/tests/test_config.py +0 -106
  548. package/template/apps/agent-server/tests/test_fingerprint.py +0 -10
  549. package/template/apps/agent-server/tests/test_multimodal.py +0 -81
  550. package/template/apps/agent-server/tests/test_openai_provider.py +0 -320
  551. package/template/apps/agent-server/tests/test_postgres_report_status.py +0 -59
  552. package/template/apps/agent-server/tests/test_postgres_report_summary.py +0 -298
  553. package/template/apps/agent-server/tests/test_postgres_store.py +0 -135
  554. package/template/apps/agent-server/tests/test_provider_attempt_reporting.py +0 -140
  555. package/template/apps/agent-server/tests/test_provider_governance.py +0 -276
  556. package/template/apps/agent-server/tests/test_report_attempt_lifecycle.py +0 -126
  557. package/template/apps/agent-server/tests/test_report_resilience.py +0 -183
  558. package/template/apps/agent-server/tests/test_report_routes.py +0 -143
  559. package/template/apps/agent-server/tests/test_report_store.py +0 -347
  560. package/template/apps/agent-server/tests/test_report_summary_parity.py +0 -116
  561. package/template/apps/agent-server/tests/test_report_terminal_sync.py +0 -177
  562. package/template/apps/agent-server/tests/test_run_capacity.py +0 -112
  563. package/template/apps/agent-server/tests/test_run_operational_logging.py +0 -114
  564. package/template/apps/agent-server/tests/test_runtime_compatibility.py +0 -119
  565. package/template/apps/agent-server/tests/test_runtime_factory_readiness.py +0 -52
  566. package/template/apps/agent-server/tests/test_sqlite_store.py +0 -182
  567. package/template/apps/agent-server/tests/test_structured_logging.py +0 -142
  568. package/template/apps/agent-server/tests/test_telemetry.py +0 -25
  569. package/template/apps/agent-server/tests/test_tool_approval.py +0 -28
  570. package/template/apps/agent-server/tests/test_tool_structured_output.py +0 -347
  571. package/template/apps/agent-server/tests/test_trajectory.py +0 -91
  572. package/template/apps/agent-server/tests/test_vision_readiness_enforcement.py +0 -72
  573. package/template/apps/agent-server/tests/test_vlm_readiness.py +0 -106
  574. package/template/apps/agent-server/uv.lock +0 -831
@@ -0,0 +1,179 @@
1
+ import { timingSafeEqual } from "node:crypto";
2
+ import {
3
+ createServer,
4
+ type IncomingMessage,
5
+ type ServerResponse,
6
+ } from "node:http";
7
+ import { once } from "node:events";
8
+ import { Readable } from "node:stream";
9
+ import { resolve } from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+ import { createCanonicalHandler } from "./runtime/index.js";
12
+ import { configFromEnvironment } from "./runtime/config.js";
13
+ import { nativeModelSlots } from "./native/config.js";
14
+ import { authorizeWorkbench, createBoundary } from "./native/boundary.js";
15
+ import { WorkbenchManager } from "./native/manager.js";
16
+ import { workbenchHandshake, workbenchHttp } from "./native/http.js";
17
+ import { attachWorkbenchSockets } from "./native/socket.js";
18
+ import { projectHost } from "./project/host.js";
19
+
20
+ export function internalAuthentication(token: string) {
21
+ if (token !== token.trim() || token.length < 32 || /[\r\n]/.test(token))
22
+ throw new Error(
23
+ "AGENT_SERVER_INTERNAL_TOKEN must be a strong internal credential",
24
+ );
25
+ const expected = Buffer.from(`Bearer ${token}`);
26
+ return (headers: Headers) => {
27
+ const actual = Buffer.from(headers.get("authorization") ?? "");
28
+ return (
29
+ actual.length === expected.length && timingSafeEqual(actual, expected)
30
+ );
31
+ };
32
+ }
33
+
34
+ export async function startAgentServer(
35
+ port = Number(process.env.PORT || 8080),
36
+ ) {
37
+ process.umask(0o077);
38
+ const authenticated = internalAuthentication(
39
+ process.env.AGENT_SERVER_INTERNAL_TOKEN ?? "",
40
+ );
41
+ const config = configFromEnvironment();
42
+ const canonical = createCanonicalHandler({ config });
43
+ const manager = new WorkbenchManager({
44
+ gateOrigin: `http://127.0.0.1:${port}`,
45
+ authorize: authorizeWorkbench,
46
+ });
47
+ const boundary = createBoundary({
48
+ manager,
49
+ projectRoutes: projectHost.boundaryRoutes,
50
+ completion: canonical.handleNativeCompletion,
51
+ });
52
+ const handle = async (request: Request): Promise<Response> => {
53
+ const path = new URL(request.url).pathname;
54
+ if (path.startsWith("/internal/boundary/")) return boundary(request);
55
+ if (path.startsWith("/internal/workbench")) {
56
+ if (!authenticated(request.headers))
57
+ return Response.json({ error: "UNAUTHENTICATED" }, { status: 401 });
58
+ if (path === "/internal/workbench-ready") {
59
+ const code =
60
+ !config.baseUrl || !config.model
61
+ ? "MODEL_ROUTE_UNAVAILABLE"
62
+ : process.platform !== "linux" || process.getuid?.() !== 0
63
+ ? "WORKBENCH_ISOLATION_UNAVAILABLE"
64
+ : nativeModelSlots() < 1
65
+ ? "WORKBENCH_CAPACITY_RESERVED"
66
+ : undefined;
67
+ return Response.json(
68
+ code ? { ready: false, code } : { ready: true, engine: "dsh" },
69
+ { status: code ? 503 : 200 },
70
+ );
71
+ }
72
+ if (
73
+ path !== "/internal/workbench-handshake" &&
74
+ !path.startsWith("/internal/workbench/")
75
+ )
76
+ return new Response(null, { status: 404 });
77
+ try {
78
+ if (path === "/internal/workbench-handshake")
79
+ return await workbenchHandshake(request, manager);
80
+ return await workbenchHttp(request, manager);
81
+ } catch {
82
+ return Response.json(
83
+ { error: "WORKBENCH_UNAVAILABLE" },
84
+ { status: 503 },
85
+ );
86
+ }
87
+ }
88
+ return (await canonical(request)) ?? new Response(null, { status: 404 });
89
+ };
90
+ const server = createServer(
91
+ (incoming, outgoing) => void transport(incoming, outgoing, handle),
92
+ );
93
+ const detachSockets = attachWorkbenchSockets(server, manager, authenticated);
94
+ await new Promise<void>((accept, reject) => {
95
+ server.once("error", reject);
96
+ server.listen(port, "0.0.0.0", accept);
97
+ });
98
+ const close = async () => {
99
+ detachSockets();
100
+ await manager.close();
101
+ await canonical.close();
102
+ server.closeAllConnections();
103
+ await new Promise<void>((accept) => server.close(() => accept()));
104
+ };
105
+ return { server, close, manager };
106
+ }
107
+
108
+ async function transport(
109
+ incoming: IncomingMessage,
110
+ outgoing: ServerResponse,
111
+ handle: (request: Request) => Promise<Response>,
112
+ ) {
113
+ const controller = new AbortController();
114
+ incoming.once("aborted", () => controller.abort());
115
+ outgoing.once("close", () => {
116
+ if (!outgoing.writableEnded) controller.abort();
117
+ });
118
+ try {
119
+ const headers = new Headers();
120
+ for (const [key, value] of Object.entries(incoming.headers)) {
121
+ if (typeof value === "string") headers.set(key, value);
122
+ else if (Array.isArray(value))
123
+ for (const item of value) headers.append(key, item);
124
+ }
125
+ const init: RequestInit & { duplex?: string } = {
126
+ method: incoming.method,
127
+ headers,
128
+ signal: controller.signal,
129
+ };
130
+ if (!["GET", "HEAD"].includes(incoming.method ?? "GET")) {
131
+ init.body = Readable.toWeb(
132
+ incoming,
133
+ ) as unknown as ReadableStream<Uint8Array>;
134
+ init.duplex = "half";
135
+ }
136
+ const response = await handle(
137
+ new Request(`http://agent.internal${incoming.url ?? "/"}`, init),
138
+ );
139
+ const responseHeaders: Record<string, string> = {};
140
+ response.headers.forEach((value, key) => {
141
+ responseHeaders[key] = value;
142
+ });
143
+ outgoing.writeHead(response.status, responseHeaders);
144
+ if (response.body) {
145
+ const reader = response.body.getReader();
146
+ try {
147
+ while (!controller.signal.aborted) {
148
+ const { value, done } = await reader.read();
149
+ if (done) break;
150
+ if (!outgoing.write(value))
151
+ await once(outgoing, "drain", { signal: controller.signal });
152
+ }
153
+ } finally {
154
+ await reader.cancel().catch(() => {});
155
+ }
156
+ }
157
+ outgoing.end();
158
+ } catch {
159
+ if (!outgoing.headersSent)
160
+ outgoing.writeHead(502, { "content-type": "application/json" });
161
+ outgoing.end(JSON.stringify({ error: "AGENT_RUNTIME_FAILED" }));
162
+ }
163
+ }
164
+
165
+ if (
166
+ process.argv[1] &&
167
+ resolve(process.argv[1]) === fileURLToPath(import.meta.url)
168
+ ) {
169
+ startAgentServer()
170
+ .then(({ close }) => {
171
+ const shutdown = () => void close().finally(() => process.exit(0));
172
+ process.once("SIGTERM", shutdown);
173
+ process.once("SIGINT", shutdown);
174
+ })
175
+ .catch(() => {
176
+ console.error("Agent Server startup failed");
177
+ process.exitCode = 1;
178
+ });
179
+ }
@@ -0,0 +1,46 @@
1
+ # 当前用户的 DSH 扩展
2
+
3
+ 固定上游为 DSH `0.2.1-rc.2`。本轮只开放原生能力,不新增服务、公开端口或第二个管理站点。
4
+
5
+ ## 插件入口与持久化
6
+
7
+ - 原生侧栏「插件」→「添加插件」:安装声明 `dsh.bundle.patch` 的 npm 包、Git 地址、压缩包 URL 或可读取的本地目录。安装、取消、日志、卸载确认、依赖构建脚本批准沿用官方 UI。
8
+ - 插件自己的配置页在「插件」内;「设置」→「内置插件」提供全局运行清单。应用托管的共享模型地址、身份等配置仍由最后一层 deployment patch 固定,更改这些字段会被上游拒绝,不应绕开覆盖。
9
+ - 上游 `plugin-manager`、`config-editor`、`settings`、`hmr` 和 `client-hmr` 原样组合。安装和启停由 HMR 实时应用,真正需要重启的情况由上游显示原因。
10
+ - 插件安装写入每个用户 `DSH_HOME/profiles/web` 的 `package.json`、`pnpm-lock.yaml`、`node_modules`、`cordis.patch.yml` 等文件。worker 使用官方 `initProfile()` 仅补缺失文件,重启不清空个人清单、锁或两层个人 patch。
11
+ - 安装器是镜像内固定的官方 npm 包 `pnpm@11.28.6`(MIT),由 Node 调用,不使用 curl 安装器。上游依赖 pnpm 的 `view/add/remove`、脚本批准和文件恢复语义;项目 monorepo 仍以 Bun 管理。Docker 补齐 Git 与 CA,便于上游 Git spec 安装。
12
+ - `tool-plugin-manager` 保持禁用;技能文本不能静默安装插件代码。安装代码由用户在原生管理界面执行。
13
+
14
+ 开发阶段 `AGENT_DSH_USER_EXTENSIONS=1` 默认开启。设置为 `0` 并重启现有 Agent Server 会关闭扩展安装、配置及清单管理入口,同时关闭个人 Skills 默认根发现。此开关不会删除已安装文件,也不会停止已经保存为启用的可信插件;要撤销已有插件代码,应先在原生 UI 卸载或停用,再重启当前用户 worker / Agent Server。它不是恶意代码安全开关。
15
+
16
+ ## Skills 的实际操作
17
+
18
+ 上游原生尚无完整 Skills 安装页;项目通过公开侧栏/main slots 提供「技能」面板:
19
+
20
+ 1. 选择当前用户的真实工作区,查看默认技能(只读)或新建、编辑个人技能。
21
+ 2. 导入 `SKILL.md` 时先在编辑器确认正文;离线 ZIP 导入保留 scripts、references、assets,
22
+ 导入不执行脚本。压缩包 4 MiB、展开 16 MiB、128 项、单文件 4 MiB、正文 128 KiB。
23
+ 3. 同名导入拒绝覆盖;编辑使用原正文 SHA256 防止旧编辑器覆盖。个人文件保存在
24
+ `.dsh/skills/<name>/SKILL.md`,官方提供方热发现,输入 `/name` 调用。
25
+ 4. 删除个人技能需再次确认;默认技能只读。导出单个技能 ZIP 后由用户自行交给其他用户主动导入,
26
+ 不共享其他用户目录、会话或整个工作区。分享前自行复核通用正文和附件,去除案件数据及凭据。
27
+ 5. 显式调用 `/windy-skill-capture` 可以把已验证的通用方法沉淀为个人技能,不能自动把案件事实
28
+ 复制到跨会话记忆。默认业务方法清单见 [Skills](../plugins/skills/README.md)。
29
+
30
+ 文件权限、压缩展开与路径校验、社区开源评估及公开接口升级检查见
31
+ [技能管理插件](../plugins/skill-library/README.md)。
32
+
33
+ 随附 `/windy-extension-guide` 提供中文步骤,只允许用户显式调用。封闭的默认 subprocess 没有网络,因此不要承诺 Agent 可以自行 `git clone` 任意互联网技能仓库;先下载可信文件再上传,或用用户明确安装的可信插件提供该能力。
34
+
35
+ ## 信任与边界
36
+
37
+ 第三方插件在当前用户独立 UID 的 DSH Host 中运行,是用户授权的可信代码。它能访问当前用户的 HOME、会话和工作区,也可能自行执行网络与代码操作;不能声称它仍被默认 subprocess adapter 或工作区 Landlock 约束。其他用户 UID、root 协调器文件权限、容量 Gate 与业务 MCP 当前身份检查仍保留;真正的 Provider / 产品内部凭据不进入 worker 环境。不要在个人插件中填入共享 Provider 真凭据。
38
+
39
+ 个人依赖、安装缓存与文件计入现有用户 HOME 软配额。超限会终止该用户 worker,安装的大型插件可能需要明确调整额度;本轮没有基于显卡型号提高容量或修改生产环境。
40
+
41
+ ## 验证及升级检查
42
+
43
+ `bun test apps/agent-server/native/extensions.test.ts apps/agent-server/plugins/locale/locale.test.ts`:真实官方 pnpm 安装本地无依赖合成 bundle,验证清单选择、锁文件和个人 patch 在再次初始化后原样保留,再卸载;真实官方文件系统提供方先观察空目录,再检测新 Skills 的 watcher 失效事件,读取、编辑、删除并确认另一用户目录未被发现。该测试不等于任意第三方包验收。另已用最终 ARM 镜像与内置浏览器验证原生安装/启停/重启保留/卸载,
44
+ 及个人 Skill 热发现和实际 slash 指令正文传入合成 Provider;详见项目验收记录。
45
+
46
+ 升级 DSH 时重新核对官方 `plugin-manager`、`config-editor`、`settings`、`ui-plugin-manager`、`skill-filesystem` 的公开契约,尤其是 profile patch 优先级、HMR、脚本批准、版本兼容检查和重启行为;升级 pnpm 需同时更新 Bun lock 并验证安装/卸载语义。
@@ -0,0 +1,73 @@
1
+ /** Bounded FIFO: queued native work owns no model slot and aborts without retries. */
2
+ export class AdmissionQueue {
3
+ private active = 0;
4
+ private waiting: Array<{ grant(): void; signal: AbortSignal }> = [];
5
+ constructor(
6
+ readonly maximum: number,
7
+ private readonly pendingLimit = 16,
8
+ private readonly timeoutMs = 90000,
9
+ private readonly available = () => true,
10
+ private readonly reserve = (): (() => void) => () => {},
11
+ ) {}
12
+ acquire(signal: AbortSignal): Promise<() => void> {
13
+ signal.throwIfAborted();
14
+ if (this.maximum < 1)
15
+ return Promise.reject(new Error("NATIVE_CAPACITY_DISABLED"));
16
+ if (!this.waiting.length && this.active < this.maximum && this.available())
17
+ return Promise.resolve(this.take());
18
+ if (this.waiting.length >= this.pendingLimit)
19
+ return Promise.reject(new Error("NATIVE_QUEUE_FULL"));
20
+ return new Promise((accept, reject) => {
21
+ const remove = () => {
22
+ clearTimeout(timer);
23
+ signal.removeEventListener("abort", abort);
24
+ const position = this.waiting.indexOf(entry);
25
+ if (position >= 0) this.waiting.splice(position, 1);
26
+ };
27
+ const abort = () => {
28
+ remove();
29
+ reject(signal.reason);
30
+ this.drain();
31
+ };
32
+ const entry = {
33
+ signal,
34
+ grant: () => {
35
+ remove();
36
+ accept(this.take());
37
+ },
38
+ };
39
+ const timer = setTimeout(() => {
40
+ remove();
41
+ reject(new Error("NATIVE_QUEUE_TIMEOUT"));
42
+ this.drain();
43
+ }, this.timeoutMs);
44
+ timer.unref?.();
45
+ this.waiting.push(entry);
46
+ signal.addEventListener("abort", abort, { once: true });
47
+ if (signal.aborted) abort();
48
+ });
49
+ }
50
+ drain() {
51
+ while (
52
+ this.waiting.length &&
53
+ this.active < this.maximum &&
54
+ this.available()
55
+ )
56
+ this.waiting[0]!.grant();
57
+ }
58
+ private take() {
59
+ const releaseReservation = this.reserve();
60
+ this.active++;
61
+ let released = false;
62
+ return () => {
63
+ if (released) return;
64
+ released = true;
65
+ this.active--;
66
+ releaseReservation();
67
+ this.drain();
68
+ };
69
+ }
70
+ snapshot() {
71
+ return { active: this.active, queued: this.waiting.length };
72
+ }
73
+ }
@@ -0,0 +1,176 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import {
3
+ authorizationUnavailableResponse,
4
+ authorizeWorkbench,
5
+ isWorkbenchAuthorizationUnavailable,
6
+ WorkbenchAuthorizationUnavailable,
7
+ type WorkbenchAuthorizationOptions,
8
+ } from "./authorization.js";
9
+
10
+ const authority = {
11
+ actorId: "synthetic-user",
12
+ session: "synthetic-session",
13
+ publicOrigin: "http://synthetic.invalid",
14
+ };
15
+ const signal = () => new AbortController().signal;
16
+ const options = (
17
+ fetcher: NonNullable<WorkbenchAuthorizationOptions["fetcher"]>,
18
+ ): WorkbenchAuthorizationOptions => ({
19
+ fetcher,
20
+ productOrigin: "http://synthetic-product.invalid",
21
+ });
22
+ const actorResponse = (id = authority.actorId, type = "user") =>
23
+ Response.json({ actor: { id, type } });
24
+
25
+ async function unavailable(
26
+ input: WorkbenchAuthorizationOptions,
27
+ expectedReason: WorkbenchAuthorizationUnavailable["reason"],
28
+ ) {
29
+ let failure: unknown;
30
+ try {
31
+ await authorizeWorkbench(authority, signal(), input);
32
+ } catch (error) {
33
+ failure = error;
34
+ }
35
+ expect(isWorkbenchAuthorizationUnavailable(failure)).toBe(true);
36
+ expect((failure as WorkbenchAuthorizationUnavailable).reason).toBe(
37
+ expectedReason,
38
+ );
39
+ expect(String(failure)).not.toContain(authority.session);
40
+ }
41
+
42
+ describe("workbench authorization distinguishes denial from unavailable", () => {
43
+ test("fresh matching admission allows; trusted actor mismatch denies", async () => {
44
+ expect(
45
+ await authorizeWorkbench(
46
+ authority,
47
+ signal(),
48
+ options(async () => actorResponse()),
49
+ ),
50
+ ).toBe(true);
51
+ for (const response of [
52
+ actorResponse("other-user"),
53
+ actorResponse(authority.actorId, "service"),
54
+ ])
55
+ expect(
56
+ await authorizeWorkbench(
57
+ authority,
58
+ signal(),
59
+ options(async () => response),
60
+ ),
61
+ ).toBe(false);
62
+ });
63
+
64
+ test("only 401 and 403 are confirmed HTTP denial", async () => {
65
+ for (const status of [401, 403])
66
+ expect(
67
+ await authorizeWorkbench(
68
+ authority,
69
+ signal(),
70
+ options(async () => new Response("synthetic", { status })),
71
+ ),
72
+ ).toBe(false);
73
+ for (const status of [201, 204, 302, 400, 404, 408, 429, 500, 503])
74
+ await unavailable(
75
+ options(async () => new Response(null, { status })),
76
+ "upstream_status",
77
+ );
78
+ });
79
+
80
+ test("malformed JSON and incomplete actor are unavailable", async () => {
81
+ await unavailable(
82
+ options(async () => new Response("not-json")),
83
+ "invalid_response",
84
+ );
85
+ for (const body of [
86
+ null,
87
+ {},
88
+ { actor: null },
89
+ { actor: {} },
90
+ { actor: { id: 1, type: "user" } },
91
+ { actor: { id: "synthetic-user" } },
92
+ ])
93
+ await unavailable(
94
+ options(async () => Response.json(body)),
95
+ "invalid_response",
96
+ );
97
+ });
98
+
99
+ test("network failures do not become denial and do not retain raw error", async () => {
100
+ await unavailable(
101
+ options(async () => {
102
+ throw new Error(`synthetic private ${authority.session}`);
103
+ }),
104
+ "network",
105
+ );
106
+ });
107
+
108
+ test("real fetch timeout is unavailable", async () => {
109
+ const server = Bun.serve({
110
+ port: 0,
111
+ async fetch() {
112
+ await Bun.sleep(100);
113
+ return actorResponse();
114
+ },
115
+ });
116
+ try {
117
+ await unavailable(
118
+ { productOrigin: server.url.origin, timeoutMs: 10 },
119
+ "timeout",
120
+ );
121
+ } finally {
122
+ await server.stop(true);
123
+ }
124
+ });
125
+
126
+ test("caller cancellation is unavailable and never grants permission", async () => {
127
+ const controller = new AbortController();
128
+ controller.abort();
129
+ await expect(
130
+ authorizeWorkbench(
131
+ authority,
132
+ controller.signal,
133
+ options(async (_url, init) => {
134
+ init.signal!.throwIfAborted();
135
+ return actorResponse();
136
+ }),
137
+ ),
138
+ ).rejects.toMatchObject({
139
+ code: "WORKBENCH_AUTHORIZATION_UNAVAILABLE",
140
+ reason: "aborted",
141
+ });
142
+ });
143
+
144
+ test("each admission is fetched and denial cannot reuse a previous success", async () => {
145
+ let calls = 0;
146
+ const input = options(async (url, init) => {
147
+ expect(url).toBe(
148
+ "http://synthetic-product.invalid/api/agent/workbench/admission",
149
+ );
150
+ expect(new Headers(init.headers).get("authorization")).toBe(
151
+ `Bearer ${authority.session}`,
152
+ );
153
+ expect(init.redirect).toBe("error");
154
+ calls++;
155
+ return calls === 1
156
+ ? actorResponse()
157
+ : new Response(null, { status: 401 });
158
+ });
159
+ expect(await authorizeWorkbench(authority, signal(), input)).toBe(true);
160
+ expect(await authorizeWorkbench(authority, signal(), input)).toBe(false);
161
+ expect(calls).toBe(2);
162
+ });
163
+
164
+ test("unavailable response is retryable 503 with no cached login result", async () => {
165
+ const response = authorizationUnavailableResponse();
166
+ expect(response.status).toBe(503);
167
+ expect(response.headers.get("retry-after")).toBe("2");
168
+ expect(response.headers.get("cache-control")).toBe("no-store");
169
+ expect(await response.json()).toEqual({
170
+ error: "WORKBENCH_AUTHORIZATION_UNAVAILABLE",
171
+ });
172
+ expect(isWorkbenchAuthorizationUnavailable(new Error("ordinary"))).toBe(
173
+ false,
174
+ );
175
+ });
176
+ });
@@ -0,0 +1,118 @@
1
+ import type { WorkbenchAuthority } from "./config.js";
2
+
3
+ export type AuthorizationUnavailableReason =
4
+ | "upstream_status"
5
+ | "invalid_response"
6
+ | "network"
7
+ | "timeout"
8
+ | "aborted";
9
+
10
+ /** Contains only safe classification metadata; never retain response bodies or credentials. */
11
+ export class WorkbenchAuthorizationUnavailable extends Error {
12
+ readonly code = "WORKBENCH_AUTHORIZATION_UNAVAILABLE";
13
+
14
+ constructor(
15
+ readonly reason: AuthorizationUnavailableReason,
16
+ readonly status?: number,
17
+ ) {
18
+ super("Workbench authorization is temporarily unavailable");
19
+ this.name = "WorkbenchAuthorizationUnavailable";
20
+ }
21
+ }
22
+
23
+ export function isWorkbenchAuthorizationUnavailable(
24
+ error: unknown,
25
+ ): error is WorkbenchAuthorizationUnavailable {
26
+ return error instanceof WorkbenchAuthorizationUnavailable;
27
+ }
28
+
29
+ export function authorizationUnavailableResponse(): Response {
30
+ return Response.json(
31
+ { error: "WORKBENCH_AUTHORIZATION_UNAVAILABLE" },
32
+ {
33
+ status: 503,
34
+ headers: { "retry-after": "2", "cache-control": "no-store" },
35
+ },
36
+ );
37
+ }
38
+
39
+ export function productOrigin(): string {
40
+ const url = new URL(
41
+ process.env.AI_TOOL_HOST_URL ??
42
+ process.env.AGENT_CONTEXT_HOST_URL ??
43
+ "http://server:9747",
44
+ );
45
+ if (
46
+ url.username ||
47
+ url.password ||
48
+ url.search ||
49
+ url.hash ||
50
+ url.pathname !== "/"
51
+ )
52
+ throw new Error("Invalid product host");
53
+ return url.origin;
54
+ }
55
+
56
+ export interface WorkbenchAuthorizationOptions {
57
+ fetcher?: (url: string, init: RequestInit) => Promise<Response>;
58
+ timeoutMs?: number;
59
+ productOrigin?: string;
60
+ }
61
+
62
+ /** false means confirmed denial; unknown authorization must never become permission or revocation. */
63
+ export async function authorizeWorkbench(
64
+ authority: WorkbenchAuthority,
65
+ signal: AbortSignal,
66
+ options: WorkbenchAuthorizationOptions = {},
67
+ ): Promise<boolean> {
68
+ const timeout = AbortSignal.timeout(options.timeoutMs ?? 5000);
69
+ const combined = AbortSignal.any([signal, timeout]);
70
+ const unavailable = () =>
71
+ new WorkbenchAuthorizationUnavailable(
72
+ signal.aborted ? "aborted" : timeout.aborted ? "timeout" : "network",
73
+ );
74
+ let response: Response;
75
+ try {
76
+ response = await (options.fetcher ?? fetch)(
77
+ `${options.productOrigin ?? productOrigin()}/api/agent/workbench/admission`,
78
+ {
79
+ headers: { authorization: `Bearer ${authority.session}` },
80
+ signal: combined,
81
+ redirect: "error",
82
+ },
83
+ );
84
+ } catch {
85
+ throw unavailable();
86
+ }
87
+ if (response.status !== 200) {
88
+ // Classification comes from status, never from an untrusted error payload.
89
+ await response.body?.cancel().catch(() => {});
90
+ if (response.status === 401 || response.status === 403) return false;
91
+ throw new WorkbenchAuthorizationUnavailable(
92
+ "upstream_status",
93
+ response.status,
94
+ );
95
+ }
96
+ let body: unknown;
97
+ try {
98
+ body = await response.json();
99
+ } catch {
100
+ if (combined.aborted) throw unavailable();
101
+ throw new WorkbenchAuthorizationUnavailable("invalid_response");
102
+ }
103
+ if (combined.aborted) throw unavailable();
104
+ const actor =
105
+ body && typeof body === "object" && "actor" in body ? body.actor : null;
106
+ if (
107
+ !actor ||
108
+ typeof actor !== "object" ||
109
+ !("id" in actor) ||
110
+ typeof actor.id !== "string" ||
111
+ !actor.id ||
112
+ !("type" in actor) ||
113
+ typeof actor.type !== "string" ||
114
+ !actor.type
115
+ )
116
+ throw new WorkbenchAuthorizationUnavailable("invalid_response");
117
+ return actor.id === authority.actorId && actor.type === "user";
118
+ }
@@ -0,0 +1,93 @@
1
+ export class ProjectBoundaryError extends Error {
2
+ constructor(
3
+ readonly status: number,
4
+ readonly code: string,
5
+ ) {
6
+ super(code);
7
+ }
8
+ }
9
+
10
+ export async function abortable<T>(
11
+ pending: Promise<T>,
12
+ signal: AbortSignal,
13
+ ): Promise<T> {
14
+ if (signal.aborted) {
15
+ void pending.catch(() => {});
16
+ signal.throwIfAborted();
17
+ }
18
+ let abort!: () => void;
19
+ try {
20
+ return await Promise.race([
21
+ pending,
22
+ new Promise<never>((_accept, reject) => {
23
+ abort = () => reject(signal.reason);
24
+ signal.addEventListener("abort", abort, { once: true });
25
+ if (signal.aborted) abort();
26
+ }),
27
+ ]);
28
+ } finally {
29
+ if (abort) signal.removeEventListener("abort", abort);
30
+ }
31
+ }
32
+
33
+ export async function boundedBytes(
34
+ stream: ReadableStream<Uint8Array> | null,
35
+ limit: number,
36
+ signal: AbortSignal,
37
+ ): Promise<Uint8Array<ArrayBuffer>> {
38
+ signal.throwIfAborted();
39
+ if (!stream) return new Uint8Array();
40
+ const reader = stream.getReader();
41
+ const chunks: Uint8Array[] = [];
42
+ let size = 0;
43
+ try {
44
+ for (;;) {
45
+ const part = await abortable(reader.read(), signal);
46
+ if (part.done) break;
47
+ size += part.value.byteLength;
48
+ if (size > limit)
49
+ throw new ProjectBoundaryError(413, "PROJECT_BODY_TOO_LARGE");
50
+ chunks.push(part.value);
51
+ }
52
+ const bytes = new Uint8Array(size);
53
+ let offset = 0;
54
+ for (const chunk of chunks) {
55
+ bytes.set(chunk, offset);
56
+ offset += chunk.byteLength;
57
+ }
58
+ return bytes;
59
+ } finally {
60
+ void reader.cancel().catch(() => {});
61
+ }
62
+ }
63
+
64
+ export async function boundedProjectResponse(
65
+ response: Response,
66
+ maximum: number,
67
+ signal: AbortSignal,
68
+ ): Promise<Response> {
69
+ const declared = Number(response.headers.get("content-length"));
70
+ if (Number.isFinite(declared) && declared > maximum) {
71
+ void response.body?.cancel().catch(() => {});
72
+ throw new ProjectBoundaryError(502, "PROJECT_RESPONSE_TOO_LARGE");
73
+ }
74
+ let bytes: Uint8Array<ArrayBuffer>;
75
+ try {
76
+ bytes = await boundedBytes(response.body, maximum, signal);
77
+ } catch (error) {
78
+ if (error instanceof ProjectBoundaryError)
79
+ throw new ProjectBoundaryError(502, "PROJECT_RESPONSE_TOO_LARGE");
80
+ throw error;
81
+ }
82
+ return new Response(
83
+ [204, 205, 304].includes(response.status) ? null : bytes,
84
+ {
85
+ status: response.status,
86
+ headers: {
87
+ "content-type":
88
+ response.headers.get("content-type") ?? "application/json",
89
+ "cache-control": "no-store",
90
+ },
91
+ },
92
+ );
93
+ }