@aiworker/web 1.22.0 → 1.23.0

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 (415) hide show
  1. package/README.md +4 -4
  2. package/bin/cli.js +14 -4
  3. package/bin/cli.test.js +165 -73
  4. package/bin/lib/cli-api-target.js +2 -2
  5. package/bin/lib/cli-args.js +119 -119
  6. package/bin/lib/cli-lifecycle.js +9 -9
  7. package/bin/lib/cli-network.js +3 -3
  8. package/bin/lib/cli-paths.js +3 -3
  9. package/bin/lib/cli-ports.js +2 -2
  10. package/bin/lib/cli-process.js +4 -4
  11. package/bin/lib/cli-startup.js +64 -15
  12. package/bin/lib/cli-tunnel-profiles.js +1 -1
  13. package/bin/lib/cli-tunnel-utils.js +2 -2
  14. package/bin/lib/commands-connect-url.js +19 -19
  15. package/bin/lib/commands-lifecycle.js +27 -27
  16. package/bin/lib/commands-logs.js +5 -5
  17. package/bin/lib/commands-models.js +1 -1
  18. package/bin/lib/commands-projects.js +1 -1
  19. package/bin/lib/commands-schedule.js +1 -1
  20. package/bin/lib/commands-serve.js +29 -29
  21. package/bin/lib/commands-session.js +1 -1
  22. package/bin/lib/commands-startup.js +45 -10
  23. package/bin/lib/commands-status.js +1 -1
  24. package/bin/lib/commands-tunnel.js +40 -40
  25. package/bin/lib/commands-update.js +1 -1
  26. package/bin/lib/commands-update.test.js +6 -6
  27. package/dist/assets/{CodeMirrorCommentWidgets-B3u7UIcE.js → CodeMirrorCommentWidgets-B1Gizi3a.js} +1 -1
  28. package/dist/assets/DiffView-DXjVsEOw.js +4 -0
  29. package/dist/assets/DirtyBranchSwitchDialog-aig6zJjg.js +1 -0
  30. package/dist/assets/FilesView-CJdG0-wk.js +17 -0
  31. package/dist/assets/GitView-BXsS3jG6.js +6 -0
  32. package/dist/assets/{JsonTreeView-B0BdZEHG.js → JsonTreeView-D_hpXBnF.js} +1 -1
  33. package/dist/assets/LinearIssuesView-BoUiLQG1.js +1 -0
  34. package/dist/assets/MarkdownImageGallery-B_B_a9KS.js +1 -0
  35. package/dist/assets/MarkdownRendererImpl-xgyyLiBM.js +12 -0
  36. package/dist/assets/OnboardingScreen-DIp84OWt.js +1 -0
  37. package/dist/assets/{PatchDiff-DvfqDql7.js → PatchDiff-8p6nLJaU.js} +1 -1
  38. package/dist/assets/PierreDiffViewer-DjC8nTk9.js +161 -0
  39. package/dist/assets/PlanView-CJTmOF6I.js +5 -0
  40. package/dist/assets/SettingsView-DD-JqIJx.js +28 -0
  41. package/dist/assets/{SettingsWindow-i45U1Cy1.js → SettingsWindow-Cpb4hM6q.js} +1 -1
  42. package/dist/assets/SymbolsNerdFontMono-Regular-aK5vsLov.woff2 +0 -0
  43. package/dist/assets/{ToolOutputDialog-BTwyh5OF.js → ToolOutputDialog-DfaKZXNU.js} +6 -6
  44. package/dist/assets/ToolPartDiffPreview-DtZLzrSK.js +8 -0
  45. package/dist/assets/{VirtualizedFileDiff-DD8lDVej.js → VirtualizedFileDiff-C8i9HpTB.js} +1 -1
  46. package/dist/assets/WalkthroughView-DeKMvZlL.js +4 -0
  47. package/dist/assets/{computeVirtualFileMetrics-BMIRgMHv.js → computeVirtualFileMetrics-BBI7ZwrC.js} +2 -2
  48. package/dist/assets/contextPanelEmbeddedChat-BdA6bdky.js +1 -0
  49. package/dist/assets/de-DCrsQ5zS.js +10 -0
  50. package/dist/assets/es-Dwv4YfH6.js +16 -0
  51. package/dist/assets/fr-BCWg4Cnx.js +14 -0
  52. package/dist/assets/ghostty-vt-DdA0Zryv.wasm +0 -0
  53. package/dist/assets/index-B68h5S5B.css +1 -0
  54. package/dist/assets/index-DVwMarHI.js +39 -0
  55. package/dist/assets/{index-CODwDsU_.js → index-jXSK5RrB.js} +1 -1
  56. package/dist/assets/{isDiffPlainText-BqayB8d3.js → isDiffPlainText-B_x_rVon.js} +1 -1
  57. package/dist/assets/{isFilePlainText-QfoiKJNY.js → isFilePlainText-DW_xMer1.js} +1 -1
  58. package/dist/assets/ja-Bruw3RYC.js +16 -0
  59. package/dist/assets/ko-idhXGF8j.js +16 -0
  60. package/dist/assets/main-BkyaQhJX.js +930 -0
  61. package/dist/assets/{main-C5DVOxc6.js → main-CzdPuL0s.js} +2 -2
  62. package/dist/assets/markdownCore-Cn4Tyejo.js +5 -0
  63. package/dist/assets/{miniChat-DUJ4irZc.js → miniChat-CCkqKOLp.js} +2 -2
  64. package/dist/assets/{mobile-CcaxB0n4.js → mobile-mvxTo055.js} +2 -2
  65. package/dist/assets/patchFileDiff-Csk4iNUi.js +13 -0
  66. package/dist/assets/pl-CGZWUqZJ.js +16 -0
  67. package/dist/assets/pt-BR-B8V7u7tA.js +16 -0
  68. package/dist/assets/renderElectronMiniChatApp-BxoyujA5.js +2 -0
  69. package/dist/assets/renderMobileApp-B48CsP4r.js +25 -0
  70. package/dist/assets/runtimeEndpointReset-Bg5gx18H.js +17 -0
  71. package/dist/assets/scheduledTasksApi-BW0Etzwz.js +1 -0
  72. package/dist/assets/{shikiHighlight-DYOWuY65.js → shikiHighlight-CRl0SUC9.js} +1 -1
  73. package/dist/assets/surface-oMvhsog3.js +1 -0
  74. package/dist/assets/tr-BK_KiO2V.js +7 -0
  75. package/dist/assets/uk-CG74xV8N.js +16 -0
  76. package/dist/assets/useAppFontEffects-CPKeOpUo.js +7284 -0
  77. package/dist/assets/useGitComparison-DH220WmO.js +1 -0
  78. package/dist/assets/useInlineCommentController-BiWz4AVb.js +2 -0
  79. package/dist/assets/useRootScrollLock-BS4-kr7P.js +1 -0
  80. package/dist/assets/{vendor-base-ui-BeMD8X_w.js → vendor-base-ui-DdV8vhHn.js} +1 -1
  81. package/dist/assets/{vendor-codemirror-language-data-DFZik9R2.js → vendor-codemirror-language-data-Bg4AEeCr.js} +2 -2
  82. package/dist/assets/vendor-zod-BPAANqvH.js +39 -0
  83. package/dist/assets/{web-components-Bhg83tjf.js → web-components-z7hfnS8n.js} +1 -1
  84. package/dist/assets/zh-CN-T4AXofZI.js +16 -0
  85. package/dist/assets/zh-TW-Dte40sxp.js +16 -0
  86. package/dist/index.html +21 -59
  87. package/dist/mini-chat.html +7 -7
  88. package/dist/mobile.html +5 -5
  89. package/package.json +3 -4
  90. package/server/index.d.ts +15 -0
  91. package/server/index.js +158 -89
  92. package/server/lib/agent-memory/actions.js +2 -2
  93. package/server/lib/agent-memory/feature-flag.js +1 -1
  94. package/server/lib/agent-memory/feature-flag.test.js +8 -8
  95. package/server/lib/agent-memory/routes.js +2 -2
  96. package/server/lib/agent-tool/runtime.js +37 -54
  97. package/server/lib/agent-tool/runtime.test.js +59 -59
  98. package/server/lib/browser-control/broker.js +3 -3
  99. package/server/lib/browser-control/broker.test.js +1 -1
  100. package/server/lib/changelog/update-notes.js +82 -0
  101. package/server/lib/changelog/update-notes.test.js +59 -0
  102. package/server/lib/client-auth/remote-clients.test.js +5 -5
  103. package/server/lib/context-obligatory/runtime.js +7 -7
  104. package/server/lib/context-obligatory/runtime.test.js +5 -5
  105. package/server/lib/data-dir-migration.js +40 -0
  106. package/server/lib/data-dir-migration.test.js +59 -0
  107. package/server/lib/dev-servers/parse.js +2 -2
  108. package/server/lib/dev-servers/parse.test.js +2 -2
  109. package/server/lib/dev-servers/routes.js +1 -1
  110. package/server/lib/dev-tunnel/DOCUMENTATION.md +13 -4
  111. package/server/lib/dev-tunnel/client.js +1 -1
  112. package/server/lib/dev-tunnel/runtime.js +5 -5
  113. package/server/lib/dev-tunnel/tunnel.test.js +21 -1
  114. package/server/lib/dictation/local/model-catalog.js +1 -1
  115. package/server/lib/dictation/local/worker-process.js +2 -2
  116. package/server/lib/event-stream/directory-ws-bridge.js +1 -1
  117. package/server/lib/event-stream/global-ws-bridge.js +1 -1
  118. package/server/lib/event-stream/protocol.test.js +4 -4
  119. package/server/lib/event-stream/runtime.test.js +18 -18
  120. package/server/lib/fs/DOCUMENTATION.md +5 -0
  121. package/server/lib/fs/routes.js +68 -26
  122. package/server/lib/fs/routes.test.js +208 -22
  123. package/server/lib/git/DOCUMENTATION.md +32 -6
  124. package/server/lib/git/identity-storage.js +1 -1
  125. package/server/lib/git/issue-2746-longpaths.test.js +4 -4
  126. package/server/lib/git/routes.js +41 -5
  127. package/server/lib/git/service.js +300 -224
  128. package/server/lib/git/service.test.js +596 -28
  129. package/server/lib/github/auth.js +8 -8
  130. package/server/lib/github/pr-status.js +1 -1
  131. package/server/lib/github/routes.js +2 -2
  132. package/server/lib/inherited-env.js +17 -10
  133. package/server/lib/inherited-env.test.js +10 -11
  134. package/server/lib/linear/auth.js +8 -8
  135. package/server/lib/linear/auth.test.js +24 -24
  136. package/server/lib/linear/issues.test.js +6 -6
  137. package/server/lib/linear/mapping.test.js +4 -4
  138. package/server/lib/linear/oauth.js +2 -2
  139. package/server/lib/linear/oauth.test.js +14 -14
  140. package/server/lib/linear/routes.js +5 -5
  141. package/server/lib/linear/routes.test.js +16 -16
  142. package/server/lib/linear/status-runtime.test.js +9 -9
  143. package/server/lib/linear/status.js +1 -1
  144. package/server/lib/linear/status.test.js +15 -15
  145. package/server/lib/linear/teams.test.js +4 -4
  146. package/server/lib/magic-prompts/routes.js +2 -2
  147. package/server/lib/mcp-reconnect/DOCUMENTATION.md +55 -0
  148. package/server/lib/mcp-reconnect/runtime.js +122 -0
  149. package/server/lib/mcp-reconnect/runtime.test.js +140 -0
  150. package/server/lib/message-queue/DOCUMENTATION.md +161 -0
  151. package/server/lib/message-queue/runtime.js +870 -0
  152. package/server/lib/message-queue/runtime.test.js +482 -0
  153. package/server/lib/network-defaults.js +23 -0
  154. package/server/lib/network-defaults.test.js +52 -0
  155. package/server/lib/notifications/apns-runtime.js +17 -17
  156. package/server/lib/notifications/apns-runtime.test.js +11 -11
  157. package/server/lib/notifications/emitter-runtime.js +1 -1
  158. package/server/lib/notifications/emitter-runtime.test.js +1 -1
  159. package/server/lib/notifications/push-runtime.js +7 -7
  160. package/server/lib/notifications/routes.js +1 -1
  161. package/server/lib/notifications/runtime.js +1 -1
  162. package/server/lib/openchamber-control/action-resolution.test.js +10 -10
  163. package/server/lib/openchamber-control/actions.js +24 -24
  164. package/server/lib/openchamber-control/error.js +4 -4
  165. package/server/lib/openchamber-control/routes.js +2 -2
  166. package/server/lib/openchamber-control/routes.test.js +5 -5
  167. package/server/lib/openchamber-control/screenshots.js +1 -1
  168. package/server/lib/openchamber-control/screenshots.test.js +1 -1
  169. package/server/lib/openchamber-control/service.js +50 -50
  170. package/server/lib/openchamber-control/service.test.js +5 -5
  171. package/server/lib/openchamber-sessions/routes.js +124 -22
  172. package/server/lib/openchamber-sessions/routes.test.js +99 -11
  173. package/server/lib/opencode/DOCUMENTATION.md +30 -6
  174. package/server/lib/opencode/auth.js +1 -1
  175. package/server/lib/opencode/bootstrap-runtime.js +8 -6
  176. package/server/lib/opencode/cli-options.js +8 -8
  177. package/server/lib/opencode/config-paths.test.js +116 -0
  178. package/server/lib/opencode/core-routes.js +8 -7
  179. package/server/lib/opencode/core-routes.test.js +11 -11
  180. package/server/lib/opencode/env-config.js +5 -5
  181. package/server/lib/opencode/env-config.test.js +7 -7
  182. package/server/lib/opencode/env-runtime.js +10 -10
  183. package/server/lib/opencode/env-runtime.test.js +18 -18
  184. package/server/lib/opencode/feature-routes-runtime.js +19 -12
  185. package/server/lib/opencode/hmr-state-runtime.js +2 -2
  186. package/server/lib/opencode/hmr-state-runtime.test.js +1 -1
  187. package/server/lib/opencode/input-history-scope.js +14 -0
  188. package/server/lib/opencode/lifecycle.js +8 -8
  189. package/server/lib/opencode/lifecycle.test.js +4 -4
  190. package/server/lib/opencode/managed-plugin-config.js +35 -0
  191. package/server/lib/opencode/managed-process-registry.js +3 -3
  192. package/server/lib/opencode/mcp-oauth-callback.test.js +2 -2
  193. package/server/lib/opencode/openchamber-routes.js +79 -19
  194. package/server/lib/opencode/openchamber-routes.test.js +139 -12
  195. package/server/lib/opencode/plugins.js +2 -2
  196. package/server/lib/opencode/plugins.test.js +1 -1
  197. package/server/lib/opencode/project-icon-routes.js +2 -2
  198. package/server/lib/opencode/project-icon-routes.test.js +1 -1
  199. package/server/lib/opencode/providers.js +44 -2
  200. package/server/lib/opencode/providers.test.js +131 -4
  201. package/server/lib/opencode/proxy.js +2 -2
  202. package/server/lib/opencode/pwa-manifest-routes.js +1 -1
  203. package/server/lib/opencode/restart-session-recovery.test.js +1 -1
  204. package/server/lib/opencode/routes-upgrade.test.js +4 -4
  205. package/server/lib/opencode/routes.js +19 -17
  206. package/server/lib/opencode/server-startup-runtime.js +6 -6
  207. package/server/lib/opencode/session-runtime.js +3 -3
  208. package/server/lib/opencode/session-runtime.test.js +6 -6
  209. package/server/lib/opencode/settings-files.js +214 -0
  210. package/server/lib/opencode/settings-helpers.js +116 -44
  211. package/server/lib/opencode/settings-helpers.test.js +354 -12
  212. package/server/lib/opencode/settings-registry.json +747 -0
  213. package/server/lib/opencode/settings-runtime.js +141 -20
  214. package/server/lib/opencode/settings-runtime.test.js +191 -4
  215. package/server/lib/opencode/shared.js +5 -2
  216. package/server/lib/opencode/shared.test.js +7 -7
  217. package/server/lib/opencode/shutdown-runtime.js +2 -0
  218. package/server/lib/opencode/skill-routes.js +2 -1
  219. package/server/lib/opencode/snippets.js +1 -2
  220. package/server/lib/opencode/startup-performance.js +1 -1
  221. package/server/lib/opencode/startup-performance.test.js +6 -6
  222. package/server/lib/opencode/static-routes-runtime.js +8 -8
  223. package/server/lib/opencode/static-routes-runtime.test.js +7 -7
  224. package/server/lib/opencode/upgrade-capability.js +2 -2
  225. package/server/lib/opencode/upgrade-capability.test.js +3 -3
  226. package/server/lib/package-manager.js +17 -42
  227. package/server/lib/package-manager.test.js +19 -19
  228. package/server/lib/permission-auto-accept/runtime.js +1 -1
  229. package/server/lib/project-context/DOCUMENTATION.md +25 -1
  230. package/server/lib/project-context/routes.http.test.js +18 -0
  231. package/server/lib/project-context/routes.js +16 -1
  232. package/server/lib/project-context/runtime.js +248 -23
  233. package/server/lib/project-context/runtime.test.js +106 -3
  234. package/server/lib/projects/DOCUMENTATION.md +76 -0
  235. package/server/lib/projects/project-config.js +144 -11
  236. package/server/lib/projects/project-id.js +17 -0
  237. package/server/lib/projects/project-setup.js +409 -0
  238. package/server/lib/projects/project-setup.test.js +557 -0
  239. package/server/lib/projects/routes.js +59 -0
  240. package/server/lib/quota/DOCUMENTATION.md +40 -2
  241. package/server/lib/quota/credentials/providers.js +4 -0
  242. package/server/lib/quota/credentials/store.js +4 -4
  243. package/server/lib/quota/credentials/store.test.js +8 -8
  244. package/server/lib/quota/index.js +1 -0
  245. package/server/lib/quota/providers/cline-pass.js +125 -0
  246. package/server/lib/quota/providers/cline-pass.test.js +103 -0
  247. package/server/lib/quota/providers/exe-dev.js +75 -0
  248. package/server/lib/quota/providers/exe-dev.test.js +47 -0
  249. package/server/lib/quota/providers/hyper.js +118 -0
  250. package/server/lib/quota/providers/hyper.test.js +126 -0
  251. package/server/lib/quota/providers/index.js +22 -0
  252. package/server/lib/quota/providers/neuralwatt.js +3 -6
  253. package/server/lib/quota/providers/neuralwatt.test.js +7 -7
  254. package/server/lib/quota/providers/ollama-cloud.js +32 -1
  255. package/server/lib/quota/providers/ollama-cloud.test.js +33 -1
  256. package/server/lib/quota/providers/opencode-go.js +3 -2
  257. package/server/lib/quota/providers/opencode-go.test.js +35 -6
  258. package/server/lib/quota/providers/openrouter.js +119 -24
  259. package/server/lib/quota/providers/openrouter.test.js +330 -0
  260. package/server/lib/quota/providers/xai.js +1 -1
  261. package/server/lib/quota/routes.js +2 -0
  262. package/server/lib/quota/utils/auth.js +1 -1
  263. package/server/lib/relay/DOCUMENTATION.md +56 -1
  264. package/server/lib/relay/cross-compat.test.js +26 -0
  265. package/server/lib/relay/downstream-scheduler.js +154 -0
  266. package/server/lib/relay/downstream-scheduler.test.js +162 -0
  267. package/server/lib/relay/e2ee.js +10 -8
  268. package/server/lib/relay/flow-control.test.js +177 -0
  269. package/server/lib/relay/host-client.js +38 -9
  270. package/server/lib/relay/host-client.test.js +9 -1
  271. package/server/lib/relay/host-lock.js +1 -1
  272. package/server/lib/relay/service.js +5 -5
  273. package/server/lib/relay/tunnel-codec.js +9 -0
  274. package/server/lib/relay/tunnel-host.js +69 -18
  275. package/server/lib/relay/tunnel-host.test.js +9 -1
  276. package/server/lib/scheduled-tasks/issue-2710-double-execution.test.js +2 -2
  277. package/server/lib/scheduled-tasks/routes.js +5 -5
  278. package/server/lib/scheduled-tasks/service.js +25 -25
  279. package/server/lib/scheduled-tasks/service.test.js +1 -1
  280. package/server/lib/security/bind-host.js +4 -4
  281. package/server/lib/security/bind-host.test.js +1 -1
  282. package/server/lib/security/request-security.js +11 -5
  283. package/server/lib/security/request-security.test.js +14 -14
  284. package/server/lib/session-assist/runtime.js +15 -18
  285. package/server/lib/session-folders/routes.js +2 -2
  286. package/server/lib/session-folders/routes.test.js +8 -8
  287. package/server/lib/session-goal/DOCUMENTATION.md +20 -7
  288. package/server/lib/session-goal/create.js +4 -2
  289. package/server/lib/session-goal/create.test.js +1 -1
  290. package/server/lib/session-goal/objectives.js +4 -4
  291. package/server/lib/session-goal/routes.js +1 -1
  292. package/server/lib/session-goal/runtime.js +91 -30
  293. package/server/lib/session-goal/runtime.test.js +428 -2
  294. package/server/lib/session-knowledge/runtime.js +11 -11
  295. package/server/lib/session-knowledge/runtime.test.js +5 -5
  296. package/server/lib/skills-catalog/DOCUMENTATION.md +1 -1
  297. package/server/lib/skills-catalog/cache.test.js +2 -2
  298. package/server/lib/skills-catalog/disk-cache.js +5 -5
  299. package/server/lib/skills-catalog/github-meta.test.js +2 -2
  300. package/server/lib/skills-catalog/install.js +3 -2
  301. package/server/lib/small-model/DOCUMENTATION.md +7 -2
  302. package/server/lib/small-model/call.js +18 -7
  303. package/server/lib/small-model/call.test.js +58 -6
  304. package/server/lib/small-model/index.js +12 -16
  305. package/server/lib/small-model/index.test.js +1 -1
  306. package/server/lib/small-model/resolve.js +1 -1
  307. package/server/lib/small-model/resolve.test.js +1 -1
  308. package/server/lib/small-model/routes.js +2 -1
  309. package/server/lib/small-model/runtime-providers.js +15 -7
  310. package/server/lib/small-model/runtime-providers.test.js +7 -1
  311. package/server/lib/system-prompt/runtime.js +3 -22
  312. package/server/lib/system-prompt/runtime.test.js +3 -3
  313. package/server/lib/terminal/DOCUMENTATION.md +14 -10
  314. package/server/lib/terminal/runtime.js +190 -31
  315. package/server/lib/terminal/runtime.test.js +572 -38
  316. package/server/lib/terminal/shells.js +20 -3
  317. package/server/lib/terminal/shells.test.js +33 -2
  318. package/server/lib/tts/base-url.js +3 -3
  319. package/server/lib/tts/routes.test.js +20 -20
  320. package/server/lib/ui-auth/ui-auth.js +12 -9
  321. package/server/lib/ui-auth/ui-auth.test.js +19 -3
  322. package/server/lib/ui-auth/ui-passkeys.js +7 -7
  323. package/server/lib/walkthrough/DOCUMENTATION.md +33 -14
  324. package/server/lib/walkthrough/index.js +1 -0
  325. package/server/lib/walkthrough/jobs.test.js +1 -1
  326. package/server/lib/walkthrough/language.test.js +1 -1
  327. package/server/lib/walkthrough/model-settings.js +11 -15
  328. package/server/lib/walkthrough/model-settings.test.js +1 -1
  329. package/server/lib/walkthrough/prompt.js +3 -1
  330. package/server/lib/walkthrough/pull-request.test.js +5 -5
  331. package/server/lib/walkthrough/reproduce-2607.test.js +2 -2
  332. package/server/lib/walkthrough/routes.test.js +26 -5
  333. package/server/lib/walkthrough/sources.js +23 -2
  334. package/server/lib/walkthrough/store.js +3 -3
  335. package/server/lib/walkthrough/store.test.js +1 -1
  336. package/server/opencode-proxy.test.js +2 -2
  337. package/server/proxy-headers.js +1 -1
  338. package/server/sse-routes.test.js +4 -4
  339. package/README.md.bak +0 -250
  340. package/bin/lib/DOCUMENTATION.md.bak +0 -163
  341. package/dist/assets/CommitSection-SGBCAW0w.js +0 -1
  342. package/dist/assets/DiffView-DluiRSla.js +0 -4
  343. package/dist/assets/FilesView-Bdq8ppva.js +0 -17
  344. package/dist/assets/GitView-Znn7VJcP.js +0 -6
  345. package/dist/assets/LinearIssuesView-jP-hXyac.js +0 -1
  346. package/dist/assets/MarkdownImageGallery-ClOvuZxC.js +0 -1
  347. package/dist/assets/MarkdownRendererImpl-Dt9mjTRN.js +0 -12
  348. package/dist/assets/OnboardingScreen-D2DG7K6b.js +0 -1
  349. package/dist/assets/PierreDiffViewer-B7m3f0d7.js +0 -157
  350. package/dist/assets/PlanView-B0F3BtPZ.js +0 -5
  351. package/dist/assets/SettingsView-BBW-S-gh.js +0 -28
  352. package/dist/assets/ToolPartDiffPreview-CUNe28U1.js +0 -8
  353. package/dist/assets/WalkthroughView-egQgxel3.js +0 -4
  354. package/dist/assets/contextPanelEmbeddedChat-C3fjDbdg.js +0 -1
  355. package/dist/assets/de-C1P6X5Rs.js +0 -9
  356. package/dist/assets/es-CDgaF1_t.js +0 -15
  357. package/dist/assets/fr-Bgxqvvz_.js +0 -13
  358. package/dist/assets/index-C57jT0Sa.css +0 -1
  359. package/dist/assets/index-DW_E3rnL.js +0 -7
  360. package/dist/assets/ja-BDRrEcNP.js +0 -15
  361. package/dist/assets/ko-Ba8sQV79.js +0 -15
  362. package/dist/assets/main-Bv5Pkngh.js +0 -928
  363. package/dist/assets/markdownCore-CZwzz5gw.js +0 -3
  364. package/dist/assets/patchFileDiff-yNfWXN4E.js +0 -10
  365. package/dist/assets/pl-Dioz29BI.js +0 -15
  366. package/dist/assets/pt-BR-DIs6ElwV.js +0 -15
  367. package/dist/assets/renderElectronMiniChatApp-BcKLHXKe.js +0 -2
  368. package/dist/assets/renderMobileApp-D9yQJy0L.js +0 -25
  369. package/dist/assets/runtimeEndpointReset-CjhvxLH0.js +0 -16
  370. package/dist/assets/scheduledTasksApi-DLW0mkQK.js +0 -1
  371. package/dist/assets/tr-DFnMlPxY.js +0 -6
  372. package/dist/assets/uk-ZrCNjM7Y.js +0 -15
  373. package/dist/assets/useAppFontEffects-CjrntdL0.js +0 -7310
  374. package/dist/assets/useInlineCommentController-CDEuSlPH.js +0 -2
  375. package/dist/assets/useRootScrollLock-BHYPkrLv.js +0 -1
  376. package/dist/assets/vendor-ghostty-web-CrxinGGH.js +0 -13
  377. package/dist/assets/vendor-zod-BLfBSgBh.js +0 -39
  378. package/dist/assets/zh-CN-iv_AV4EC.js +0 -15
  379. package/dist/assets/zh-TW-CzEUk38j.js +0 -15
  380. package/server/index.d.ts.bak +0 -39
  381. package/server/lib/agent-tool/DOCUMENTATION.md.bak +0 -119
  382. package/server/lib/browser-control/DOCUMENTATION.md.bak +0 -50
  383. package/server/lib/context-obligatory/DOCUMENTATION.md.bak +0 -19
  384. package/server/lib/dev-tunnel/DOCUMENTATION.md.bak +0 -57
  385. package/server/lib/dictation/DOCUMENTATION.md.bak +0 -100
  386. package/server/lib/event-stream/DOCUMENTATION.md.bak +0 -62
  387. package/server/lib/fs/DOCUMENTATION.md.bak +0 -47
  388. package/server/lib/git/DOCUMENTATION.md.bak +0 -193
  389. package/server/lib/github/DOCUMENTATION.md.bak +0 -183
  390. package/server/lib/linear/DOCUMENTATION.md.bak +0 -97
  391. package/server/lib/linear/OAUTH-BROKER-HANDOFF.md.bak +0 -91
  392. package/server/lib/markdown-image-grants/DOCUMENTATION.md.bak +0 -40
  393. package/server/lib/notifications/APNS.md.bak +0 -135
  394. package/server/lib/notifications/DOCUMENTATION.md.bak +0 -138
  395. package/server/lib/openchamber-control/DOCUMENTATION.md.bak +0 -64
  396. package/server/lib/opencode/DOCUMENTATION.md.bak +0 -431
  397. package/server/lib/opencode/managed-process-registry.d.ts.bak +0 -13
  398. package/server/lib/opencode/provider-env-aliases.d.ts.bak +0 -3
  399. package/server/lib/permission-auto-accept/DOCUMENTATION.md.bak +0 -34
  400. package/server/lib/project-context/DOCUMENTATION.md.bak +0 -160
  401. package/server/lib/quota/DOCUMENTATION.md.bak +0 -123
  402. package/server/lib/relay/DOCUMENTATION.md.bak +0 -100
  403. package/server/lib/scheduled-tasks/DOCUMENTATION.md.bak +0 -182
  404. package/server/lib/session-assist/DOCUMENTATION.md.bak +0 -66
  405. package/server/lib/session-goal/DOCUMENTATION.md.bak +0 -213
  406. package/server/lib/session-knowledge/DOCUMENTATION.md.bak +0 -89
  407. package/server/lib/skills-catalog/DOCUMENTATION.md.bak +0 -151
  408. package/server/lib/small-model/DOCUMENTATION.md.bak +0 -212
  409. package/server/lib/system-prompt/DOCUMENTATION.md.bak +0 -36
  410. package/server/lib/terminal/DOCUMENTATION.md.bak +0 -50
  411. package/server/lib/text/DOCUMENTATION.md.bak +0 -35
  412. package/server/lib/tts/DOCUMENTATION.md.bak +0 -147
  413. package/server/lib/tunnels/DOCUMENTATION.md.bak +0 -21
  414. package/server/lib/ui-auth/DOCUMENTATION.md.bak +0 -44
  415. package/server/lib/walkthrough/DOCUMENTATION.md.bak +0 -411
