@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
@@ -5,7 +5,7 @@ import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
5
5
  const createWorktreeMock = vi.fn(async () => ({
6
6
  head: 'abc123',
7
7
  name: 'side-task',
8
- branch: 'openchamber/side-task',
8
+ branch: 'aiworker/side-task',
9
9
  path: '/repo/worktrees/side-task',
10
10
  }));
11
11
  const getWorktreeBootstrapStatusMock = vi.fn(async () => ({
@@ -17,6 +17,7 @@ const getWorktreeBootstrapStatusMock = vi.fn(async () => ({
17
17
  const sessionCreateMock = vi.fn(async () => ({ data: { id: 'ses_123' } }));
18
18
  const sessionForkMock = vi.fn(async () => ({ data: { id: 'ses_fork', title: 'Forked session' } }));
19
19
  const sessionMessagesMock = vi.fn(async () => ({ data: [] }));
20
+ const sessionUpdateMock = vi.fn(async ({ sessionID }) => ({ data: { id: sessionID, time: { archived: 1 } } }));
20
21
 
21
22
  let existingSessionMessages = [];
22
23
  let dispatchedUserMessageSeq = 0;
@@ -66,10 +67,10 @@ const selectionInputResponse = (url) => {
66
67
  };
67
68
  const sessionCommandMock = vi.fn(async () => ({ data: {} }));
68
69
  const commandListMock = vi.fn(async () => ({ data: [] }));
69
- globalThis.__openchamberCreateWorktreeMock = createWorktreeMock;
70
- globalThis.__openchamberGetWorktreeBootstrapStatusMock = getWorktreeBootstrapStatusMock;
70
+ globalThis.__aiworkerCreateWorktreeMock = createWorktreeMock;
71
+ globalThis.__aiworkerGetWorktreeBootstrapStatusMock = getWorktreeBootstrapStatusMock;
71
72
 
72
- let registerOpenChamberSessionRoutes;
73
+ let registerAiWorkerSessionRoutes;
73
74
 
74
75
  vi.mock('@opencode-ai/sdk/v2', () => ({
75
76
  createOpencodeClient: () => ({
@@ -78,6 +79,7 @@ vi.mock('@opencode-ai/sdk/v2', () => ({
78
79
  fork: sessionForkMock,
79
80
  messages: sessionMessagesMock,
80
81
  command: sessionCommandMock,
82
+ update: sessionUpdateMock,
81
83
  },
82
84
  command: {
83
85
  list: commandListMock,
@@ -86,8 +88,8 @@ vi.mock('@opencode-ai/sdk/v2', () => ({
86
88
  }));
87
89
 
88
90
  vi.mock('../git/index.js', () => ({
89
- createWorktree: (...args) => globalThis.__openchamberCreateWorktreeMock(...args),
90
- getWorktreeBootstrapStatus: (...args) => globalThis.__openchamberGetWorktreeBootstrapStatusMock(...args),
91
+ createWorktree: (...args) => globalThis.__aiworkerCreateWorktreeMock(...args),
92
+ getWorktreeBootstrapStatus: (...args) => globalThis.__aiworkerGetWorktreeBootstrapStatusMock(...args),
91
93
  }));
92
94
 
93
95
  const createApp = (overrides = {}, options = {}) => {
@@ -96,7 +98,7 @@ const createApp = (overrides = {}, options = {}) => {
96
98
  app.use(express.json());
97
99
  }
98
100
  const calls = [];
99
- registerOpenChamberSessionRoutes(app, {
101
+ registerAiWorkerSessionRoutes(app, {
100
102
  readSettingsFromDiskMigrated: async () => ({ projects: [{ id: 'proj_1', path: '/repo/app' }] }),
101
103
  sanitizeProjects: (projects) => projects,
102
104
  validateDirectoryPath: async (directory) => ({ ok: true, directory }),
@@ -108,9 +110,9 @@ const createApp = (overrides = {}, options = {}) => {
108
110
  return { app, calls };
109
111
  };
110
112
 
111
- describe('openchamber session routes', () => {
113
+ describe('aiworker session routes', () => {
112
114
  beforeAll(async () => {
113
- ({ registerOpenChamberSessionRoutes } = await import('./routes.js'));
115
+ ({ registerAiWorkerSessionRoutes } = await import('./routes.js'));
114
116
  });
115
117
 
116
118
  beforeEach(() => {
@@ -132,6 +134,92 @@ describe('openchamber session routes', () => {
132
134
  sessionCommandMock.mockResolvedValue({ data: {} });
133
135
  commandListMock.mockReset();
134
136
  commandListMock.mockResolvedValue({ data: [] });
137
+ sessionUpdateMock.mockReset();
138
+ sessionUpdateMock.mockImplementation(async ({ sessionID }) => ({ data: { id: sessionID, time: { archived: 1 } } }));
139
+ });
140
+
141
+ describe('archiving a batch of sessions', () => {
142
+ it('archives every id against the resolved directory and returns the archived sessions', async () => {
143
+ const { app } = createApp();
144
+ const response = await request(app)
145
+ .post('/api/openchamber/sessions/archive')
146
+ .send({ directory: '/repo/app', ids: ['ses_a', 'ses_b'], archivedAt: 1700 })
147
+ .expect(200);
148
+
149
+ expect(response.body.directory).toBe('/repo/app');
150
+ expect(response.body.archived.map((session) => session.id)).toEqual(['ses_a', 'ses_b']);
151
+ expect(response.body.failedIds).toEqual([]);
152
+ expect(sessionUpdateMock).toHaveBeenCalledTimes(2);
153
+ expect(sessionUpdateMock).toHaveBeenCalledWith({
154
+ sessionID: 'ses_a',
155
+ directory: '/repo/app',
156
+ time: { archived: 1700 },
157
+ });
158
+ });
159
+
160
+ it('keeps archiving after a failed session and reports it as failed', async () => {
161
+ sessionUpdateMock.mockImplementation(async ({ sessionID }) => {
162
+ if (sessionID === 'ses_b') throw new Error('session.update failed');
163
+ return { data: { id: sessionID } };
164
+ });
165
+
166
+ const { app } = createApp();
167
+ const response = await request(app)
168
+ .post('/api/openchamber/sessions/archive')
169
+ .send({ directory: '/repo/app', ids: ['ses_a', 'ses_b', 'ses_c'] })
170
+ .expect(200);
171
+
172
+ expect(response.body.archived.map((session) => session.id)).toEqual(['ses_a', 'ses_c']);
173
+ expect(response.body.failedIds).toEqual(['ses_b']);
174
+ });
175
+
176
+ it('reports a session the server did not confirm as failed instead of archived', async () => {
177
+ sessionUpdateMock.mockImplementation(async ({ sessionID }) => (
178
+ sessionID === 'ses_b' ? { data: null } : { data: { id: sessionID } }
179
+ ));
180
+
181
+ const { app } = createApp();
182
+ const response = await request(app)
183
+ .post('/api/openchamber/sessions/archive')
184
+ .send({ directory: '/repo/app', ids: ['ses_a', 'ses_b'] })
185
+ .expect(200);
186
+
187
+ expect(response.body.archived.map((session) => session.id)).toEqual(['ses_a']);
188
+ expect(response.body.failedIds).toEqual(['ses_b']);
189
+ });
190
+
191
+ it('rejects an empty batch, an oversized batch, and non-string ids', async () => {
192
+ const { app } = createApp();
193
+
194
+ await request(app).post('/api/openchamber/sessions/archive').send({ directory: '/repo/app', ids: [] }).expect(400);
195
+ await request(app)
196
+ .post('/api/openchamber/sessions/archive')
197
+ .send({ directory: '/repo/app', ids: Array.from({ length: 501 }, (_, index) => `ses_${index}`) })
198
+ .expect(400);
199
+ await request(app)
200
+ .post('/api/openchamber/sessions/archive')
201
+ .send({ directory: '/repo/app', ids: ['ses_a', ''] })
202
+ .expect(400);
203
+ await request(app)
204
+ .post('/api/openchamber/sessions/archive')
205
+ .send({ directory: '/repo/app', ids: ['ses_a'], archivedAt: -1 })
206
+ .expect(400);
207
+
208
+ expect(sessionUpdateMock).not.toHaveBeenCalled();
209
+ });
210
+
211
+ it('rejects a directory the runtime does not accept', async () => {
212
+ const { app } = createApp({
213
+ validateDirectoryPath: async () => ({ ok: false, error: 'Invalid directory' }),
214
+ });
215
+
216
+ await request(app)
217
+ .post('/api/openchamber/sessions/archive')
218
+ .send({ directory: '/elsewhere', ids: ['ses_a'] })
219
+ .expect(400);
220
+
221
+ expect(sessionUpdateMock).not.toHaveBeenCalled();
222
+ });
135
223
  });
136
224
 
137
225
  it('creates a session for a directory', async () => {
@@ -379,7 +467,7 @@ describe('openchamber session routes', () => {
379
467
  .post('/api/openchamber/sessions')
380
468
  .send({
381
469
  directory: '/repo/app',
382
- worktree: { name: 'side-task', branchName: 'openchamber/side-task', startRef: 'main' },
470
+ worktree: { name: 'side-task', branchName: 'aiworker/side-task', startRef: 'main' },
383
471
  setUpstream: false,
384
472
  prompt: 'Run this',
385
473
  model: 'openai/gpt-5.5',
@@ -389,7 +477,7 @@ describe('openchamber session routes', () => {
389
477
  expect(createWorktreeMock).toHaveBeenCalledWith('/repo/app', {
390
478
  mode: 'new',
391
479
  name: 'side-task',
392
- branchName: 'openchamber/side-task',
480
+ branchName: 'aiworker/side-task',
393
481
  startRef: 'main',
394
482
  setUpstream: false,
395
483
  });
@@ -34,6 +34,8 @@ This module provides OpenCode server integration utilities for the web server ru
34
34
  - `packages/web/server/lib/opencode/startup-performance.js`: opt-in startup phase diagnostics with fixed labels and numeric metadata allowlists.
35
35
  - `packages/web/server/lib/agent-tool/runtime.js`: managed OpenCode custom-tool materialization, environment injection, loopback authentication, and fixed CLI action dispatch.
36
36
  - `packages/web/server/lib/system-prompt/runtime.js`: opt-in managed OpenCode system-prompt optimizer materialization and plugin injection.
37
+ - `packages/web/server/lib/mcp-reconnect/runtime.js`: always-on managed OpenCode plugin that reconnects MCP servers OpenCode marked `failed`, with per-server backoff.
38
+ - `packages/web/server/lib/opencode/managed-plugin-config.js`: the one `OPENCODE_CONFIG_CONTENT` merge every managed plugin (agent tools, system prompt optimizer, MCP reconnect) appends itself through.
37
39
  - `packages/web/server/lib/opencode/server-utils-runtime.js`: shared server runtime utilities for OpenCode proxy wiring, OpenCode port/readiness helpers, and snapshot fetchers.
38
40
  - `packages/web/server/lib/opencode/openchamber-routes.js`: AiWorker update and models metadata route registration.
39
41
  - `packages/web/server/lib/opencode/pwa-manifest-routes.js`: PWA manifest route registration with recent-session shortcut resolution and short-lived caching.
@@ -61,12 +63,12 @@ This module provides OpenCode server integration utilities for the web server ru
61
63
 
62
64
  ## Public exports (providers.js)
63
65
  - `getProviderSources(providerId, workingDirectory)`: Resolves which OpenCode config layers define a provider.
64
- - `upsertProviderConfig(providerId, config, workingDirectory, scope?, options?)`: Validates and writes a custom OpenAI-compatible provider block (`npm`, `name`, `options.baseURL`, `models`, optional `env`/`headers`) into the user/project/custom config layer. Does not store API keys. Requires `config.env` or `options.hasStoredAuth` (auth already written via OpenCode `auth.set`). Edit flows must pass the provider's effective existing layer (`custom` > `project` > `user`) so updates do not create a global user override.
65
- - `validateCustomProviderConfig(providerId, config, options?)`: Structural validation for custom provider payloads (id format, http(s) base URL, models, credentials via `env` or `hasStoredAuth`).
66
+ - `upsertProviderConfig(providerId, config, workingDirectory, scope?, options?)`: Validates and writes a custom provider block (`npm`, `name`, `options.baseURL`, `models`, optional `env`/`headers`) into the user/project/custom config layer. The adapter may be OpenAI Chat Completions, OpenAI Responses, or Anthropic Messages. Existing provider, option, and retained-model fields not managed by the form are preserved; omitted models, headers, and env credentials remain explicit removals. Updating a legacy `providers` entry migrates it to the canonical `provider` key. Does not store API keys. Requires `config.env` or `options.hasStoredAuth` (auth already written via OpenCode `auth.set`). Edit flows must pass the provider's effective existing layer (`custom` > `project` > `user`) so updates do not create a global user override.
67
+ - `validateCustomProviderConfig(providerId, config, options?)`: Structural validation for custom provider payloads (id format, adapter allowlist `@ai-sdk/openai-compatible`/`@ai-sdk/openai`/`@ai-sdk/anthropic`, http(s) base URL, models, credentials via `env` or `hasStoredAuth`).
66
68
  - `removeProviderConfig(providerId, workingDirectory, scope?)`: Removes a provider block from the selected config layer.
67
69
 
68
70
  ## Public exports (shared.js)
69
- - `OPENCODE_CONFIG_DIR`, `AGENT_DIR`, `COMMAND_DIR`, `SKILL_DIR`, `CONFIG_FILE`: Path constants. `OPENCODE_CONFIG` is resolved at call time for the custom config layer path.
71
+ - `OPENCODE_CONFIG_DIR`, `AGENT_DIR`, `COMMAND_DIR`, `SKILL_DIR`, `CONFIG_FILE`: Path constants rooted at `$XDG_CONFIG_HOME/opencode` when `XDG_CONFIG_HOME` is non-empty, otherwise `~/.config/opencode`. These constants are evaluated when the module loads; no files are migrated. `OPENCODE_CONFIG` remains a separate explicit config-file path and is resolved at call time for the custom config layer; it does not replace the global config directory.
70
72
  - `AGENT_SCOPE`, `COMMAND_SCOPE`, `SKILL_SCOPE`: Scope constants with USER and PROJECT values.
71
73
  - `ensureDirs()`: Creates required OpenCode directories.
72
74
  - `parseMdFile(filePath)`, `writeMdFile(filePath, frontmatter, body)`: Markdown file operations with YAML frontmatter.
@@ -130,7 +132,8 @@ The runtime maintains active-session count incrementally from idempotent activit
130
132
  - `killProcessOnPort(port)`
131
133
 
132
134
  Managed OpenCode launch also merges the environment returned by the agent-tool
133
- runtime. PATH and `OPENCODE_SERVER_PASSWORD` remain lifecycle-owned and cannot
135
+ runtime, the opt-in system prompt optimizer, and the always-on MCP reconnect
136
+ plugin, each appending its `file://` entry to the previous one's config. PATH and `OPENCODE_SERVER_PASSWORD` remain lifecycle-owned and cannot
134
137
  be replaced by injected values. External OpenCode processes receive no
135
138
  AiWorker tool injection. Managed launch env strips AppImage `ARGV0` before
136
139
  spawn so zsh-backed OpenCode tools do not rewrite child argv[0] to the AppImage
@@ -208,7 +211,13 @@ Managed health failures are classified as `timeout`, `connection_refused`, `conn
208
211
  - `writeSettingsToDisk(settings)`
209
212
  - `persistSettings(changes)`
210
213
  - Persistent permission auto-accept policy is stored under `permissionAutoAccept`; execution ownership lives in `lib/permission-auto-accept/`.
211
- - Shared sidebar preferences are stored as validated top-level fields: `sidebarProjectDisplayMode`, `sidebarSessionGroupingMode`, `sidebarProjectSortOrder`, and `sidebarShowRecentSection`. Device-local picker selection and sticky-header state do not enter `settings.json`.
214
+ - Queued follow-up messages live in `<data-dir>/message-queue.json`, not in settings; execution ownership lives in `lib/message-queue/`.
215
+ - Shared sidebar preferences are stored as validated top-level fields: `sidebarProjectDisplayMode`, `sidebarSessionGroupingMode`, `sidebarProjectSortOrder`, and `sidebarShowRecentSection`. Device-local picker selection and sticky-header state do not enter either settings file.
216
+ - Two files (`settings-files.js`): `settings.json` holds instance facts and any legacy or unknown keys; `preferences.json` beside it holds every key the generated registry snapshot (`settings-registry.json`) marks `profile`, as `{ version: 1, fields: { key: { value, updatedAt, surfaces? } } }`. Keys the snapshot marks `perSurface` are stored per surface kind: `GET`/`PUT /api/config/settings` read the client's kind from the `surface` query parameter (`settingsSurfaceOf`; the legacy `x-openchamber-surface` header is still honoured, but a header forces a CORS preflight that cross-origin shells and older instances refuse, so clients must not send one) (`web`, `desktop`, `vscode`, `mobile`; anything else means base), `persistSettings(changes, { surface })` writes a changed per-surface key under `surfaces[surface]` and never touches its base, and `readSettingsFromDisk({ surface })` resolves that kind's value first, the base otherwise. Callers without a surface (migrations, the seed, server-side feature writers) read and write the base. `readSettingsFromDisk()` returns the merged document and seeds `preferences.json` once from an existing `settings.json` (which it leaves intact). An existing `preferences.json` that fails to parse is a failure, not an empty profile: it is never seeded or overwritten, the merged read serves the instance part, and `persistSettings` drops profile keys with a warning until the file is fixed or removed. `writeSettingsToDisk(document)` splits by scope and writes `settings.json` as the instance part plus a copy of the profile's base values (`legacySettingsDocumentOf`): a build from before the split reads only that file, so a rollback keeps the user's preferences, while current builds ignore the copy because `preferences.json` wins in the merge; device keys are dropped from writes. Modules that read one profile key off the disk on a hot path use `readMergedSettingsSync`.
217
+
218
+ ## Public exports (settings-files.js)
219
+ - `parsePreferencesDocument(raw)`, `serializePreferencesDocument(fields)`, `flattenPreferences(fields)`, `buildPreferencesFields(previousFields, document, now)`, `instancePartOf(document)`, `seedPreferencesFrom(document, now)`, `readMergedSettingsSync({ fs, path, settingsFilePath })`, `getSettingsScope(key)`, `isProfileSettingsKey(key)`, `isDeviceSettingsKey(key)`, `preferencesFilePathFor(settingsFilePath, path)`.
220
+ - The VS Code extension host writes the same two files with the same shape (`packages/vscode/src/settings-files.ts`); format changes go to both.
212
221
 
213
222
  ## Public exports (settings-helpers.js)
214
223
  - `createSettingsHelpers(dependencies)`: creates settings helper runtime for settings request/response shaping.
@@ -359,9 +368,20 @@ before starting managed OpenCode. The managed custom tool therefore receives
359
368
  an authoritative loopback callback URL even when AiWorker binds port `0`.
360
369
 
361
370
  ## Public exports (openchamber-routes.js)
371
+ Browser completion checks use `appType=web&updateStatus=true` to stay on the
372
+ Desktop Host's native updater. A rejected native restart is retained in the
373
+ server process and returned to these polls as `DESKTOP_UPDATE_RESTART_FAILED`;
374
+ ordinary availability checks remain usable so a browser reload can offer a
375
+ retry. Starting another installation clears the previous restart error.
376
+ The shared UI's `lib/web-update.ts` parses install/check responses and waits
377
+ for the installed native target version, rather than treating absence of a
378
+ newer release as installation success. Poll requests have individual deadlines
379
+ within a ten-minute overall deadline.
380
+
362
381
  - `registerAiWorkerRoutes(app, dependencies)`: registers AiWorker endpoints:
363
382
  - `GET /api/openchamber/update-check`
364
383
  - `POST /api/openchamber/update-install`
384
+ - Desktop-managed hosts delegate authenticated Web update requests to the Electron main process, which checks, downloads, and applies the update through `electron-updater` before restarting the host.
365
385
  - Foreground servers running under a systemd user unit queue installation in
366
386
  a separate transient unit and restart the configured service afterwards.
367
387
  `AIWORKER_SYSTEMD_UNIT` overrides the default `aiworker.service`.
@@ -417,7 +437,7 @@ an authoritative loopback callback URL even when AiWorker binds port `0`.
417
437
 
418
438
  ## Storage and configuration
419
439
  - Provider auth: `~/.local/share/opencode/auth.json`.
420
- - User config: `~/.config/opencode/opencode.json`.
440
+ - User config: `$XDG_CONFIG_HOME/opencode/opencode.json`, falling back to `~/.config/opencode/opencode.json` when unset or blank.
421
441
  - Project config: `<workingDirectory>/.opencode/opencode.json` or `opencode.json`.
422
442
  - Custom config: `OPENCODE_CONFIG` env var path.
423
443
  - Rate limit config: `AIWORKER_RATE_LIMIT_MAX_ATTEMPTS`, `AIWORKER_RATE_LIMIT_NO_IP_MAX_ATTEMPTS` env vars.
@@ -429,3 +449,7 @@ an authoritative loopback callback URL even when AiWorker binds port `0`.
429
449
  - Config merging follows priority: custom > project > user.
430
450
  - UI auth uses scrypt for password hashing with constant-time comparison.
431
451
  - Tunnel auth treats `host.docker.internal` as local-only when the socket remote IP is private/loopback.
452
+
453
+ The behavior `GET /api/behavior/agents-md` response includes `path`, the effective
454
+ server-side filename, whether or not the file exists. Settings displays this
455
+ path without deriving a directory from the browser environment.
@@ -30,7 +30,7 @@ function writeAuthFile(auth) {
30
30
  if (process.platform !== 'win32') fs.chmodSync(OPENCODE_DATA_DIR, 0o700);
31
31
 
32
32
  if (fs.existsSync(AUTH_FILE)) {
33
- const backupFile = `${AUTH_FILE}.openchamber.backup`;
33
+ const backupFile = `${AUTH_FILE}.aiworker.backup`;
34
34
  fs.copyFileSync(AUTH_FILE, backupFile);
35
35
  if (process.platform !== 'win32') fs.chmodSync(backupFile, 0o600);
36
36
  console.log(`Created auth backup: ${backupFile}`);
@@ -6,7 +6,7 @@ export const createBootstrapRuntime = (dependencies) => {
6
6
  registerAuthAndAccessRoutes,
7
7
  registerTtsRoutes,
8
8
  registerNotificationRoutes,
9
- registerOpenChamberRoutes,
9
+ registerAiWorkerRoutes,
10
10
  registerAgentToolRoutes = () => {},
11
11
  express,
12
12
  } = dependencies;
@@ -14,7 +14,7 @@ export const createBootstrapRuntime = (dependencies) => {
14
14
  const setupBaseRoutes = (app, options) => {
15
15
  const {
16
16
  process,
17
- openchamberVersion,
17
+ aiworkerVersion,
18
18
  runtimeName,
19
19
  serverStartedAt,
20
20
  gracefulShutdown,
@@ -56,13 +56,14 @@ export const createBootstrapRuntime = (dependencies) => {
56
56
  path,
57
57
  server,
58
58
  __dirname,
59
- openchamberDataDir,
59
+ aiworkerDataDir,
60
60
  modelsDevApiUrl,
61
61
  modelsMetadataCacheTtl,
62
62
  fetchFreeZenModels,
63
63
  getCachedZenModels,
64
64
  setAutoAcceptSession,
65
65
  agentToolRuntime,
66
+ desktopUpdater,
66
67
  } = options;
67
68
 
68
69
  const uiAuthController = createUiAuth({
@@ -77,7 +78,7 @@ export const createBootstrapRuntime = (dependencies) => {
77
78
  registerServerStatusRoutes(app, {
78
79
  express,
79
80
  process,
80
- openchamberVersion,
81
+ aiworkerVersion,
81
82
  runtimeName,
82
83
  serverStartedAt,
83
84
  gracefulShutdown,
@@ -140,19 +141,20 @@ export const createBootstrapRuntime = (dependencies) => {
140
141
  setAutoAcceptSession,
141
142
  });
142
143
 
143
- registerOpenChamberRoutes(app, {
144
+ registerAiWorkerRoutes(app, {
144
145
  fs,
145
146
  os,
146
147
  path,
147
148
  process,
148
149
  server,
149
150
  __dirname,
150
- openchamberDataDir,
151
+ aiworkerDataDir,
151
152
  modelsDevApiUrl,
152
153
  modelsMetadataCacheTtl,
153
154
  readSettingsFromDiskMigrated,
154
155
  fetchFreeZenModels,
155
156
  getCachedZenModels,
157
+ desktopUpdater,
156
158
  });
157
159
 
158
160
  return {
@@ -7,19 +7,19 @@ export const parseServeCliOptions = ({
7
7
  }) => {
8
8
  const args = Array.isArray(argv) ? [...argv] : [];
9
9
  const envPassword =
10
- env.OPENCHAMBER_UI_PASSWORD ||
10
+ env.AIWORKER_UI_PASSWORD ||
11
11
  env.OPENCODE_UI_PASSWORD ||
12
12
  null;
13
- const envCfTunnel = env.OPENCHAMBER_TRY_CF_TUNNEL === 'true';
14
- const envTunnelProvider = env.OPENCHAMBER_TUNNEL_PROVIDER || undefined;
15
- const envTunnelMode = env.OPENCHAMBER_TUNNEL_MODE || undefined;
16
- const envTunnelConfigRaw = env.OPENCHAMBER_TUNNEL_CONFIG;
13
+ const envCfTunnel = env.AIWORKER_TRY_CF_TUNNEL === 'true';
14
+ const envTunnelProvider = env.AIWORKER_TUNNEL_PROVIDER || undefined;
15
+ const envTunnelMode = env.AIWORKER_TUNNEL_MODE || undefined;
16
+ const envTunnelConfigRaw = env.AIWORKER_TUNNEL_CONFIG;
17
17
  const envTunnelConfig = typeof envTunnelConfigRaw === 'string'
18
18
  ? (envTunnelConfigRaw.trim().length > 0 ? envTunnelConfigRaw.trim() : null)
19
19
  : undefined;
20
- const envTunnelToken = env.OPENCHAMBER_TUNNEL_TOKEN || undefined;
21
- const envTunnelHostname = env.OPENCHAMBER_TUNNEL_HOSTNAME || undefined;
22
- const envApiOnly = env.OPENCHAMBER_API_ONLY === '1' || env.OPENCHAMBER_API_ONLY === 'true';
20
+ const envTunnelToken = env.AIWORKER_TUNNEL_TOKEN || undefined;
21
+ const envTunnelHostname = env.AIWORKER_TUNNEL_HOSTNAME || undefined;
22
+ const envApiOnly = env.AIWORKER_API_ONLY === '1' || env.AIWORKER_API_ONLY === 'true';
23
23
 
24
24
  const options = {
25
25
  port: defaultPort,
@@ -0,0 +1,116 @@
1
+ import fs from 'fs';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ import { afterEach, describe, expect, it, vi } from 'vitest';
5
+
6
+ const originalXdgConfigHome = process.env.XDG_CONFIG_HOME;
7
+ const originalOpenCodeConfig = process.env.OPENCODE_CONFIG;
8
+
9
+ afterEach(() => {
10
+ if (originalXdgConfigHome === undefined) delete process.env.XDG_CONFIG_HOME;
11
+ else process.env.XDG_CONFIG_HOME = originalXdgConfigHome;
12
+ if (originalOpenCodeConfig === undefined) delete process.env.OPENCODE_CONFIG;
13
+ else process.env.OPENCODE_CONFIG = originalOpenCodeConfig;
14
+ vi.resetModules();
15
+ });
16
+
17
+ async function loadOpenCodeModules() {
18
+ vi.resetModules();
19
+ return Promise.all([
20
+ import('./shared.js'),
21
+ import('./agents.js'),
22
+ import('./commands.js'),
23
+ import('./skills.js'),
24
+ import('./snippets.js'),
25
+ import('./plugins.js'),
26
+ import('./routes.js'),
27
+ ]);
28
+ }
29
+
30
+ describe('OpenCode global config paths', () => {
31
+ it('derives all shared constants from a non-empty XDG_CONFIG_HOME', async () => {
32
+ const xdgConfigHome = fs.mkdtempSync(path.join(os.tmpdir(), 'openchamber-xdg-'));
33
+ process.env.XDG_CONFIG_HOME = xdgConfigHome;
34
+
35
+ const [{ OPENCODE_CONFIG_DIR, AGENT_DIR, COMMAND_DIR, SKILL_DIR, CONFIG_FILE }] = await loadOpenCodeModules();
36
+ const configDir = path.join(xdgConfigHome, 'opencode');
37
+ expect(OPENCODE_CONFIG_DIR).toBe(configDir);
38
+ expect(AGENT_DIR).toBe(path.join(configDir, 'agents'));
39
+ expect(COMMAND_DIR).toBe(path.join(configDir, 'commands'));
40
+ expect(SKILL_DIR).toBe(path.join(configDir, 'skills'));
41
+ expect(CONFIG_FILE).toBe(path.join(configDir, 'config.json'));
42
+
43
+ fs.rmSync(xdgConfigHome, { recursive: true, force: true });
44
+ });
45
+
46
+ it.each([undefined, ' '])('falls back to ~/.config/opencode when XDG_CONFIG_HOME is %s', async (xdgConfigHome) => {
47
+ if (xdgConfigHome === undefined) delete process.env.XDG_CONFIG_HOME;
48
+ else process.env.XDG_CONFIG_HOME = xdgConfigHome;
49
+
50
+ const [{ OPENCODE_CONFIG_DIR }] = await loadOpenCodeModules();
51
+ expect(OPENCODE_CONFIG_DIR).toBe(path.join(os.homedir(), '.config', 'opencode'));
52
+ });
53
+
54
+ it('keeps global CRUD below XDG_CONFIG_HOME while project files stay in the project', async () => {
55
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'openchamber-config-paths-'));
56
+ const xdgConfigHome = path.join(root, 'xdg');
57
+ const projectDir = path.join(root, 'project');
58
+ process.env.XDG_CONFIG_HOME = xdgConfigHome;
59
+ delete process.env.OPENCODE_CONFIG;
60
+
61
+ const [, agents, commands, skills, snippets, plugins] = await loadOpenCodeModules();
62
+ agents.createAgent('global-agent', { description: 'Global', prompt: 'Global prompt' }, projectDir, 'user');
63
+ commands.createCommand('global-command', { description: 'Global', template: 'Global template' }, projectDir, 'user');
64
+ skills.createSkill('global-skill', { description: 'Global', instructions: 'Global instructions' }, projectDir, 'user');
65
+ snippets.createSnippet('global-snippet', { content: 'Global snippet' }, projectDir, 'global');
66
+ plugins.createPluginEntry({ spec: 'global-plugin', scope: 'user' }, projectDir);
67
+
68
+ const configDir = path.join(xdgConfigHome, 'opencode');
69
+ expect(fs.existsSync(path.join(configDir, 'agents', 'global-agent.md'))).toBe(true);
70
+ expect(fs.existsSync(path.join(configDir, 'commands', 'global-command.md'))).toBe(true);
71
+ expect(fs.existsSync(path.join(configDir, 'skills', 'global-skill', 'SKILL.md'))).toBe(true);
72
+ expect(fs.existsSync(path.join(configDir, 'snippet', 'global-snippet.md'))).toBe(true);
73
+ expect(JSON.parse(fs.readFileSync(path.join(configDir, 'config.json'), 'utf8')).plugin).toEqual(['global-plugin']);
74
+
75
+ agents.createAgent('project-agent', { description: 'Project', prompt: 'Project prompt' }, projectDir, 'project');
76
+ commands.createCommand('project-command', { description: 'Project', template: 'Project template' }, projectDir, 'project');
77
+ skills.createSkill('project-skill', { description: 'Project', instructions: 'Project instructions' }, projectDir, 'project');
78
+
79
+ expect(fs.existsSync(path.join(projectDir, '.opencode', 'agents', 'project-agent.md'))).toBe(true);
80
+ expect(fs.existsSync(path.join(projectDir, '.opencode', 'commands', 'project-command.md'))).toBe(true);
81
+ expect(fs.existsSync(path.join(projectDir, '.opencode', 'skills', 'project-skill', 'SKILL.md'))).toBe(true);
82
+
83
+ fs.rmSync(root, { recursive: true, force: true });
84
+ });
85
+
86
+ it('writes global AGENTS.md below XDG_CONFIG_HOME', async () => {
87
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'openchamber-agents-md-'));
88
+ process.env.XDG_CONFIG_HOME = path.join(root, 'xdg');
89
+ delete process.env.OPENCODE_CONFIG;
90
+
91
+ const [, , , , , , routes] = await loadOpenCodeModules();
92
+ const handlers = new Map();
93
+ const app = {
94
+ get(route, ...callbacks) { handlers.set(`GET ${route}`, callbacks.at(-1)); },
95
+ put(route, ...callbacks) { handlers.set(`PUT ${route}`, callbacks.at(-1)); },
96
+ post() {},
97
+ delete() {},
98
+ };
99
+ routes.registerOpenCodeRoutes(app, {});
100
+
101
+ const response = { json: vi.fn(), status: vi.fn(() => response) };
102
+ await handlers.get('GET /api/behavior/agents-md')({}, response);
103
+ expect(response.json).toHaveBeenLastCalledWith({
104
+ content: '', exists: false, path: path.join(process.env.XDG_CONFIG_HOME, 'opencode', 'AGENTS.md'),
105
+ });
106
+
107
+ await handlers.get('PUT /api/behavior/agents-md')({ body: { content: 'Global behavior' } }, response);
108
+
109
+ expect(fs.readFileSync(path.join(process.env.XDG_CONFIG_HOME, 'opencode', 'AGENTS.md'), 'utf8')).toBe('Global behavior');
110
+ await handlers.get('GET /api/behavior/agents-md')({}, response);
111
+ expect(response.json).toHaveBeenLastCalledWith({
112
+ content: 'Global behavior', exists: true, path: path.join(process.env.XDG_CONFIG_HOME, 'opencode', 'AGENTS.md'),
113
+ });
114
+ fs.rmSync(root, { recursive: true, force: true });
115
+ });
116
+ });
@@ -28,12 +28,12 @@ export const registerServerStatusRoutes = (app, dependencies) => {
28
28
  const {
29
29
  express,
30
30
  process,
31
- openchamberVersion,
31
+ aiworkerVersion,
32
32
  runtimeName,
33
33
  serverStartedAt,
34
34
  gracefulShutdown,
35
35
  getHealthSnapshot,
36
- // Port this OpenChamber instance serves on and the tunnel public URL (if
36
+ // Port this AiWorker instance serves on and the tunnel public URL (if
37
37
  // a tunnel is active). Exposed on /api/system/info so the UI can surface
38
38
  // the active instance's service URLs. Optional: older wiring omits them
39
39
  // and the endpoint reports null.
@@ -101,7 +101,7 @@ export const registerServerStatusRoutes = (app, dependencies) => {
101
101
  const isDevShutdownAllowed = () => {
102
102
  // Dev-only escape hatch: allow terminating the whole dev process group.
103
103
  // This should never be enabled in production runtimes.
104
- return process.env.OPENCHAMBER_DEV_SHUTDOWN === 'true';
104
+ return process.env.AIWORKER_DEV_SHUTDOWN === 'true';
105
105
  };
106
106
 
107
107
  const isSameOriginRequest = (req) => {
@@ -209,7 +209,7 @@ export const registerServerStatusRoutes = (app, dependencies) => {
209
209
  res.json({
210
210
  status: 'ok',
211
211
  timestamp: new Date().toISOString(),
212
- openchamberVersion,
212
+ aiworkerVersion,
213
213
  runtime: runtimeName,
214
214
  compatibility,
215
215
  ...(serverId ? { serverId } : {}),
@@ -221,7 +221,7 @@ export const registerServerStatusRoutes = (app, dependencies) => {
221
221
  const serverId = await resolveServerId();
222
222
  res.json({
223
223
  status: 'ok',
224
- openchamberVersion,
224
+ aiworkerVersion,
225
225
  runtime: runtimeName,
226
226
  startedAt: serverStartedAt,
227
227
  compatibility,
@@ -324,7 +324,7 @@ export const registerServerStatusRoutes = (app, dependencies) => {
324
324
 
325
325
  app.get('/api/system/info', (_req, res) => {
326
326
  res.json({
327
- openchamberVersion,
327
+ aiworkerVersion,
328
328
  runtime: runtimeName,
329
329
  pid: process.pid,
330
330
  startedAt: serverStartedAt,
@@ -376,7 +376,7 @@ export const registerAuthAndAccessRoutes = (app, dependencies) => {
376
376
  getServerId = async () => null,
377
377
  // Display name a paired device shows for THIS server (issuing machine's
378
378
  // hostname), distinct from the per-device pairing label typed by the operator.
379
- getServerLabel = () => 'OpenChamber',
379
+ getServerLabel = () => 'AiWorker',
380
380
  } = dependencies;
381
381
  const PAIRING_REDEEM_RATE_LIMIT_WINDOW_MS = 5 * 60 * 1000;
382
382
  const PAIRING_REDEEM_RATE_LIMIT_MAX_ATTEMPTS = 10;
@@ -1065,6 +1065,7 @@ export const registerCommonRequestMiddleware = (app, dependencies) => {
1065
1065
  req.path.startsWith('/api/push') ||
1066
1066
  req.path.startsWith('/api/notifications') ||
1067
1067
  req.path.startsWith('/api/permission-auto-accept') ||
1068
+ req.path.startsWith('/api/message-queue') ||
1068
1069
  req.path.startsWith('/api/provider') ||
1069
1070
  req.path.startsWith('/api/session-folders') ||
1070
1071
  req.path.startsWith('/api/small-model') ||
@@ -17,7 +17,7 @@ describe('core-routes', () => {
17
17
  shutdownOpts = opts;
18
18
  }),
19
19
  getHealthSnapshot: () => ({ status: 'ok' }),
20
- openchamberVersion: '1.0.0',
20
+ aiworkerVersion: '1.0.0',
21
21
  runtimeName: 'test',
22
22
  express,
23
23
  };
@@ -35,7 +35,7 @@ describe('core-routes', () => {
35
35
  const dependencies = {
36
36
  gracefulShutdown: vi.fn(async () => {}),
37
37
  getHealthSnapshot: () => ({ status: 'ok' }),
38
- openchamberVersion: '1.0.0',
38
+ aiworkerVersion: '1.0.0',
39
39
  runtimeName: 'test',
40
40
  express,
41
41
  tunnelAuthController: {
@@ -62,7 +62,7 @@ describe('core-routes', () => {
62
62
  const dependencies = {
63
63
  gracefulShutdown: vi.fn(async () => {}),
64
64
  getHealthSnapshot: () => ({ status: 'ok' }),
65
- openchamberVersion: '1.0.0',
65
+ aiworkerVersion: '1.0.0',
66
66
  runtimeName: 'test',
67
67
  express,
68
68
  tunnelAuthController: {
@@ -89,7 +89,7 @@ describe('core-routes', () => {
89
89
  const dependencies = {
90
90
  gracefulShutdown: vi.fn(async () => {}),
91
91
  getHealthSnapshot: () => ({ status: 'ok' }),
92
- openchamberVersion: '1.0.0',
92
+ aiworkerVersion: '1.0.0',
93
93
  runtimeName: 'test',
94
94
  express,
95
95
  tunnelAuthController: {
@@ -438,7 +438,7 @@ describe('core-routes', () => {
438
438
  expect(response.headers['cache-control']).toBe('no-store');
439
439
  expect(response.body).toMatchObject({
440
440
  ok: true,
441
- server: { label: 'OpenChamber', url: 'http://runtime.example', fingerprint: 'ABCD-1234' },
441
+ server: { label: 'AiWorker', url: 'http://runtime.example', fingerprint: 'ABCD-1234' },
442
442
  client: { id: 'client-1', authMethod: 'pairing' },
443
443
  clientToken: 'oc_client_token',
444
444
  });
@@ -690,7 +690,7 @@ describe('client auth routes', () => {
690
690
 
691
691
  const current = await request(app)
692
692
  .post('/api/client-auth/clients')
693
- .send({ label: 'OpenChamber Desktop', clientKind: 'desktop-local' });
693
+ .send({ label: 'AiWorker Desktop', clientKind: 'desktop-local' });
694
694
  const other = await request(app)
695
695
  .post('/api/client-auth/clients')
696
696
  .send({ label: 'Other device' });
@@ -725,7 +725,7 @@ describe('client auth routes', () => {
725
725
 
726
726
  const desktop = await request(app)
727
727
  .post('/api/client-auth/clients')
728
- .send({ label: 'OpenChamber Desktop', clientKind: 'desktop-local' });
728
+ .send({ label: 'AiWorker Desktop', clientKind: 'desktop-local' });
729
729
  const other = await request(app)
730
730
  .post('/api/client-auth/clients')
731
731
  .send({ label: 'Other device' });
@@ -758,7 +758,7 @@ describe('client auth routes', () => {
758
758
 
759
759
  const desktop = await request(app)
760
760
  .post('/api/client-auth/clients')
761
- .send({ label: 'OpenChamber Desktop', clientKind: 'desktop-local' });
761
+ .send({ label: 'AiWorker Desktop', clientKind: 'desktop-local' });
762
762
  const remote = await request(app)
763
763
  .post('/api/client-auth/clients')
764
764
  .send({ label: 'Phone' });
@@ -827,14 +827,14 @@ describe('client auth routes', () => {
827
827
  serverStartedAt: '2026-01-01T00:00:00.000Z',
828
828
  gracefulShutdown: vi.fn(async () => {}),
829
829
  getHealthSnapshot: () => ({ status: 'ok' }),
830
- openchamberVersion: '1.0.0',
830
+ aiworkerVersion: '1.0.0',
831
831
  runtimeName: 'test',
832
832
  express,
833
833
  });
834
834
 
835
835
  const response = await request(app).get('/api/system/info');
836
836
  expect(response.status).toBe(200);
837
- expect(response.body.openchamberVersion).toBe('1.0.0');
837
+ expect(response.body.aiworkerVersion).toBe('1.0.0');
838
838
  expect(response.body.runtime).toBe('test');
839
839
  expect(response.body.pid).toBeTypeOf('number');
840
840
  expect(response.body.startedAt).toBeTypeOf('string');
@@ -849,7 +849,7 @@ describe('client auth routes', () => {
849
849
  serverStartedAt: '2026-01-01T00:00:00.000Z',
850
850
  gracefulShutdown: vi.fn(async () => {}),
851
851
  getHealthSnapshot: () => ({ status: 'ok' }),
852
- openchamberVersion: '1.0.0',
852
+ aiworkerVersion: '1.0.0',
853
853
  runtimeName: 'test',
854
854
  express,
855
855
  getServerPort: () => 9988,