@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,8 +1,19 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { dirname, join } from 'node:path';
5
+ import { fileURLToPath, pathToFileURL } from 'node:url';
1
6
  import { describe, expect, it } from 'vitest';
2
7
 
8
+ import {
9
+ DEFAULT_INPUT_HISTORY_LIMIT,
10
+ } from './input-history-scope.js';
3
11
  import { createSettingsHelpers } from './settings-helpers.js';
4
12
  import { createSettingsNormalizationRuntime } from './settings-normalization-runtime.js';
5
13
 
14
+ const testFilePath = fileURLToPath(import.meta.url);
15
+ const packagesWebDir = join(dirname(testFilePath), '..', '..', '..');
16
+
6
17
  const createTestHelpers = () => createSettingsHelpers({
7
18
  normalizePathForPersistence: (value) => value,
8
19
  normalizeDirectoryPath: (value) => value,
@@ -58,6 +69,79 @@ const createTestHelpersWithRealSanitizers = () => {
58
69
  };
59
70
 
60
71
  describe('settings helpers', () => {
72
+ it('round-trips telemetry opt-in with the hidden list and preserves it across unrelated writes', () => {
73
+ const helpers = createTestHelpers();
74
+ const legacy = helpers.sanitizeSettingsUpdate({ workStatusHiddenSections: [] });
75
+ expect(legacy.workStatusHiddenSectionsExplicit).toBeUndefined();
76
+ const changes = helpers.sanitizeSettingsUpdate({ workStatusHiddenSections: [], workStatusHiddenSectionsExplicit: true });
77
+ const saved = helpers.mergePersistedSettings(legacy, changes);
78
+ const reloaded = helpers.formatSettingsResponse(JSON.parse(JSON.stringify(saved)));
79
+ expect(reloaded.workStatusHiddenSections).toEqual([]);
80
+ expect(reloaded.workStatusHiddenSectionsExplicit).toBe(true);
81
+ const next = helpers.mergePersistedSettings(reloaded, helpers.sanitizeSettingsUpdate({ workStatusPanelEnabled: false }));
82
+ expect(helpers.formatSettingsResponse(next).workStatusHiddenSectionsExplicit).toBe(true);
83
+ expect(helpers.sanitizeSettingsUpdate({ workStatusHiddenSectionsExplicit: 'true' }).workStatusHiddenSectionsExplicit).toBeUndefined();
84
+ });
85
+ it('imports from the packed @aiworker/web tarball without escaping the published package', async () => {
86
+ const tempRoot = mkdtempSync(join(tmpdir(), 'settings-helpers-pack-'));
87
+ const packDir = join(tempRoot, 'pack');
88
+ const extractDir = join(tempRoot, 'extract');
89
+
90
+ try {
91
+ mkdirSync(packDir);
92
+ mkdirSync(extractDir);
93
+ execFileSync('npm', ['pack', '--silent', '--pack-destination', packDir], {
94
+ cwd: packagesWebDir,
95
+ stdio: 'pipe',
96
+ });
97
+
98
+ const tarballName = readdirSync(packDir).find((entry) => entry.endsWith('.tgz'));
99
+ expect(tarballName).toBeTruthy();
100
+
101
+ execFileSync('tar', ['-xzf', join(packDir, tarballName), '-C', extractDir], {
102
+ stdio: 'pipe',
103
+ });
104
+
105
+ const extractedModule = await import(
106
+ pathToFileURL(join(extractDir, 'package', 'server', 'lib', 'opencode', 'settings-helpers.js')).href
107
+ );
108
+
109
+ const helpers = extractedModule.createSettingsHelpers({
110
+ normalizePathForPersistence: (value) => value,
111
+ normalizeDirectoryPath: (value) => value,
112
+ normalizeTunnelBootstrapTtlMs: (value) => value,
113
+ normalizeTunnelSessionTtlMs: (value) => value,
114
+ normalizeTunnelProvider: (value) => value,
115
+ normalizeTunnelMode: (value) => value,
116
+ normalizeOptionalPath: (value) => value,
117
+ normalizeManagedRemoteTunnelHostname: (value) => value,
118
+ normalizeManagedRemoteTunnelPresets: () => undefined,
119
+ normalizeManagedRemoteTunnelPresetTokens: () => undefined,
120
+ sanitizeTypographySizesPartial: () => undefined,
121
+ normalizeStringArray: (input) => input,
122
+ sanitizeModelRefs: () => undefined,
123
+ sanitizeSkillCatalogs: () => undefined,
124
+ sanitizeProjects: () => undefined,
125
+ });
126
+
127
+ expect(helpers.sanitizeSettingsUpdate({ inputHistoryScope: 'global' })).toEqual({
128
+ inputHistoryScope: 'global',
129
+ });
130
+ expect(helpers.sanitizeSettingsUpdate({ inputHistoryScope: 'session' })).toEqual({
131
+ inputHistoryScope: 'session',
132
+ });
133
+ expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: 40 })).toEqual({
134
+ inputHistoryLimit: 40,
135
+ });
136
+ expect(helpers.formatSettingsResponse({})).toMatchObject({
137
+ inputHistoryScope: 'session',
138
+ inputHistoryLimit: DEFAULT_INPUT_HISTORY_LIMIT,
139
+ });
140
+ } finally {
141
+ rmSync(tempRoot, { recursive: true, force: true });
142
+ }
143
+ });
144
+
61
145
  it('accepts only booleans for draft starter visibility', () => {
62
146
  const helpers = createTestHelpers();
63
147
 
@@ -66,6 +150,14 @@ describe('settings helpers', () => {
66
150
  expect(helpers.sanitizeSettingsUpdate({ draftStartersVisible: 'false' })).toEqual({});
67
151
  });
68
152
 
153
+ it('sanitizes both Enter settings independently', () => {
154
+ const helpers = createTestHelpers();
155
+
156
+ expect(helpers.sanitizeSettingsUpdate({ enterToSend: true })).toEqual({ enterToSend: true });
157
+ expect(helpers.sanitizeSettingsUpdate({ enterToSendConfigured: false })).toEqual({ enterToSendConfigured: false });
158
+ expect(helpers.sanitizeSettingsUpdate({ enterToSend: 'true', enterToSendConfigured: 1 })).toEqual({});
159
+ });
160
+
69
161
  it('sanitizes shared sidebar display preferences', () => {
70
162
  const helpers = createTestHelpers();
71
163
 
@@ -88,6 +180,15 @@ describe('settings helpers', () => {
88
180
  })).toEqual({});
89
181
  });
90
182
 
183
+ it('persists valid tool JSON view modes', () => {
184
+ const helpers = createTestHelpers();
185
+
186
+ expect(helpers.sanitizeSettingsUpdate({ toolJsonViewMode: 'summary' })).toEqual({ toolJsonViewMode: 'summary' });
187
+ expect(helpers.sanitizeSettingsUpdate({ toolJsonViewMode: 'formatted' })).toEqual({ toolJsonViewMode: 'formatted' });
188
+ expect(helpers.sanitizeSettingsUpdate({ toolJsonViewMode: 'raw' })).toEqual({ toolJsonViewMode: 'raw' });
189
+ expect(helpers.sanitizeSettingsUpdate({ toolJsonViewMode: 'unknown' })).toEqual({});
190
+ });
191
+
91
192
  it('accepts only booleans for wide chat layout', () => {
92
193
  const helpers = createTestHelpers();
93
194
 
@@ -134,6 +235,74 @@ describe('settings helpers', () => {
134
235
  expect(helpers.sanitizeSettingsUpdate({ messageStreamTransport: 'websocket' })).toEqual({});
135
236
  });
136
237
 
238
+ it('accepts inputHistoryScope as a persisted shared setting', () => {
239
+ const helpers = createTestHelpers();
240
+
241
+ expect(helpers.sanitizeSettingsUpdate({ inputHistoryScope: 'global' })).toEqual({
242
+ inputHistoryScope: 'global',
243
+ });
244
+ expect(helpers.sanitizeSettingsUpdate({ inputHistoryScope: 'session' })).toEqual({
245
+ inputHistoryScope: 'session',
246
+ });
247
+ });
248
+
249
+ it('accepts valid inputHistoryLimit values as a persisted shared setting', () => {
250
+ const helpers = createTestHelpers();
251
+
252
+ expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: 1 })).toEqual({
253
+ inputHistoryLimit: 1,
254
+ });
255
+ expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: 40 })).toEqual({
256
+ inputHistoryLimit: 40,
257
+ });
258
+ expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: 100 })).toEqual({
259
+ inputHistoryLimit: 100,
260
+ });
261
+ });
262
+
263
+ it('rejects invalid inputHistoryLimit values', () => {
264
+ const helpers = createTestHelpers();
265
+
266
+ expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: 0 })).toEqual({});
267
+ expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: 101 })).toEqual({});
268
+ expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: 1.5 })).toEqual({});
269
+ expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: '40' })).toEqual({});
270
+ expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: Number.NaN })).toEqual({});
271
+ expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: Number.POSITIVE_INFINITY })).toEqual({});
272
+ expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: Number.NEGATIVE_INFINITY })).toEqual({});
273
+ });
274
+
275
+ it('rejects invalid inputHistoryScope values', () => {
276
+ const helpers = createTestHelpers();
277
+
278
+ expect(helpers.sanitizeSettingsUpdate({ inputHistoryScope: 'workspace' })).toEqual({});
279
+ });
280
+
281
+ it('defaults inputHistoryScope to session in formatted settings responses', () => {
282
+ const helpers = createTestHelpers();
283
+
284
+ expect(helpers.formatSettingsResponse({ inputHistoryScope: 'global' })).toMatchObject({
285
+ inputHistoryScope: 'global',
286
+ });
287
+ expect(helpers.formatSettingsResponse({})).toMatchObject({
288
+ inputHistoryScope: 'session',
289
+ });
290
+ });
291
+
292
+ it('defaults missing inputHistoryLimit to 40 in formatted settings responses and preserves valid values', () => {
293
+ const helpers = createTestHelpers();
294
+
295
+ expect(helpers.formatSettingsResponse({})).toMatchObject({
296
+ inputHistoryLimit: DEFAULT_INPUT_HISTORY_LIMIT,
297
+ });
298
+ expect(helpers.formatSettingsResponse({ inputHistoryLimit: 1 })).toMatchObject({
299
+ inputHistoryLimit: 1,
300
+ });
301
+ expect(helpers.formatSettingsResponse({ inputHistoryLimit: 100 })).toMatchObject({
302
+ inputHistoryLimit: 100,
303
+ });
304
+ });
305
+
137
306
  it('sanitizes the persisted terminal shell', () => {
138
307
  const helpers = createTestHelpers();
139
308
 
@@ -316,6 +485,27 @@ describe('settings helpers', () => {
316
485
  });
317
486
  });
