@aiworker/web 1.22.0 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (415) hide show
  1. package/README.md +4 -4
  2. package/bin/cli.js +14 -4
  3. package/bin/cli.test.js +165 -73
  4. package/bin/lib/cli-api-target.js +2 -2
  5. package/bin/lib/cli-args.js +119 -119
  6. package/bin/lib/cli-lifecycle.js +9 -9
  7. package/bin/lib/cli-network.js +3 -3
  8. package/bin/lib/cli-paths.js +3 -3
  9. package/bin/lib/cli-ports.js +2 -2
  10. package/bin/lib/cli-process.js +4 -4
  11. package/bin/lib/cli-startup.js +64 -15
  12. package/bin/lib/cli-tunnel-profiles.js +1 -1
  13. package/bin/lib/cli-tunnel-utils.js +2 -2
  14. package/bin/lib/commands-connect-url.js +19 -19
  15. package/bin/lib/commands-lifecycle.js +27 -27
  16. package/bin/lib/commands-logs.js +5 -5
  17. package/bin/lib/commands-models.js +1 -1
  18. package/bin/lib/commands-projects.js +1 -1
  19. package/bin/lib/commands-schedule.js +1 -1
  20. package/bin/lib/commands-serve.js +29 -29
  21. package/bin/lib/commands-session.js +1 -1
  22. package/bin/lib/commands-startup.js +45 -10
  23. package/bin/lib/commands-status.js +1 -1
  24. package/bin/lib/commands-tunnel.js +40 -40
  25. package/bin/lib/commands-update.js +1 -1
  26. package/bin/lib/commands-update.test.js +6 -6
  27. package/dist/assets/{CodeMirrorCommentWidgets-B3u7UIcE.js → CodeMirrorCommentWidgets-B1Gizi3a.js} +1 -1
  28. package/dist/assets/DiffView-DXjVsEOw.js +4 -0
  29. package/dist/assets/DirtyBranchSwitchDialog-aig6zJjg.js +1 -0
  30. package/dist/assets/FilesView-CJdG0-wk.js +17 -0
  31. package/dist/assets/GitView-BXsS3jG6.js +6 -0
  32. package/dist/assets/{JsonTreeView-B0BdZEHG.js → JsonTreeView-D_hpXBnF.js} +1 -1
  33. package/dist/assets/LinearIssuesView-BoUiLQG1.js +1 -0
  34. package/dist/assets/MarkdownImageGallery-B_B_a9KS.js +1 -0
  35. package/dist/assets/MarkdownRendererImpl-xgyyLiBM.js +12 -0
  36. package/dist/assets/OnboardingScreen-DIp84OWt.js +1 -0
  37. package/dist/assets/{PatchDiff-DvfqDql7.js → PatchDiff-8p6nLJaU.js} +1 -1
  38. package/dist/assets/PierreDiffViewer-DjC8nTk9.js +161 -0
  39. package/dist/assets/PlanView-CJTmOF6I.js +5 -0
  40. package/dist/assets/SettingsView-DD-JqIJx.js +28 -0
  41. package/dist/assets/{SettingsWindow-i45U1Cy1.js → SettingsWindow-Cpb4hM6q.js} +1 -1
  42. package/dist/assets/SymbolsNerdFontMono-Regular-aK5vsLov.woff2 +0 -0
  43. package/dist/assets/{ToolOutputDialog-BTwyh5OF.js → ToolOutputDialog-DfaKZXNU.js} +6 -6
  44. package/dist/assets/ToolPartDiffPreview-DtZLzrSK.js +8 -0
  45. package/dist/assets/{VirtualizedFileDiff-DD8lDVej.js → VirtualizedFileDiff-C8i9HpTB.js} +1 -1
  46. package/dist/assets/WalkthroughView-DeKMvZlL.js +4 -0
  47. package/dist/assets/{computeVirtualFileMetrics-BMIRgMHv.js → computeVirtualFileMetrics-BBI7ZwrC.js} +2 -2
  48. package/dist/assets/contextPanelEmbeddedChat-BdA6bdky.js +1 -0
  49. package/dist/assets/de-DCrsQ5zS.js +10 -0
  50. package/dist/assets/es-Dwv4YfH6.js +16 -0
  51. package/dist/assets/fr-BCWg4Cnx.js +14 -0
  52. package/dist/assets/ghostty-vt-DdA0Zryv.wasm +0 -0
  53. package/dist/assets/index-B68h5S5B.css +1 -0
  54. package/dist/assets/index-DVwMarHI.js +39 -0
  55. package/dist/assets/{index-CODwDsU_.js → index-jXSK5RrB.js} +1 -1
  56. package/dist/assets/{isDiffPlainText-BqayB8d3.js → isDiffPlainText-B_x_rVon.js} +1 -1
  57. package/dist/assets/{isFilePlainText-QfoiKJNY.js → isFilePlainText-DW_xMer1.js} +1 -1
  58. package/dist/assets/ja-Bruw3RYC.js +16 -0
  59. package/dist/assets/ko-idhXGF8j.js +16 -0
  60. package/dist/assets/main-BkyaQhJX.js +930 -0
  61. package/dist/assets/{main-C5DVOxc6.js → main-CzdPuL0s.js} +2 -2
  62. package/dist/assets/markdownCore-Cn4Tyejo.js +5 -0
  63. package/dist/assets/{miniChat-DUJ4irZc.js → miniChat-CCkqKOLp.js} +2 -2
  64. package/dist/assets/{mobile-CcaxB0n4.js → mobile-mvxTo055.js} +2 -2
  65. package/dist/assets/patchFileDiff-Csk4iNUi.js +13 -0
  66. package/dist/assets/pl-CGZWUqZJ.js +16 -0
  67. package/dist/assets/pt-BR-B8V7u7tA.js +16 -0
  68. package/dist/assets/renderElectronMiniChatApp-BxoyujA5.js +2 -0
  69. package/dist/assets/renderMobileApp-B48CsP4r.js +25 -0
  70. package/dist/assets/runtimeEndpointReset-Bg5gx18H.js +17 -0
  71. package/dist/assets/scheduledTasksApi-BW0Etzwz.js +1 -0
  72. package/dist/assets/{shikiHighlight-DYOWuY65.js → shikiHighlight-CRl0SUC9.js} +1 -1
  73. package/dist/assets/surface-oMvhsog3.js +1 -0
  74. package/dist/assets/tr-BK_KiO2V.js +7 -0
  75. package/dist/assets/uk-CG74xV8N.js +16 -0
  76. package/dist/assets/useAppFontEffects-CPKeOpUo.js +7284 -0
  77. package/dist/assets/useGitComparison-DH220WmO.js +1 -0
  78. package/dist/assets/useInlineCommentController-BiWz4AVb.js +2 -0
  79. package/dist/assets/useRootScrollLock-BS4-kr7P.js +1 -0
  80. package/dist/assets/{vendor-base-ui-BeMD8X_w.js → vendor-base-ui-DdV8vhHn.js} +1 -1
  81. package/dist/assets/{vendor-codemirror-language-data-DFZik9R2.js → vendor-codemirror-language-data-Bg4AEeCr.js} +2 -2
  82. package/dist/assets/vendor-zod-BPAANqvH.js +39 -0
  83. package/dist/assets/{web-components-Bhg83tjf.js → web-components-z7hfnS8n.js} +1 -1
  84. package/dist/assets/zh-CN-T4AXofZI.js +16 -0
  85. package/dist/assets/zh-TW-Dte40sxp.js +16 -0
  86. package/dist/index.html +21 -59
  87. package/dist/mini-chat.html +7 -7
  88. package/dist/mobile.html +5 -5
  89. package/package.json +3 -4
  90. package/server/index.d.ts +15 -0
  91. package/server/index.js +158 -89
  92. package/server/lib/agent-memory/actions.js +2 -2
  93. package/server/lib/agent-memory/feature-flag.js +1 -1
  94. package/server/lib/agent-memory/feature-flag.test.js +8 -8
  95. package/server/lib/agent-memory/routes.js +2 -2
  96. package/server/lib/agent-tool/runtime.js +37 -54
  97. package/server/lib/agent-tool/runtime.test.js +59 -59
  98. package/server/lib/browser-control/broker.js +3 -3
  99. package/server/lib/browser-control/broker.test.js +1 -1
  100. package/server/lib/changelog/update-notes.js +82 -0
  101. package/server/lib/changelog/update-notes.test.js +59 -0
  102. package/server/lib/client-auth/remote-clients.test.js +5 -5
  103. package/server/lib/context-obligatory/runtime.js +7 -7
  104. package/server/lib/context-obligatory/runtime.test.js +5 -5
  105. package/server/lib/data-dir-migration.js +40 -0
  106. package/server/lib/data-dir-migration.test.js +59 -0
  107. package/server/lib/dev-servers/parse.js +2 -2
  108. package/server/lib/dev-servers/parse.test.js +2 -2
  109. package/server/lib/dev-servers/routes.js +1 -1
  110. package/server/lib/dev-tunnel/DOCUMENTATION.md +13 -4
  111. package/server/lib/dev-tunnel/client.js +1 -1
  112. package/server/lib/dev-tunnel/runtime.js +5 -5
  113. package/server/lib/dev-tunnel/tunnel.test.js +21 -1
  114. package/server/lib/dictation/local/model-catalog.js +1 -1
  115. package/server/lib/dictation/local/worker-process.js +2 -2
  116. package/server/lib/event-stream/directory-ws-bridge.js +1 -1
  117. package/server/lib/event-stream/global-ws-bridge.js +1 -1
  118. package/server/lib/event-stream/protocol.test.js +4 -4
  119. package/server/lib/event-stream/runtime.test.js +18 -18
  120. package/server/lib/fs/DOCUMENTATION.md +5 -0
  121. package/server/lib/fs/routes.js +68 -26
  122. package/server/lib/fs/routes.test.js +208 -22
  123. package/server/lib/git/DOCUMENTATION.md +32 -6
  124. package/server/lib/git/identity-storage.js +1 -1
  125. package/server/lib/git/issue-2746-longpaths.test.js +4 -4
  126. package/server/lib/git/routes.js +41 -5
  127. package/server/lib/git/service.js +300 -224
  128. package/server/lib/git/service.test.js +596 -28
  129. package/server/lib/github/auth.js +8 -8
  130. package/server/lib/github/pr-status.js +1 -1
  131. package/server/lib/github/routes.js +2 -2
  132. package/server/lib/inherited-env.js +17 -10
  133. package/server/lib/inherited-env.test.js +10 -11
  134. package/server/lib/linear/auth.js +8 -8
  135. package/server/lib/linear/auth.test.js +24 -24
  136. package/server/lib/linear/issues.test.js +6 -6
  137. package/server/lib/linear/mapping.test.js +4 -4
  138. package/server/lib/linear/oauth.js +2 -2
  139. package/server/lib/linear/oauth.test.js +14 -14
  140. package/server/lib/linear/routes.js +5 -5
  141. package/server/lib/linear/routes.test.js +16 -16
  142. package/server/lib/linear/status-runtime.test.js +9 -9
  143. package/server/lib/linear/status.js +1 -1
  144. package/server/lib/linear/status.test.js +15 -15
  145. package/server/lib/linear/teams.test.js +4 -4
  146. package/server/lib/magic-prompts/routes.js +2 -2
  147. package/server/lib/mcp-reconnect/DOCUMENTATION.md +55 -0
  148. package/server/lib/mcp-reconnect/runtime.js +122 -0
  149. package/server/lib/mcp-reconnect/runtime.test.js +140 -0
  150. package/server/lib/message-queue/DOCUMENTATION.md +161 -0
  151. package/server/lib/message-queue/runtime.js +870 -0
  152. package/server/lib/message-queue/runtime.test.js +482 -0
  153. package/server/lib/network-defaults.js +23 -0
  154. package/server/lib/network-defaults.test.js +52 -0
  155. package/server/lib/notifications/apns-runtime.js +17 -17
  156. package/server/lib/notifications/apns-runtime.test.js +11 -11
  157. package/server/lib/notifications/emitter-runtime.js +1 -1
  158. package/server/lib/notifications/emitter-runtime.test.js +1 -1
  159. package/server/lib/notifications/push-runtime.js +7 -7
  160. package/server/lib/notifications/routes.js +1 -1
  161. package/server/lib/notifications/runtime.js +1 -1
  162. package/server/lib/openchamber-control/action-resolution.test.js +10 -10
  163. package/server/lib/openchamber-control/actions.js +24 -24
  164. package/server/lib/openchamber-control/error.js +4 -4
  165. package/server/lib/openchamber-control/routes.js +2 -2
  166. package/server/lib/openchamber-control/routes.test.js +5 -5
  167. package/server/lib/openchamber-control/screenshots.js +1 -1
  168. package/server/lib/openchamber-control/screenshots.test.js +1 -1
  169. package/server/lib/openchamber-control/service.js +50 -50
  170. package/server/lib/openchamber-control/service.test.js +5 -5
  171. package/server/lib/openchamber-sessions/routes.js +124 -22
  172. package/server/lib/openchamber-sessions/routes.test.js +99 -11
  173. package/server/lib/opencode/DOCUMENTATION.md +30 -6
  174. package/server/lib/opencode/auth.js +1 -1
  175. package/server/lib/opencode/bootstrap-runtime.js +8 -6
  176. package/server/lib/opencode/cli-options.js +8 -8
  177. package/server/lib/opencode/config-paths.test.js +116 -0
  178. package/server/lib/opencode/core-routes.js +8 -7
  179. package/server/lib/opencode/core-routes.test.js +11 -11
  180. package/server/lib/opencode/env-config.js +5 -5
  181. package/server/lib/opencode/env-config.test.js +7 -7
  182. package/server/lib/opencode/env-runtime.js +10 -10
  183. package/server/lib/opencode/env-runtime.test.js +18 -18
  184. package/server/lib/opencode/feature-routes-runtime.js +19 -12
  185. package/server/lib/opencode/hmr-state-runtime.js +2 -2
  186. package/server/lib/opencode/hmr-state-runtime.test.js +1 -1
  187. package/server/lib/opencode/input-history-scope.js +14 -0
  188. package/server/lib/opencode/lifecycle.js +8 -8
  189. package/server/lib/opencode/lifecycle.test.js +4 -4
  190. package/server/lib/opencode/managed-plugin-config.js +35 -0
  191. package/server/lib/opencode/managed-process-registry.js +3 -3
  192. package/server/lib/opencode/mcp-oauth-callback.test.js +2 -2
  193. package/server/lib/opencode/openchamber-routes.js +79 -19
  194. package/server/lib/opencode/openchamber-routes.test.js +139 -12
  195. package/server/lib/opencode/plugins.js +2 -2
  196. package/server/lib/opencode/plugins.test.js +1 -1
  197. package/server/lib/opencode/project-icon-routes.js +2 -2
  198. package/server/lib/opencode/project-icon-routes.test.js +1 -1
  199. package/server/lib/opencode/providers.js +44 -2
  200. package/server/lib/opencode/providers.test.js +131 -4
  201. package/server/lib/opencode/proxy.js +2 -2
  202. package/server/lib/opencode/pwa-manifest-routes.js +1 -1
  203. package/server/lib/opencode/restart-session-recovery.test.js +1 -1
  204. package/server/lib/opencode/routes-upgrade.test.js +4 -4
  205. package/server/lib/opencode/routes.js +19 -17
  206. package/server/lib/opencode/server-startup-runtime.js +6 -6
  207. package/server/lib/opencode/session-runtime.js +3 -3
  208. package/server/lib/opencode/session-runtime.test.js +6 -6
  209. package/server/lib/opencode/settings-files.js +214 -0
  210. package/server/lib/opencode/settings-helpers.js +116 -44
  211. package/server/lib/opencode/settings-helpers.test.js +354 -12
  212. package/server/lib/opencode/settings-registry.json +747 -0
  213. package/server/lib/opencode/settings-runtime.js +141 -20
  214. package/server/lib/opencode/settings-runtime.test.js +191 -4
  215. package/server/lib/opencode/shared.js +5 -2
  216. package/server/lib/opencode/shared.test.js +7 -7
  217. package/server/lib/opencode/shutdown-runtime.js +2 -0
  218. package/server/lib/opencode/skill-routes.js +2 -1
  219. package/server/lib/opencode/snippets.js +1 -2
  220. package/server/lib/opencode/startup-performance.js +1 -1
  221. package/server/lib/opencode/startup-performance.test.js +6 -6
  222. package/server/lib/opencode/static-routes-runtime.js +8 -8
  223. package/server/lib/opencode/static-routes-runtime.test.js +7 -7
  224. package/server/lib/opencode/upgrade-capability.js +2 -2
  225. package/server/lib/opencode/upgrade-capability.test.js +3 -3
  226. package/server/lib/package-manager.js +17 -42
  227. package/server/lib/package-manager.test.js +19 -19
  228. package/server/lib/permission-auto-accept/runtime.js +1 -1
  229. package/server/lib/project-context/DOCUMENTATION.md +25 -1
  230. package/server/lib/project-context/routes.http.test.js +18 -0
  231. package/server/lib/project-context/routes.js +16 -1
  232. package/server/lib/project-context/runtime.js +248 -23
  233. package/server/lib/project-context/runtime.test.js +106 -3
  234. package/server/lib/projects/DOCUMENTATION.md +76 -0
  235. package/server/lib/projects/project-config.js +144 -11
  236. package/server/lib/projects/project-id.js +17 -0
  237. package/server/lib/projects/project-setup.js +409 -0
  238. package/server/lib/projects/project-setup.test.js +557 -0
  239. package/server/lib/projects/routes.js +59 -0
  240. package/server/lib/quota/DOCUMENTATION.md +40 -2
  241. package/server/lib/quota/credentials/providers.js +4 -0
  242. package/server/lib/quota/credentials/store.js +4 -4
  243. package/server/lib/quota/credentials/store.test.js +8 -8
  244. package/server/lib/quota/index.js +1 -0
  245. package/server/lib/quota/providers/cline-pass.js +125 -0
  246. package/server/lib/quota/providers/cline-pass.test.js +103 -0
  247. package/server/lib/quota/providers/exe-dev.js +75 -0
  248. package/server/lib/quota/providers/exe-dev.test.js +47 -0
  249. package/server/lib/quota/providers/hyper.js +118 -0
  250. package/server/lib/quota/providers/hyper.test.js +126 -0
  251. package/server/lib/quota/providers/index.js +22 -0
  252. package/server/lib/quota/providers/neuralwatt.js +3 -6
  253. package/server/lib/quota/providers/neuralwatt.test.js +7 -7
  254. package/server/lib/quota/providers/ollama-cloud.js +32 -1
  255. package/server/lib/quota/providers/ollama-cloud.test.js +33 -1
  256. package/server/lib/quota/providers/opencode-go.js +3 -2
  257. package/server/lib/quota/providers/opencode-go.test.js +35 -6
  258. package/server/lib/quota/providers/openrouter.js +119 -24
  259. package/server/lib/quota/providers/openrouter.test.js +330 -0
  260. package/server/lib/quota/providers/xai.js +1 -1
  261. package/server/lib/quota/routes.js +2 -0
  262. package/server/lib/quota/utils/auth.js +1 -1
  263. package/server/lib/relay/DOCUMENTATION.md +56 -1
  264. package/server/lib/relay/cross-compat.test.js +26 -0
  265. package/server/lib/relay/downstream-scheduler.js +154 -0
  266. package/server/lib/relay/downstream-scheduler.test.js +162 -0
  267. package/server/lib/relay/e2ee.js +10 -8
  268. package/server/lib/relay/flow-control.test.js +177 -0
  269. package/server/lib/relay/host-client.js +38 -9
  270. package/server/lib/relay/host-client.test.js +9 -1
  271. package/server/lib/relay/host-lock.js +1 -1
  272. package/server/lib/relay/service.js +5 -5
  273. package/server/lib/relay/tunnel-codec.js +9 -0
  274. package/server/lib/relay/tunnel-host.js +69 -18
  275. package/server/lib/relay/tunnel-host.test.js +9 -1
  276. package/server/lib/scheduled-tasks/issue-2710-double-execution.test.js +2 -2
  277. package/server/lib/scheduled-tasks/routes.js +5 -5
  278. package/server/lib/scheduled-tasks/service.js +25 -25
  279. package/server/lib/scheduled-tasks/service.test.js +1 -1
  280. package/server/lib/security/bind-host.js +4 -4
  281. package/server/lib/security/bind-host.test.js +1 -1
  282. package/server/lib/security/request-security.js +11 -5
  283. package/server/lib/security/request-security.test.js +14 -14
  284. package/server/lib/session-assist/runtime.js +15 -18
  285. package/server/lib/session-folders/routes.js +2 -2
  286. package/server/lib/session-folders/routes.test.js +8 -8
  287. package/server/lib/session-goal/DOCUMENTATION.md +20 -7
  288. package/server/lib/session-goal/create.js +4 -2
  289. package/server/lib/session-goal/create.test.js +1 -1
  290. package/server/lib/session-goal/objectives.js +4 -4
  291. package/server/lib/session-goal/routes.js +1 -1
  292. package/server/lib/session-goal/runtime.js +91 -30
  293. package/server/lib/session-goal/runtime.test.js +428 -2
  294. package/server/lib/session-knowledge/runtime.js +11 -11
  295. package/server/lib/session-knowledge/runtime.test.js +5 -5
  296. package/server/lib/skills-catalog/DOCUMENTATION.md +1 -1
  297. package/server/lib/skills-catalog/cache.test.js +2 -2
  298. package/server/lib/skills-catalog/disk-cache.js +5 -5
  299. package/server/lib/skills-catalog/github-meta.test.js +2 -2
  300. package/server/lib/skills-catalog/install.js +3 -2
  301. package/server/lib/small-model/DOCUMENTATION.md +7 -2
  302. package/server/lib/small-model/call.js +18 -7
  303. package/server/lib/small-model/call.test.js +58 -6
  304. package/server/lib/small-model/index.js +12 -16
  305. package/server/lib/small-model/index.test.js +1 -1
  306. package/server/lib/small-model/resolve.js +1 -1
  307. package/server/lib/small-model/resolve.test.js +1 -1
  308. package/server/lib/small-model/routes.js +2 -1
  309. package/server/lib/small-model/runtime-providers.js +15 -7
  310. package/server/lib/small-model/runtime-providers.test.js +7 -1
  311. package/server/lib/system-prompt/runtime.js +3 -22
  312. package/server/lib/system-prompt/runtime.test.js +3 -3
  313. package/server/lib/terminal/DOCUMENTATION.md +14 -10
  314. package/server/lib/terminal/runtime.js +190 -31
  315. package/server/lib/terminal/runtime.test.js +572 -38
  316. package/server/lib/terminal/shells.js +20 -3
  317. package/server/lib/terminal/shells.test.js +33 -2
  318. package/server/lib/tts/base-url.js +3 -3
  319. package/server/lib/tts/routes.test.js +20 -20
  320. package/server/lib/ui-auth/ui-auth.js +12 -9
  321. package/server/lib/ui-auth/ui-auth.test.js +19 -3
  322. package/server/lib/ui-auth/ui-passkeys.js +7 -7
  323. package/server/lib/walkthrough/DOCUMENTATION.md +33 -14
  324. package/server/lib/walkthrough/index.js +1 -0
  325. package/server/lib/walkthrough/jobs.test.js +1 -1
  326. package/server/lib/walkthrough/language.test.js +1 -1
  327. package/server/lib/walkthrough/model-settings.js +11 -15
  328. package/server/lib/walkthrough/model-settings.test.js +1 -1
  329. package/server/lib/walkthrough/prompt.js +3 -1
  330. package/server/lib/walkthrough/pull-request.test.js +5 -5
  331. package/server/lib/walkthrough/reproduce-2607.test.js +2 -2
  332. package/server/lib/walkthrough/routes.test.js +26 -5
  333. package/server/lib/walkthrough/sources.js +23 -2
  334. package/server/lib/walkthrough/store.js +3 -3
  335. package/server/lib/walkthrough/store.test.js +1 -1
  336. package/server/opencode-proxy.test.js +2 -2
  337. package/server/proxy-headers.js +1 -1
  338. package/server/sse-routes.test.js +4 -4
  339. package/README.md.bak +0 -250
  340. package/bin/lib/DOCUMENTATION.md.bak +0 -163
  341. package/dist/assets/CommitSection-SGBCAW0w.js +0 -1
  342. package/dist/assets/DiffView-DluiRSla.js +0 -4
  343. package/dist/assets/FilesView-Bdq8ppva.js +0 -17
  344. package/dist/assets/GitView-Znn7VJcP.js +0 -6
  345. package/dist/assets/LinearIssuesView-jP-hXyac.js +0 -1
  346. package/dist/assets/MarkdownImageGallery-ClOvuZxC.js +0 -1
  347. package/dist/assets/MarkdownRendererImpl-Dt9mjTRN.js +0 -12
  348. package/dist/assets/OnboardingScreen-D2DG7K6b.js +0 -1
  349. package/dist/assets/PierreDiffViewer-B7m3f0d7.js +0 -157
  350. package/dist/assets/PlanView-B0F3BtPZ.js +0 -5
  351. package/dist/assets/SettingsView-BBW-S-gh.js +0 -28
  352. package/dist/assets/ToolPartDiffPreview-CUNe28U1.js +0 -8
  353. package/dist/assets/WalkthroughView-egQgxel3.js +0 -4
  354. package/dist/assets/contextPanelEmbeddedChat-C3fjDbdg.js +0 -1
  355. package/dist/assets/de-C1P6X5Rs.js +0 -9
  356. package/dist/assets/es-CDgaF1_t.js +0 -15
  357. package/dist/assets/fr-Bgxqvvz_.js +0 -13
  358. package/dist/assets/index-C57jT0Sa.css +0 -1
  359. package/dist/assets/index-DW_E3rnL.js +0 -7
  360. package/dist/assets/ja-BDRrEcNP.js +0 -15
  361. package/dist/assets/ko-Ba8sQV79.js +0 -15
  362. package/dist/assets/main-Bv5Pkngh.js +0 -928
  363. package/dist/assets/markdownCore-CZwzz5gw.js +0 -3
  364. package/dist/assets/patchFileDiff-yNfWXN4E.js +0 -10
  365. package/dist/assets/pl-Dioz29BI.js +0 -15
  366. package/dist/assets/pt-BR-DIs6ElwV.js +0 -15
  367. package/dist/assets/renderElectronMiniChatApp-BcKLHXKe.js +0 -2
  368. package/dist/assets/renderMobileApp-D9yQJy0L.js +0 -25
  369. package/dist/assets/runtimeEndpointReset-CjhvxLH0.js +0 -16
  370. package/dist/assets/scheduledTasksApi-DLW0mkQK.js +0 -1
  371. package/dist/assets/tr-DFnMlPxY.js +0 -6
  372. package/dist/assets/uk-ZrCNjM7Y.js +0 -15
  373. package/dist/assets/useAppFontEffects-CjrntdL0.js +0 -7310
  374. package/dist/assets/useInlineCommentController-CDEuSlPH.js +0 -2
  375. package/dist/assets/useRootScrollLock-BHYPkrLv.js +0 -1
  376. package/dist/assets/vendor-ghostty-web-CrxinGGH.js +0 -13
  377. package/dist/assets/vendor-zod-BLfBSgBh.js +0 -39
  378. package/dist/assets/zh-CN-iv_AV4EC.js +0 -15
  379. package/dist/assets/zh-TW-CzEUk38j.js +0 -15
  380. package/server/index.d.ts.bak +0 -39
  381. package/server/lib/agent-tool/DOCUMENTATION.md.bak +0 -119
  382. package/server/lib/browser-control/DOCUMENTATION.md.bak +0 -50
  383. package/server/lib/context-obligatory/DOCUMENTATION.md.bak +0 -19
  384. package/server/lib/dev-tunnel/DOCUMENTATION.md.bak +0 -57
  385. package/server/lib/dictation/DOCUMENTATION.md.bak +0 -100
  386. package/server/lib/event-stream/DOCUMENTATION.md.bak +0 -62
  387. package/server/lib/fs/DOCUMENTATION.md.bak +0 -47
  388. package/server/lib/git/DOCUMENTATION.md.bak +0 -193
  389. package/server/lib/github/DOCUMENTATION.md.bak +0 -183
  390. package/server/lib/linear/DOCUMENTATION.md.bak +0 -97
  391. package/server/lib/linear/OAUTH-BROKER-HANDOFF.md.bak +0 -91
  392. package/server/lib/markdown-image-grants/DOCUMENTATION.md.bak +0 -40
  393. package/server/lib/notifications/APNS.md.bak +0 -135
  394. package/server/lib/notifications/DOCUMENTATION.md.bak +0 -138
  395. package/server/lib/openchamber-control/DOCUMENTATION.md.bak +0 -64
  396. package/server/lib/opencode/DOCUMENTATION.md.bak +0 -431
  397. package/server/lib/opencode/managed-process-registry.d.ts.bak +0 -13
  398. package/server/lib/opencode/provider-env-aliases.d.ts.bak +0 -3
  399. package/server/lib/permission-auto-accept/DOCUMENTATION.md.bak +0 -34
  400. package/server/lib/project-context/DOCUMENTATION.md.bak +0 -160
  401. package/server/lib/quota/DOCUMENTATION.md.bak +0 -123
  402. package/server/lib/relay/DOCUMENTATION.md.bak +0 -100
  403. package/server/lib/scheduled-tasks/DOCUMENTATION.md.bak +0 -182
  404. package/server/lib/session-assist/DOCUMENTATION.md.bak +0 -66
  405. package/server/lib/session-goal/DOCUMENTATION.md.bak +0 -213
  406. package/server/lib/session-knowledge/DOCUMENTATION.md.bak +0 -89
  407. package/server/lib/skills-catalog/DOCUMENTATION.md.bak +0 -151
  408. package/server/lib/small-model/DOCUMENTATION.md.bak +0 -212
  409. package/server/lib/system-prompt/DOCUMENTATION.md.bak +0 -36
  410. package/server/lib/terminal/DOCUMENTATION.md.bak +0 -50
  411. package/server/lib/text/DOCUMENTATION.md.bak +0 -35
  412. package/server/lib/tts/DOCUMENTATION.md.bak +0 -147
  413. package/server/lib/tunnels/DOCUMENTATION.md.bak +0 -21
  414. package/server/lib/ui-auth/DOCUMENTATION.md.bak +0 -44
  415. package/server/lib/walkthrough/DOCUMENTATION.md.bak +0 -411
