@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,193 +0,0 @@
1
- # Git Module Documentation
2
-
3
- ## Purpose
4
- This module provides Git repository operations for the web server runtime, including repository management, branch/worktree operations, status/diff queries, commit handling, and merge/rebase workflows.
5
-
6
- ## Entrypoints and structure
7
- - `packages/web/server/lib/git/`: Git module directory containing all Git-related functionality.
8
- - `index.js`: Public API entry point imported by `packages/web/server/index.js`.
9
- - `routes.js`: Express route registration for `/api/git/*` endpoints.
10
- - `service.js`: Core Git operations (repository, branch, worktree, commit, merge/rebase, status/diff, log).
11
- - `credentials.js`: Git credentials management.
12
- - `identity-storage.js`: Git identity (user.name, user.email) storage.
13
-
14
- ## Public API
15
-
16
- The following functions are exported and used by the web server:
17
-
18
- ### Repository Operations
19
- - `isGitRepository(directory)`: Check if a directory is a Git repository.
20
- - `getGlobalIdentity()`: Get global Git user.name, user.email, and core.sshCommand.
21
- - `getCurrentIdentity(directory)`: Get local Git identity (fallback to global if not set locally).
22
- - `hasLocalIdentity(directory)`: Check if local Git identity is configured.
23
- - `setLocalIdentity(directory, profile)`: Set local Git identity (userName, userEmail, authType, sshKey/host).
24
- - `getRemoteUrl(directory, remoteName)`: Get URL for a specific remote.
25
-
26
- ### Status and Diff Operations
27
- - `getStatus(directory)`: Get comprehensive Git status including current branch, tracking, ahead/behind, file changes, diff stats, merge/rebase state.
28
- - `getDiff(directory, { path, staged, contextLines })`: Get diff output for files or entire working tree. Untracked symbolic links are represented as link entries without following their targets.
29
- - `getRangeDiff(directory, { base, head, path, contextLines })`: Get diff between two refs. Uses three-dot `base...head` semantics, so work merged into `head` from `base` is excluded and only the branch's own changes are returned. Prefers `origin/<base>` when that remote-tracking ref exists, so a stale local base branch does not resurface already-merged commits. Exposed as `GET /api/git/range-diff` (`path` optional; omit it for the whole range).
30
- - `getRangeFiles(directory, { base, head })`: Get list of changed files between two refs.
31
- - `getFileDiff(directory, { path, staged })`: Get original and modified file contents for a single file (handles images as data URLs and symbolic links as their link-target text).
32
- - `listUntrackedPaths(directory)`: List individual untracked file paths honoring ignore rules. Much cheaper than `getStatus` when that is all a caller needs. Deliberately not `--directory`: collapsed directory entries end in a slash and are rejected by the per-file diff helpers, so a caller would silently lose every file inside a new directory.
33
- - `getUntrackedDiffs(directory, filePaths, { concurrency, contextLines })`: Diffs for untracked files against an empty tree. Resolves the repository context once instead of per file (`getDiff` re-resolves every call, costing an extra `rev-parse` each time) and bounds how many diff processes run at once. Returns one entry per input path in order; unreadable paths yield `''` rather than failing the batch.
34
- - `collectDiffs(directory, files)`: Collect diff output for multiple files.
35
- - `revertFile(directory, filePath, options)`: Revert a file. Default scope `all` discards staged and working-tree changes; scope `working` discards only unstaged/working-tree changes.
36
- - `stageFile(directory, filePath)`: Add one file path to the index.
37
- - `unstageFile(directory, filePath)`: Remove one file path from the index while preserving working-tree content.
38
- - `applyHunk(directory, filePath, options)`: Apply a single-hunk patch via `git apply`. `options.action` is `stage` (`git apply --cached`), `unstage` (`git apply --cached --reverse`), or `discard` (`git apply --reverse` in the working tree). The patch is written to a temp file; a `--check` runs first so a stale hunk fails with a clear "refresh and try again" error instead of a partial mutation. The patch target path must match the requested file.
39
-
40
- ### Branch Operations
41
- - `getBranches(directory)`: Get list of local and remote branches (filtered to active remote branches).
42
- - `createBranch(directory, branchName, options)`: Create and checkout a new branch.
43
- - `checkoutBranch(directory, branchName)`: Checkout an existing branch. A remote-tracking name (`origin/main`, or the `remotes/`-prefixed form) resolves to the local branch of that name, created with `--track` when it does not exist yet, because the branch selector offers remote branches as places to work rather than commits to inspect — a literal checkout of the remote ref would detach HEAD. A local branch whose own name looks like a remote ref wins over that resolution, and anything unresolvable is checked out as requested. The returned `branch` is the branch that was actually checked out, which callers should report instead of the requested name.
44
- - `deleteBranch(directory, branch, options)`: Delete a branch (supports force flag).
45
- - `renameBranch(directory, oldName, newName)`: Rename a branch and preserve upstream tracking.
46
- - `getRemotes(directory)`: Get list of configured remotes.
47
-
48
- ### Worktree Operations
49
- - `getWorktrees(directory)`: List all git worktrees for a repository.
50
- - `validateWorktreeCreate(directory, input)`: Validate worktree creation parameters (mode, branchName, startRef, upstream config).
51
- - `createWorktree(directory, input)`: Create a new worktree (supports 'new' and 'existing' modes, upstream setup). After populating the worktree, the repository's `post-checkout` hook runs once with git's standard arguments (null ref as previous HEAD, the checked-out HEAD, and flag `1`) from the worktree directory, mirroring `git worktree add` without `--no-checkout`; a missing or non-executable hook is skipped and a failing hook is logged as a warning, never failing worktree creation or the session bootstrap.
52
- - `removeWorktree(directory, input)`: Remove a worktree (optionally delete local branch).
53
- - `isLinkedWorktree(directory)`: Check if directory is a linked worktree (not primary).
54
-
55
- ### Worktree creation from a GitHub pull request
56
- The UI provisions `pr-<owner>` via `ensureRemoteName`/`ensureRemoteUrl`
57
- (HTTPS clone URL preferred over SSH) and checks out
58
- `remotes/pr-<owner>/<head>`. A missing head URL or unreachable fork fails with
59
- a clear error before a worktree is kept. If upstream fetch fails during
60
- bootstrap, tracking is left unset rather than writing `branch.*.remote` /
61
- `branch.*.merge` for a ref that was never fetched.
62
-
63
- ### Commit and Remote Operations
64
- - `commit(directory, message, options)`: Create a commit from the current index. `options.stageFiles` may be provided with `options.files` by older callers to stage only selected unstaged rows before committing, but the shared Git panel now stages/unstages explicitly before commit.
65
- - `pull(directory, options)`: Pull changes from remote.
66
- - `push(directory, options)`: Push changes to remote (auto-sets upstream if needed).
67
- - `fetch(directory, options)`: Fetch changes from remote.
68
- - `removeRemote(directory, options)`: Remove a configured remote (except `origin`).
69
- - `deleteRemoteBranch(directory, options)`: Delete a remote branch.
70
-
71
- ### Log Operations
72
- - `getLog(directory, options)`: Get commit history with stats (supports maxCount, from, to, file filters).
73
- - `getCommitFiles(directory, commitHash)`: Get file changes for a specific commit.
74
- - `getCommitFileDiff(directory, hash, filePath, isBinary)`: Get before/after content for a specific file in a commit. Returns `{ original, modified, isBinary }`. Runs `git show <hash>^:<path>` and `git show <hash>:<path>` in parallel; returns empty strings on failure (added/deleted/root-commit edge cases).
75
-
76
- ### Merge and Rebase Operations
77
- - `rebase(directory, options)`: Start a rebase onto a target branch.
78
- - `abortRebase(directory)`: Abort an in-progress rebase.
79
- - `continueRebase(directory)`: Continue a rebase after conflict resolution.
80
- - `merge(directory, options)`: Merge a branch into current branch.
81
- - `abortMerge(directory)`: Abort an in-progress merge.
82
- - `continueMerge(directory)`: Continue a merge after conflict resolution.
83
- - `getConflictDetails(directory)`: Get detailed conflict information including operation type, unmerged files, and diff.
84
-
85
- ### Stash Operations
86
- - `listStashes(directory)`: List stash entries with ref, message, relative time, and hash.
87
- - `countStashFiles(directory, refs)`: Batch-count changed files for stash refs with bounded concurrency.
88
- - `stashPush(directory, options)`: Stash changes, always including untracked files, with optional message.
89
- - `stashApply(directory, options)`: Apply a stash by ref without removing it.
90
- - `stashPop(directory, options)`: Apply a stash by ref and drop it only after a successful apply.
91
- - `stashDrop(directory, options)`: Drop a stash by ref.
92
-
93
- ## Internal Helpers
94
-
95
- The following functions are internal helpers used by exported functions:
96
- - `buildSshCommand(sshKeyPath)`: Build SSH command string for git config.
97
- - `buildGitEnv()`: Build Git environment with SSH_AUTH_SOCK resolution.
98
- - `createGit(directory)`: Create simple-git instance with environment.
99
- - `normalizeDirectoryPath(value)`: Normalize directory paths (supports ~ expansion).
100
- - `cleanBranchName(branch)`: Remove refs/heads/ or refs/ prefixes.
101
- - `parseWorktreePorcelain(raw)`: Parse `git worktree list --porcelain` output.
102
- - `resolveWorktreeProjectContext(directory)`: Resolve project context (projectID, primaryWorktree, worktreeRoot).
103
- - `resolveCandidateDirectory(...)`: Generate unique worktree directory candidates.
104
- - `resolveBranchForExistingMode(...)`: Resolve branch for existing-mode worktree creation.
105
- - `applyUpstreamConfiguration(...)`: Set upstream tracking for new branches.
106
- - `runPostCheckoutHook(directory)`: Invoke the worktree's `post-checkout` hook after population, because `git worktree add --no-checkout` and the bootstrap's `git reset --hard` never run git hooks. Runs with git's standard arguments and the worktree as cwd; skips missing/non-executable hooks and never throws on hook failure.
107
- - And various other internal helpers for Git command execution and parsing.
108
-
109
- ## Response Contracts
110
-
111
- ### Status Response
112
- - `current`: Current branch name.
113
- - `tracking`: Upstream branch (e.g., 'origin/main').
114
- - `ahead`: Number of commits ahead of upstream.
115
- - `behind`: Number of commits behind upstream.
116
- - `upstreamComparison`: Optional comparison against `upstream/<current-branch>`, with `{ remote, branch, ahead, behind }`.
117
- - `files`: Array of file objects with `path`, `index`, `working_dir` status codes.
118
- - `isClean`: Boolean indicating if working tree is clean.
119
- - `diffStats`: Object mapping file paths to `{ insertions, deletions }`.
120
- - `mergeInProgress`: Object with `{ head, message }` if merge in progress.
121
- - `rebaseInProgress`: Object with `{ headName, onto }` if rebase in progress.
122
-
123
- ### Branches Response
124
- - `all`: Local branches plus every branch each reachable remote reports via `ls-remote --heads`, formatted as `remotes/<remote>/<branch>`. This is a union: local remote-tracking refs deleted on the remote are pruned, and branches that exist on the remote without a local tracking ref (never fetched) are still included, so a freshly pushed branch appears without requiring a fetch. A remote that fails to answer keeps its locally known branches in the list: "we could not ask" must not be reported as "these branches are gone", because callers use this list to decide whether a base branch exists at all.
125
- - `current`: Current branch name.
126
- - `branches`: Per-branch detail keyed by branch name, as reported by `git branch`. Remote-only entries in `all` — branches `ls-remote` reported that were never fetched — have **no** entry here, because `git branch` never saw them. Consumers must treat a missing detail entry as normal and read the name from `all`.
127
- - Never-fetched remote-only branches also have no local ref, so any operation that resolves one locally has to account for that: `checkoutBranch` fetches the single branch (`git fetch <remote> <branch>`) before creating the tracking branch, and the range helpers (`getRangeDiff`, `getRangeFiles`) reject an unresolvable ref with `Ref "<ref>" is not available locally. Fetch it before comparing.` instead of surfacing git's "ambiguous argument".
128
- - `defaultBranches`: Each remote's default branch, keyed by remote name. Read from the local `remotes/<name>/HEAD` symbolic ref; for a remote that has none — clone writes it, a hand-added remote may not — the remote itself is asked once with `ls-remote --symref`. A remote that answers neither is absent rather than guessed, and consumers fall back to conventional branch names. Omitted entirely by runtimes that do not provide this Git metadata.
129
-
130
- ### Runtime availability of range diffs
131
- - `GET /api/git/range-diff` is served by the AiWorker web server, so it is available to web, desktop, and mobile clients. The shared `GitAPI.getGitRangeDiff` is therefore optional: web supplies the HTTP implementation, and VS Code does not implement it because the extension host serves Git through its own bridge rather than these routes. Features built on range diffs (currently the AI diff walkthrough) are not offered in VS Code.
132
-
133
- ### Staged and unstaged change handling
134
- - `status.files` exposes both `index` and `working_dir` codes. Shared UI uses these as separate scopes: staged rows are derived from non-empty `index` statuses, while unstaged rows are derived from `working_dir` statuses and untracked files.
135
- - A file with both staged and unstaged changes can appear in both UI sections. Staged rows request diffs with `staged: true`; unstaged rows request normal working-tree diffs.
136
- - The shared Git panel exposes explicit staging actions. Unstaged rows use `stageFile`, staged rows use `unstageFile`, and commits operate on the current staged index.
137
- - `stageFiles` remains supported for callers that need to stage a selected unstaged subset as part of commit. In that mode the server temporarily unstages unrelated index entries, stages `stageFiles`, commits from the index, then restores temporarily unstaged entries.
138
- ### Worktree Create/Remove Response
139
- - `head`: HEAD commit SHA.
140
- - `name`: Worktree name.
141
- - `branch`: Local branch name.
142
- - `path`: Absolute path to worktree directory.
143
- - `directoryCreated`: Present when create returned after the target directory exists while background Git/bootstrap work continues.
144
- - `bootstrapStatus`: Background setup state. The legacy `status` remains `pending`, `ready`, or `failed`, while `phase` reports `directory-created`, `git-ready`, or `setup-ready`. Fast create starts at `pending`/`directory-created`; population and upstream Git completion advances to `pending`/`git-ready` before setup/start scripts; completed setup is `ready`/`setup-ready`. A missing in-memory state falls back to `ready`/`setup-ready`; clients continue to accept legacy status responses that omit `phase`.
145
- - Fast-create background failures remove OpenCode sandbox metadata for directories that never became Git worktrees, and remove the pre-created directory only if it is still empty. User-created files are never recursively deleted by this cleanup.
146
- - Worktree removal waits for any active create/bootstrap task for that directory before deleting it, preventing a background Git or setup task from restoring removed state or racing filesystem cleanup.
147
- - Worktree bootstrap retries transient `index.lock` conflicts. If the lock remains byte-for-byte and metadata-identical across the retry window, it is treated as stale, removed, and population continues automatically; changing locks are left untouched and reported as failures.
148
- - Worktree population enables Git `core.longpaths` (local repo config plus `-c core.longpaths=true` on `git reset --hard`) so deeply nested checkouts under the managed data-dir worktree root do not fail on Windows MAX_PATH with "Filename too long". Path-component limits that the filesystem itself rejects still fail bootstrap, with a clearer path-length guidance message.
149
-
150
- ### Log Response
151
- - `all`: Array of commit objects with hash, date, message, author info, stats.
152
- - `latest`: Latest commit object or null.
153
- - `total`: Total number of commits.
154
-
155
- ## Notes for Contributors
156
-
157
- ### Adding a New Git Operation
158
- 1. Add the function to `packages/web/server/lib/git/service.js`.
159
- 2. Export the function if it's part of the public API.
160
- 3. Use `createGit(directory)` to get a simple-git instance with the correct environment. `directory` is required (`baseDir`); never omit it so commands cannot inherit `process.cwd()`.
161
- 4. Use `runGitCommand(cwd, args)` for direct git command execution with better error handling.
162
- 5. Use `runGitCommandOrThrow(cwd, args, fallbackMessage)` for commands that must succeed.
163
- 6. Return consistent error messages; use `parseGitErrorText(error)` to extract meaningful git errors.
164
- 7. Update this file with the new function in the appropriate API section.
165
-
166
- ### SSH Key Handling
167
- - SSH keys are escaped and validated via `escapeSshKeyPath` to prevent command injection.
168
- - On Windows, paths are converted to MSYS format (`C:/path` → `/c/path`).
169
- - SSH_AUTH_SOCK is automatically resolved via `resolveSshAuthSock` (checks GPG agent, gpgconf).
170
-
171
- ### Working directory (simple-git)
172
- - Repository operations always pass an explicit `baseDir` (the opened project/directory path) into simple-git. Omitting `baseDir` would default to `process.cwd()`, which breaks when the server was launched from a neutral directory (e.g. `$HOME`) while the opened project lives elsewhere.
173
- - Global identity reads use the user home directory as `baseDir` (they do not need a repository).
174
- - A `GitError` / non-repository result from status or check must not abort project/session enumeration: routes return a soft non-repo payload and log a warning.
175
-
176
- ### Worktree Naming
177
- - Worktree names are slugified via `slugWorktreeName`.
178
- - Random names use adjectives/nouns from `OPENCODE_ADJECTIVES` and `OPENCODE_NOUNS` lists.
179
- - Branches created for new worktrees use `aiworker/<worktree-name>` pattern.
180
-
181
- ### Cross-Platform Considerations
182
- - Use `normalizeDirectoryPath` for all directory inputs to handle `~` and path separators.
183
- - Use `canonicalPath` for path comparisons to handle case-insensitive filesystems (Windows).
184
- - Windows Git commands use MSYS/MinGW paths; avoid direct Windows paths in git commands.
185
-
186
- ### Error Handling
187
- - All exported functions should throw errors with descriptive messages.
188
- - Use `console.error` for logging Git operation failures.
189
- - Return structured objects for operations that need partial success reporting (e.g., merge/rebase conflicts).
190
-
191
- ### Testing
192
- - Run `bun run type-check`, `bun run lint`, and `bun run build` before finalizing changes.
193
- - Consider edge cases: non-Git directories, missing remotes, conflict states, concurrent worktree operations.
@@ -1,183 +0,0 @@
1
- # GitHub Module Documentation
2
-
3
- ## Purpose
4
-
5
- - This module owns GitHub auth, Octokit access, repo resolution, and Pull Request status resolution for AiWorker.
6
- - From user perspective, this is the layer that lets the app know which PR belongs to a local branch and keeps that UI feeling current.
7
-
8
- ## Entrypoints and structure
9
-
10
- - `packages/web/server/lib/github/index.js`: public server entrypoint. `routes.js` loads it lazily with `await import('./index.js')` and destructures the handler it needs, so a re-export removed from here breaks a route at request time rather than at build time. Static "unused export" reports do not see these consumers.
11
- - `packages/web/server/lib/github/routes.js`: Express route registration for `/api/github/*` endpoints.
12
- - `packages/web/server/lib/github/auth.js`: auth storage, multi-account support, client id, scope config.
13
- - `packages/web/server/lib/github/device-flow.js`: OAuth device flow.
14
- - `packages/web/server/lib/github/octokit.js`: Octokit factory for the current auth.
15
- - `packages/web/server/lib/github/repo/index.js`: remote URL parsing and directory-to-repo resolution.
16
- - `packages/web/server/lib/github/pr-status.js`: PR lookup across remotes, forks, and upstreams.
17
- - `packages/web/server/index.js`: API route layer that calls this module.
18
- - `packages/web/src/api/github.ts`: web client wrapper for GitHub endpoints.
19
-
20
- ## Public exports
21
-
22
- ### Auth
23
-
24
- - `getGitHubAuth()`: current auth entry.
25
- - `getGitHubAuthAccounts()`: all configured accounts.
26
- - `setGitHubAuth({ accessToken, scope, tokenType, user, accountId })`: save or update account.
27
- - `activateGitHubAuth(accountId)`: switch active account.
28
- - `clearGitHubAuth()`: clear current account.
29
- - `getGitHubClientId()`: resolve client id.
30
- - `getGitHubScopes()`: resolve scopes.
31
- - `GITHUB_AUTH_FILE`: auth file path.
32
-
33
- ### Device flow
34
-
35
- - `startDeviceFlow({ clientId, scope })`: request device code.
36
- - `exchangeDeviceCode({ clientId, deviceCode })`: poll for access token.
37
-
38
- ### Octokit
39
-
40
- - `getOctokitOrNull()`: current Octokit or `null`.
41
-
42
- ### Repo
43
-
44
- - `parseGitHubRemoteUrl(raw)`: parse SSH or HTTPS remote URL into `{ owner, repo, url }`.
45
- - `resolveGitHubRepoFromDirectory(directory, remoteName)`: resolve GitHub repo from a local git remote.
46
-
47
- ## Auth storage and config
48
-
49
- - Auth storage: `~/.config/openchamber/github-auth.json`
50
- - Writes are atomic and file mode is `0o600`.
51
- - Client ID resolution order: `AIWORKER_GITHUB_CLIENT_ID` -> `settings.json` -> default.
52
- - Scope resolution order: `AIWORKER_GITHUB_SCOPES` -> `settings.json` -> default.
53
- - Account id resolution order: explicit `accountId` -> user login -> user id -> token prefix.
54
-
55
- ## PR integration overview
56
-
57
- - The UI asks `github.prStatus(directory, branch, remote?)` from `packages/web/src/api/github.ts`.
58
- - That hits `GET /api/github/pr/status` in `packages/web/server/index.js`.
59
- - The route calls `resolveGitHubPrStatus(...)` in `packages/web/server/lib/github/pr-status.js`.
60
- - The resolver finds the most likely repo and PR for a local branch.
61
- - The route then enriches that result with checks, mergeability, and permission-related fields.
62
- - The client caches and shares the result between sidebar and Git view.
63
-
64
- ## Consumers of PR data
65
-
66
- - `packages/ui/src/components/session/SessionSidebar.tsx` reads all PR entries and maps them to `directory::branch`.
67
- - `packages/ui/src/components/session/sidebar/SessionGroupSection.tsx` renders the compact badge, PR number, title, checks summary, and GitHub link.
68
- - `packages/ui/src/components/views/git/PullRequestSection.tsx` uses the same shared entry for the full PR workflow.
69
- - `packages/ui/src/components/ui/MemoryDebugPanel.tsx` reads request counters for debugging.
70
-
71
- ## How PR resolution works
72
-
73
- - It reads local git status and remotes first.
74
- - It ranks remotes in this order: explicit remote, tracking remote, `origin`, `upstream`, then the rest.
75
- - It resolves those remotes into GitHub repos.
76
- - It expands each repo through `parent` and `source` so PRs in upstream repos can still be found.
77
- - It skips PR lookup when the current branch matches that repo's default branch.
78
- - It first searches for **open** PRs by likely source owner plus exact head branch.
79
- - If that fails, it falls back to broader GitHub search for open PRs on the branch name.
80
- - An **open PR from any candidate repo always wins** over a closed/merged one, so a merged fork PR can never hide an open upstream PR for the same head.
81
- - Only when no target has an open PR does it return the branch's newest closed/merged PR, as history.
82
- - History is looked up **only for the ranked-first remote and the branch's own name** — the repo it actually pushes to. Live status is worth searching the whole fork network for; history is not, and asking every target for it multiplies serial GitHub calls until the route hits its `12s` resolve timeout and returns no status at all.
83
- - The history answer is remembered per repo+branch so discovery polls do not re-query it: a found closed/merged record for `6h`, and "no history yet" for `10m`. A found record only changes if a second PR appears on the same head, and while that one is open the open-PR path wins without ever reading this cache.
84
- - Creating, merging, or closing a PR invalidates both the shared repo pull list and that remembered history.
85
- - The route skips the checks summary and the merge-permission lookup for a closed/merged PR: neither is actionable, and both cost extra GitHub calls.
86
- - `403` and `404` during repo lookups are treated as expected gaps, not hard errors.
87
-
88
- ## Shared client state model
89
-
90
- - Client key is effectively `directory::branch`.
91
- - One entry stores last known status, loading state, error, timestamps, watcher count, identity, and resolved remote.
92
- - Requests are deduplicated by branch signature, not by component instance.
93
- - This keeps sidebar and Git view aligned and avoids duplicated fetches.
94
-
95
- ## Persistence
96
-
97
- - PR state is persisted in local storage under `aiworker.github-pr-status`.
98
- - Persisted fields include status, timestamps, identity, and resolved remote.
99
- - Runtime-only details are not persisted.
100
- - Persisted entries expire after 12 hours.
101
- - On reload, users get last known state first, then background refresh resumes.
102
-
103
- ## Polling and refresh model
104
-
105
- - There are two layers: entry-level polling in `useGitHubPrStatusStore` and repo scanning in `useGitHubPrBackgroundTracking`.
106
- - Entry-level polling decides when a known branch should revalidate PR state.
107
- - Background tracking decides which directories and branches should even be watched.
108
-
109
- ## Entry-level polling rules
110
-
111
- - Start watching -> immediate refresh.
112
- - If no PR is found yet -> retry after `2s` and `5s`.
113
- - Still no PR -> discovery refresh every `5m`.
114
- - Open PR with pending checks -> refresh about every `1m`.
115
- - Open PR with non-pending checks -> refresh about every `5m`.
116
- - Open PR without a stable checks signal -> refresh about every `2m`.
117
- - Closed or merged PR -> discovery refresh every `5m` (do not permanently stop polling).
118
- - Hidden tab -> skip polling.
119
- - Non-forced refreshes use a `90s` TTL.
120
- - Failed non-forced attempts also observe the `90s` TTL so transient server or rate-limit failures cannot retry on every sidebar update. Forced user/action refreshes bypass this guard.
121
-
122
- ## Persistence notes for terminal PRs
123
-
124
- - Closed/merged branch associations are persisted like open ones, so a reload still shows that the branch's PR was merged.
125
- - Hydrate resets `lastDiscoveryPollAt` for them, so restored history revalidates on the first watcher tick instead of waiting out a discovery interval.
126
-
127
- ## Background tracking rules
128
-
129
- - Track up to `50` likely directories.
130
- - Sources are current directory, projects, worktrees, active sessions, and archived sessions.
131
- - Active directory branch TTL is `15s`.
132
- - Background directory branch TTL is `2m`.
133
- - Background scan wakes every `15s`, but only fetches directories whose TTL expired.
134
- - Each scan reads `branch`, `tracking`, `ahead`, and `behind` from git status.
135
- - If any of those branch signals change, that branch's PR status refreshes immediately.
136
- - After that, one more delayed refresh runs after `5s` to catch GitHub eventual consistency.
137
-
138
- ## UI refresh triggers
139
-
140
- - App or tab becomes visible.
141
- - Window regains focus.
142
- - Current branch changes.
143
- - Tracking branch changes.
144
- - Ahead or behind changes.
145
- - User selects a different remote in Git view.
146
- - GitHub auth state changes.
147
-
148
- ## Action-based refreshes in Git view
149
-
150
- - After `Create PR` -> refresh now, then after `2s` and `5s`.
151
- - After `Merge PR` -> refresh now, then after `2s` and `5s`.
152
- - After `Mark ready for review` -> refresh now, then after `2s` and `5s`.
153
- - After `Update PR` -> refresh now, then after `2s` and `5s`.
154
-
155
- ## Sidebar behavior
156
-
157
- - Sidebar shows only compact PR state.
158
- - Aggregation is by `directory::branch`, so multiple sessions on one branch share one signal.
159
- - If multiple entries exist, sidebar keeps the strongest visible PR state.
160
- - Visual state is based on PR health, not merge permissions.
161
-
162
- ## Git view behavior
163
-
164
- - Git view watches one branch directly.
165
- - It supports create, edit, mark ready, and merge.
166
- - It can probe alternate remotes so fork-heavy setups still find the right PR.
167
- - It uses the same shared store as the sidebar.
168
-
169
- ## Failure handling
170
-
171
- - If GitHub is disconnected, API returns `connected: false`.
172
- - If a repo is private or inaccessible, resolver calls may quietly return no PR.
173
- - Sidebar stays quiet on missing or inaccessible PR state.
174
- - Git view is where explicit PR-level problems should be shown.
175
-
176
- ## Notes for contributors
177
-
178
- - Keep the UI calm. Do not add noisy diagnostics to the sidebar.
179
- - Prefer shared state over per-component fetches.
180
- - Prefer event-shaped refreshes over blind frequent polling.
181
- - Prefer correctness for fork and multi-remote setups over assuming `origin` is enough.
182
- - Device flow handles GitHub `authorization_pending` at caller level.
183
- - Repo parser supports `git@github.com:`, `ssh://git@github.com/`, and `https://github.com/`.
@@ -1,97 +0,0 @@
1
- # Linear Module Documentation
2
-
3
- ## Purpose
4
-
5
- This module owns Linear OAuth, issue lookup, Linear-team-to-project mapping, issue status updates, and session status comments on Linear issues. Credentials live on the AiWorker server, so web, desktop, and a phone paired to that host share them. You can store more than one Linear workspace; exactly one is current. Issue list, mapping, and new OAuth default to the current workspace. Session status comments use the workspace that started the session. The right-hand context panel lists issues for the current workspace, can switch workspace, filters the list, shows a read-only card, changes status or closes the issue, and starts a session or worktree. Start session stays visible in a footer while the issue card scrolls. The chat picker lists issues and attaches them to a message. New Worktree can also start from a Linear issue in the currently active project. A session started from a Linear issue can post started/completed/failure comments, each with an AiWorker session link. Those comments are opt-in and only appear when this server has a publicly reachable address.
6
-
7
- VS Code omits Linear (`RuntimeAPIs.linear` is optional). Hide Linear UI when the API is missing.
8
-
9
- ## Entrypoints and structure
10
-
11
- - `packages/web/server/lib/linear/index.js`: public server entrypoint. `routes.js` loads it lazily with `await import('./index.js')`.
12
- - `packages/web/server/lib/linear/routes.js`: Express registration for the public callback, `/api/linear/auth/*`, `/api/linear/issues/*`, `/api/linear/mapping`, and `/api/linear/session-status`.
13
- - `packages/web/server/lib/linear/auth.js`: auth file, client id, scopes, redirect URI.
14
- - `packages/web/server/lib/linear/oauth.js`: authorization-code + PKCE S256, public callback broker handoff, refresh, revoke.
15
- - `packages/web/server/lib/linear/client.js`: GraphQL helper, viewer/organization lookup, and access-token refresh. GraphQL errors prefer `extensions.userPresentableMessage` / validation constraints over the generic `Argument Validation Error` label. User-facing Linear errors set `LinearApiError.userError`. Requests send `public-file-urls-expire-in: 3600` so file URLs in issue descriptions and comments are temporarily readable in the panel.
16
- - `packages/web/server/lib/linear/issues.js`: list/search/get issues, team workflow states, `issueUpdate`, and `commentCreate`. Parses identifiers and Linear URLs. `issueUpdate` resolves identifiers to UUIDs first because Linear's mutation does not accept `ENG-12`. List/get include `state.id`, `priority` (0–4), and labels (`id`, `name`, sanitized hex `color`) so the panel can show them and update status.
17
- - `packages/web/server/lib/linear/teams.js`: list Linear teams for mapping UI.
18
- - `packages/web/server/lib/linear/mapping.js`: persist default and per-team AiWorker project paths. Separate from the auth file so disconnect does not wipe maps.
19
- - `packages/web/server/lib/linear/status.js`: persist per-session started/completed/failure flags and post the matching Linear comment with an open-session URL. Posts nothing unless the user opted in and the session origin is public; `isPublicSessionOrigin` rejects loopback, private LAN, carrier-grade NAT, link-local and single-label hosts. The dedupe file keeps the newest 500 sessions.
20
- - `packages/web/server/lib/linear/status-runtime.js`: on the OpenCode event hub, first `session.status` idle after started posts completed once; `session.error` (except abort) posts failure once.
21
- - `packages/web/src/api/linear.ts`: web client wrapper. Electron and hosted/Capacitor mobile reuse it. VS Code omits `linear`.
22
-
23
- ## Public routes
24
-
25
- - `GET /linear/oauth/callback`: public fallback for an explicitly configured direct redirect URI. The built-in flow uses the stable callback broker instead, because desktop and self-hosted instances may have private or dynamic addresses.
26
- - `GET /api/linear/auth/status`: connected flag, current user/organization/scope, and `workspaces` (id, name, current, user, authorizedAt). Never returns tokens. A 401 on the current workspace drops that workspace only; if another remains, status returns that one instead of disconnected. Identity refresh does not bump `authorizedAt`.
27
- - `POST /api/linear/auth/start`: returns `{ authorizationUrl, expiresIn, scope }`. Body may include `origin: "desktop"` so the callback page can raise the desktop window. The authorize URL uses `prompt=consent` so Add workspace can pick a different Linear org. Completing OAuth stores or replaces that org and makes it current.
28
- - `POST /api/linear/auth/activate`: body `{ organizationId }`. Makes that stored workspace current. 400 if the id is missing, 404 if it is not stored.
29
- - `DELETE /api/linear/auth`: revokes the current workspace refresh token when present, then drops that workspace only. Other stored workspaces stay. Mapping is kept.
30
- - `GET /api/linear/issues/list?query=&cursor=&status=&assignee=&teamId=&priority=`: issues from the current workspace. Omitted `status` is incomplete states (same as the chat picker). The panel sends `all`, `backlog`, `todo` (Linear `unstarted`), `started` (In Progress, excluding the In Review name), `inReview` (state name In Review), `completed` (Done), `canceled` (excluding the Duplicate name), or `duplicate` (state type or name Duplicate). `assignee` is `any` (default) or `me`. `teamId` limits the list to that Linear team. `priority` is `all` (default), `none`, `urgent`, `high`, `medium`, or `low`. An identifier or Linear URL returns that issue even if it is completed and ignores the other filters. Each issue includes `state.id` when Linear sends it, plus `priority` (0 none through 4 low) and `labels`. Never returns tokens.
31
- - `GET /api/linear/issues/get?id=`: one issue by UUID or identifier, including description, comments, team, `state.id`, priority, and labels.
32
- - `GET /api/linear/issues/states?teamId=`: workflow states for that Linear team (`id`, `name`, `type`, `position`), ordered like Linear's workflow: type (backlog, unstarted, started, completed, canceled) then position. Missing `teamId` is 400. Linear not-found or validation errors are 400 with Linear's presentable message. Disconnected is `{ connected: false }` with HTTP 200.
33
- - `POST /api/linear/issues/update`: body `{ id, stateId }`. `id` may be a UUID, identifier, or Linear URL; identifiers are resolved before `issueUpdate` because Linear's mutation requires a UUID. Returns the updated issue. Closing an issue is this same call with the team's first `type: completed` state. Missing `id` or `stateId` is 400. Linear validation (for example a non-UUID `stateId`) is 400 with Linear's presentable message. A GraphQL 401 clears that workspace only. Disconnected is `{ connected: false }` with HTTP 200.
34
- - `GET /api/linear/mapping`: stored default project plus live Linear teams with their mapped paths. Missing file is empty mapping. Malformed file is 500, not empty success. Disconnected is `{ connected: false }` with HTTP 200.
35
- - `PUT /api/linear/mapping`: replace default project and per-team paths. Body `{ defaultProjectPath, teamProjectPaths }`. Failed write does not touch tokens. Disconnected is `{ connected: false }` and does not save.
36
- - `GET /api/linear/preferences`: `{ sessionComments }`. `PUT /api/linear/preferences` with body `{ sessionComments: boolean }` replaces it and returns the stored value. A non-boolean body is 400. The preference is server-side because the event hub posts completed/failure without going through the interface.
37
- - `POST /api/linear/session-status`: post a started/completed/failure comment on the linked Linear issue. Body `{ kind, sessionId, issueIdentifier?, sessionOrigin? }`. `started` requires `issueIdentifier`. `completed` and `failure` reuse the stored issue and open URL from `started`. Each kind posts at most once per session. Answers in this order: disconnected is `{ connected: false }` with HTTP 200; comments turned off is `skipped: 'disabled'`; a `sessionOrigin` nobody else can reach is `skipped: 'origin-not-public'`. `sessionOrigin` must be `http` or `https` with no path, and must resolve to a public host — loopback, private LAN and desktop deep links post no comment at all rather than a link only its author can open. Comment bodies are one markdown link: `[AiWorker session started](url)` so Linear keeps the `?session=` query. The comment carries no issue or session title: it already sits on the issue, and titles routinely contain brackets that would break the link. Invalid body is 400.
38
-
39
- `POST /api/linear/auth/start`, `PUT /api/linear/mapping`, `POST /api/linear/issues/update`, and `POST /api/linear/session-status` parse JSON on the route (`16kb`). They are not on the `/api` 50mb allowlist.
40
-
41
- Disconnected list/get/states/update/mapping/session-status return `{ connected: false }` with HTTP 200 so the picker and panel can show an empty state. Missing `id` on get is 400. Missing `teamId` on states is 400.
42
-
43
- ## Auth storage and config
44
-
45
- - Auth storage: `~/.config/openchamber/linear-auth.json` (or `$AIWORKER_DATA_DIR/linear-auth.json`). Shape is `{ workspaces: [ { accessToken, refreshToken, user, organization, workspaceId, current, authorizedAt, ... } ] }`. `workspaceId` is the Linear organization id, or `user:<id>` when there is no org, or `legacy` for a migrated token with neither. A legacy single-object file is rewritten to this list on read. Reconnecting the same org replaces that slot.
46
- - Mapping storage: `~/.config/openchamber/linear-mapping.json` (same data dir). Shape is `{ workspaces: { [workspaceId]: { defaultProjectPath, teamProjectPaths } } }`. Reads and writes use the current workspace slice. A legacy flat file is wrapped under the current workspace id on read. Disconnect does not wipe maps. Writes are atomic and file mode is `0o600`.
47
- - Session status storage: `~/.config/openchamber/linear-session-status.json` (same data dir). Writes are atomic and file mode is `0o600`. Dedupes started/completed/failure per AiWorker session id.
48
- - Writes are atomic and file mode is `0o600`.
49
- - Client ID: `AIWORKER_LINEAR_CLIENT_ID` -> `settings.json` `linearClientId` -> baked-in public default.
50
- - Client secret: `AIWORKER_LINEAR_CLIENT_SECRET` -> `settings.json` `linearClientSecret`. Optional with PKCE. Do not commit a secret.
51
- - Scopes: `AIWORKER_LINEAR_SCOPES` -> `settings.json` `linearScopes` -> `read,write,comments:create`.
52
- - Session comments: `settings.json` `linearSessionComments`, boolean, absent means off. Written only through `PUT /api/linear/preferences`.
53
- - Broker URL: `AIWORKER_LINEAR_BROKER_URL` -> `settings.json` `linearBrokerUrl` -> `https://api.aiworker.dev/v1/oauth/linear`.
54
- - Redirect URI: `AIWORKER_LINEAR_REDIRECT_URI` -> `settings.json` `linearRedirectUri` -> `<broker-url>/callback`. Setting an explicit redirect URI bypasses the broker for custom/self-hosted OAuth applications.
55
-
56
- Linear requires an exact callback match. The built-in application registers `https://api.aiworker.dev/v1/oauth/linear/callback`; the broker holds only the short-lived authorization code. The local AiWorker server keeps the claim secret and PKCE verifier, exchanges the code for tokens locally, then acknowledges the handoff. Custom brokers must expose `/start`, `/callback`, `/poll`, and `/complete` with the same contract.
57
-
58
- ## OAuth contract
59
-
60
- - Authorization code + PKCE S256. Linear has no device flow.
61
- - The broker stores hashes of OAuth state and a separate claim secret for ten minutes. It never receives the PKCE verifier or Linear tokens. The local status polling path claims a completed broker result and persists tokens on the AiWorker server.
62
- - Access tokens expire in 24 hours. Refresh tokens rotate; persist the new refresh token from every successful refresh. Concurrent refreshes share one in-flight promise per workspace.
63
- - `invalid_grant` / 401 on refresh clears that workspace only so a dead token cannot loop. If it was the last workspace, status becomes disconnected.
64
- - A GraphQL 401 after a valid-looking token also clears that workspace. A network failure while a token is stored does not: status stays connected with the last known user.
65
-
66
- ## Project mapping
67
-
68
- AiWorker has projects (directories), not accounts or organizations. Mapping is how create-session (picker and the right-hand panel) picks a directory:
69
-
70
- 1. If the issue's Linear team has a project path, use that.
71
- 2. Otherwise use the default project path.
72
- 3. If neither is set, the UI tells the user to map the team in Settings → Integrations. It does not fall back to the currently active project.
73
-
74
- A worktree started from the panel or picker is created in that mapped project. New Worktree from Git is different: it stays in the currently active project.
75
-
76
- ## Shared UI
77
-
78
- - `RuntimeAPIs.linear` is optional. Hide Linear settings, the chat picker, and the panel when it is missing (VS Code).
79
- - Store: `packages/ui/src/stores/useLinearAuthStore.ts`. App start refreshes it from `App.tsx` and `MobileApp.tsx`, not `VSCodeApp`.
80
- - Settings: first-party section on the Integrations page. Connect opens the authorization URL and polls status until the workspace list or current `authorizedAt` changes, so Add workspace is not treated as done just because a workspace was already connected. When connected, map a default project and optional per-team projects for the current workspace. Other stored workspaces appear in a list with Switch to. Disconnect removes the current workspace only. The panel can also switch the current workspace when more than one is stored.
81
- - Context panel: desktop/web right-hand rail surface `linear` (`packages/ui/src/components/views/LinearIssuesView.tsx`). Singleton like git/pr. The rail icon is hidden until a Linear workspace is connected; disconnecting while the panel is open closes it. List/search defaults to all issues; the status filter is All, Backlog, To Do, In Progress, In Review, Done, Canceled, and Duplicate, matching the card status order. Identifier/URL still finds completed. Status, assignee, team, and priority filters persist in `useUIStore` so they survive rail switches. Non-default list filters and search tint the filter icon `text-primary`, same as the context rail; one control clears them, not the workspace switch. Changing those filters keeps the previous list until the next page arrives and does not disable the filter row. On a narrow panel search and the filters other than status drop to icons; status keeps its label. The card shows priority and labels. Comments render as an avatar timeline matching the pull request panel, so both context surfaces read alike; comment authors carry `avatarUrl`. The card is read-only except status (`issueUpdate`) and Close (first completed workflow state). Start session stays in a footer while the description and comments scroll. Start session / worktree share `startLinearIssueSession` with the picker. No create-issue, no writing comments, no polling. VS Code and the mobile workspace drawer omit this rail.
82
- - Chat: composer attach menu "Link Linear Issue" attaches body and comments as `linear-issue` context on the next send. Exclusive with a linked GitHub issue or PR. The attached issue is stored on session metadata (`kind: 'linear'`) so work status can show it. Clicking that work-status row opens the Linear rail when Linear is connected on desktop/web; otherwise the Linear URL. Managed Chats do not offer start-from-issue; those sessions have no project directory.
83
- - Worktree: New Worktree can start from a Linear issue. It uses the currently active project and does not consult team-to-project mapping. GitHub issue/PR and Linear issue are exclusive on that form.
84
- - Status comments: off until the user turns them on in Settings -> Integrations -> Linear (`LinearSessionComments.tsx`). When on, create-session and worktree-from-Linear post `started` after the session exists. The event hub posts `completed` on the first idle after that, and `failure` on `session.error` except `MessageAbortedError`. Failed comments must not fail session create. Comment bodies are English (they live on Linear) and are one markdown link named `AiWorker session started` (or completed/failed). Web uses `/?session=<id>` on the current origin; desktop reports the loopback origin its own server listens on, not `openchamber-ui://`. A Linear comment is read by the whole team, so the server posts nothing when that origin is not publicly reachable rather than publishing a link only its author could open. Opening `/?session=` selects that session after the global session list can resolve its directory.
85
- - Magic prompts: `linear.issue.review.visible` / `.instructions`. Do not reuse the GitHub issue-review templates for Linear.
86
-
87
- ## Notes for contributors
88
-
89
- The implementation and deployment hand-off for the stable callback broker is
90
- in [`OAUTH-BROKER-HANDOFF.md`](./OAUTH-BROKER-HANDOFF.md). It records the exact
91
- Linear redirect URI that must be registered and why the original loopback
92
- callback could not support packaged desktop or arbitrary self-hosted servers.
93
-
94
- - Do not log tokens, codes, verifiers, or the client secret.
95
- - Do not add Linear under Git or as a third-party plugin row.
96
- - Actor is `user`. Do not enable Linear client-credentials tokens for this flow.
97
- - One OAuth grant is still one Linear organization. The server stores many grants and keeps one current. Webhooks and inbound Linear issue actions are out of scope until a later change.
@@ -1,91 +0,0 @@
1
- # Linear OAuth broker hand-off
2
-
3
- ## Required Linear application change
4
-
5
- Register this exact redirect URI in the Linear OAuth application used by the
6
- baked-in client ID:
7
-
8
- `https://api.aiworker.dev/v1/oauth/linear/callback`
9
-
10
- Linear compares the full redirect URI, including scheme, host, path, and port.
11
- Deploy the API broker and apply its D1 migration before testing this branch.
12
-
13
- ## Why the original callback failed
14
-
15
- The first implementation redirected Linear back to the AiWorker server:
16
-
17
- `http://127.0.0.1:<listen-port>/linear/oauth/callback`
18
-
19
- That address is not stable across AiWorker runtimes:
20
-
21
- - packaged desktop prefers its stored local port and can select another free
22
- port when needed;
23
- - local development and the CLI use different ports;
24
- - self-hosted servers may sit behind a reverse proxy or have no public inbound
25
- address at all.
26
-
27
- Linear requires an exact pre-registered callback. Registering every possible
28
- desktop or self-hosted address is impossible, and forcing desktop onto one port
29
- would make startup fail whenever another process owns that port.
30
-
31
- ## New flow
32
-
33
- The built-in Linear client now uses the stable callback broker in
34
- `openchamber-website/apps/api`:
35
-
36
- 1. The AiWorker server generates OAuth state, a PKCE verifier, and a separate
37
- claim secret.
38
- 2. The broker stores only hashes of state and the claim secret for ten minutes.
39
- 3. Linear sends its authorization code to the stable public callback.
40
- 4. The AiWorker server polls the broker with state and the claim secret.
41
- 5. The AiWorker server exchanges the code using the PKCE verifier and stores
42
- the Linear tokens locally.
43
- 6. After persistence succeeds, AiWorker acknowledges the hand-off and the
44
- broker marks it consumed.
45
-
46
- The broker never receives the PKCE verifier, access token, or refresh token.
47
- Private Relay is not involved; the local server only needs outbound HTTPS.
48
-
49
- ## Compatibility and configuration
50
-
51
- - `AIWORKER_LINEAR_BROKER_URL` or `settings.json` `linearBrokerUrl` selects a
52
- self-hosted broker. The default is
53
- `https://api.aiworker.dev/v1/oauth/linear`.
54
- - `AIWORKER_LINEAR_REDIRECT_URI` or `settings.json` `linearRedirectUri`
55
- bypasses the broker and preserves the direct callback flow for a custom
56
- Linear OAuth application.
57
-
58
- ## Owning files
59
-
60
- AiWorker:
61
-
62
- - `auth.js`: broker and redirect configuration.
63
- - `oauth.js`: PKCE, broker registration/poll/acknowledgement, token exchange.
64
- - `routes.js`: starts authorization and completes broker results during status
65
- polling.
66
-
67
- Hosted API, in the `openchamber-website` repository:
68
-
69
- - `apps/api/src/routes/linear-oauth.ts`
70
- - `apps/api/migrations/0010_linear_oauth_transactions.sql`
71
- - `apps/api/LINEAR-OAUTH.md`
72
-
73
- ## Validation
74
-
75
- AiWorker focused tests:
76
-
77
- ```sh
78
- bunx vitest run \
79
- packages/web/server/lib/linear/oauth.test.js \
80
- packages/web/server/lib/linear/auth.test.js \
81
- packages/web/server/lib/linear/routes.test.js
82
- ```
83
-
84
- Hosted API checks:
85
-
86
- ```sh
87
- cd apps/api
88
- bun test src/routes/linear-oauth.test.ts
89
- bun run check
90
- bun run build
91
- ```
@@ -1,40 +0,0 @@
1
- # Markdown Image Grants
2
-
3
- ## Purpose
4
-
5
- This module lets the Markdown image gallery display images that an assistant
6
- explicitly referenced from OpenCode's temporary directory when the UI is on a
7
- different machine.
8
-
9
- ## Contract
10
-
11
- - Chat Markdown rendering is independent: assistant image syntax renders as an
12
- icon and filename, while the gallery only reads finalized Markdown to collect
13
- image candidates.
14
- - `POST /api/openchamber/sessions/:sessionId/markdown-image-grants` prepares up to 12
15
- local images in one message-level request. The server fetches the assistant
16
- message once and verifies every exact image source before reading files.
17
- - Authorization recognizes the same common inline and reference-style image
18
- destinations collected by the UI, including balanced parentheses, while
19
- excluding fenced and inline code.
20
- - Relative and workspace-contained absolute paths resolve against the active
21
- directory. Other absolute paths are accepted only inside
22
- `os.tmpdir()/opencode` after `realpath` resolution.
23
- - PNG, JPEG, GIF, and WebP files are signature-checked and limited to 10 MiB.
24
- - Prepare requests inspect only file metadata and signatures. Workspace images
25
- reuse the existing authenticated `/api/fs/raw` asset route directly. Images
26
- under `os.tmpdir()/opencode` receive the existing path-bound `raw`
27
- `outsideFileGrant`; this module does not add another asset lifetime, copy, or
28
- storage layer. Missing files return per-source results so the gallery can
29
- remove only those items.
30
-
31
- The routes are AiWorker-owned and must be registered before the generic
32
- OpenCode proxy. Web, Electron, hosted mobile, and Capacitor use the shared
33
- server implementation. VS Code does not call this route for workspace images;
34
- those use its local filesystem bridge. If called, the grant route returns an
35
- explicit unsupported response because OpenCode temporary images are not
36
- supported there.
37
-
38
- Requests to OpenCode carry the directory in a percent-encoded
39
- `x-opencode-directory` header, matching the SDK wire format; OpenCode rejects
40
- raw non-ASCII header values.