@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
@@ -0,0 +1,214 @@
1
+ // The two settings files and how a merged document is split between them.
2
+ //
3
+ // `settings.json` holds instance facts (and, untouched, whatever legacy keys
4
+ // older builds left there). `preferences.json` holds the user's profile: the
5
+ // keys the settings registry marks `profile`, each with the time the store
6
+ // last accepted a new value for it. Device keys never reach either file.
7
+ //
8
+ // The VS Code extension host writes the same two files with the same shape
9
+ // (`packages/vscode/src/settings-files.ts`); keep the format changes in sync.
10
+ import { createRequire } from 'node:module';
11
+
12
+ const registry = createRequire(import.meta.url)('./settings-registry.json');
13
+
14
+ const PREFERENCES_FILE_NAME = 'preferences.json';
15
+ const PREFERENCES_DOCUMENT_VERSION = 1;
16
+
17
+ /** The registry scope for a key, or `null` when the registry does not know it. */
18
+ const getSettingsScope = (key) => registry.fields[key]?.scope ?? null;
19
+
20
+ export const isProfileSettingsKey = (key) => getSettingsScope(key) === 'profile';
21
+ export const isDeviceSettingsKey = (key) => getSettingsScope(key) === 'device';
22
+
23
+ /** Profile keys the owner chose to store per surface kind (a change on a phone stays on phones). */
24
+ const isPerSurfaceSettingsKey = (key) => registry.fields[key]?.perSurface === true;
25
+
26
+ const SETTINGS_SURFACES = Object.freeze(['web', 'desktop', 'vscode', 'mobile']);
27
+
28
+ export const normalizeSettingsSurface = (value) => (
29
+ typeof value === 'string' && SETTINGS_SURFACES.includes(value.trim()) ? value.trim() : null
30
+ );
31
+
32
+ /**
33
+ * Which surface kind a settings request comes from; `null` means "base".
34
+ * Clients send `?surface=<kind>` (a query parameter keeps the request
35
+ * CORS-simple for cross-origin shells and older instances); the
36
+ * `x-openchamber-surface` header is still honoured for clients that sent it.
37
+ */
38
+ export const settingsSurfaceOf = (req) => (
39
+ normalizeSettingsSurface(req.query?.surface) ?? normalizeSettingsSurface(req.get?.('x-openchamber-surface'))
40
+ );
41
+
42
+ export const preferencesFilePathFor = (settingsFilePath, path) => path.join(path.dirname(settingsFilePath), PREFERENCES_FILE_NAME);
43
+
44
+ const isPlainObject = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
45
+
46
+ const sameValue = (left, right) => {
47
+ if (left === right) return true;
48
+ if (left === undefined || right === undefined) return false;
49
+ return JSON.stringify(left) === JSON.stringify(right);
50
+ };
51
+
52
+ const parseStamp = (value) => (Number.isFinite(value) ? value : 0);
53
+
54
+ /**
55
+ * Parse the text of a preferences file. A missing file is the caller's case
56
+ * (ENOENT); anything that is not a version-1 document with a `fields` object
57
+ * is a failure, never an empty profile.
58
+ *
59
+ * An entry is `{ value, updatedAt }` for the base value, optionally with
60
+ * `surfaces: { [surface]: { value, updatedAt } }` for per-surface keys; a
61
+ * per-surface key that was only ever set from one surface kind has no base.
62
+ */
63
+ export const parsePreferencesDocument = (raw) => {
64
+ let parsed;
65
+ try {
66
+ parsed = JSON.parse(raw);
67
+ } catch (error) {
68
+ return { ok: false, reason: `invalid JSON: ${error instanceof Error ? error.message : String(error)}` };
69
+ }
70
+ if (!isPlainObject(parsed) || parsed.version !== PREFERENCES_DOCUMENT_VERSION || !isPlainObject(parsed.fields)) {
71
+ return { ok: false, reason: 'not a version-1 preferences document' };
72
+ }
73
+ const fields = {};
74
+ for (const [key, entry] of Object.entries(parsed.fields)) {
75
+ if (!isPlainObject(entry) || (!('value' in entry) && !isPlainObject(entry.surfaces))) {
76
+ return { ok: false, reason: `field "${key}" is not a { value, updatedAt } entry` };
77
+ }
78
+ const next = { updatedAt: parseStamp(entry.updatedAt) };
79
+ if ('value' in entry) next.value = entry.value;
80
+ if (isPlainObject(entry.surfaces)) {
81
+ next.surfaces = {};
82
+ for (const [surface, surfaceEntry] of Object.entries(entry.surfaces)) {
83
+ if (!SETTINGS_SURFACES.includes(surface) || !isPlainObject(surfaceEntry) || !('value' in surfaceEntry)) {
84
+ return { ok: false, reason: `field "${key}" has an invalid surface entry "${surface}"` };
85
+ }
86
+ next.surfaces[surface] = { value: surfaceEntry.value, updatedAt: parseStamp(surfaceEntry.updatedAt) };
87
+ }
88
+ }
89
+ fields[key] = next;
90
+ }
91
+ return { ok: true, fields };
92
+ };
93
+
94
+ export const serializePreferencesDocument = (fields) => JSON.stringify({ version: PREFERENCES_DOCUMENT_VERSION, fields }, null, 2);
95
+
96
+ /**
97
+ * The plain key → value view of preference fields as one surface kind sees it:
98
+ * that surface's own value first, the base value otherwise; a key with neither
99
+ * is absent (the client keeps what it holds, or its default).
100
+ */
101
+ export const flattenPreferences = (fields, surface = null) => {
102
+ const values = {};
103
+ for (const [key, entry] of Object.entries(fields)) {
104
+ const own = surface && entry.surfaces ? entry.surfaces[surface] : undefined;
105
+ if (own) {
106
+ values[key] = own.value;
107
+ } else if ('value' in entry) {
108
+ values[key] = entry.value;
109
+ }
110
+ }
111
+ return values;
112
+ };
113
+
114
+ /**
115
+ * The next preference fields for a merged document: every profile key it
116
+ * carries, stamped `now` when its value differs from what the file held and
117
+ * keeping the earlier stamp otherwise. Profile keys the document no longer
118
+ * carries are dropped (that is how a cleared key leaves the file).
119
+ *
120
+ * Per-surface keys: when the write comes from a surface kind (`surface`) and
121
+ * the key is among the keys that write changed (`changedKeys`), the value goes
122
+ * under `surfaces[surface]` and the base is left as it was; a per-surface key
123
+ * the write did not change keeps its whole entry (the document only carries
124
+ * that surface's resolved view of it). Without a surface (migrations, the
125
+ * one-time seed) the base is written.
126
+ */
127
+ export const buildPreferencesFields = (previousFields, document, now, { surface = null, changedKeys = null } = {}) => {
128
+ const fields = {};
129
+ const changed = changedKeys ? new Set(changedKeys) : null;
130
+ for (const [key, value] of Object.entries(document)) {
131
+ if (value === undefined || !isProfileSettingsKey(key)) continue;
132
+ const previous = previousFields[key];
133
+ if (isPerSurfaceSettingsKey(key) && surface) {
134
+ if (changed && !changed.has(key)) {
135
+ if (previous) fields[key] = previous;
136
+ continue;
137
+ }
138
+ const previousOwn = previous?.surfaces?.[surface];
139
+ const own = previousOwn && sameValue(previousOwn.value, value) ? previousOwn : { value, updatedAt: now };
140
+ fields[key] = {
141
+ ...(previous ?? { updatedAt: 0 }),
142
+ surfaces: { ...(previous?.surfaces ?? {}), [surface]: own },
143
+ };
144
+ continue;
145
+ }
146
+ if (previous && 'value' in previous && sameValue(previous.value, value)) {
147
+ fields[key] = previous;
148
+ } else {
149
+ fields[key] = { ...(previous ?? {}), value, updatedAt: now };
150
+ }
151
+ }
152
+ return fields;
153
+ };
154
+
155
+ /**
156
+ * The part of a merged document that belongs in `settings.json`: everything
157
+ * that is not a profile key. Device keys older builds persisted stay in place
158
+ * as a read-once seed for clients; the write path never adds new ones.
159
+ */
160
+ export const instancePartOf = (document) => {
161
+ const instance = {};
162
+ for (const [key, value] of Object.entries(document)) {
163
+ if (value === undefined || isProfileSettingsKey(key)) continue;
164
+ instance[key] = value;
165
+ }
166
+ return instance;
167
+ };
168
+
169
+ /** The profile keys of a document (the part `instancePartOf` leaves out). */
170
+ export const profilePartOf = (document) => {
171
+ const profile = {};
172
+ for (const [key, value] of Object.entries(document)) {
173
+ if (value !== undefined && isProfileSettingsKey(key)) profile[key] = value;
174
+ }
175
+ return profile;
176
+ };
177
+
178
+ /**
179
+ * What `settings.json` holds after a write: the instance part plus a copy of
180
+ * the profile's base values. The copy is for builds that predate the split —
181
+ * they read only this file, so a rollback still finds the user's preferences.
182
+ * Current builds ignore it: `preferences.json` wins in the merged read.
183
+ */
184
+ export const legacySettingsDocumentOf = (document, preferenceFields) => ({
185
+ ...instancePartOf(document),
186
+ ...flattenPreferences(preferenceFields),
187
+ });
188
+
189
+ /** The profile keys of a document, as they would seed a fresh preferences file. */
190
+ export const seedPreferencesFrom = (document, now) => buildPreferencesFields({}, document, now);
191
+
192
+ /**
193
+ * Synchronous merged read for server modules that consult one or two profile
194
+ * keys on a hot path (small-model resolution, goal/assist toggles). A missing
195
+ * or unreadable preferences file contributes nothing, and the caller's own
196
+ * default applies — the same "missing is not default" rule the clients use.
197
+ */
198
+ export const readMergedSettingsSync = ({ fs, path, settingsFilePath }) => {
199
+ let settings = {};
200
+ try {
201
+ const parsed = JSON.parse(fs.readFileSync(settingsFilePath, 'utf8'));
202
+ if (isPlainObject(parsed)) settings = parsed;
203
+ } catch {
204
+ settings = {};
205
+ }
206
+ let preferences = {};
207
+ try {
208
+ const parsed = parsePreferencesDocument(fs.readFileSync(preferencesFilePathFor(settingsFilePath, path), 'utf8'));
209
+ if (parsed.ok) preferences = flattenPreferences(parsed.fields);
210
+ } catch {
211
+ preferences = {};
212
+ }
213
+ return { ...settings, ...preferences };
214
+ };
@@ -1,5 +1,39 @@
1
+ import { createRequire } from 'node:module';
2
+
1
3
  import { isAgentMemoryFeatureAvailable } from '../agent-memory/feature-flag.js';