318
487
 
488
+ it('accepts and rejects invalid Enter-to-send preference values', () => {
489
+ const helpers = createTestHelpers();
490
+
491
+ expect(helpers.sanitizeSettingsUpdate({ enterToSend: true, enterToSendConfigured: true })).toEqual({
492
+ enterToSend: true,
493
+ enterToSendConfigured: true,
494
+ });
495
+ expect(helpers.sanitizeSettingsUpdate({ enterToSend: false, enterToSendConfigured: true })).toEqual({
496
+ enterToSend: false,
497
+ enterToSendConfigured: true,
498
+ });
499
+ expect(helpers.sanitizeSettingsUpdate({ enterToSend: false, enterToSendConfigured: false })).toEqual({
500
+ enterToSend: false,
501
+ enterToSendConfigured: false,
502
+ });
503
+ expect(helpers.sanitizeSettingsUpdate({ enterToSend: 'true' })).toEqual({});
504
+ expect(helpers.sanitizeSettingsUpdate({ enterToSend: 1 })).toEqual({});
505
+ expect(helpers.sanitizeSettingsUpdate({ enterToSendConfigured: 'true' })).toEqual({});
506
+ expect(helpers.sanitizeSettingsUpdate({ enterToSendConfigured: 1 })).toEqual({});
507
+ });
508
+
319
509
  it('accepts dismissed OpenCode update toast version as a persisted shared setting', () => {
320
510
  const helpers = createTestHelpers();
321
511
 
@@ -353,24 +543,24 @@ describe('settings helpers', () => {
353
543
 
354
544
  it('includes transient desktop LAN access runtime status in desktop settings response', () => {
355
545
  const helpers = createTestHelpers();
356
- const previousRuntime = process.env.OPENCHAMBER_RUNTIME;
357
- const previousActive = process.env.OPENCHAMBER_DESKTOP_LAN_ACCESS_ACTIVE;
358
- const previousReason = process.env.OPENCHAMBER_DESKTOP_LAN_ACCESS_BLOCKED_REASON;
546
+ const previousRuntime = process.env.AIWORKER_RUNTIME;
547
+ const previousActive = process.env.AIWORKER_DESKTOP_LAN_ACCESS_ACTIVE;
548
+ const previousReason = process.env.AIWORKER_DESKTOP_LAN_ACCESS_BLOCKED_REASON;
359
549
  try {
360
- process.env.OPENCHAMBER_RUNTIME = 'desktop';
361
- process.env.OPENCHAMBER_DESKTOP_LAN_ACCESS_ACTIVE = 'false';
362
- process.env.OPENCHAMBER_DESKTOP_LAN_ACCESS_BLOCKED_REASON = 'missing-password';
550
+ process.env.AIWORKER_RUNTIME = 'desktop';
551
+ process.env.AIWORKER_DESKTOP_LAN_ACCESS_ACTIVE = 'false';
552
+ process.env.AIWORKER_DESKTOP_LAN_ACCESS_BLOCKED_REASON = 'missing-password';
363
553
 
364
554
  const response = helpers.formatSettingsResponse({ desktopLanAccessEnabled: true });
365
555
  expect(response.desktopLanAccessActive).toBe(false);
366
556
  expect(response.desktopLanAccessBlockedReason).toBe('missing-password');
367
557
  } finally {
368
- if (typeof previousRuntime === 'string') process.env.OPENCHAMBER_RUNTIME = previousRuntime;
369
- else delete process.env.OPENCHAMBER_RUNTIME;
370
- if (typeof previousActive === 'string') process.env.OPENCHAMBER_DESKTOP_LAN_ACCESS_ACTIVE = previousActive;
371
- else delete process.env.OPENCHAMBER_DESKTOP_LAN_ACCESS_ACTIVE;
372
- if (typeof previousReason === 'string') process.env.OPENCHAMBER_DESKTOP_LAN_ACCESS_BLOCKED_REASON = previousReason;
373
- else delete process.env.OPENCHAMBER_DESKTOP_LAN_ACCESS_BLOCKED_REASON;
558
+ if (typeof previousRuntime === 'string') process.env.AIWORKER_RUNTIME = previousRuntime;
559
+ else delete process.env.AIWORKER_RUNTIME;
560
+ if (typeof previousActive === 'string') process.env.AIWORKER_DESKTOP_LAN_ACCESS_ACTIVE = previousActive;
561
+ else delete process.env.AIWORKER_DESKTOP_LAN_ACCESS_ACTIVE;
562
+ if (typeof previousReason === 'string') process.env.AIWORKER_DESKTOP_LAN_ACCESS_BLOCKED_REASON = previousReason;
563
+ else delete process.env.AIWORKER_DESKTOP_LAN_ACCESS_BLOCKED_REASON;
374
564
  }
375
565
  });
376
566
 
@@ -534,3 +724,155 @@ describe('settings helpers', () => {
534
724
  });
535
725
  });
536
726
  });