@@ -1,160 +0,0 @@
1
- # Project Context
2
-
3
- Server-owned storage for the Project Notes surface: free-form notes, todos, and
4
- plan markdown files.
5
-
6
- The managed Chats root (`~/.config/openchamber/chats`) is also one context owner. Every dated per-session directory beneath it resolves to that root, so Notes, Todo, Plans, pinned knowledge, and project memory are shared across ordinary chats without registering Chats as a user project.
7
-
8
- ## Ownership
9
-
10
- | Path | Owner | Contents |
11
- |---|---|---|
12
- | `<projectsDir>/<projectId>.json` | shared UI (`packages/ui/src/lib/openchamberConfig.ts`), plus server-owned `version` / `scheduledTasks` | worktree setup, draft starters, project actions |
13
- | `<projectsDir>/<projectId>/context.json` | **this module, exclusively** | notes, todos, plan manifest |
14
- | `<projectsDir>/<projectId>/plans/*.md` | **this module, exclusively** | plan bodies |
15
-
16
- The split is the point. Both files were previously one, written by the client
17
- with a whole-file read-modify-write. Adding a server writer to that file would
18
- have made unrelated features (project actions, draft starters) clobber notes
19
- across processes, with no lock able to span both sides. Separate files remove
20
- the shared resource instead of trying to coordinate access to it.
21
-
22
- Nothing outside this module may write `context.json` or the `plans` directory.
23
-
24
- ## Storage format
25
-
26
- ```json
27
- {
28
- "version": 2,
29
- "notes": [{
30
- "id": "", "body": "", "createdAt": 0, "updatedAt": 0,
31
- "source": "manual | selection | agent",
32
- "origin": { "sessionId": "", "messageId": "" }
33
- }],
34
- "todos": [{ "id": "", "text": "", "completed": false, "createdAt": 0 }],
35
- "plans": [{ "id": "", "file": "1700000000-title.md", "title": "", "createdAt": 0 }]
36
- }
37
- ```
38
-
39
- Notes are entries, not one blob. Version 1 stored a single string; it converts
40
- to a single `manual` note on read (an empty string converts to no notes at
41
- all). The conversion lives in the read path rather than a separate migration
42
- pass so that every reader — including one racing a writer — sees one shape.
43
- Legacy `pinned` fields may remain in existing files but are ignored; attachment
44
- ownership lives in each session's metadata.
45
-
46
- `source` records where a note came from, and `origin` links it back to the
47
- message it was distilled from, so a note taken off a chat selection can be
48
- traced to its conversation.
49
-
50
- Notes and todos are written through separate routes. That split is what stops a
51
- todo toggle from persisting half-typed notes alongside it, and stops an
52
- agent-authored note from clobbering a concurrent todo change.
53
-
54
- Plan links store a **base name**, never a path. The file always lives in
55
- `<projectId>/plans/`, so moving the project storage directory cannot invalidate
56
- a reference and a caller can never address a file outside it. `title` is
57
- denormalized into the manifest so listing plans costs one read rather than one
58
- read per plan; `readPlan` returns the title parsed from the file, which wins if
59
- the two ever disagree.
60
-
61
- ## Routes
62
-
63
- | Method | Route | Notes |
64
- |---|---|---|
65
- | GET | `/api/project-context/:projectId` | full context; missing file is `200` empty |
66
- | PUT | `/api/project-context/:projectId/todos` | replaces the whole list; returns committed context |
67
- | POST | `/api/project-context/:projectId/notes` | `201`; takes `{body, source?, origin?}` |
68
- | PATCH | `/api/project-context/:projectId/notes/:noteId` | patches `body`; legacy `pinned` input is ignored by session knowledge; `404` when unknown |
69
- | DELETE | `/api/project-context/:projectId/notes/:noteId` | `404` when unknown |
70
- | PATCH | `/api/project-context/:projectId/plans/:planId` | legacy project pin state only; session attachment uses session knowledge; `404` when unknown |
71
- | GET | `/api/project-context/:projectId/plans/:planId` | `404` when the link or its markdown is gone |
72
- | POST | `/api/project-context/:projectId/plans` | `201`; takes `{title, body}`, never a path |
73
- | PUT | `/api/project-context/:projectId/plans/:planId` | takes the whole `{raw}` document; `404` when the link or its markdown is gone |
74
- | DELETE | `/api/project-context/:projectId/plans/:planId` | `404` when unknown |
75
-
76
- **Body parsing is attached per route.** This server has no global JSON parser:
77
- `core-routes` parses only an allowlist of `/api` path prefixes so the generic
78
- OpenCode proxy keeps an unread request stream, and every other `/api` request
79
- passes through untouched. A write route that forgets `express.json()` therefore
80
- sees `req.body` as `undefined` and rejects every request as a malformed body —
81
- which is exactly how this shipped once. `routes.http.test.js` mounts the routes
82
- on a bare express app so that failure mode fails the suite instead of the user.
83
-
84
- `projectId` is validated against `/^[a-zA-Z0-9._:-]+$/`, which rejects
85
- separators and traversal. Validation failures are `400`; malformed stored data
86
- and I/O failures are `500`.
87
-
88
- ## Invariants
89
-
90
- - **Missing is not malformed.** A missing `context.json` is authoritative empty
91
- data. Unparseable JSON is a failure that propagates as `500`, so the client
92
- preserves what it already has instead of rendering an empty panel over intact
93
- data on disk.
94
- - **Writes are serialized per project** through an in-process lock, and land via
95
- write-to-temp + rename so a crash cannot leave a half-written file.
96
- - **`readContext` never takes the lock.** Every mutator calls it while already
97
- holding the lock, so locking there would deadlock. The legacy migration it can
98
- trigger is safe unlocked: both writes are atomic renames of identical content.
99
- - **Plan create writes markdown before the manifest entry**; delete removes the
100
- manifest entry before the file. Either partial failure leaves an unreferenced
101
- markdown file, which is inert. The reverse order would leave a manifest entry
102
- that renders as a plan and fails to open.
103
- - **Plan update takes the raw document, not title + body.** The editor owns
104
- the file verbatim; reassembling it from parsed parts would rewrite the
105
- heading and reformat what the user typed. The manifest title is re-derived
106
- from the saved content, and the file name never changes with the title — it
107
- is the stable identity behind the link.
108
- - **Plan update refuses to recreate a deleted file.** If the markdown vanished
109
- underneath an open editor the link is already dead; writing would resurrect
110
- content the user believes was discarded, so it returns `404` instead.
111
- - **A note patch touches only the fields it names.** Pinning sends `pinned`
112
- alone, so it cannot roll back an edit that landed between the two requests,
113
- and editing does not reset a pin. Editing bumps `updatedAt`; pinning does not,
114
- because a pin is not a change to what the note says.
115
- - **A note body can be clamped but never blanked.** An empty body is rejected
116
- rather than stored, since a note with nothing in it is indistinguishable from
117
- a delete the user did not ask for.
118
- - **Notes are capped at 200 per project.** Past that, creation fails loudly
119
- instead of silently evicting the oldest entry.
120
- - **Per-entry sanitization never fails the whole read.** A malformed todo or
121
- plan link is dropped; the rest of the context still loads.
122
-
123
- ## Legacy migration
124
-
125
- `projectNotes`, `projectTodos`, and `projectPlanFiles` originally lived in
126
- `<projectId>.json`. On the first read with no `context.json`, those three keys
127
- are moved out and deleted from the client-owned file; every other key is
128
- preserved untouched.
129
-
130
- Plan links carried absolute paths. Migration converts each to a base name. A
131
- file already in the plans directory is used in place; one referenced from
132
- elsewhere — a stale path left by an earlier project id — is copied in rather
133
- than dropped. A link whose markdown cannot be found at all is discarded, since
134
- it could not have been opened either way.
135
-
136
- The legacy keys are removed only after `context.json` is durably written, so any
137
- failure simply leaves the migration to run again on the next read. Repeat and
138
- concurrent reads converge on identical content.
139
-
140
- ## Cross-module contract
141
-
142
- `packages/web/server/lib/opencode/settings-runtime.js` merges project storage
143
- when a project id changes. Its `mergeProjectContextFiles` step must run before
144
- `moveDirectoryContents`, because that mover only renames into a free
145
- destination and would otherwise discard the old `context.json` whenever the
146
- destination already had one.
147
-
148
- `mergeProjectContextFiles` merges every list by identity and deliberately does
149
- not convert a version 1 string note: this module owns that conversion, and
150
- doing it in two places would mean two definitions of the same migration.
151
-
152
- `mergeProjectConfigData` still merges the legacy `projectNotes` /
153
- `projectTodos` / `projectPlanFiles` keys. That is deliberate: a project whose
154
- context has not been migrated yet keeps its data in `<projectId>.json`, and the
155
- migration picks it up from the merged destination afterwards.
156
-
157
- ## Tests
158
-
159
- - `runtime.test.js` — storage, sanitization, migration, locking, plan lifecycle.
160
- - `routes.test.js` — status-code mapping, payload validation, failure surfacing.
@@ -1,123 +0,0 @@
1
- # Quota Module Documentation
2
-
3
- ## Purpose
4
- This module fetches quota and usage signals for supported providers in the web server runtime.
5
-
6
- ## Entrypoints and structure
7
- - `packages/web/server/lib/quota/index.js`: public entrypoint imported by `packages/web/server/index.js`.
8
- - `packages/web/server/lib/quota/routes.js`: Express route registration for quota endpoints.
9
- - `packages/web/server/lib/quota/providers/index.js`: provider registry, configured-provider list, and provider dispatcher.
10
- - `packages/web/server/lib/quota/providers/google/`: Google-specific auth, API, and transform modules.
11
- - `packages/web/server/lib/quota/providers/claude/`: Claude credential discovery, usage transforms, and rate-limit handling.
12
- - `packages/web/server/lib/quota/utils/`: shared auth, transform, and formatting helpers.
13
-
14
- ## Supported provider IDs (dispatcher)
15
-
16
- These provider IDs are currently dispatchable via `fetchQuotaForProvider(providerId)` in `packages/web/server/lib/quota/providers/index.js`.
17
-
18
- | Provider ID | Display name | Module | Auth aliases/keys |
19
- | --- | --- | --- | --- |
20
- | `claude` | Claude | `providers/claude/` | Claude Code Keychain entry, Claude Code credentials file, OpenCode `auth.json` (`anthropic`, `claude`), `CLAUDE_CODE_OAUTH_TOKEN` |
21
- | `codex` | Codex | `providers/codex.js` | `openai`, `codex`, `chatgpt` |
22
- | `command-code` | Command Code | `providers/command-code.js` | `command-code` OAuth/API credential in OpenCode `auth.json`, or `COMMAND_CODE_API_KEY` |
23
- | `cursor` | Cursor | `providers/cursor.js` | Environment/token files, AiWorker-managed credentials, or explicit one-time Cursor import |
24
- | `crof` | CrofAI | `providers/crof.js` | `crof` (API key under `key` or `token`) |
25
- | `deepseek` | DeepSeek | `providers/deepseek.js` | `deepseek` (API key under `key` or `token`) |
26
- | `google` | Google | `providers/google/index.js` | `google`, `google.oauth`, Antigravity accounts file |
27
- | `github-copilot` | GitHub Copilot | `providers/copilot.js` | `github-copilot`, `copilot` |
28
- | `github-copilot-addon` | GitHub Copilot Add-on | `providers/copilot.js` | `github-copilot`, `copilot` |
29
- | `kimi-for-coding` | Kimi for Coding | `providers/kimi.js` | `kimi-for-coding`, `kimi` |
30
- | `nano-gpt` | NanoGPT | `providers/nanogpt.js` | `nano-gpt`, `nanogpt`, `nano_gpt` |
31
- | `openrouter` | OpenRouter | `providers/openrouter.js` | `openrouter` |
32
- | `zai-coding-plan` | z.ai | `providers/zai.js` | `zai-coding-plan`, `zai`, `z.ai` |
33
- | `zhipuai-coding-plan` | Zhipu AI Coding Plan | `providers/zhipuai-coding-plan.js` | `zhipuai-coding-plan`, `zhipuai`, `zhipu` |
34
- | `minimax-coding-plan` | MiniMax Coding Plan (minimax.io) | `providers/minimax-coding-plan.js` / `providers/minimax-shared.js` | `minimax-coding-plan` |
35
- | `minimax-cn-coding-plan` | MiniMax Coding Plan (minimaxi.com) | `providers/minimax-cn-coding-plan.js` / `providers/minimax-shared.js` | `minimax-cn-coding-plan` |
36
- | `ollama-cloud` | Ollama Cloud | `providers/ollama-cloud.js` | Manual cookie stored under `~/.config/openchamber/quota/` |
37
- | `wafer` | Wafer.ai | `providers/wafer.js` | `wafer`, `wafer-ai`, `wafer_ai`, `wafer.ai` |
38
- | `opencode-go` | OpenCode Go | `providers/opencode-go.js` | `opencode-go` API key from OpenCode `auth.json` |
39
- | `neuralwatt` | NeuralWatt | `providers/neuralwatt.js` | `neuralwatt` (API key under `key` or `token`) |
40
- | `xai` | xAI | `providers/xai.js` | `xai` OAuth entry in OpenCode `auth.json` |
41
-
42
- ## Internal-only provider module
43
- - `providers/openai.js` exists for logic parity/reuse but is intentionally not registered for dispatcher ID routing.
44
-
45
- ## Response contract
46
- All providers should return results via shared helpers to preserve API shape:
47
- - Required fields: `providerId`, `providerName`, `ok`, `configured`, `usage`, `fetchedAt`
48
- - Optional field: `error`
49
- - Unsupported provider requests should return `ok: false`, `configured: false`, `error: Unsupported provider`
50
-
51
- Provider modules must export `providerId`, `providerName`, `aliases`, `isConfigured(auth?)`, and `fetchQuota()`.
52
- `fetchQuota()` should return a quota result with `usage.windows` keyed by window name (for example `5h`, `7d`, `daily`) and optional provider-specific `usage.models` data.
53
-
54
- Ollama Cloud and Cursor credentials are explicitly managed through Settings. OpenCode Go usage uses `GET https://opencode.ai/zen/go/v1/usage` with the `opencode-go` API key from OpenCode `auth.json` as a bearer token. The server validates managed credentials before atomic `0600` writes and never returns secrets through its API. AiWorker never scans browser cookie stores or automatically reads Cursor storage; Cursor import is an explicit one-time user action and never modifies Cursor's database.
55
-
56
- Command Code usage resolves account scope through `GET /alpha/whoami`, then reads server-backed credit balances and five-hour/weekly limits from `GET /alpha/billing/credits?orgId=...`. Personal accounts return `org: null` and use `/alpha/billing/credits` without an `orgId`; organization accounts include their organization id. Web/Electron and VS Code read the standard `command-code` OpenCode auth entry (including OAuth `access`) or `COMMAND_CODE_API_KEY`; credentials remain in the owning runtime and are never returned to shared UI.
57
-
58
- On the first OpenCode Go usage refresh after upgrading, AiWorker deletes the obsolete `quota/opencode-go.json` credential file without reading its cookie value.
59
-
60
- ## Claude credential and limit semantics
61
-
62
- Claude quota reports the subscription limits Claude Code itself is bound by, read from `GET https://api.anthropic.com/api/oauth/usage`.
63
-
64
- - **Credential sources**, in priority order: the macOS Keychain entry `Claude Code-credentials`, then `${CLAUDE_CONFIG_DIR:-~/.claude}/.credentials.json` (the Linux/WSL location), then the OpenCode `auth.json` entry, then `CLAUDE_CODE_OAUTH_TOKEN`. The Keychain wins on macOS because the credentials file there is a leftover Claude Code no longer updates.
65
- - **All sources are read-only.** AiWorker never writes to Claude Code's credential store and never refreshes the OAuth token, because Anthropic does not support two live refresh tokens for one `client_id` — refreshing here would sign the user out of Claude Code. Credentials are read fresh per request so a Claude Code refresh is picked up immediately; an expired token yields an explicit "open Claude Code to sign in again" error rather than a bare 401.
66
- - **Limits come from the `limits` array**, keyed by `kind`: `session` maps to the `5h` window, `weekly_all` to `7d`, and `weekly_scoped` to a per-model `7d` window named by `scope.model.display_name`. The legacy `five_hour`/`seven_day` fields are only a fallback; `seven_day_sonnet`/`seven_day_opus` are no longer populated by Anthropic. Unrecognized limit kinds and Anthropic's rotating internal code names (`nimbus_quill`, `tangelo`, ...) are ignored rather than guessed at.
67
- - **Extra usage** is reported as the `extra_usage` window from `spend`, only while `spend.enabled` is true, with a money `valueLabel`.
68
- - **Rate limiting**: Anthropic returns 429 aggressively. The last successful usage payload is cached in memory and reserved during a cooldown (`Retry-After`, else five minutes, capped at one hour). The cache is keyed by a hash of the access and refresh tokens, so switching accounts drops it instead of showing the previous account's numbers.
69
- - **Runtime parity**: Web/Electron and VS Code preserve the last successful Claude values during the same bounded 429 cooldown. Quota dispatchers also coalesce concurrent refreshes for the same provider in each runtime, while requests for different providers remain parallel.
70
-
71
- ## Add a new provider (quick steps)
72
- 1. Choose module shape based on complexity:
73
- - Simple providers: create `packages/web/server/lib/quota/providers/<provider>.js`.
74
- - Complex providers (multi-source auth, multiple API calls, non-trivial transforms): create `packages/web/server/lib/quota/providers/<provider>/` with split modules like Google (`index.js`, `auth.js`, `api.js`, `transforms.js`).
75
- 2. Export `providerId`, `providerName`, `aliases`, `isConfigured`, and `fetchQuota`.
76
- 3. Use shared helpers from `packages/web/server/lib/quota/utils/index.js` (`buildResult`, `toUsageWindow`, auth/conversion helpers) to keep payload shape consistent.
77
- 4. Register the provider in `packages/web/server/lib/quota/providers/index.js`.
78
- 5. If needed for direct use, export a named fetcher from `packages/web/server/lib/quota/providers/index.js` and `packages/web/server/lib/quota/index.js`.
79
- 6. Update this file with the new provider ID, module path, and alias/auth details.
80
- 7. Validate with `bun run type-check`, `bun run lint`, and `bun run build`.
81
-
82
- ## MiniMax M3 / Token Plan migration
83
-
84
- In 2025/2026 MiniMax rebranded "Coding Plan" to "Token Plan" alongside the M3 model release. The API underwent breaking changes:
85
-
86
- - **Endpoint fallback**: The provider tries `/v1/token_plan/remains` (M3) first, falling back to legacy `/v1/api/openplatform/coding_plan/remains`.
87
- - **Field semantics**: On the `token_plan/remains` endpoint, `current_interval_usage_count` returns **remaining** quota (not consumed). The provider computes `used = total - remaining` for this endpoint. The legacy `coding_plan/remains` endpoint retains the old semantics (`usage_count = consumed`).
88
- - **Percentage-based plans**: Legacy Coding Plan accounts return `current_interval_total_count: 0` but include `current_interval_remaining_percent`. The provider prefers this field when count fields are absent.
89
- - **model_remains array**: Now contains entries for multiple model categories (chat, speech, video, image). The provider selects the chat-model entry by matching `MiniMax-M*`, then `general`/`chat`/`text` by name, then any entry with a remaining percent.
90
- - **Window status**: The `current_interval_status` and `current_weekly_status` fields indicate whether a window is active. Status `3` means the window is not applicable for the current plan tier (e.g. legacy plans without weekly limits). The provider omits inactive windows.
91
-
92
- ## Kimi for Coding field semantics
93
-
94
- `GET https://api.kimi.com/coding/v1/usages` is inconsistent about which field carries consumption:
95
- - The weekly `usage` block returns `used` (consumed) with no `remaining` field.
96
- - Each `limits[].detail` rate-limit block returns `remaining` (available) with no `used` field.
97
-
98
- The provider computes `usedPercent` from whichever of `used`/`remaining` is present (`used` takes precedence when both exist) rather than assuming one field name. Both `packages/web/server/lib/quota/providers/kimi.js` and `packages/vscode/src/quotaProviders.ts` (`fetchKimiQuota`) must stay in sync — the VS Code extension duplicates this parsing logic rather than importing it.
99
-
100
- ## GitHub Copilot quota semantics
101
-
102
- GitHub Copilot usage exposes only the `premium_interactions` snapshot as the
103
- `premium_interactions` window. Shared UI labels that window **AI Credits** and treats it as
104
- the provider's primary usage marker. Legacy chat-request quota and unlimited
105
- completion quota are intentionally omitted. Keep
106
- `packages/web/server/lib/quota/providers/copilot.js` and
107
- `packages/vscode/src/quotaProviders.ts` in sync.
108
-
109
- The `/copilot_internal/user` endpoint is undocumented; its quota semantics mirror
110
- what `microsoft/vscode-copilot-chat` consumes (`CopilotUserQuotaInfo`). Each
111
- snapshot carries `entitlement`, `remaining`, `unlimited`, and
112
- `percent_remaining`. Providers must honor these rules:
113
-
114
- - `unlimited: true` renders a percent-less window with an "Unlimited" value label.
115
- - Percent math requires a positive `entitlement`; entitlements of `0`, `-1`, or null are unusable.
116
- - When entitlement/remaining are unusable, fall back to `100 - percent_remaining`.
117
- - Snapshots other than `premium_interactions` (legacy annual plans) yield zero windows.
118
-
119
- ## Notes for contributors
120
- - Keep provider IDs stable; clients use them directly.
121
- - Avoid adding alias-based dispatch in `fetchQuotaForProvider`; dispatch currently expects exact provider IDs.
122
- - Keep Google behavior changes isolated and review `providers/google/*` together.
123
- - Z.ai Coding Plan exposes separate 5-hour and weekly token/credit limit entries plus a monthly `TIME_LIMIT` for MCP tools. The API renamed the limit type from `TOKENS_LIMIT` to `CREDIT_LIMIT` (same `unit`/`number` window semantics); `CREDIT_LIMIT` entries additionally carry `usage` (total), `currentValue` (consumed), and `remaining`, surfaced as a credit `valueLabel`, and the payload's `data.level` becomes `planLabel`. Web and VS Code must preserve these windows and stay in sync.
@@ -1,100 +0,0 @@
1
- # Relay Module Documentation
2
-
3
- ## Purpose
4
-
5
- The private relay lets an AiWorker client (mobile app, browser, or another desktop) reach a user's AiWorker instance through AiWorker-hosted infrastructure when the instance is not directly reachable (behind NAT, no public URL, no tunnel). The instance dials **outbound** to the relay; nothing needs to be exposed inbound.
6
-
7
- Traffic is **end-to-end encrypted between the two endpoints** (client and host instance). The relay infrastructure forwards opaque ciphertext and cannot read application traffic — it is an untrusted transport, not a trusted middlebox.
8
-
9
- This module (`packages/web/server/lib/relay/`) is the **host side**: it runs inside the AiWorker web server (so it works for Electron desktop, headless server, and CLI installs alike). The **client side** lives in `packages/ui/src/lib/relay/`. The **relay service itself** is a separate Cloudflare Worker in the `openchamber-website` repo and only brokers connections.
10
-
11
- ## The three layers
12
-
13
- Traffic is modeled as three stacked layers. The relay understands only Layer 1; Layers 2–3 exist solely between the client and the host.
14
-
15
- 1. **Relay routing (Layer 1)** — outbound WebSocket connections to the relay, connection brokering, and host authentication to the relay. The relay routes each client to the correct host and forwards frames verbatim.
16
- 2. **End-to-end encryption (Layer 2)** — an authenticated encrypted channel established directly between client and host, keyed so the relay cannot participate. Built on standard WebCrypto primitives (ECDH key agreement + AEAD framing). The host's encryption public key is distributed to the client out-of-band via the pairing payload and is the client's trust anchor.
17
- 3. **Tunnel multiplexing (Layer 3)** — because an AiWorker client speaks many concurrent HTTP requests, an event stream (SSE), and WebSockets to one origin, the encrypted channel carries a small multiplexing protocol. It frames HTTP request/response (including streamed bodies) and WebSocket sub-streams so the whole app works over one encrypted connection.
18
-
19
- ## Entrypoints and structure
20
-
21
- Host side (`packages/web/server/lib/relay/`):
22
- - `service.js` — thin entrypoint: relay config (enabled flag + relay URL), the management routes (`GET/POST /api/openchamber/relay/{status,enable,disable}`), a `getPairingCandidate()` accessor (the relay transport candidate folded into pairing-v2 links when enabled, consumed by the pairing-session route in `core-routes.js`), and lifecycle wiring. Started from `packages/web/server/index.js` only when the user has explicitly enabled the relay. The relay endpoint defaults to the AiWorker-hosted relay but can be pinned to a self-hosted relay via the `AIWORKER_RELAY_URL` env var (must be `ws://`/`wss://`); when set it overrides the stored setting for the host connection, the pairing candidate, and status, so paired clients inherit the endpoint automatically.
23
- - `identity.js` — the host's stable identity: the long-lived signing keypair (shared with the push relay, defines the routing id) plus a long-lived encryption keypair (the E2EE trust anchor). Reused across restarts; never rotated implicitly.
24
- - `signing-key.js` — storage/derivation of the signing keypair and the routing id, shared with the notifications runtime.
25
- - `host-client.js` — the long-lived connection manager: one outbound control connection to the relay, a per-client data connection for each connected device, reconnect/backoff, and the E2EE responder handshake per connection.
26
- - `host-lock.js` — the per-machine host claim. Every local instance sharing the data dir shares the relay identity (same serverId), so concurrent relay hosts evict each other at the relay worker (`4001: Control replaced`) and paired devices land on whichever local process won last. The claim file (`<data-dir>/relay-host.lock`, `{ pid }`) makes this deterministic: `service.js` only starts the host when no LIVE process holds the claim (stale claims from dead pids are ignored), goes to `standby` otherwise, and a 30s watcher both takes over when the claimant dies and stands down when another process claims. A standby watcher waits a 2-minute grace after the claim frees before taking over, so a cleanly restarting host (app update/relaunch) — which reclaims at boot with no wait — always wins the restart window over a bystander instance. Explicit user intent — creating a pairing link or hitting `/relay/enable` — force-claims; the previous holder's watcher sees the takeover and backs off instead of fighting. Instances created with `allowPassiveHost: false` (dev servers via `AIWORKER_RELAY_HOST=off`, the Electron dev shell via `AIWORKER_ELECTRON_DEV`; `AIWORKER_RELAY_HOST=on` overrides) never start the host passively at all — boot, demand reconcile, and watcher takeover leave them in `standby`; only explicit enable/pairing hosts there. The claim is cooperative (the relay worker still enforces the single host slot); it only decides which process keeps retrying.
27
- - `tunnel-host.js` — the per-connection dispatcher: decrypts tunnel frames and forwards HTTP/SSE/WS to the local server over loopback, then streams responses back. Enforces a path allowlist and never injects credentials.
28
- - `e2ee.js`, `tunnel-codec.js` — host-side (JS) mirrors of the shared crypto and framing (see "Two implementations" below).
29
-
30
- Client side (`packages/ui/src/lib/relay/`):
31
- - `protocol.ts` — the shared contract: constants, frame types, message shapes. The normative source both implementations follow.
32
- - `crypto.ts`, `handshake.ts` — the E2EE primitives and handshake state machines (initiator + responder).
33
- - `tunnel-codec.ts` — Layer 3 frame codec, fragmentation, and outbound frame batching.
34
- - `tunnel-client.ts` — the client tunnel: exposes a `fetch()`-compatible and a WebSocket-compatible surface backed by the encrypted tunnel.
35
- - `tunnel-payloads.ts`, `runtime-tunnel.ts`, `runtime-socket.ts` — payload helpers, the active-tunnel singleton, and the shared "open a runtime WebSocket the right way" helper.
36
-
37
- Relay is not a separate link format: it is one transport candidate inside the unified **pairing v2** payload (`packages/ui/src/lib/connectionPayload.ts`). A relay candidate is `{ type: 'relay', relayUrl, serverId, hostEncPubJwk }` — no embedded token; the client redeems the one-time pairing secret over the tunnel like any other candidate.
38
-
39
- ## What travels the tunnel
40
-
41
- Everything a client normally sends to the single AiWorker origin:
42
- - **HTTP** — REST endpoints and proxied OpenCode SDK calls under `/api/*`, plus `/auth/*` and `/health`.
43
- - **SSE** — long-lived streamed responses (the event stream and notifications). These are just HTTP responses whose body streams; the tunnel needs no special SSE handling.
44
- - **WebSocket** — the endpoints that use a real socket (the global event stream on platforms that support WS, terminal I/O, dictation).
45
-
46
- The host dispatcher restricts tunneled traffic to explicit path allowlists (one for HTTP, one for WS).
47
-
48
- Request bodies crossing the tunnel are buffered on the host and forwarded to loopback only once the client's `StreamEnd` frame arrives (bodies above ~512 KB stream live instead). A body whose frames were lost in transit therefore never reaches the loopback server as an empty/truncated chunked body — the host aborts the stream and the client sees an ambiguous transport failure it can retry, instead of the loopback server's bare `400` ("Failed to send message (400)" from the mobile app).
49
-
50
- ## Authentication model
51
-
52
- - The tunnel is **transport only**. The AiWorker server still authenticates every tunneled request exactly as it authenticates a direct remote client. The relay path grants reachability, not authorization.
53
- - Clients carry their normal credential. HTTP and SSE requests authenticate with the client's bearer token (a header). **WebSocket upgrades cannot send headers**, so they authenticate with a short-lived URL-scoped token minted beforehand and passed as a query parameter. This asymmetry is important when adding new WebSocket features (see the skill).
54
- - The host authenticates itself to the relay with a signed handshake using its long-lived signing key.
55
- - Enabling the relay is explicit opt-in and disabled by default; disabling it severs all relay reachability immediately.
56
-
57
- ## End-to-end flow (overview)
58
-
59
- 1. **Pairing.** The host issues a pairing-v2 link (QR / deep link) carrying a one-time secret and a list of transport candidates. When the relay is enabled, one candidate is the relay transport (its endpoint, routing id, and encryption public key — the E2EE trust anchor). The client redeems the secret over the first reachable candidate; over the relay candidate it opens the E2EE tunnel first, then redeems through it, and stores the connection.
60
- 2. **Presence.** When the relay is enabled, the host opens one outbound control connection and waits.
61
- 3. **Connect.** The client connects for a given routing id; the relay notifies the host over the control connection; the host opens a matching per-client data connection.
62
- 4. **Handshake.** Over that connection pair, client and host run the E2EE handshake and derive a shared encrypted channel the relay cannot read.
63
- 5. **Traffic.** All normal app traffic is multiplexed and encrypted through that channel. On the host, decrypted requests are dispatched to the local server over loopback with the actual loopback origin, so normal origin checks still apply without trusting client-supplied origin metadata; responses stream back encrypted. Reconnects re-establish a fresh channel and the app's existing retry machinery recovers.
64
-
65
- ## Candidate refresh (staying off the relay when direct works)
66
-
67
- Pairing-payload transport candidates are a snapshot: when DHCP hands the host
68
- machine a new LAN address, a device's saved direct candidate goes stale and the
69
- device silently degrades to relay-only. To recover, an already-paired client can
70
- call `GET /api/client-auth/connection/candidates` (UI session or client bearer;
71
- registered with the auth/access routes) over any live transport — including
72
- through the tunnel — to learn the server's **current** LAN URLs plus the relay
73
- candidate, and update its saved candidate set (mobile: `mobileConnections.ts`;
74
- desktop: `desktopRelayRestore.ts`).
75
-
76
- Identity gating: the response carries the stable `serverId` (base64url SHA-256 of
77
- the public signing JWK — the same identity the relay routes by, exposed by the
78
- relay service's `getServerId()` and echoed unauthenticated on `/health` and
79
- `/api/version`). Clients ignore a refresh whose `serverId` does not match their
80
- pinned relay identity, and verify `/health`'s `serverId` on a learned address
81
- **before** sending their bearer token to it — a re-assigned LAN address may now
82
- belong to a different machine.
83
-
84
- ## Two implementations, kept in sync
85
-
86
- The E2EE and framing logic exists twice: TypeScript in `packages/ui/src/lib/relay/` (shared by the client and the normative reference) and a JavaScript mirror in this module (the host, which is plain JS ESM). They **must stay byte-compatible** — a client encrypted by one must decrypt on the other. A cross-compatibility test (`cross-compat.test.js`) imports the TS modules directly and exercises a full TS-client ↔ JS-host exchange. Any change to the wire format, frame codec, handshake, or batching must update both sides and keep that test green.
87
-
88
- ## Runtime integration (client)
89
-
90
- Relay mode plugs into the existing client transport layer rather than a parallel path: `runtime-switch` activates the tunnel singleton, `runtime-fetch` routes runtime requests through it, `runtime-url`/`runtime-socket` yield tunnel-backed URLs and sockets, and `runtime-auth` mints the URL-scoped token through the tunnel. Direct-URL connections and the Electron realtime-proxy path are unaffected.
91
-
92
- ## Design invariants (do not regress)
93
-
94
- - The relay never sees plaintext application traffic; it sees only routing metadata (routing id, connection identifiers, timestamps, coarse counts).
95
- - Pairing secrets travel in URL fragments only, never in query strings, never logged.
96
- - The host dispatcher never injects credentials; the server authenticates each tunneled request.
97
- - The tunnel is transparent to the app: adding relay support to a feature should not require the feature to know the relay exists — it goes through the shared runtime transport helpers.
98
- - The two implementations stay byte-compatible and the wire format is versioned/negotiated so mixed client/host app versions degrade gracefully rather than break.
99
-
100
- For the operational rules that keep future changes (new WebSocket endpoints, transport refactors, terminal/voice porting) from breaking this, load the `relay-transport` skill.
@@ -1,182 +0,0 @@
1
- # Scheduled Tasks module
2
-
3
- Server-owned scheduled task runtime and routes for AiWorker-only automation.
4
-
5
- ## Scope
6
-
7
- - Per-project scheduled task persistence is owned by `packages/web/server/lib/projects/project-config.js`.
8
- - Markdown loop discovery/parsing is owned by `packages/web/server/lib/scheduled-tasks/loops.js`.
9
- - Runtime orchestration and execution is owned by `packages/web/server/lib/scheduled-tasks/runtime.js`.
10
- - This module is AiWorker feature logic; it is intentionally separate from OpenCode proxy/runtime internals.
11
-
12
- ## Cross-instance occurrence claiming
13
-
14
- Multiple AiWorker server processes can share the same on-disk project config
15
- (for example CLI `serve` on port 3000 and the Electron desktop server on port
16
- 57123). Each process keeps its own timers, so without coordination a daily (or
17
- weekly / cron / once) slot would dispatch twice.
18
-
19
- Before a **scheduled** run creates a session, the runtime claims the occurrence
20
- in shared project config under the project write lock:
21
-
22
- - Writes `state.lastScheduledFor` to the armed `nextRunAt` timestamp and advances
23
- `state.nextRunAt` to the following occurrence.
24
- - A second instance that loses the claim skips session creation and reschedules
25
- from the winner's persisted `nextRunAt`.
26
- - Project config writes also take a cross-process `.json.lock` file so the
27
- read-modify-write is serialized across processes, not only within one process.
28
- - The sharing processes may run different AiWorker versions. Normalization
29
- keeps only the fields a build knows, so every writer persists tasks it did
30
- not change verbatim from disk and swaps only `state` onto a task whose state
31
- it updated; a task goes out normalized only when it was deliberately
32
- replaced (upsert, loop adoption). An older server touching the file after a
33
- run therefore cannot strip fields a newer build added, such as a task's goal
34
- or auto-accept settings.
35
- - Lock timeout / filesystem errors on claim, manual-start, or completion state
36
- writes always release the in-process running slot (via `finally`) and best-effort
37
- re-arm the **next future** occurrence; they must not leave the task permanently
38
- "running" or reject unhandled from the queue pump.
39
- - Project write locks release the in-process promise chain even when
40
- `acquireProjectFileLock` times out, so a later write for the same project can
41
- proceed after the on-disk lock is cleared (a hung chain would permanently wedge
42
- every mutating API and strand `runTask` before its `finally`).
43
- - Re-arm helpers only schedule a persisted `nextRunAt` when it is still in the
44
- future. A past slot (common for `once` after claim, which cannot advance
45
- `nextRunAt`) falls back to `computeNextRunAt` — which returns null for a
46
- consumed/past once occurrence — so a losing instance stops instead of
47
- spinning delay-0 timers against the project lock.
48
- - On claim lock/fs failure, best-effort persist `lastStatus: error` + `lastError`
49
- when nobody else claimed the occurrence, so a past `once` task is not left
50
- enabled-but-inert with only a warn log. Recurring schedules still re-arm the
51
- next slot.
52
- - On completion-write failure after a session already ran, in-memory status is
53
- set to a terminal value and a single persist retry is attempted so
54
- `lastStatus` does not stay `running`. Manual `runNow` still returns the
55
- `sessionID` as a successful dispatch (`ok` follows run status, with
56
- `persistError` set) rather than a hard 500; the run API and Scheduled Tasks
57
- UI surface `persistError` as a warning toast.
58
- - The claim predicate rejects a duplicate solely via `lastScheduledFor` within
59
- slack of this occurrence. It does not consult advanced on-disk `nextRunAt`
60
- (that field is routinely overwritten by a second instance syncing inside
61
- `TASK_DUE_SLACK_MS`, including on later days when `lastScheduledFor` is already
62
- set from a prior claim).
63
- - Claiming always writes `nextRunAt` (including `undefined`) so a past once-slot
64
- is cleared when there is no following occurrence.
65
-
66
- Manual `runNow` does not claim a schedule occurrence.
67
-
68
- ## Files
69
-
70
- - `packages/web/server/lib/scheduled-tasks/runtime.js`
71
- - Next-run computation (daily/weekly/cron compatibility)
72
- - Timer scheduling and queueing
73
- - Concurrency controls
74
- - Session create + prompt_async execution
75
- - Emits AiWorker task-run events
76
-
77
- - `packages/web/server/lib/scheduled-tasks/loops.js`
78
- - Discovery of `.agents/loops/*.md` (project scope, ancestors up to the worktree root) and `~/.agents/loops/*.md` (user scope)
79
- - Frontmatter parsing into scheduled-task definitions
80
- - `syncProject` reconciles discovered loops with the persisted task list on every project sync (startup, task list load, task save/delete)
81
-
82
- - `packages/web/server/lib/scheduled-tasks/routes.js`
83
- - Scheduled task CRUD endpoints
84
- - Listing tasks reconciles loop files first, so opening the Scheduled Tasks UI discovers file additions, edits, and removals without a server restart
85
- - Loop-file endpoints toggle `enabled` in frontmatter or delete the authoritative markdown file, then reconcile the project
86
- - Manual run endpoint
87
- - AiWorker events SSE stream endpoint
88
-
89
- ## Loop file format
90
-
91
- Portable, git-commit-able scheduled-task definitions:
92
-
93
- ```markdown
94
- ---
95
- name: daily-digest
96
- schedule: "0 9 * * *"
97
- enabled: true
98
- model: anthropic/claude-sonnet-4-5
99
- agent: plan
100
- timezone: Europe/Kyiv
101
- ---
102
- Summarize repository changes since yesterday.
103
- ```
104
-
105
- Field mapping (model: `packages/ui/src/lib/scheduledTasksApi.ts`):
106
-
107
- | Frontmatter | Task field |
108
- |---|---|
109
- | `name` | `name` (required, max 80 characters — longer names are rejected as malformed) |
110
- | `schedule` | `schedule.kind: "cron"` + `schedule.cron` (required, cron-only in the portable format) |
111
- | `enabled` | `enabled` (default `false` — a loop only runs when the file explicitly enables it; add `enabled: true` to activate) |
112
- | `model` | split on the first `/` into `execution.providerID` / `execution.modelID` (required) |
113
- | `agent` | `execution.agent` (optional) |
114
- | `timezone` | `schedule.timezone` (optional, IANA; defaults to the server zone) |
115
- | body | `execution.prompt` (required) |
116
-
117
- `thinking_level` and `goalEnabled`/`goalTokenBudget` are not part of the portable
118
- format (UI/JSON-only today); `daily`/`weekly`/`once` schedules remain UI/JSON-only.
119
- Runtime state (`lastRunAt`, `nextRunAt`, `lastStatus`, `lastError`, `lastSessionId`,
120
- `lastDurationMs`) is never written to the markdown file — it continues to live in
121
- the project config state store.
122
-
123
- ## Loop reconciliation rules
124
-
125
- `projectConfigRuntime.reconcileLoopTasks(projectID, loops)` runs inside the
126
- project write lock on every `syncProject` when the project path is known:
127
-
128
- - **Identity.** For loop-owned tasks (carrying the `loopFile` marker) identity
129
- is the loop file path: a loop takes its task over regardless of the task's
130
- current name, so renaming the loop (the `name` field, or a UI rename) renames
131
- the task in place instead of leaving a stale duplicate behind. A loop whose
132
- name matches a JSON task (no `loopFile`) takes that task over instead: its
133
- schedule/execution/enabled are overwritten from the file while the task's
134
- `id` and runtime `state` are preserved (markdown wins on conflict).
135
- - **UI-only fields survive adoption.** Execution fields the file format does
136
- not define (`goalEnabled`, `goalTokenBudget`, `permissionAutoAccept`,
137
- `variant`) are preserved from the task when a loop adopts it; only fields the
138
- file defines are re-applied.
139
- - **Deletion.** A task carrying the `loopFile` marker whose loop file is no
140
- longer discovered (removed or renamed) is unscheduled (removed from the
141
- config). The marker is persisted in the config file, so removal is detected
142
- across restarts. JSON-configured tasks without the marker are never removed.
143
- A task whose loop file still exists but is currently unparseable is KEPT with
144
- its last good definition — a transiently malformed file (mid-edit, bad merge)
145
- never deletes a task or its runtime state.
146
- - **Creation.** Loops without a matching task are created under a deterministic
147
- `loop:<scope>:<name>` id so runtime state survives restarts. At most one task
148
- is driven per loop file; orphan duplicates of the same file are unscheduled.
149
- - **Scope precedence.** Project-scope loops shadow user-scope loops with the
150
- same name; among project files the nearest ancestor wins.
151
- - **Malformed files** (missing `name`/`schedule`/`model`/body, invalid cron,
152
- unreadable) are reported to the scheduler as `definition: null` entries and
153
- warned about; they never block valid loops in the same or other scopes.
154
- - **Loop-file mutations.** The loop file remains authoritative. The scheduled-
155
- tasks UI opens it in the built-in file editor, updates its `enabled`
156
- frontmatter through the loop-file endpoint, and deletes the file through the
157
- loop-file endpoint after confirmation. Each mutation reconciles the project.
158
- The general task deletion API still rejects loop-sourced tasks while their
159
- file exists; once the file is gone, deleting an orphan task is allowed.
160
-
161
- ## Public exports (runtime.js)
162
-
163
- - `createScheduledTasksRuntime(dependencies)`
164
- - Returned API:
165
- - `start()`
166
- - `stop()`
167
- - `syncAllProjects()`
168
- - `syncProject(projectId)`
169
- - `runNow(projectId, taskId)`
170
-
171
- ## Public exports (routes.js)
172
-
173
- - `registerScheduledTaskRoutes(app, dependencies)`
174
- - Registers:
175
- - `GET /api/projects/:projectId/scheduled-tasks`
176
- - `PUT /api/projects/:projectId/scheduled-tasks`
177
- - `DELETE /api/projects/:projectId/scheduled-tasks/:taskId`
178
- - `PATCH /api/projects/:projectId/scheduled-tasks/:taskId/loop-file`
179
- - `DELETE /api/projects/:projectId/scheduled-tasks/:taskId/loop-file`
180
- - `POST /api/projects/:projectId/scheduled-tasks/:taskId/run`
181
- - `GET /api/openchamber/scheduled-tasks/status`
182
- - `GET /api/openchamber/events`