2
4
 
5
+ // Generated from packages/ui/src/lib/settings/registry.ts by
6
+ // `bun run settings-registry:generate`; `registry.test.ts` fails when stale.
7
+ // The server is plain ESM without a bundler, so the snapshot is read with
8
+ // `createRequire` (import attributes differ across the Node versions we run on).
9
+ const settingsRegistry = createRequire(import.meta.url)('./settings-registry.json');
10
+
11
+ /**
12
+ * Whether a client may persist this key through PUT /api/config/settings:
13
+ * it must be a registry key, not a server-computed flag, not a device field
14
+ * that only lives in the browser, and not one the desktop shell writes itself.
15
+ */
16
+ const isPersistableSettingsKey = (key) => {
17
+ const field = settingsRegistry.fields[key];
18
+ if (!field) return false;
19
+ if (field.computed || field.local) return false;
20
+ if (field.owner === 'desktop-shell') return false;
21
+ return true;
22
+ };
23
+
24
+ /** Keys accepted on write but never returned by a read. */
25
+ const SECRET_SETTINGS_KEYS = Object.freeze(
26
+ Object.entries(settingsRegistry.fields)
27
+ .filter(([, field]) => field.secret === true)
28
+ .map(([key]) => key),
29
+ );
30
+ import {
31
+ DEFAULT_INPUT_HISTORY_LIMIT,
32
+ DEFAULT_INPUT_HISTORY_SCOPE,
33
+ isInputHistoryLimit,
34
+ isInputHistoryScope,
35
+ } from './input-history-scope.js';
36
+
3
37
  export const createSettingsHelpers = (dependencies) => {
4
38
  const {
5
39
  normalizePathForPersistence,
@@ -12,7 +46,6 @@ export const createSettingsHelpers = (dependencies) => {
12
46
  normalizeManagedRemoteTunnelHostname,
13
47
  normalizeManagedRemoteTunnelPresets,
14
48
  normalizeManagedRemoteTunnelPresetTokens,
15
- sanitizeTypographySizesPartial,
16
49
  normalizeStringArray,
17
50
  sanitizeModelRefs,
18
51
  sanitizeSkillCatalogs,
@@ -140,6 +173,12 @@ export const createSettingsHelpers = (dependencies) => {
140
173
  if (typeof candidate.themeVariant === 'string' && (candidate.themeVariant === 'light' || candidate.themeVariant === 'dark')) {
141
174
  result.themeVariant = candidate.themeVariant;
142
175
  }
176
+ if (typeof candidate.inputHistoryScope === 'string' && isInputHistoryScope(candidate.inputHistoryScope)) {
177
+ result.inputHistoryScope = candidate.inputHistoryScope;
178
+ }
179
+ if (isInputHistoryLimit(candidate.inputHistoryLimit)) {
180
+ result.inputHistoryLimit = candidate.inputHistoryLimit;
181
+ }
143
182
  if (typeof candidate.useSystemTheme === 'boolean') {
144
183
  result.useSystemTheme = candidate.useSystemTheme;
145
184
  }
@@ -191,6 +230,9 @@ export const createSettingsHelpers = (dependencies) => {
191
230
  ...new Set(candidate.workStatusHiddenSections.filter((entry) => typeof entry === 'string' && entry.length > 0)),
192
231
  ];
193
232
  }
233
+ if (typeof candidate.workStatusHiddenSectionsExplicit === 'boolean') {
234
+ result.workStatusHiddenSectionsExplicit = candidate.workStatusHiddenSectionsExplicit;
235
+ }
194
236
  if (typeof candidate.desktopLanAccessEnabled === 'boolean') {
195
237
  result.desktopLanAccessEnabled = candidate.desktopLanAccessEnabled;
196
238
  }
@@ -301,9 +343,6 @@ export const createSettingsHelpers = (dependencies) => {
301
343
  if (typeof candidate.monoFont === 'string' && candidate.monoFont.length > 0) {
302
344
  result.monoFont = candidate.monoFont;
303
345
  }
304
- if (typeof candidate.markdownDisplayMode === 'string' && candidate.markdownDisplayMode.length > 0) {
305
- result.markdownDisplayMode = candidate.markdownDisplayMode;
306
- }
307
346
  if (typeof candidate.githubClientId === 'string') {
308
347
  const trimmed = candidate.githubClientId.trim();
309
348
  if (trimmed.length > 0) {
@@ -319,6 +358,45 @@ export const createSettingsHelpers = (dependencies) => {
319
358
  if (typeof candidate.showReasoningTraces === 'boolean') {
320
359
  result.showReasoningTraces = candidate.showReasoningTraces;
321
360
  }
361
+ if (typeof candidate.streamingAutoFollowEnabled === 'boolean') {
362
+ result.streamingAutoFollowEnabled = candidate.streamingAutoFollowEnabled;
363
+ }
364
+ if (typeof candidate.codeBlockLineWrap === 'boolean') {
365
+ result.codeBlockLineWrap = candidate.codeBlockLineWrap;
366
+ }
367
+ if (typeof candidate.autoSaveEnabled === 'boolean') {
368
+ result.autoSaveEnabled = candidate.autoSaveEnabled;
369
+ }
370
+ if (typeof candidate.diffWrapLines === 'boolean') {
371
+ result.diffWrapLines = candidate.diffWrapLines;
372
+ }
373
+ if (typeof candidate.persistChatDraft === 'boolean') {
374
+ result.persistChatDraft = candidate.persistChatDraft;
375
+ }
376
+ if (typeof candidate.allowPromptingSubagentSessions === 'boolean') {
377
+ result.allowPromptingSubagentSessions = candidate.allowPromptingSubagentSessions;
378
+ }
379
+ if (typeof candidate.showOpenCodeRestartConfirm === 'boolean') {
380
+ result.showOpenCodeRestartConfirm = candidate.showOpenCodeRestartConfirm;
381
+ }
382
+ if (typeof candidate.sessionTabsEnabled === 'boolean') {
383
+ result.sessionTabsEnabled = candidate.sessionTabsEnabled;
384
+ }
385
+ if (typeof candidate.largeTextPasteBehavior === 'string') {
386
+ const mode = candidate.largeTextPasteBehavior.trim();
387
+ if (mode === 'ask' || mode === 'attach' || mode === 'inline') {
388
+ result.largeTextPasteBehavior = mode;
389
+ }
390
+ }
391
+ if (typeof candidate.fileEditorKeymap === 'string') {
392
+ const mode = candidate.fileEditorKeymap.trim();
393
+ if (mode === 'default' || mode === 'vim') {
394
+ result.fileEditorKeymap = mode;
395
+ }
396
+ }
397
+ if (Array.isArray(candidate.providerOrder)) {
398
+ result.providerOrder = normalizeStringArray(candidate.providerOrder);
399
+ }
322
400
  if (typeof candidate.sessionRecapEnabled === 'boolean') {
323
401
  result.sessionRecapEnabled = candidate.sessionRecapEnabled;
324
402
  }
@@ -440,11 +518,6 @@ export const createSettingsHelpers = (dependencies) => {
440
518
  result.managedRemoteTunnelSelectedPresetId = id || undefined;
441
519
  }
442
520
 
443
- const typography = sanitizeTypographySizesPartial(candidate.typographySizes);
444
- if (typography) {
445
- result.typographySizes = typography;
446
- }
447
-
448
521
  if (typeof candidate.defaultModel === 'string') {
449
522
  const trimmed = candidate.defaultModel.trim();
450
523
  result.defaultModel = trimmed.length > 0 ? trimmed : undefined;
@@ -490,14 +563,6 @@ export const createSettingsHelpers = (dependencies) => {
490
563
  const trimmed = candidate.zenModel.trim();
491
564
  result.zenModel = trimmed.length > 0 ? trimmed : undefined;
492
565
  }
493
- if (typeof candidate.gitProviderId === 'string') {
494
- const trimmed = candidate.gitProviderId.trim();
495
- result.gitProviderId = trimmed.length > 0 ? trimmed : undefined;
496
- }
497
- if (typeof candidate.gitModelId === 'string') {
498
- const trimmed = candidate.gitModelId.trim();
499
- result.gitModelId = trimmed.length > 0 ? trimmed : undefined;
500
- }
501
566
  if (typeof candidate.pwaAppName === 'string') {
502
567
  result.pwaAppName = normalizePwaAppName(candidate.pwaAppName, undefined);
503
568
  }
@@ -510,15 +575,15 @@ export const createSettingsHelpers = (dependencies) => {
510
575
  result.mobileKeyboardMode = mode;
511
576
  }
512
577
  }
513
- if (typeof candidate.toolCallExpansion === 'string') {
514
- const mode = candidate.toolCallExpansion.trim();
515
- if (mode === 'collapsed' || mode === 'activity' || mode === 'detailed' || mode === 'changes') {
516
- result.toolCallExpansion = mode;
517
- }
518
- }
519
578
  if (typeof candidate.inputSpellcheckEnabled === 'boolean') {
520
579
  result.inputSpellcheckEnabled = candidate.inputSpellcheckEnabled;
521
580
  }
581
+ if (candidate.enterToSend === true || candidate.enterToSend === false) {
582
+ result.enterToSend = candidate.enterToSend;
583
+ }
584
+ if (candidate.enterToSendConfigured === true || candidate.enterToSendConfigured === false) {
585
+ result.enterToSendConfigured = candidate.enterToSendConfigured;
586
+ }
522
587
  if (typeof candidate.showOpenCodeUpdateNotifications === 'boolean') {
523
588
  result.showOpenCodeUpdateNotifications = candidate.showOpenCodeUpdateNotifications;
524
589
  }
@@ -601,9 +666,6 @@ export const createSettingsHelpers = (dependencies) => {
601
666
  if (typeof candidate.promptNavigatorEnabled === 'boolean') {
602
667
  result.promptNavigatorEnabled = candidate.promptNavigatorEnabled;
603
668
  }
604
- if (typeof candidate.expandedEditorToolbar === 'boolean') {
605
- result.expandedEditorToolbar = candidate.expandedEditorToolbar;
606
- }
607
669
  if (typeof candidate.wideChatLayoutEnabled === 'boolean') {
608
670
  result.wideChatLayoutEnabled = candidate.wideChatLayoutEnabled;
609
671
  }
@@ -687,6 +749,12 @@ export const createSettingsHelpers = (dependencies) => {
687
749
  result.gitChangesViewMode = mode;
688
750
  }
689
751
  }
752
+ if (typeof candidate.toolJsonViewMode === 'string') {
753
+ const mode = candidate.toolJsonViewMode.trim();
754
+ if (mode === 'summary' || mode === 'formatted' || mode === 'raw') {
755
+ result.toolJsonViewMode = mode;
756
+ }
757
+ }
690
758
  if (typeof candidate.directoryShowHidden === 'boolean') {
691
759
  result.directoryShowHidden = candidate.directoryShowHidden;
692
760
  }
@@ -700,11 +768,6 @@ export const createSettingsHelpers = (dependencies) => {
700
768
  }
701
769
  }
702
770
 
703
- // Message limit — single setting for fetch / trim / Load More chunk
704
- if (typeof candidate.messageLimit === 'number' && Number.isFinite(candidate.messageLimit)) {
705
- result.messageLimit = Math.max(10, Math.min(500, Math.round(candidate.messageLimit)));
706
- }
707
-
708
771
  const skillCatalogs = sanitizeSkillCatalogs(candidate.skillCatalogs);
709
772
  if (skillCatalogs) {
710
773
  result.skillCatalogs = skillCatalogs;
@@ -888,6 +951,16 @@ export const createSettingsHelpers = (dependencies) => {
888
951
  }
889
952
  }
890
953
 
954
+ // The registry is the last word on what a client may persist: a key the
955
+ // code above still names but the registry no longer lists is dropped here,
956
+ // so the two cannot drift apart silently (settings-helpers.test.js checks
957
+ // the other direction).
958
+ for (const key of Object.keys(result)) {
959
+ if (!isPersistableSettingsKey(key)) {
960
+ delete result[key];
961
+ }
962
+ }
963
+
891
964
  return result;
892
965
  };
893
966
 
@@ -898,13 +971,6 @@ export const createSettingsHelpers = (dependencies) => {
898
971
  ? current.securityScopedBookmarks
899
972
  : [];
900
973
 
901
- const nextTypographySizes = changes.typographySizes
902
- ? {
903
- ...(current.typographySizes || {}),
904
- ...changes.typographySizes
905
- }
906
- : current.typographySizes;
907
-
908
974
  const next = {
909
975
  ...current,
910
976
  ...changes,
@@ -913,7 +979,6 @@ export const createSettingsHelpers = (dependencies) => {
913
979
  baseBookmarks.filter((entry) => typeof entry === 'string' && entry.length > 0)
914
980
  )
915
981
  ),
916
- typographySizes: nextTypographySizes
917
982
  };
918
983
 
919
984
  return next;
@@ -921,30 +986,37 @@ export const createSettingsHelpers = (dependencies) => {
921
986
 
922
987
  const formatSettingsResponse = (settings) => {
923
988
  const sanitized = sanitizeSettingsUpdate(settings);
924
- delete sanitized.managedRemoteTunnelToken;
989
+ for (const key of SECRET_SETTINGS_KEYS) {
990
+ delete sanitized[key];
991
+ }
925
992
  const bookmarks = normalizeStringArray(settings.securityScopedBookmarks);
926
993
  const hasManagedRemoteTunnelToken = typeof settings?.managedRemoteTunnelToken === 'string' && settings.managedRemoteTunnelToken.trim().length > 0;
994
+ const hasDesktopUiPassword = typeof settings?.desktopUiPassword === 'string' && settings.desktopUiPassword.trim().length > 0;
927
995
  const pwaAppName = normalizePwaAppName(settings?.pwaAppName, '');
928
996
  const pwaOrientation = normalizePwaOrientation(settings?.pwaOrientation, 'system');
929
997
  const mobileKeyboardMode = normalizeMobileKeyboardMode(settings?.mobileKeyboardMode, 'native');
998
+ const inputHistoryScope = sanitized.inputHistoryScope ?? DEFAULT_INPUT_HISTORY_SCOPE;
999
+ const inputHistoryLimit = sanitized.inputHistoryLimit ?? DEFAULT_INPUT_HISTORY_LIMIT;
930
1000
 
931
1001
  return {
932
1002
  ...sanitized,
933
1003
  hasManagedRemoteTunnelToken,
1004
+ hasDesktopUiPassword,
934
1005
  // Tells the client whether agent memory exists in this build at all, so
935
1006
  // its settings row and panel tab can be absent rather than merely off.
936
1007
  agentMemoryFeatureAvailable: isAgentMemoryFeatureAvailable(),
937
1008
  ...(pwaAppName ? { pwaAppName } : {}),
938
1009
  pwaOrientation,
939
1010
  mobileKeyboardMode,
1011
+ inputHistoryScope,
1012
+ inputHistoryLimit,
940
1013
  securityScopedBookmarks: bookmarks,
941
1014
  pinnedDirectories: normalizeStringArray(settings.pinnedDirectories),
942
- typographySizes: sanitizeTypographySizesPartial(settings.typographySizes),
943
- ...(process.env.OPENCHAMBER_RUNTIME === 'desktop'
1015
+ ...(process.env.AIWORKER_RUNTIME === 'desktop'
944
1016
  ? {
945
- desktopLanAccessActive: process.env.OPENCHAMBER_DESKTOP_LAN_ACCESS_ACTIVE === 'true',
1017
+ desktopLanAccessActive: process.env.AIWORKER_DESKTOP_LAN_ACCESS_ACTIVE === 'true',
946
1018
  desktopLanAccessBlockedReason:
947
- process.env.OPENCHAMBER_DESKTOP_LAN_ACCESS_BLOCKED_REASON === 'missing-password'
1019
+ process.env.AIWORKER_DESKTOP_LAN_ACCESS_BLOCKED_REASON === 'missing-password'
948
1020
  ? 'missing-password'
949
1021
  : null,
950
1022
  }