727
+
728
+ describe('settings registry gate', () => {
729
+ const registryPath = join(dirname(testFilePath), 'settings-registry.json');
730
+ const registry = JSON.parse(readFileSync(registryPath, 'utf8'));
731
+ const persistableKeys = Object.entries(registry.fields)
732
+ .filter(([, field]) => !field.computed && !field.local && field.owner !== 'desktop-shell')
733
+ .map(([key]) => key);
734
+
735
+ // One valid value per persistable registry key. The test below fails when a
736
+ // key is added to the registry without a line here, and when the sanitizer
737
+ // stops accepting a key the registry still lists — that is the drift the
738
+ // registry exists to end.
739
+ const validValues = {
740
+ themeId: 'openchamber-dark', useSystemTheme: true, themeVariant: 'dark', lightThemeId: 'openchamber-light', darkThemeId: 'openchamber-dark',
741
+ splashBgLight: '#fff', splashFgLight: '#000', splashBgDark: '#000', splashFgDark: '#fff',
742
+ lastDirectory: '/home/testuser/project', homeDirectory: '/home/testuser', opencodeBinary: '/usr/local/bin/opencode',
743
+ projects: [{ id: 'p', path: '/home/testuser/project' }], activeProjectId: 'p',
744
+ securityScopedBookmarks: ['bookmark'], pinnedDirectories: ['/home/testuser/project'],
745
+ desktopLanAccessEnabled: true, desktopKeepAwakeEnabled: true, desktopMinimizeToTrayEnabled: true, desktopMacMenuBarEnabled: true,
746
+ desktopUiPassword: 'secret', githubClientId: 'client', githubScopes: 'repo', skillCatalogs: [{ id: 'c', label: 'C', source: 'https://x' }],
747
+ defaultGitIdentityId: 'global', permissionAutoAccept: { sessions: { s: true }, revision: 1 },
748
+ agentControlToolEnabled: true, agentWebToolEnabled: true, agentMemoryToolEnabled: true, openCodeUpdateToastDismissedVersion: '1.0.0',
749
+ autoDeleteEnabled: true, autoDeleteAfterDays: 30, sessionRetentionAction: 'archive', terminalShell: 'zsh', terminalLoginShells: ['zsh'],
750
+ openInAppId: 'vscode', dictationEnabled: true, sttProvider: 'local', sttServerUrl: 'http://localhost:8001/v1', sttModel: 'm', sttLocalModel: 'm', sttLanguage: 'en',
751
+ tunnelProvider: 'cloudflare', tunnelMode: 'quick', tunnelBootstrapTtlMs: 600000, tunnelSessionTtlMs: 86400000, managedLocalTunnelConfigPath: '/tmp/x',
752
+ managedRemoteTunnelHostname: 'x.example', managedRemoteTunnelToken: 'token', managedRemoteTunnelPresets: [{ id: 'a', name: 'A', hostname: 'a.example' }],
753
+ managedRemoteTunnelSelectedPresetId: 'a', managedRemoteTunnelPresetTokens: { a: 'token' },
754
+ sidebarProjectDisplayMode: 'all', sidebarSessionGroupingMode: 'flat', sidebarProjectSortOrder: 'manual', sidebarShowRecentSection: true,
755
+ workStatusPanelEnabled: true, workStatusHiddenSections: ['mcp'], workStatusHiddenSectionsExplicit: true,
756
+ showReasoningTraces: true, streamingAutoFollowEnabled: true, collapsibleThinkingBlocks: true, showTextJustificationActivity: true,
757
+ chatRenderMode: 'live', activityRenderMode: 'summary', mermaidRenderingMode: 'svg', userMessageRenderingMode: 'markdown', collapsibleUserMessages: true,
758
+ stickyUserHeader: true, promptNavigatorEnabled: true, wideChatLayoutEnabled: true, showSplitAssistantMessageActions: true, showToolFileIcons: true,
759
+ codeBlockLineWrap: true, showTurnChangedFiles: true, showExpandedBashTools: true, showExpandedEditTools: true, toolJsonViewMode: 'raw',
760
+ timeFormatPreference: '24h', weekStartPreference: 'monday', messageStreamTransport: 'ws', diffLayoutPreference: 'inline', diffWrapLines: true,
761
+ gitChangesViewMode: 'tree', gitmojiEnabled: true, defaultFileViewerPreview: true, directoryShowHidden: true, filesViewShowGitignored: true,
762
+ fileEditorKeymap: 'vim', autoSaveEnabled: true, autoCreateWorktree: true, sessionTabsEnabled: true, showOpenCodeRestartConfirm: true,
763
+ allowPromptingSubagentSessions: true, inputSpellcheckEnabled: true, enterToSend: true, enterToSendConfigured: true, persistChatDraft: true,
764
+ largeTextPasteBehavior: 'attach', followUpBehavior: 'steer', queueModeEnabled: true, inputHistoryScope: 'global', inputHistoryLimit: 40,
765
+ draftStarters: [{ type: 'command', name: 'plan-feature' }], draftStartersVisible: true, draftStartersCraftGoalAdded: true, draftStartersScheduleTaskAdded: true,
766
+ fontSize: 100, terminalFontSize: 14, editorFontSize: 14, uiFont: 'inter', monoFont: 'jetbrains-mono', padding: 100, cornerRadius: 8,
767
+ shortcutOverrides: { 'chat.send': 'mod+enter' },
768
+ defaultModel: 'anthropic/claude', defaultVariant: 'high', defaultAgent: 'build', smallModelUseDefault: false, smallModelOverride: 'anthropic/haiku',
769
+ walkthroughModelOverride: 'anthropic/claude', zenModel: 'zen/model',
770
+ favoriteModels: [{ providerID: 'anthropic', modelID: 'claude' }], hiddenModels: [{ providerID: 'openai', modelID: 'gpt' }], collapsedModelProviders: ['openai'],
771
+ recentModels: [{ providerID: 'anthropic', modelID: 'claude' }], recentAgents: ['build'], recentEfforts: { 'anthropic/claude': ['high'] }, providerOrder: ['anthropic'],
772
+ sessionRecapEnabled: true, sessionSuggestionEnabled: true, sessionGoalEnabled: true, sessionGoalDefaultBudgetEnabled: true, sessionGoalDefaultBudget: 5,
773
+ summarizeLastMessage: true, summaryThreshold: 100, summaryLength: 50, maxLastMessageLength: 200, showDeletionDialog: true,
774
+ nativeNotificationsEnabled: true, notificationMode: 'always', notifyOnSubtasks: true, notifyOnCompletion: true, notifyOnError: true, notifyOnQuestion: true,
775
+ notificationTemplates: { completion: { title: 't', message: 'm' } }, showOpenCodeUpdateNotifications: true, reportUsage: true,
776
+ usageDisplayMode: 'usage', usageDropdownProviders: ['anthropic'], usageSelectedModels: { anthropic: ['claude'] }, usageCollapsedFamilies: { anthropic: ['f'] },
777
+ usageExpandedFamilies: { anthropic: ['f'] }, usageModelGroups: { anthropic: { customGroups: [{ id: 'g', label: 'G', models: ['claude'], order: 0 }] } },
778
+ globalBehaviorPrompt: 'Be brief.', responseStyleEnabled: true, responseStylePreset: 'concise', responseStyleCustomInstructions: 'x', optimizeSystemPrompt: true,
779
+ pwaAppName: 'AiWorker', pwaOrientation: 'portrait', mobileKeyboardMode: 'native', desktopWindowControlsPosition: 'left', desktopWindowControlsStyle: 'classic',
780
+ inputBarOffset: 10,
781
+ };
782
+
783
+ it('accepts a valid value for every persistable registry key (no server-side drift)', () => {
784
+ // The shared test helpers stub the injected list sanitizers to `undefined`
785
+ // (they are covered by their own suites); here they must pass values through
786
+ // so a key is judged by the sanitizer's own branch, not by a stub.
787
+ const helpers = createSettingsHelpers({
788
+ normalizePathForPersistence: (value) => value,
789
+ normalizeDirectoryPath: (value) => value,
790
+ normalizeTunnelBootstrapTtlMs: (value) => value,
791
+ normalizeTunnelSessionTtlMs: (value) => value,
792
+ normalizeTunnelProvider: (value) => value,
793
+ normalizeTunnelMode: (value) => value,
794
+ normalizeOptionalPath: (value) => value,
795
+ normalizeManagedRemoteTunnelHostname: (value) => value,
796
+ normalizeManagedRemoteTunnelPresets: (value) => value,
797
+ normalizeManagedRemoteTunnelPresetTokens: (value) => value,
798
+ normalizeStringArray: (input) => input,
799
+ sanitizeModelRefs: (value) => value,
800
+ sanitizeSkillCatalogs: (value) => value,
801
+ sanitizeProjects: (value) => value,
802
+ });
803
+ const missingFixture = persistableKeys.filter((key) => !(key in validValues));
804
+ expect(missingFixture).toEqual([]);
805
+
806
+ const rejected = persistableKeys.filter((key) => {
807
+ const result = helpers.sanitizeSettingsUpdate({ [key]: validValues[key] });
808
+ // `queueModeEnabled` is absorbed into `followUpBehavior` on purpose.
809
+ const landedAs = key === 'queueModeEnabled' ? 'followUpBehavior' : key;
810
+ return result[landedAs] === undefined;
811
+ });
812
+ expect(rejected).toEqual([]);
813
+ });
814
+
815
+ it('drops keys the registry does not list, computed flags, and desktop-shell-owned keys', () => {
816
+ const helpers = createTestHelpers();
817
+ expect(helpers.sanitizeSettingsUpdate({
818
+ markdownDisplayMode: 'raw',
819
+ toolCallExpansion: 'collapsed',
820
+ expandedEditorToolbar: true,
821
+ typographySizes: { base: 14 },
822
+ gitProviderId: 'anthropic',
823
+ gitModelId: 'claude',
824
+ messageLimit: 200,
825
+ agentMemoryFeatureAvailable: true,
826
+ desktopHosts: [],
827
+ notARealKey: 1,
828
+ })).toEqual({});
829
+ });
830
+
831
+ it('never returns secret keys from a formatted response', () => {
832
+ const helpers = createTestHelpers();
833
+ const secretKeys = Object.entries(registry.fields).filter(([, field]) => field.secret).map(([key]) => key);
834
+ expect(secretKeys).toContain('managedRemoteTunnelToken');
835
+ expect(secretKeys).toContain('desktopUiPassword');
836
+ expect(secretKeys).toContain('managedRemoteTunnelPresetTokens');
837
+ const response = helpers.formatSettingsResponse({
838
+ managedRemoteTunnelToken: 'token',
839
+ desktopUiPassword: 'pw',
840
+ managedRemoteTunnelPresetTokens: { a: 'tok' },
841
+ themeId: 'x',
842
+ });
843
+ for (const key of secretKeys) {
844
+ expect(response).not.toHaveProperty(key);
845
+ }
846
+ expect(response.hasManagedRemoteTunnelToken).toBe(true);
847
+ expect(response.hasDesktopUiPassword).toBe(true);
848
+ expect(helpers.formatSettingsResponse({ desktopUiPassword: '' }).hasDesktopUiPassword).toBe(false);
849
+ });
850
+
851
+ it('accepts the newly shared profile fields', () => {
852
+ const helpers = createTestHelpersWithRealSanitizers();
853
+ expect(helpers.sanitizeSettingsUpdate({
854
+ providerOrder: ['b', 'a', 'a'],
855
+ diffWrapLines: true,
856
+ persistChatDraft: false,
857
+ largeTextPasteBehavior: 'inline',
858
+ fileEditorKeymap: 'vim',
859
+ allowPromptingSubagentSessions: true,
860
+ showOpenCodeRestartConfirm: false,
861
+ codeBlockLineWrap: true,
862
+ streamingAutoFollowEnabled: false,
863
+ autoSaveEnabled: false,
864
+ })).toEqual({
865
+ providerOrder: ['b', 'a'],
866
+ diffWrapLines: true,
867
+ persistChatDraft: false,
868
+ largeTextPasteBehavior: 'inline',
869
+ fileEditorKeymap: 'vim',
870
+ allowPromptingSubagentSessions: true,
871
+ showOpenCodeRestartConfirm: false,
872
+ codeBlockLineWrap: true,
873
+ streamingAutoFollowEnabled: false,
874
+ autoSaveEnabled: false,
875
+ });
876
+ expect(helpers.sanitizeSettingsUpdate({ largeTextPasteBehavior: 'maybe', fileEditorKeymap: 'emacs' })).toEqual({});
877
+ });
878
+ });