@aiworker/web 1.22.0 → 1.22.2

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 (354) hide show
  1. package/README.md +4 -4
  2. package/bin/cli.js +7 -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-CSICpWQD.js} +1 -1
  28. package/dist/assets/{DiffView-DluiRSla.js → DiffView-hDBKesA_.js} +3 -3
  29. package/dist/assets/DirtyBranchSwitchDialog-C22HdWj4.js +1 -0
  30. package/dist/assets/FilesView-CdWzeOp9.js +17 -0
  31. package/dist/assets/GitView-VQQkYuUw.js +6 -0
  32. package/dist/assets/{JsonTreeView-B0BdZEHG.js → JsonTreeView-6lrhwD3q.js} +1 -1
  33. package/dist/assets/LinearIssuesView-Ba6Q9569.js +1 -0
  34. package/dist/assets/{MarkdownImageGallery-ClOvuZxC.js → MarkdownImageGallery-Czv_mhvS.js} +1 -1
  35. package/dist/assets/MarkdownRendererImpl-BrMcswiy.js +12 -0
  36. package/dist/assets/{OnboardingScreen-D2DG7K6b.js → OnboardingScreen-ChxQoAkx.js} +1 -1
  37. package/dist/assets/{PatchDiff-DvfqDql7.js → PatchDiff-BzcZPlOq.js} +1 -1
  38. package/dist/assets/{PierreDiffViewer-B7m3f0d7.js → PierreDiffViewer-BchBtZlp.js} +2 -2
  39. package/dist/assets/PlanView-DyDt_nZ_.js +5 -0
  40. package/dist/assets/SettingsView-BKf5xBsP.js +28 -0
  41. package/dist/assets/{SettingsWindow-i45U1Cy1.js → SettingsWindow-DDQYaKWQ.js} +1 -1
  42. package/dist/assets/{ToolOutputDialog-BTwyh5OF.js → ToolOutputDialog-iYF8Y2bz.js} +6 -6
  43. package/dist/assets/ToolPartDiffPreview-CdjbOVMM.js +8 -0
  44. package/dist/assets/{VirtualizedFileDiff-DD8lDVej.js → VirtualizedFileDiff-fFFm2QgH.js} +1 -1
  45. package/dist/assets/{WalkthroughView-egQgxel3.js → WalkthroughView-DOeCsMju.js} +2 -2
  46. package/dist/assets/{computeVirtualFileMetrics-BMIRgMHv.js → computeVirtualFileMetrics-CzgLum_K.js} +2 -2
  47. package/dist/assets/{contextPanelEmbeddedChat-C3fjDbdg.js → contextPanelEmbeddedChat-C0ZLAepL.js} +1 -1
  48. package/dist/assets/{de-C1P6X5Rs.js → de-B5JaA3SA.js} +6 -5
  49. package/dist/assets/{es-CDgaF1_t.js → es-EPIH88ii.js} +6 -5
  50. package/dist/assets/{fr-Bgxqvvz_.js → fr-CAMfxUdZ.js} +6 -5
  51. package/dist/assets/{index-CODwDsU_.js → index-Bl3LSbjn.js} +1 -1
  52. package/dist/assets/index-DF5kMP-i.js +39 -0
  53. package/dist/assets/index-Dl3xbAB_.css +1 -0
  54. package/dist/assets/{isDiffPlainText-BqayB8d3.js → isDiffPlainText-Dx-dB_8l.js} +1 -1
  55. package/dist/assets/{isFilePlainText-QfoiKJNY.js → isFilePlainText-CWFPwmnU.js} +1 -1
  56. package/dist/assets/{ja-BDRrEcNP.js → ja-CifOE1VN.js} +7 -6
  57. package/dist/assets/{ko-Ba8sQV79.js → ko-BBDyAyYQ.js} +7 -6
  58. package/dist/assets/{main-C5DVOxc6.js → main-DnBAoktx.js} +2 -2
  59. package/dist/assets/main-MhSaOZoB.js +930 -0
  60. package/dist/assets/{markdownCore-CZwzz5gw.js → markdownCore-BrBwOOMn.js} +2 -2
  61. package/dist/assets/{miniChat-DUJ4irZc.js → miniChat-BKyvLseN.js} +2 -2
  62. package/dist/assets/{mobile-CcaxB0n4.js → mobile-DKjeFgMN.js} +2 -2
  63. package/dist/assets/{patchFileDiff-yNfWXN4E.js → patchFileDiff-o8ms1me8.js} +1 -1
  64. package/dist/assets/pl-DgEHYfFM.js +16 -0
  65. package/dist/assets/{pt-BR-DIs6ElwV.js → pt-BR-DuWHojUw.js} +6 -5
  66. package/dist/assets/{renderElectronMiniChatApp-BcKLHXKe.js → renderElectronMiniChatApp-CDgBwwCS.js} +2 -2
  67. package/dist/assets/renderMobileApp-DJIKIK1r.js +25 -0
  68. package/dist/assets/runtimeEndpointReset-CYJ9O_xX.js +17 -0
  69. package/dist/assets/{scheduledTasksApi-DLW0mkQK.js → scheduledTasksApi-D8yamh1b.js} +1 -1
  70. package/dist/assets/{shikiHighlight-DYOWuY65.js → shikiHighlight-TEQCmzW8.js} +1 -1
  71. package/dist/assets/tr-D5m2yIWL.js +7 -0
  72. package/dist/assets/{uk-ZrCNjM7Y.js → uk-D_q60oog.js} +6 -5
  73. package/dist/assets/{useAppFontEffects-CjrntdL0.js → useAppFontEffects-D7sNpuL2.js} +161 -190
  74. package/dist/assets/useInlineCommentController-Brz_cLcQ.js +2 -0
  75. package/dist/assets/{useRootScrollLock-BHYPkrLv.js → useRootScrollLock-lXEnWlaU.js} +1 -1
  76. package/dist/assets/{vendor-codemirror-language-data-DFZik9R2.js → vendor-codemirror-language-data-Dp3KMRQG.js} +2 -2
  77. package/dist/assets/vendor-zod-CK21ihK-.js +39 -0
  78. package/dist/assets/{web-components-Bhg83tjf.js → web-components-_mNEMjFY.js} +1 -1
  79. package/dist/assets/{zh-CN-iv_AV4EC.js → zh-CN-D8QvsVeg.js} +6 -5
  80. package/dist/assets/{zh-TW-CzEUk38j.js → zh-TW-B9t7rQQO.js} +6 -5
  81. package/dist/index.html +22 -22
  82. package/dist/mini-chat.html +7 -7
  83. package/dist/mobile.html +5 -5
  84. package/package.json +3 -3
  85. package/server/index.js +118 -85
  86. package/server/lib/agent-memory/actions.js +2 -2
  87. package/server/lib/agent-memory/feature-flag.js +1 -1
  88. package/server/lib/agent-memory/feature-flag.test.js +8 -8
  89. package/server/lib/agent-memory/routes.js +2 -2
  90. package/server/lib/agent-tool/runtime.js +37 -54
  91. package/server/lib/agent-tool/runtime.test.js +59 -59
  92. package/server/lib/browser-control/broker.js +3 -3
  93. package/server/lib/browser-control/broker.test.js +1 -1
  94. package/server/lib/changelog/update-notes.js +82 -0
  95. package/server/lib/changelog/update-notes.test.js +59 -0
  96. package/server/lib/client-auth/remote-clients.test.js +5 -5
  97. package/server/lib/context-obligatory/runtime.js +7 -7
  98. package/server/lib/context-obligatory/runtime.test.js +5 -5
  99. package/server/lib/dev-servers/parse.js +2 -2
  100. package/server/lib/dev-servers/parse.test.js +2 -2
  101. package/server/lib/dev-servers/routes.js +1 -1
  102. package/server/lib/dev-tunnel/DOCUMENTATION.md +13 -4
  103. package/server/lib/dev-tunnel/client.js +1 -1
  104. package/server/lib/dev-tunnel/runtime.js +5 -5
  105. package/server/lib/dev-tunnel/tunnel.test.js +21 -1
  106. package/server/lib/dictation/local/model-catalog.js +1 -1
  107. package/server/lib/dictation/local/worker-process.js +2 -2
  108. package/server/lib/event-stream/directory-ws-bridge.js +1 -1
  109. package/server/lib/event-stream/global-ws-bridge.js +1 -1
  110. package/server/lib/event-stream/protocol.test.js +4 -4
  111. package/server/lib/event-stream/runtime.test.js +6 -6
  112. package/server/lib/fs/DOCUMENTATION.md +2 -0
  113. package/server/lib/fs/routes.js +37 -26
  114. package/server/lib/fs/routes.test.js +98 -21
  115. package/server/lib/git/DOCUMENTATION.md +3 -1
  116. package/server/lib/git/identity-storage.js +1 -1
  117. package/server/lib/git/issue-2746-longpaths.test.js +4 -4
  118. package/server/lib/git/routes.js +17 -1
  119. package/server/lib/git/service.js +116 -26
  120. package/server/lib/git/service.test.js +174 -3
  121. package/server/lib/github/auth.js +8 -8
  122. package/server/lib/github/pr-status.js +1 -1
  123. package/server/lib/github/routes.js +2 -2
  124. package/server/lib/inherited-env.js +1 -1
  125. package/server/lib/inherited-env.test.js +2 -2
  126. package/server/lib/linear/auth.js +8 -8
  127. package/server/lib/linear/auth.test.js +24 -24
  128. package/server/lib/linear/issues.test.js +6 -6
  129. package/server/lib/linear/mapping.test.js +4 -4
  130. package/server/lib/linear/oauth.js +2 -2
  131. package/server/lib/linear/oauth.test.js +14 -14
  132. package/server/lib/linear/routes.js +5 -5
  133. package/server/lib/linear/routes.test.js +16 -16
  134. package/server/lib/linear/status-runtime.test.js +9 -9
  135. package/server/lib/linear/status.js +1 -1
  136. package/server/lib/linear/status.test.js +15 -15
  137. package/server/lib/linear/teams.test.js +4 -4
  138. package/server/lib/magic-prompts/routes.js +2 -2
  139. package/server/lib/mcp-reconnect/DOCUMENTATION.md +55 -0
  140. package/server/lib/mcp-reconnect/runtime.js +122 -0
  141. package/server/lib/mcp-reconnect/runtime.test.js +140 -0
  142. package/server/lib/message-queue/DOCUMENTATION.md +158 -0
  143. package/server/lib/message-queue/runtime.js +870 -0
  144. package/server/lib/message-queue/runtime.test.js +482 -0
  145. package/server/lib/notifications/apns-runtime.js +17 -17
  146. package/server/lib/notifications/apns-runtime.test.js +11 -11
  147. package/server/lib/notifications/emitter-runtime.js +1 -1
  148. package/server/lib/notifications/emitter-runtime.test.js +1 -1
  149. package/server/lib/notifications/push-runtime.js +7 -7
  150. package/server/lib/notifications/routes.js +1 -1
  151. package/server/lib/notifications/runtime.js +1 -1
  152. package/server/lib/openchamber-control/action-resolution.test.js +10 -10
  153. package/server/lib/openchamber-control/actions.js +24 -24
  154. package/server/lib/openchamber-control/error.js +4 -4
  155. package/server/lib/openchamber-control/routes.js +2 -2
  156. package/server/lib/openchamber-control/routes.test.js +5 -5
  157. package/server/lib/openchamber-control/screenshots.js +1 -1
  158. package/server/lib/openchamber-control/screenshots.test.js +1 -1
  159. package/server/lib/openchamber-control/service.js +50 -50
  160. package/server/lib/openchamber-control/service.test.js +5 -5
  161. package/server/lib/openchamber-sessions/routes.js +124 -22
  162. package/server/lib/openchamber-sessions/routes.test.js +99 -11
  163. package/server/lib/opencode/DOCUMENTATION.md +13 -5
  164. package/server/lib/opencode/auth.js +1 -1
  165. package/server/lib/opencode/bootstrap-runtime.js +6 -6
  166. package/server/lib/opencode/cli-options.js +8 -8
  167. package/server/lib/opencode/config-paths.test.js +116 -0
  168. package/server/lib/opencode/core-routes.js +8 -7
  169. package/server/lib/opencode/core-routes.test.js +11 -11
  170. package/server/lib/opencode/env-config.js +5 -5
  171. package/server/lib/opencode/env-config.test.js +7 -7
  172. package/server/lib/opencode/env-runtime.js +10 -10
  173. package/server/lib/opencode/env-runtime.test.js +18 -18
  174. package/server/lib/opencode/feature-routes-runtime.js +17 -12
  175. package/server/lib/opencode/hmr-state-runtime.js +2 -2
  176. package/server/lib/opencode/hmr-state-runtime.test.js +1 -1
  177. package/server/lib/opencode/input-history-scope.js +14 -0
  178. package/server/lib/opencode/lifecycle.js +8 -8
  179. package/server/lib/opencode/lifecycle.test.js +4 -4
  180. package/server/lib/opencode/managed-plugin-config.js +35 -0
  181. package/server/lib/opencode/managed-process-registry.js +3 -3
  182. package/server/lib/opencode/mcp-oauth-callback.test.js +2 -2
  183. package/server/lib/opencode/openchamber-routes.js +15 -15
  184. package/server/lib/opencode/openchamber-routes.test.js +11 -11
  185. package/server/lib/opencode/plugins.js +2 -2
  186. package/server/lib/opencode/plugins.test.js +1 -1
  187. package/server/lib/opencode/project-icon-routes.js +2 -2
  188. package/server/lib/opencode/project-icon-routes.test.js +1 -1
  189. package/server/lib/opencode/providers.js +44 -2
  190. package/server/lib/opencode/providers.test.js +131 -4
  191. package/server/lib/opencode/proxy.js +2 -2
  192. package/server/lib/opencode/pwa-manifest-routes.js +1 -1
  193. package/server/lib/opencode/restart-session-recovery.test.js +1 -1
  194. package/server/lib/opencode/routes-upgrade.test.js +4 -4
  195. package/server/lib/opencode/routes.js +14 -14
  196. package/server/lib/opencode/server-startup-runtime.js +6 -6
  197. package/server/lib/opencode/session-runtime.js +3 -3
  198. package/server/lib/opencode/session-runtime.test.js +6 -6
  199. package/server/lib/opencode/settings-helpers.js +31 -3
  200. package/server/lib/opencode/settings-helpers.test.js +189 -12
  201. package/server/lib/opencode/settings-runtime.js +2 -2
  202. package/server/lib/opencode/settings-runtime.test.js +29 -0
  203. package/server/lib/opencode/shared.js +5 -2
  204. package/server/lib/opencode/shared.test.js +7 -7
  205. package/server/lib/opencode/shutdown-runtime.js +2 -0
  206. package/server/lib/opencode/skill-routes.js +2 -1
  207. package/server/lib/opencode/snippets.js +1 -2
  208. package/server/lib/opencode/startup-performance.js +1 -1
  209. package/server/lib/opencode/startup-performance.test.js +6 -6
  210. package/server/lib/opencode/static-routes-runtime.js +8 -8
  211. package/server/lib/opencode/static-routes-runtime.test.js +7 -7
  212. package/server/lib/opencode/upgrade-capability.js +2 -2
  213. package/server/lib/opencode/upgrade-capability.test.js +3 -3
  214. package/server/lib/package-manager.js +17 -42
  215. package/server/lib/package-manager.test.js +19 -19
  216. package/server/lib/permission-auto-accept/runtime.js +1 -1
  217. package/server/lib/project-context/routes.js +1 -1
  218. package/server/lib/projects/project-config.js +2 -2
  219. package/server/lib/quota/DOCUMENTATION.md +9 -1
  220. package/server/lib/quota/credentials/providers.js +4 -0
  221. package/server/lib/quota/credentials/store.js +4 -4
  222. package/server/lib/quota/credentials/store.test.js +8 -8
  223. package/server/lib/quota/index.js +1 -0
  224. package/server/lib/quota/providers/exe-dev.js +75 -0
  225. package/server/lib/quota/providers/exe-dev.test.js +47 -0
  226. package/server/lib/quota/providers/hyper.js +118 -0
  227. package/server/lib/quota/providers/hyper.test.js +126 -0
  228. package/server/lib/quota/providers/index.js +15 -0
  229. package/server/lib/quota/providers/ollama-cloud.js +1 -1
  230. package/server/lib/quota/providers/opencode-go.js +2 -1
  231. package/server/lib/quota/providers/opencode-go.test.js +9 -5
  232. package/server/lib/quota/providers/xai.js +1 -1
  233. package/server/lib/quota/routes.js +2 -0
  234. package/server/lib/quota/utils/auth.js +1 -1
  235. package/server/lib/relay/DOCUMENTATION.md +1 -1
  236. package/server/lib/relay/host-client.js +1 -1
  237. package/server/lib/relay/host-client.test.js +9 -1
  238. package/server/lib/relay/host-lock.js +1 -1
  239. package/server/lib/relay/service.js +5 -5
  240. package/server/lib/relay/tunnel-host.js +3 -1
  241. package/server/lib/relay/tunnel-host.test.js +9 -1
  242. package/server/lib/scheduled-tasks/issue-2710-double-execution.test.js +2 -2
  243. package/server/lib/scheduled-tasks/routes.js +5 -5
  244. package/server/lib/scheduled-tasks/service.js +25 -25
  245. package/server/lib/scheduled-tasks/service.test.js +1 -1
  246. package/server/lib/security/bind-host.js +4 -4
  247. package/server/lib/security/bind-host.test.js +1 -1
  248. package/server/lib/security/request-security.js +11 -5
  249. package/server/lib/security/request-security.test.js +14 -14
  250. package/server/lib/session-assist/runtime.js +10 -9
  251. package/server/lib/session-folders/routes.js +2 -2
  252. package/server/lib/session-folders/routes.test.js +8 -8
  253. package/server/lib/session-goal/DOCUMENTATION.md +20 -7
  254. package/server/lib/session-goal/create.js +4 -2
  255. package/server/lib/session-goal/create.test.js +1 -1
  256. package/server/lib/session-goal/objectives.js +4 -4
  257. package/server/lib/session-goal/routes.js +1 -1
  258. package/server/lib/session-goal/runtime.js +88 -22
  259. package/server/lib/session-goal/runtime.test.js +428 -2
  260. package/server/lib/session-knowledge/runtime.js +11 -11
  261. package/server/lib/session-knowledge/runtime.test.js +5 -5
  262. package/server/lib/skills-catalog/DOCUMENTATION.md +1 -1
  263. package/server/lib/skills-catalog/cache.test.js +2 -2
  264. package/server/lib/skills-catalog/disk-cache.js +5 -5
  265. package/server/lib/skills-catalog/github-meta.test.js +2 -2
  266. package/server/lib/skills-catalog/install.js +3 -2
  267. package/server/lib/small-model/DOCUMENTATION.md +4 -0
  268. package/server/lib/small-model/call.js +9 -3
  269. package/server/lib/small-model/call.test.js +29 -6
  270. package/server/lib/small-model/index.js +8 -7
  271. package/server/lib/small-model/index.test.js +1 -1
  272. package/server/lib/small-model/resolve.js +1 -1
  273. package/server/lib/small-model/resolve.test.js +1 -1
  274. package/server/lib/small-model/routes.js +2 -1
  275. package/server/lib/system-prompt/runtime.js +3 -22
  276. package/server/lib/system-prompt/runtime.test.js +3 -3
  277. package/server/lib/terminal/DOCUMENTATION.md +11 -7
  278. package/server/lib/terminal/runtime.js +180 -26
  279. package/server/lib/terminal/runtime.test.js +554 -27
  280. package/server/lib/terminal/shells.js +20 -3
  281. package/server/lib/terminal/shells.test.js +33 -2
  282. package/server/lib/tts/base-url.js +3 -3
  283. package/server/lib/tts/routes.test.js +20 -20
  284. package/server/lib/ui-auth/ui-auth.js +12 -9
  285. package/server/lib/ui-auth/ui-auth.test.js +19 -3
  286. package/server/lib/ui-auth/ui-passkeys.js +7 -7
  287. package/server/lib/walkthrough/index.js +1 -0
  288. package/server/lib/walkthrough/jobs.test.js +1 -1
  289. package/server/lib/walkthrough/language.test.js +1 -1
  290. package/server/lib/walkthrough/model-settings.js +3 -3
  291. package/server/lib/walkthrough/model-settings.test.js +1 -1
  292. package/server/lib/walkthrough/pull-request.test.js +5 -5
  293. package/server/lib/walkthrough/reproduce-2607.test.js +2 -2
  294. package/server/lib/walkthrough/routes.test.js +26 -5
  295. package/server/lib/walkthrough/store.js +3 -3
  296. package/server/lib/walkthrough/store.test.js +1 -1
  297. package/server/opencode-proxy.test.js +2 -2
  298. package/server/proxy-headers.js +1 -1
  299. package/server/sse-routes.test.js +4 -4
  300. package/README.md.bak +0 -250
  301. package/bin/lib/DOCUMENTATION.md.bak +0 -163
  302. package/dist/assets/CommitSection-SGBCAW0w.js +0 -1
  303. package/dist/assets/FilesView-Bdq8ppva.js +0 -17
  304. package/dist/assets/GitView-Znn7VJcP.js +0 -6
  305. package/dist/assets/LinearIssuesView-jP-hXyac.js +0 -1
  306. package/dist/assets/MarkdownRendererImpl-Dt9mjTRN.js +0 -12
  307. package/dist/assets/PlanView-B0F3BtPZ.js +0 -5
  308. package/dist/assets/SettingsView-BBW-S-gh.js +0 -28
  309. package/dist/assets/ToolPartDiffPreview-CUNe28U1.js +0 -8
  310. package/dist/assets/index-C57jT0Sa.css +0 -1
  311. package/dist/assets/index-DW_E3rnL.js +0 -7
  312. package/dist/assets/main-Bv5Pkngh.js +0 -928
  313. package/dist/assets/pl-Dioz29BI.js +0 -15
  314. package/dist/assets/renderMobileApp-D9yQJy0L.js +0 -25
  315. package/dist/assets/runtimeEndpointReset-CjhvxLH0.js +0 -16
  316. package/dist/assets/tr-DFnMlPxY.js +0 -6
  317. package/dist/assets/useInlineCommentController-CDEuSlPH.js +0 -2
  318. package/dist/assets/vendor-zod-BLfBSgBh.js +0 -39
  319. package/server/index.d.ts.bak +0 -39
  320. package/server/lib/agent-tool/DOCUMENTATION.md.bak +0 -119
  321. package/server/lib/browser-control/DOCUMENTATION.md.bak +0 -50
  322. package/server/lib/context-obligatory/DOCUMENTATION.md.bak +0 -19
  323. package/server/lib/dev-tunnel/DOCUMENTATION.md.bak +0 -57
  324. package/server/lib/dictation/DOCUMENTATION.md.bak +0 -100
  325. package/server/lib/event-stream/DOCUMENTATION.md.bak +0 -62
  326. package/server/lib/fs/DOCUMENTATION.md.bak +0 -47
  327. package/server/lib/git/DOCUMENTATION.md.bak +0 -193
  328. package/server/lib/github/DOCUMENTATION.md.bak +0 -183
  329. package/server/lib/linear/DOCUMENTATION.md.bak +0 -97
  330. package/server/lib/linear/OAUTH-BROKER-HANDOFF.md.bak +0 -91
  331. package/server/lib/markdown-image-grants/DOCUMENTATION.md.bak +0 -40
  332. package/server/lib/notifications/APNS.md.bak +0 -135
  333. package/server/lib/notifications/DOCUMENTATION.md.bak +0 -138
  334. package/server/lib/openchamber-control/DOCUMENTATION.md.bak +0 -64
  335. package/server/lib/opencode/DOCUMENTATION.md.bak +0 -431
  336. package/server/lib/opencode/managed-process-registry.d.ts.bak +0 -13
  337. package/server/lib/opencode/provider-env-aliases.d.ts.bak +0 -3
  338. package/server/lib/permission-auto-accept/DOCUMENTATION.md.bak +0 -34
  339. package/server/lib/project-context/DOCUMENTATION.md.bak +0 -160
  340. package/server/lib/quota/DOCUMENTATION.md.bak +0 -123
  341. package/server/lib/relay/DOCUMENTATION.md.bak +0 -100
  342. package/server/lib/scheduled-tasks/DOCUMENTATION.md.bak +0 -182
  343. package/server/lib/session-assist/DOCUMENTATION.md.bak +0 -66
  344. package/server/lib/session-goal/DOCUMENTATION.md.bak +0 -213
  345. package/server/lib/session-knowledge/DOCUMENTATION.md.bak +0 -89
  346. package/server/lib/skills-catalog/DOCUMENTATION.md.bak +0 -151
  347. package/server/lib/small-model/DOCUMENTATION.md.bak +0 -212
  348. package/server/lib/system-prompt/DOCUMENTATION.md.bak +0 -36
  349. package/server/lib/terminal/DOCUMENTATION.md.bak +0 -50
  350. package/server/lib/text/DOCUMENTATION.md.bak +0 -35
  351. package/server/lib/tts/DOCUMENTATION.md.bak +0 -147
  352. package/server/lib/tunnels/DOCUMENTATION.md.bak +0 -21
  353. package/server/lib/ui-auth/DOCUMENTATION.md.bak +0 -44
  354. 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,6 +211,7 @@ 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/`.
214
+ - Queued follow-up messages live in `<data-dir>/message-queue.json`, not in settings; execution ownership lives in `lib/message-queue/`.
211
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 `settings.json`.
212
216
 
213
217
  ## Public exports (settings-helpers.js)
@@ -417,7 +421,7 @@ an authoritative loopback callback URL even when AiWorker binds port `0`.
417
421
 
418
422
  ## Storage and configuration
419
423
  - Provider auth: `~/.local/share/opencode/auth.json`.
420
- - User config: `~/.config/opencode/opencode.json`.
424
+ - User config: `$XDG_CONFIG_HOME/opencode/opencode.json`, falling back to `~/.config/opencode/opencode.json` when unset or blank.
421
425
  - Project config: `<workingDirectory>/.opencode/opencode.json` or `opencode.json`.
422
426
  - Custom config: `OPENCODE_CONFIG` env var path.
423
427
  - Rate limit config: `AIWORKER_RATE_LIMIT_MAX_ATTEMPTS`, `AIWORKER_RATE_LIMIT_NO_IP_MAX_ATTEMPTS` env vars.
@@ -429,3 +433,7 @@ an authoritative loopback callback URL even when AiWorker binds port `0`.
429
433
  - Config merging follows priority: custom > project > user.
430
434
  - UI auth uses scrypt for password hashing with constant-time comparison.
431
435
  - Tunnel auth treats `host.docker.internal` as local-only when the socket remote IP is private/loopback.
436
+
437
+ The behavior `GET /api/behavior/agents-md` response includes `path`, the effective
438
+ server-side filename, whether or not the file exists. Settings displays this
439
+ 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,7 +56,7 @@ 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,
@@ -77,7 +77,7 @@ export const createBootstrapRuntime = (dependencies) => {
77
77
  registerServerStatusRoutes(app, {
78
78
  express,
79
79
  process,
80
- openchamberVersion,
80
+ aiworkerVersion,
81
81
  runtimeName,
82
82
  serverStartedAt,
83
83
  gracefulShutdown,
@@ -140,14 +140,14 @@ export const createBootstrapRuntime = (dependencies) => {
140
140
  setAutoAcceptSession,
141
141
  });
142
142
 
143
- registerOpenChamberRoutes(app, {
143
+ registerAiWorkerRoutes(app, {
144
144
  fs,
145
145
  os,
146
146
  path,
147
147
  process,
148
148
  server,
149
149
  __dirname,
150
- openchamberDataDir,
150
+ aiworkerDataDir,
151
151
  modelsDevApiUrl,
152
152
  modelsMetadataCacheTtl,
153
153
  readSettingsFromDiskMigrated,
@@ -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,
@@ -28,8 +28,8 @@ export const resolveOpenCodeEnvConfig = (options = {}) => {
28
28
  const configuredOpenCodePort = (() => {
29
29
  const raw =
30
30
  env.OPENCODE_PORT ||
31
- env.OPENCHAMBER_OPENCODE_PORT ||
32
- env.OPENCHAMBER_INTERNAL_PORT;
31
+ env.AIWORKER_OPENCODE_PORT ||
32
+ env.AIWORKER_INTERNAL_PORT;
33
33
  if (!raw) {
34
34
  return null;
35
35
  }
@@ -72,20 +72,20 @@ export const resolveOpenCodeEnvConfig = (options = {}) => {
72
72
  const effectivePort = configuredOpenCodeHost?.port ?? configuredOpenCodePort;
73
73
 
74
74
  const configuredOpenCodeHostname = (() => {
75
- const raw = env.OPENCHAMBER_OPENCODE_HOSTNAME;
75
+ const raw = env.AIWORKER_OPENCODE_HOSTNAME;
76
76
  if (typeof raw !== 'string') {
77
77
  return '127.0.0.1';
78
78
  }
79
79
  const trimmed = raw.trim();
80
80
  if (!trimmed) {
81
81
  logger.warn(
82
- `[config] Ignoring OPENCHAMBER_OPENCODE_HOSTNAME=${JSON.stringify(raw)}: empty after trimming`,
82
+ `[config] Ignoring AIWORKER_OPENCODE_HOSTNAME=${JSON.stringify(raw)}: empty after trimming`,
83
83
  );
84
84
  return '127.0.0.1';
85
85
  }
86
86
  if (!isValidOpenCodeHostname(trimmed)) {
87
87
  logger.error(
88
- `[config] Rejecting OPENCHAMBER_OPENCODE_HOSTNAME=${JSON.stringify(raw)}: `
88
+ `[config] Rejecting AIWORKER_OPENCODE_HOSTNAME=${JSON.stringify(raw)}: `
89
89
  + 'must be a valid hostname or IP address (for example 127.0.0.1, 0.0.0.0, localhost, [::1]); '
90
90
  + 'falling back to 127.0.0.1 (loopback only)',
91
91
  );