@@ -1,14 +1,14 @@
1
1
  import path from 'node:path';
2
2
  import { createOpencodeClient } from '@opencode-ai/sdk/v2';
3
- import { OpenChamberControlError, asControlError } from './error.js';
4
- import { OPENCHAMBER_ALL_ACTIONS } from './actions.js';
3
+ import { AiWorkerControlError, asControlError } from './error.js';
4
+ import { AIWORKER_ALL_ACTIONS } from './actions.js';
5
5
  import { writeScreenshot } from './screenshots.js';
6
6
 
7
7
  const DEFAULT_WAIT_TIMEOUT_SECONDS = 600;
8
8
  const MAX_WAIT_TIMEOUT_SECONDS = 86_400;
9
9
  const WAIT_POLL_INTERVAL_MS = 500;
10
10
  // One service, both capabilities: which tool asked is the caller's concern.
11
- const CONTROL_ACTIONS = new Set(OPENCHAMBER_ALL_ACTIONS);
11
+ const CONTROL_ACTIONS = new Set(AIWORKER_ALL_ACTIONS);
12
12
  const SCHEDULE_TASK_ID_ACTIONS = new Set([
13
13
  'schedule.run',
14
14
  'schedule.delete',
@@ -25,7 +25,7 @@ const positiveInteger = (value, fallback, field) => {
25
25
  if (value === undefined || value === null) return fallback;
26
26
  const number = Number(value);
27
27
  if (!Number.isSafeInteger(number) || number < 1) {
28
- throw new OpenChamberControlError(`${field} must be a positive integer`, 400);
28
+ throw new AiWorkerControlError(`${field} must be a positive integer`, 400);
29
29
  }
30
30
  return number;
31
31
  };
@@ -33,7 +33,7 @@ const positiveInteger = (value, fallback, field) => {
33
33
  const normalizeWaitTimeoutMs = (value) => {
34
34
  const seconds = value === undefined || value === null ? DEFAULT_WAIT_TIMEOUT_SECONDS : Number(value);
35
35
  if (!Number.isSafeInteger(seconds) || seconds < 1 || seconds > MAX_WAIT_TIMEOUT_SECONDS) {
36
- throw new OpenChamberControlError(`timeout must be from 1 to ${MAX_WAIT_TIMEOUT_SECONDS} seconds`, 400);
36
+ throw new AiWorkerControlError(`timeout must be from 1 to ${MAX_WAIT_TIMEOUT_SECONDS} seconds`, 400);
37
37
  }
38
38
  return seconds * 1000;
39
39
  };
@@ -64,20 +64,20 @@ const extractTextMessages = (messages, role = 'all') => {
64
64
 
65
65
  const parseModel = (value) => {
66
66
  const model = asNonEmptyString(value);
67
- if (!model) throw new OpenChamberControlError('model is required', 400);
67
+ if (!model) throw new AiWorkerControlError('model is required', 400);
68
68
  const slashIndex = model.indexOf('/');
69
69
  if (slashIndex <= 0 || slashIndex === model.length - 1) {
70
- throw new OpenChamberControlError('model must be in provider/model format', 400);
70
+ throw new AiWorkerControlError('model must be in provider/model format', 400);
71
71
  }
72
72
  return { providerID: model.slice(0, slashIndex), modelID: model.slice(slashIndex + 1) };
73
73
  };
74
74
 
75
75
  const parseWeekdays = (value) => {
76
76
  const raw = asNonEmptyString(value);
77
- if (!raw) throw new OpenChamberControlError('weekly is required', 400);
77
+ if (!raw) throw new AiWorkerControlError('weekly is required', 400);
78
78
  const weekdays = raw.split(',').map((entry) => Number.parseInt(entry.trim(), 10));
79
79
  if (weekdays.some((entry) => !Number.isInteger(entry) || entry < 0 || entry > 6)) {
80
- throw new OpenChamberControlError('weekly must contain weekdays from 0 to 6', 400);
80
+ throw new AiWorkerControlError('weekly must contain weekdays from 0 to 6', 400);
81
81
  }
82
82
  return Array.from(new Set(weekdays)).sort((a, b) => a - b);
83
83
  };
@@ -89,18 +89,18 @@ const buildSchedule = (input) => {
89
89
  const cron = asNonEmptyString(input.cron);
90
90
  const selectors = [daily, weekly, once, cron].filter(Boolean);
91
91
  if (selectors.length !== 1) {
92
- throw new OpenChamberControlError('Provide exactly one of daily, weekly, once, or cron', 400);
92
+ throw new AiWorkerControlError('Provide exactly one of daily, weekly, once, or cron', 400);
93
93
  }
94
94
  const timezone = asNonEmptyString(input.timezone);
95
95
  if (daily) return { kind: 'daily', times: [daily], ...(timezone ? { timezone } : {}) };
96
96
  if (weekly) {
97
97
  const time = asNonEmptyString(input.time);
98
- if (!time) throw new OpenChamberControlError('time is required with weekly', 400);
98
+ if (!time) throw new AiWorkerControlError('time is required with weekly', 400);
99
99
  return { kind: 'weekly', weekdays: parseWeekdays(weekly), times: [time], ...(timezone ? { timezone } : {}) };
100
100
  }
101
101
  if (once) {
102
102
  const time = asNonEmptyString(input.time);
103
- if (!time) throw new OpenChamberControlError('time is required with once', 400);
103
+ if (!time) throw new AiWorkerControlError('time is required with once', 400);
104
104
  return { kind: 'once', date: once, time, ...(timezone ? { timezone } : {}) };
105
105
  }
106
106
  return { kind: 'cron', cron, ...(timezone ? { timezone } : {}) };
@@ -109,15 +109,15 @@ const buildSchedule = (input) => {
109
109
  const buildScheduledTask = (input) => {
110
110
  const name = asNonEmptyString(input.name);
111
111
  const prompt = asNonEmptyString(input.prompt);
112
- if (!name) throw new OpenChamberControlError('name is required', 400);
113
- if (!prompt) throw new OpenChamberControlError('prompt is required', 400);
112
+ if (!name) throw new AiWorkerControlError('name is required', 400);
113
+ if (!prompt) throw new AiWorkerControlError('prompt is required', 400);
114
114
  const model = parseModel(input.model);
115
115
  const goalTokenBudget = input.goalTokenBudget;
116
116
  if (goalTokenBudget !== undefined && input.goal !== true) {
117
- throw new OpenChamberControlError('goalTokenBudget requires goal', 400);
117
+ throw new AiWorkerControlError('goalTokenBudget requires goal', 400);
118
118
  }
119
119
  if (goalTokenBudget !== undefined && (!Number.isSafeInteger(goalTokenBudget) || goalTokenBudget < 1000 || goalTokenBudget > 100_000_000)) {
120
- throw new OpenChamberControlError('goalTokenBudget must be from 1000 to 100000000', 400);
120
+ throw new AiWorkerControlError('goalTokenBudget must be from 1000 to 100000000', 400);
121
121
  }
122
122
  return {
123
123
  name,
@@ -134,7 +134,7 @@ const buildScheduledTask = (input) => {
134
134
  };
135
135
  };
136
136
 
137
- export const createOpenChamberControlService = (dependencies) => {
137
+ export const createAiWorkerControlService = (dependencies) => {
138
138
  const {
139
139
  readSettingsFromDiskMigrated,
140
140
  sanitizeProjects,
@@ -152,11 +152,11 @@ export const createOpenChamberControlService = (dependencies) => {
152
152
 
153
153
  const wait = (duration, signal) => {
154
154
  if (!signal) return sleep(duration);
155
- if (signal.aborted) return Promise.reject(new OpenChamberControlError('OpenChamber action was cancelled', 499));
155
+ if (signal.aborted) return Promise.reject(new AiWorkerControlError('AiWorker action was cancelled', 499));
156
156
  return new Promise((resolve, reject) => {
157
157
  const onAbort = () => {
158
158
  signal.removeEventListener('abort', onAbort);
159
- reject(new OpenChamberControlError('OpenChamber action was cancelled', 499));
159
+ reject(new AiWorkerControlError('AiWorker action was cancelled', 499));
160
160
  };
161
161
  signal.addEventListener('abort', onAbort, { once: true });
162
162
  sleep(duration).then(() => {
@@ -201,7 +201,7 @@ export const createOpenChamberControlService = (dependencies) => {
201
201
  const response = await client.session.status({ directory });
202
202
  const statuses = response?.data;
203
203
  if (!statuses || typeof statuses !== 'object' || Array.isArray(statuses)) {
204
- throw new OpenChamberControlError('Invalid session status response', 500);
204
+ throw new AiWorkerControlError('Invalid session status response', 500);
205
205
  }
206
206
  return statuses[sessionID] || { type: 'idle' };
207
207
  };
@@ -223,7 +223,7 @@ export const createOpenChamberControlService = (dependencies) => {
223
223
  const deadline = now() + timeoutMs;
224
224
  let observedActivity = false;
225
225
  while (true) {
226
- if (signal?.aborted) throw new OpenChamberControlError('OpenChamber action was cancelled', 499);
226
+ if (signal?.aborted) throw new AiWorkerControlError('AiWorker action was cancelled', 499);
227
227
  const status = await sessionStatus(client, sessionID, directory);
228
228
  if (status.type === 'busy' || status.type === 'retry') {
229
229
  observedActivity = true;
@@ -238,7 +238,7 @@ export const createOpenChamberControlService = (dependencies) => {
238
238
  }
239
239
  const remaining = deadline - now();
240
240
  if (remaining <= 0) {
241
- throw new OpenChamberControlError(`Session did not become idle within ${Math.ceil(timeoutMs / 1000)} seconds`, 500);
241
+ throw new AiWorkerControlError(`Session did not become idle within ${Math.ceil(timeoutMs / 1000)} seconds`, 500);
242
242
  }
243
243
  await wait(Math.min(WAIT_POLL_INTERVAL_MS, remaining), signal);
244
244
  }
@@ -262,8 +262,8 @@ export const createOpenChamberControlService = (dependencies) => {
262
262
  };
263
263
 
264
264
  const executeSessionAction = async (action, input, contextDirectory, signal) => {
265
- if (input.timeout !== undefined && input.wait !== true) throw new OpenChamberControlError('timeout requires wait', 400);
266
- if (input.lastAssistant === true && input.wait !== true) throw new OpenChamberControlError('lastAssistant requires wait', 400);
265
+ if (input.timeout !== undefined && input.wait !== true) throw new AiWorkerControlError('timeout requires wait', 400);
266
+ if (input.lastAssistant === true && input.wait !== true) throw new AiWorkerControlError('lastAssistant requires wait', 400);
267
267
  const sessionID = asNonEmptyString(input.sessionId);
268
268
  let directory = asNonEmptyString(input.directory) || (!input.projectId ? asNonEmptyString(contextDirectory) : null);
269
269
  if (sessionID && action !== 'session.create' && !asNonEmptyString(input.directory) && !input.projectId) {
@@ -293,7 +293,7 @@ export const createOpenChamberControlService = (dependencies) => {
293
293
  if (action === 'session.create') {
294
294
  result = await sessionService.create(payload);
295
295
  } else {
296
- if (!sessionID) throw new OpenChamberControlError('sessionId is required', 400);
296
+ if (!sessionID) throw new AiWorkerControlError('sessionId is required', 400);
297
297
  if (action === 'session.send') {
298
298
  result = await sessionService.send(sessionID, payload);
299
299
  } else {
@@ -335,11 +335,11 @@ export const createOpenChamberControlService = (dependencies) => {
335
335
  const readViewport = (required) => {
336
336
  const viewport = asNonEmptyString(input.viewport);
337
337
  if (!viewport) {
338
- if (required) throw new OpenChamberControlError('viewport is required for browser.resize', 400);
338
+ if (required) throw new AiWorkerControlError('viewport is required for browser.resize', 400);
339
339
  return;
340
340
  }
341
341
  if (!['mobile', 'tablet', 'desktop', 'fill'].includes(viewport)) {
342
- throw new OpenChamberControlError('viewport must be mobile, tablet, desktop, or fill', 400);
342
+ throw new AiWorkerControlError('viewport must be mobile, tablet, desktop, or fill', 400);
343
343
  }
344
344
  parameters.viewport = viewport;
345
345
  };
@@ -354,15 +354,15 @@ export const createOpenChamberControlService = (dependencies) => {
354
354
  if (action === 'browser.open') {
355
355
  readViewport(false);
356
356
  const url = asNonEmptyString(input.url);
357
- if (!url) throw new OpenChamberControlError('url is required for browser.open', 400);
357
+ if (!url) throw new AiWorkerControlError('url is required for browser.open', 400);
358
358
  let parsed;
359
359
  try {
360
360
  parsed = new URL(url);
361
361
  } catch {
362
- throw new OpenChamberControlError('url must be an absolute http(s) URL', 400);
362
+ throw new AiWorkerControlError('url must be an absolute http(s) URL', 400);
363
363
  }
364
364
  if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
365
- throw new OpenChamberControlError('url must use http or https', 400);
365
+ throw new AiWorkerControlError('url must use http or https', 400);
366
366
  }
367
367
  parameters.url = parsed.toString();
368
368
  }
@@ -372,7 +372,7 @@ export const createOpenChamberControlService = (dependencies) => {
372
372
  const selector = asNonEmptyString(input.selector);
373
373
  const text = asNonEmptyString(input.text);
374
374
  if (!selector && !text) {
375
- throw new OpenChamberControlError('browser.click requires selector or text', 400);
375
+ throw new AiWorkerControlError('browser.click requires selector or text', 400);
376
376
  }
377
377
  if (selector) parameters.selector = selector;
378
378
  if (text) parameters.text = text;
@@ -385,15 +385,15 @@ export const createOpenChamberControlService = (dependencies) => {
385
385
 
386
386
  if (action === 'browser.inspect') {
387
387
  const selector = asNonEmptyString(input.selector);
388
- if (!selector) throw new OpenChamberControlError('selector is required for browser.inspect', 400);
388
+ if (!selector) throw new AiWorkerControlError('selector is required for browser.inspect', 400);
389
389
  parameters.selector = selector;
390
390
  }
391
391
 
392
392
  if (action === 'browser.type') {
393
393
  const selector = asNonEmptyString(input.selector);
394
- if (!selector) throw new OpenChamberControlError('selector is required for browser.type', 400);
394
+ if (!selector) throw new AiWorkerControlError('selector is required for browser.type', 400);
395
395
  if (typeof input.value !== 'string') {
396
- throw new OpenChamberControlError('value is required for browser.type', 400);
396
+ throw new AiWorkerControlError('value is required for browser.type', 400);
397
397
  }
398
398
  parameters.selector = selector;
399
399
  parameters.value = input.value;
@@ -404,10 +404,10 @@ export const createOpenChamberControlService = (dependencies) => {
404
404
  const selector = asNonEmptyString(input.selector);
405
405
  const direction = asNonEmptyString(input.direction);
406
406
  if (!selector && !direction) {
407
- throw new OpenChamberControlError('browser.scroll requires direction or selector', 400);
407
+ throw new AiWorkerControlError('browser.scroll requires direction or selector', 400);
408
408
  }
409
409
  if (direction && !['up', 'down', 'top', 'bottom'].includes(direction)) {
410
- throw new OpenChamberControlError('direction must be up, down, top, or bottom', 400);
410
+ throw new AiWorkerControlError('direction must be up, down, top, or bottom', 400);
411
411
  }
412
412
  if (selector) parameters.selector = selector;
413
413
  if (direction) parameters.direction = direction;
@@ -425,7 +425,7 @@ export const createOpenChamberControlService = (dependencies) => {
425
425
  if (action === 'browser.capture') {
426
426
  const directory = asNonEmptyString(input.directory) || asNonEmptyString(contextDirectory);
427
427
  if (!directory) {
428
- throw new OpenChamberControlError('directory is required to save a screenshot', 400);
428
+ throw new AiWorkerControlError('directory is required to save a screenshot', 400);
429
429
  }
430
430
  const capture = result && typeof result === 'object' ? result : {};
431
431
  const saved = await writeScreenshot({
@@ -457,17 +457,17 @@ export const createOpenChamberControlService = (dependencies) => {
457
457
  const execute = async (action, input = {}, contextDirectory, options = {}) => {
458
458
  try {
459
459
  if (!CONTROL_ACTIONS.has(action)) {
460
- throw new OpenChamberControlError(`Unsupported OpenChamber action: ${action || 'missing'}`, 400);
460
+ throw new AiWorkerControlError(`Unsupported AiWorker action: ${action || 'missing'}`, 400);
461
461
  }
462
462
  if (action.startsWith('memory.')) {
463
463
  if (!agentMemoryActions) {
464
- throw new OpenChamberControlError('Agent memory is not available on this server', 503);
464
+ throw new AiWorkerControlError('Agent memory is not available on this server', 503);
465
465
  }
466
466
  return agentMemoryActions.execute(action, input, contextDirectory);
467
467
  }
468
468
  if (action.startsWith('browser.')) {
469
469
  if (!browserControl) {
470
- throw new OpenChamberControlError('The in-app browser is not available on this server', 503);
470
+ throw new AiWorkerControlError('The in-app browser is not available on this server', 503);
471
471
  }
472
472
  return browserAction(action, input, options.signal, contextDirectory);
473
473
  }
@@ -477,7 +477,7 @@ export const createOpenChamberControlService = (dependencies) => {
477
477
  if (action.startsWith('schedule.')) {
478
478
  const taskID = asNonEmptyString(input.taskId);
479
479
  if (SCHEDULE_TASK_ID_ACTIONS.has(action) && !taskID) {
480
- throw new OpenChamberControlError('taskId is required', 400);
480
+ throw new AiWorkerControlError('taskId is required', 400);
481
481
  }
482
482
  const explicitProjectID = asNonEmptyString(input.projectId);
483
483
  const explicitDirectory = asNonEmptyString(input.directory);
@@ -501,7 +501,7 @@ export const createOpenChamberControlService = (dependencies) => {
501
501
  return { deleted: true, tasks: await scheduledTaskService.remove(projectID, taskID) };
502
502
  case 'schedule.toggle': {
503
503
  if (typeof input.disabled !== 'boolean') {
504
- throw new OpenChamberControlError('disabled is required for schedule.toggle', 400);
504
+ throw new AiWorkerControlError('disabled is required for schedule.toggle', 400);
505
505
  }
506
506
  const enabled = input.disabled === false;
507
507
  return { task: await scheduledTaskService.setEnabled(projectID, taskID, enabled), enabled };
@@ -536,18 +536,18 @@ export const createOpenChamberControlService = (dependencies) => {
536
536
  }
537
537
  return { sessions, limit, directory, archived: input.all === true ? 'included' : 'excluded' };
538
538
  }
539
- if (!sessionID) throw new OpenChamberControlError('sessionId is required', 400);
540
- if (!directory) throw new OpenChamberControlError('directory is required', 400);
539
+ if (!sessionID) throw new AiWorkerControlError('sessionId is required', 400);
540
+ if (!directory) throw new AiWorkerControlError('directory is required', 400);
541
541
  if (action === 'session.status') {
542
542
  return { sessionId: sessionID, directory, sessionStatus: await sessionStatus(client, sessionID, directory) };
543
543
  }
544
544
  if (action === 'session.messages') {
545
- if (input.timeout !== undefined && input.wait !== true) throw new OpenChamberControlError('timeout requires wait', 400);
545
+ if (input.timeout !== undefined && input.wait !== true) throw new AiWorkerControlError('timeout requires wait', 400);
546
546
  const role = input.lastAssistant === true ? 'assistant' : (asNonEmptyString(input.role) || 'all');
547
- if (!['all', 'user', 'assistant'].includes(role)) throw new OpenChamberControlError('role must be all, user, or assistant', 400);
547
+ if (!['all', 'user', 'assistant'].includes(role)) throw new AiWorkerControlError('role must be all, user, or assistant', 400);
548
548
  const last = input.last === true || input.lastAssistant === true;
549
- if (input.all === true && (last || input.limit !== undefined)) throw new OpenChamberControlError('all cannot be combined with last or limit', 400);
550
- if (last && input.limit !== undefined) throw new OpenChamberControlError('last cannot be combined with limit', 400);
549
+ if (input.all === true && (last || input.limit !== undefined)) throw new AiWorkerControlError('all cannot be combined with last or limit', 400);
550
+ if (last && input.limit !== undefined) throw new AiWorkerControlError('last cannot be combined with limit', 400);
551
551
  const currentStatus = input.wait === true
552
552
  ? await waitForIdle({ client, sessionID, directory, timeoutMs: normalizeWaitTimeoutMs(input.timeout), requireActivity: false, startedAt: now(), signal: options.signal })
553
553
  : await sessionStatus(client, sessionID, directory);
@@ -555,9 +555,9 @@ export const createOpenChamberControlService = (dependencies) => {
555
555
  return { sessionId: sessionID, directory, role, sessionStatus: currentStatus, messages: await sessionMessages(client, sessionID, directory, role, limit) };
556
556
  }
557
557
  }
558
- throw new OpenChamberControlError(`Unsupported OpenChamber action: ${action || 'missing'}`, 400);
558
+ throw new AiWorkerControlError(`Unsupported AiWorker action: ${action || 'missing'}`, 400);
559
559
  } catch (error) {
560
- throw asControlError(error, `Failed to execute ${action || 'OpenChamber action'}`);
560
+ throw asControlError(error, `Failed to execute ${action || 'AiWorker action'}`);
561
561
  }
562
562
  };
563
563
 
@@ -4,7 +4,7 @@ import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import fs from 'node:fs/promises';
6
6
 
7
- import { createOpenChamberControlService } from './service.js';
7
+ import { createAiWorkerControlService } from './service.js';
8
8
 
9
9
  const createService = (overrides = {}) => {
10
10
  const client = {
@@ -28,7 +28,7 @@ const createService = (overrides = {}) => {
28
28
  remove: vi.fn(),
29
29
  setEnabled: vi.fn(),
30
30
  };
31
- const service = createOpenChamberControlService({
31
+ const service = createAiWorkerControlService({
32
32
  readSettingsFromDiskMigrated: vi.fn(async () => ({
33
33
  projects: [{ id: 'project-1', path: '/repo', label: 'Repo' }],
34
34
  defaultModel: 'provider/model',
@@ -47,7 +47,7 @@ const createService = (overrides = {}) => {
47
47
  return { service, client, sessionService, scheduledTaskService };
48
48
  };
49
49
 
50
- describe('OpenChamber control service', () => {
50
+ describe('AiWorker control service', () => {
51
51
  it('serves project and model projections without an HTTP or CLI round trip', async () => {
52
52
  const { service } = createService();
53
53
  await expect(service.execute('projects.list')).resolves.toEqual({
@@ -262,7 +262,7 @@ describe('OpenChamber control service', () => {
262
262
 
263
263
  it('rejects actions outside the fixed contract', async () => {
264
264
  const { service } = createService();
265
- await expect(service.execute('session.delete')).rejects.toThrow('Unsupported OpenChamber action');
265
+ await expect(service.execute('session.delete')).rejects.toThrow('Unsupported AiWorker action');
266
266
  });
267
267
  });
268
268
 
@@ -289,7 +289,7 @@ describe('browser capture', () => {
289
289
 
290
290
  const result = await service.execute('browser.capture', { label: 'After fix' }, directory);
291
291
 
292
- expect(result.path.startsWith('.openchamber/screenshots/after-fix-')).toBe(true);
292
+ expect(result.path.startsWith('.aiworker/screenshots/after-fix-')).toBe(true);
293
293
  expect(result.path.endsWith('.png')).toBe(true);
294
294
  expect(result.url).toBe('http://localhost:3000/');
295
295
  expect(result.viewport).toEqual({ mode: 'mobile', width: 390, height: 844 });
@@ -4,7 +4,7 @@ import { createWorktree, getWorktreeBootstrapStatus } from '../git/index.js';
4
4
  import { expandSnippets } from '../opencode/snippets.js';
5
5
  import { expandCommandGoalObjective, parseScheduledCommandPrompt } from '../scheduled-tasks/runtime.js';
6
6
  import { buildGoalIntroText, createSessionGoal } from '../session-goal/create.js';
7
- import { OpenChamberControlError, asControlError } from '../openchamber-control/error.js';
7
+ import { AiWorkerControlError, asControlError } from '../openchamber-control/error.js';
8
8
 
9
9
  const asNonEmptyString = (value) => {
10
10
  if (typeof value !== 'string') return null;
@@ -253,6 +253,40 @@ const latestCompletedAssistantMessageID = async ({ client, sessionID, directory
253
253
  return asNonEmptyString(latest?.id);
254
254
  };
255
255
 
256
+ /**
257
+ * Upper bound on one archive batch.
258
+ *
259
+ * The batch is applied one session at a time against OpenCode, so an unbounded
260
+ * list would hold a request open for as long as the list is large. Callers with
261
+ * more sessions than this send several batches and keep their own partial
262
+ * results.
263
+ */
264
+ const MAX_ARCHIVE_BATCH = 500;
265
+
266
+ const parseArchiveRequest = (payload) => {
267
+ const rawIds = payload?.ids;
268
+ if (!Array.isArray(rawIds) || rawIds.length === 0) {
269
+ return { ok: false, error: 'ids must be a non-empty array of session ids' };
270
+ }
271
+ if (rawIds.length > MAX_ARCHIVE_BATCH) {
272
+ return { ok: false, error: `ids must contain at most ${MAX_ARCHIVE_BATCH} session ids` };
273
+ }
274
+
275
+ const ids = [];
276
+ for (const value of rawIds) {
277
+ const id = asNonEmptyString(value);
278
+ if (!id) return { ok: false, error: 'ids must contain non-empty session ids' };
279
+ ids.push(id);
280
+ }
281
+
282
+ const archivedAt = payload?.archivedAt;
283
+ if (archivedAt !== undefined && (!Number.isSafeInteger(archivedAt) || archivedAt <= 0)) {
284
+ return { ok: false, error: 'archivedAt must be a positive integer timestamp' };
285
+ }
286
+
287
+ return { ok: true, ids, archivedAt: archivedAt ?? Date.now() };
288
+ };
289
+
256
290
  const resolveRequestedDirectory = async ({ payload, readSettingsFromDiskMigrated, sanitizeProjects, validateDirectoryPath }) => {
257
291
  const projectID = asNonEmptyString(payload?.projectId) || asNonEmptyString(payload?.projectID);
258
292
  if (projectID) {
@@ -292,12 +326,12 @@ const waitForWorktreeBootstrapReady = async ({ directory }) => {
292
326
  for (;;) {
293
327
  const status = await getWorktreeBootstrapStatus(directory);
294
328
  if (status?.status === 'failed') {
295
- throw new OpenChamberControlError(`Worktree bootstrap failed: ${status.error || 'unknown error'}`, 500);
329
+ throw new AiWorkerControlError(`Worktree bootstrap failed: ${status.error || 'unknown error'}`, 500);
296
330
  }
297
331
  const phase = status?.phase;
298
332
  if (status?.status === 'ready' || phase === 'git-ready' || phase === 'setup-ready') return;
299
333
  if (Date.now() >= deadline) {
300
- throw new OpenChamberControlError('Timed out waiting for the worktree bootstrap', 500);
334
+ throw new AiWorkerControlError('Timed out waiting for the worktree bootstrap', 500);
301
335
  }
302
336
  await new Promise((resolve) => setTimeout(resolve, WORKTREE_BOOTSTRAP_POLL_MS));
303
337
  }
@@ -350,7 +384,7 @@ const resolveWorktreeInput = (payload) => {
350
384
  };
351
385
  };
352
386
 
353
- export const createOpenChamberSessionService = (dependencies) => {
387
+ export const createAiWorkerSessionService = (dependencies) => {
354
388
  const {
355
389
  readSettingsFromDiskMigrated,
356
390
  sanitizeProjects,
@@ -404,23 +438,23 @@ export const createOpenChamberSessionService = (dependencies) => {
404
438
  if (requestedAgent && agents.length > 0) {
405
439
  const agent = agents.find((entry) => entry?.name === requestedAgent) || null;
406
440
  if (!agent) {
407
- throw new OpenChamberControlError(`Unknown agent '${requestedAgent}' for ${directory}`, 400);
441
+ throw new AiWorkerControlError(`Unknown agent '${requestedAgent}' for ${directory}`, 400);
408
442
  }
409
443
  if (!isPrimaryAgentMode(agent.mode)) {
410
- throw new OpenChamberControlError(`Agent '${requestedAgent}' is a subagent and cannot receive a prompt directly`, 400);
444
+ throw new AiWorkerControlError(`Agent '${requestedAgent}' is a subagent and cannot receive a prompt directly`, 400);
411
445
  }
412
446
  }
413
447
 
414
448
  if (requestedModel && providers.length > 0) {
415
449
  if (!hasProviderModel(providers, requestedModel.providerID, requestedModel.modelID)) {
416
- throw new OpenChamberControlError(
450
+ throw new AiWorkerControlError(
417
451
  `Unknown model '${requestedModel.providerID}/${requestedModel.modelID}' for ${directory}`,
418
452
  400,
419
453
  );
420
454
  }
421
455
  if (requestedVariant
422
456
  && !resolveVariant(providers, requestedModel.providerID, requestedModel.modelID, requestedVariant)) {
423
- throw new OpenChamberControlError(
457
+ throw new AiWorkerControlError(
424
458
  `Unknown variant '${requestedVariant}' for model '${requestedModel.providerID}/${requestedModel.modelID}'`,
425
459
  400,
426
460
  );
@@ -499,7 +533,7 @@ export const createOpenChamberSessionService = (dependencies) => {
499
533
  tokenBudget: goalInput.tokenBudget,
500
534
  providerID: model.providerID,
501
535
  modelID: model.modelID,
502
- onWarning: (message, error) => console.warn(`[OpenChamberSessions] ${message}:`, error?.message || error),
536
+ onWarning: (message, error) => console.warn(`[AiWorkerSessions] ${message}:`, error?.message || error),
503
537
  });
504
538
  }
505
539
 
@@ -579,12 +613,70 @@ export const createOpenChamberSessionService = (dependencies) => {
579
613
  return { model, agent, variant, promptDispatched: true, dispatchedAsCommand: Boolean(resolvedCommand) };
580
614
  };
581
615
 
616
+ /**
617
+ * Archive a batch of sessions in one request.
618
+ *
619
+ * The UI archives every session linked to a worktree before removing it.
620
+ * Doing that from the browser costs one request per session plus a store
621
+ * reconciliation between each of them, which is what made deleting a
622
+ * worktree with many sessions take tens of seconds. Here the batch stays on
623
+ * the server, next to OpenCode, and the client reconciles once.
624
+ *
625
+ * Sessions are updated one at a time on purpose: they are archived against a
626
+ * single OpenCode instance, and a fan-out of concurrent writes would trade a
627
+ * UI stall for server event-loop starvation. One failed session never stops
628
+ * the batch — it is reported in `failedIds` while the rest still archive, so
629
+ * callers keep the partial-failure behaviour they already show.
630
+ */
631
+ const archive = async (payload = {}) => {
632
+ const parsed = parseArchiveRequest(payload);
633
+ if (!parsed.ok) {
634
+ throw new AiWorkerControlError(parsed.error, 400);
635
+ }
636
+
637
+ const resolvedDirectory = await resolveRequestedDirectory({
638
+ payload,
639
+ readSettingsFromDiskMigrated,
640
+ sanitizeProjects,
641
+ validateDirectoryPath,
642
+ });
643
+ if (!resolvedDirectory.ok) {
644
+ throw new AiWorkerControlError(resolvedDirectory.error, resolvedDirectory.status || 400);
645
+ }
646
+
647
+ if (typeof waitForOpenCodeReady === 'function') await waitForOpenCodeReady(10_000, 250);
648
+
649
+ const directory = resolvedDirectory.directory;
650
+ const baseUrl = buildOpenCodeUrl('/', '').replace(/\/$/, '');
651
+ const client = createOpencodeClient({ baseUrl, headers: getOpenCodeAuthHeaders() });
652
+
653
+ const archived = [];
654
+ const failedIds = [];
655
+ for (const sessionID of parsed.ids) {
656
+ try {
657
+ const response = await client.session.update({
658
+ sessionID,
659
+ directory,
660
+ time: { archived: parsed.archivedAt },
661
+ });
662
+ const session = response?.data;
663
+ if (session?.id) archived.push(session);
664
+ else failedIds.push(sessionID);
665
+ } catch (error) {
666
+ console.warn('[AiWorkerSessions] failed to archive session', sessionID, error);
667
+ failedIds.push(sessionID);
668
+ }
669
+ }
670
+
671
+ return { directory, archived, failedIds };
672
+ };
673
+
582
674
  const create = async (payload = {}) => {
583
675
  const title = asNonEmptyString(payload.title);
584
676
  const prompt = asNonEmptyString(payload.prompt);
585
677
  const goalInput = resolveGoalInput(payload, prompt);
586
678
  if (!goalInput.ok) {
587
- throw new OpenChamberControlError(goalInput.error, 400);
679
+ throw new AiWorkerControlError(goalInput.error, 400);
588
680
  }
589
681
  const model = resolveRequestedModel(payload);
590
682
  const agent = asNonEmptyString(payload.agent);
@@ -597,14 +689,14 @@ export const createOpenChamberSessionService = (dependencies) => {
597
689
  validateDirectoryPath,
598
690
  });
599
691
  if (!resolvedDirectory.ok) {
600
- throw new OpenChamberControlError(resolvedDirectory.error, resolvedDirectory.status || 400);
692
+ throw new AiWorkerControlError(resolvedDirectory.error, resolvedDirectory.status || 400);
601
693
  }
602
694
 
603
695
  const worktreeInput = resolveWorktreeInput(payload);
604
696
  let worktree = null;
605
697
  let sessionDirectory = resolvedDirectory.directory;
606
698
  if (payload?.worktree && !worktreeInput) {
607
- throw new OpenChamberControlError('worktree.name is required when worktree is provided', 400);
699
+ throw new AiWorkerControlError('worktree.name is required when worktree is provided', 400);
608
700
  }
609
701
 
610
702
  if (typeof waitForOpenCodeReady === 'function') await waitForOpenCodeReady(10_000, 250);
@@ -692,10 +784,10 @@ export const createOpenChamberSessionService = (dependencies) => {
692
784
  const runExisting = async (action, sourceSessionId, payload = {}) => {
693
785
  const sourceSessionID = asNonEmptyString(sourceSessionId);
694
786
  const prompt = asNonEmptyString(payload.prompt);
695
- if (!sourceSessionID) throw new OpenChamberControlError('sessionId is required', 400);
696
- if (!prompt) throw new OpenChamberControlError('prompt is required', 400);
787
+ if (!sourceSessionID) throw new AiWorkerControlError('sessionId is required', 400);
788
+ if (!prompt) throw new AiWorkerControlError('prompt is required', 400);
697
789
  const goalInput = resolveGoalInput(payload, prompt);
698
- if (!goalInput.ok) throw new OpenChamberControlError(goalInput.error, 400);
790
+ if (!goalInput.ok) throw new AiWorkerControlError(goalInput.error, 400);
699
791
  const requestedModel = resolveRequestedModel(payload);
700
792
 
701
793
  let targetSessionID = sourceSessionID;
@@ -709,7 +801,7 @@ export const createOpenChamberSessionService = (dependencies) => {
709
801
  validateDirectoryPath,
710
802
  });
711
803
  if (!resolvedDirectory.ok) {
712
- throw new OpenChamberControlError(resolvedDirectory.error, resolvedDirectory.status || 400);
804
+ throw new AiWorkerControlError(resolvedDirectory.error, resolvedDirectory.status || 400);
713
805
  }
714
806
  directory = resolvedDirectory.directory;
715
807
  if (typeof waitForOpenCodeReady === 'function') await waitForOpenCodeReady(10_000, 250);
@@ -794,7 +886,7 @@ export const createOpenChamberSessionService = (dependencies) => {
794
886
  const statusCode = Number(error?.statusCode) || 500;
795
887
  const forkCreated = action === 'fork' && targetSessionID !== sourceSessionID;
796
888
  const goalConfigured = error?.goalConfigured === true;
797
- throw new OpenChamberControlError(
889
+ throw new AiWorkerControlError(
798
890
  error instanceof Error ? error.message : `Failed to ${action} session`,
799
891
  statusCode,
800
892
  {
@@ -813,6 +905,7 @@ export const createOpenChamberSessionService = (dependencies) => {
813
905
 
814
906
  return {
815
907
  create,
908
+ archive,
816
909
  send: (sessionID, payload) => runExisting('send', sessionID, payload),
817
910
  fork: (sessionID, payload) => runExisting('fork', sessionID, payload),
818
911
  };
@@ -831,18 +924,27 @@ const sendServiceError = (res, error, fallback) => {
831
924
  });
832
925
  };
833
926
 
834
- export const registerOpenChamberSessionRoutes = (app, dependencies) => {
835
- const service = dependencies.sessionService || createOpenChamberSessionService(dependencies);
927
+ export const registerAiWorkerSessionRoutes = (app, dependencies) => {
928
+ const service = dependencies.sessionService || createAiWorkerSessionService(dependencies);
836
929
 
837
930
  app.post('/api/openchamber/sessions', express.json({ limit: '1mb' }), async (req, res) => {
838
931
  try {
839
932
  return res.json(await service.create(req.body && typeof req.body === 'object' ? req.body : {}));
840
933
  } catch (error) {
841
- console.error('[OpenChamberSessions] failed to create session:', error);
934
+ console.error('[AiWorkerSessions] failed to create session:', error);
842
935
  return sendServiceError(res, error, 'Failed to create session');
843
936
  }
844
937
  });
845
938
 
939
+ app.post('/api/openchamber/sessions/archive', express.json({ limit: '1mb' }), async (req, res) => {
940
+ try {
941
+ return res.json(await service.archive(req.body && typeof req.body === 'object' ? req.body : {}));
942
+ } catch (error) {
943
+ console.error('[AiWorkerSessions] failed to archive sessions:', error);
944
+ return sendServiceError(res, error, 'Failed to archive sessions');
945
+ }
946
+ });
947
+
846
948
  app.post(
847
949
  '/api/openchamber/sessions/:sessionId/send',
848
950
  express.json({ limit: '1mb' }),
@@ -850,7 +952,7 @@ export const registerOpenChamberSessionRoutes = (app, dependencies) => {
850
952
  try {
851
953
  return res.json(await service.send(req.params.sessionId, req.body));
852
954
  } catch (error) {
853
- console.error('[OpenChamberSessions] failed to send session:', error);
955
+ console.error('[AiWorkerSessions] failed to send session:', error);
854
956
  return sendServiceError(res, error, 'Failed to send session');
855
957
  }
856
958
  },
@@ -862,7 +964,7 @@ export const registerOpenChamberSessionRoutes = (app, dependencies) => {
862
964
  try {
863
965
  return res.json(await service.fork(req.params.sessionId, req.body));
864
966
  } catch (error) {
865
- console.error('[OpenChamberSessions] failed to fork session:', error);
967
+ console.error('[AiWorkerSessions] failed to fork session:', error);
866
968
  return sendServiceError(res, error, 'Failed to fork session');
867
969
  }
868
970
  },