agentbox-app 0.1.13 → 0.1.16

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 (278) hide show
  1. package/README.md +24 -9
  2. package/bin/agentbox.mjs +23 -1
  3. package/briefs/message-rules.md +36 -8
  4. package/briefs/worker.md +46 -23
  5. package/main/account-discovery.mjs +122 -30
  6. package/main/account-tooling.mjs +29 -1
  7. package/main/account-usage.mjs +46 -0
  8. package/main/agent-sessions.mjs +282 -268
  9. package/main/agents.mjs +179 -466
  10. package/main/analytics.mjs +12 -2
  11. package/main/answer-modes.mjs +103 -37
  12. package/main/approval-prompt-core.mjs +197 -0
  13. package/main/approval-prompt-server.mjs +4 -138
  14. package/main/approvals.mjs +101 -297
  15. package/main/artifact-path.mjs +47 -18
  16. package/main/claude-input.mjs +48 -4
  17. package/main/claude-plan.mjs +48 -0
  18. package/main/claude-session-open.mjs +28 -0
  19. package/main/claude-usage-process.mjs +40 -0
  20. package/main/claude-usage.mjs +18 -40
  21. package/main/cloud/account.mjs +179 -0
  22. package/main/cloud/aws.mjs +127 -0
  23. package/main/cloud/browser-return.mjs +58 -0
  24. package/main/cloud/clients.mjs +15 -0
  25. package/main/cloud/codex-cloud.mjs +53 -0
  26. package/main/cloud/config.mjs +107 -0
  27. package/main/cloud/docs.mjs +219 -0
  28. package/main/cloud/exec.mjs +27 -0
  29. package/main/cloud/host.mjs +165 -0
  30. package/main/cloud/kit.mjs +80 -0
  31. package/main/cloud/logins.mjs +543 -0
  32. package/main/cloud/managed.mjs +115 -0
  33. package/main/cloud/marker.mjs +104 -0
  34. package/main/cloud/org.mjs +53 -0
  35. package/main/cloud/reuse.mjs +208 -0
  36. package/main/cloud/run-cli.mjs +177 -0
  37. package/main/cloud/run.mjs +1934 -0
  38. package/main/cloud/usage.mjs +76 -0
  39. package/main/cloud-permission.mjs +51 -0
  40. package/main/codex-account.mjs +78 -0
  41. package/main/codex-app-server.mjs +276 -409
  42. package/main/codex-approvals.mjs +148 -433
  43. package/main/codex-models.mjs +20 -2
  44. package/main/codex-session.mjs +212 -507
  45. package/main/codex-threads-worker.mjs +12 -0
  46. package/main/codex-threads.mjs +71 -3
  47. package/main/codex-usage-file.mjs +5 -3
  48. package/main/codex-usage.mjs +56 -7
  49. package/main/codex-watch.mjs +17 -3
  50. package/main/codex.mjs +95 -363
  51. package/main/config.mjs +11 -1
  52. package/main/corner-tag.mjs +340 -19
  53. package/main/dev-window.mjs +1 -1
  54. package/main/engine-bin.mjs +232 -282
  55. package/main/engine-setup.mjs +21 -9
  56. package/main/feedback.mjs +3 -25
  57. package/main/folder-pictures.mjs +2 -2
  58. package/main/freeze-recorder-thread.mjs +86 -0
  59. package/main/freeze-recorder.mjs +146 -0
  60. package/main/fresh-user.mjs +20 -9
  61. package/main/git-change-offthread.mjs +17 -3
  62. package/main/git-change-thread.mjs +5 -2
  63. package/main/harnesses/claude.mjs +32 -11
  64. package/main/harnesses/codex.mjs +9 -2
  65. package/main/importable-threads.mjs +64 -6
  66. package/main/ipc.mjs +362 -111
  67. package/main/leftovers.mjs +117 -25
  68. package/main/liquid-glass.mjs +26 -0
  69. package/main/live-replies.mjs +10 -4
  70. package/main/main-went-red.mjs +330 -0
  71. package/main/main.mjs +199 -84
  72. package/main/memory-gate-history.mjs +36 -10
  73. package/main/memory-gate-server.mjs +62 -0
  74. package/main/memory-gate.mjs +14 -1
  75. package/main/menu.mjs +4 -2
  76. package/main/message-priority.mjs +2 -2
  77. package/main/mic.mjs +38 -0
  78. package/main/native/liquid-glass/build/liquid-glass.node +0 -0
  79. package/main/new-chats-watch.mjs +110 -0
  80. package/main/new-user-window.mjs +25 -0
  81. package/main/notify.mjs +24 -8
  82. package/main/phone-alerts.mjs +117 -0
  83. package/main/phone-inbox.mjs +625 -0
  84. package/main/phone-link.mjs +29 -9
  85. package/main/phone-uploads.mjs +476 -0
  86. package/main/picture-shape.mjs +114 -0
  87. package/main/quit-sequence.mjs +143 -0
  88. package/main/refresh-agent-models.mjs +15 -2
  89. package/main/relay-client.mjs +69 -1
  90. package/main/repeats.mjs +10 -4
  91. package/main/row-label.mjs +12 -41
  92. package/main/run-change.mjs +13 -0
  93. package/main/run-ledger.mjs +135 -0
  94. package/main/save-attachments.mjs +41 -0
  95. package/main/serve.mjs +45 -3
  96. package/main/settings.mjs +220 -44
  97. package/main/shell-path.mjs +185 -37
  98. package/main/ship-conflict-brief.mjs +119 -0
  99. package/main/ship-queue.mjs +115 -19
  100. package/main/source-updater.mjs +18 -10
  101. package/main/stage-attachment.mjs +68 -0
  102. package/main/stall-watch.mjs +50 -0
  103. package/main/store/home.mjs +87 -232
  104. package/main/store/paths.mjs +11 -0
  105. package/main/store/teammates-files.mjs +99 -0
  106. package/main/store/work-items.mjs +231 -13
  107. package/main/store.mjs +226 -52
  108. package/main/supervisor.mjs +3103 -341
  109. package/main/task-folders.mjs +430 -30
  110. package/main/task-terminals.mjs +110 -34
  111. package/main/team/index.mjs +114 -10
  112. package/main/team/memory-cloud.mjs +183 -1
  113. package/main/team/room-hours.mjs +48 -0
  114. package/main/team/room-setup.mjs +31 -0
  115. package/main/team/rooms-memory.mjs +454 -0
  116. package/main/team/rooms-shape.mjs +42 -0
  117. package/main/team/rooms-supabase.mjs +324 -0
  118. package/main/team/rooms.mjs +575 -0
  119. package/main/team/session.mjs +96 -26
  120. package/main/team/supabase-backend.mjs +180 -0
  121. package/main/team/sync.mjs +109 -1
  122. package/main/teammates.mjs +580 -0
  123. package/main/terminal-host.mjs +143 -0
  124. package/main/terminal-hosts.mjs +261 -0
  125. package/main/transcript-search.mjs +80 -0
  126. package/main/webview-guard.mjs +45 -0
  127. package/main/worktree-include.mjs +90 -219
  128. package/mcp/core/documents.mjs +3 -1
  129. package/mcp/core/repeats.mjs +88 -0
  130. package/mcp/core/teammates.mjs +222 -0
  131. package/mcp/core/work.mjs +76 -4
  132. package/mcp/stdio.mjs +24 -11
  133. package/mcp/tools.mjs +116 -8
  134. package/package.json +21 -5
  135. package/renderer/dist/assets/{abnfDiagram-YUKMZFIV-DPPuMWt-.js → abnfDiagram-YUKMZFIV-CoWB6YUK.js} +1 -1
  136. package/renderer/dist/assets/{arc-HmFfdseH.js → arc-Ch0NrCul.js} +1 -1
  137. package/renderer/dist/assets/{architectureDiagram-47P4ROYG-DxJ3zHrH.js → architectureDiagram-47P4ROYG-CXz9M5tQ.js} +1 -1
  138. package/renderer/dist/assets/{blockDiagram-E7TT5TSB-CbTXzOqQ.js → blockDiagram-E7TT5TSB-DchGUuHH.js} +1 -1
  139. package/renderer/dist/assets/{c4Diagram-CRA5TL53-X5ItFyLn.js → c4Diagram-CRA5TL53-Cip-zNyr.js} +1 -1
  140. package/renderer/dist/assets/channel-BQuQSL--.js +1 -0
  141. package/renderer/dist/assets/{chunk-2Q5K7J3B-DC12Ho_L.js → chunk-2Q5K7J3B-BoXid_2r.js} +1 -1
  142. package/renderer/dist/assets/{chunk-5VM5RSS4-ClVtfPd0.js → chunk-5VM5RSS4-Cpez1rRz.js} +1 -1
  143. package/renderer/dist/assets/{chunk-7TKQ45FW-DgcOm0HT.js → chunk-7TKQ45FW-DKA84YkE.js} +1 -1
  144. package/renderer/dist/assets/{chunk-AW2ZBBNX-C01s4yoF.js → chunk-AW2ZBBNX-Dg-SumPG.js} +1 -1
  145. package/renderer/dist/assets/{chunk-FVRAUYC3-Bj0zxhR4.js → chunk-FVRAUYC3-06TCvPm1.js} +2 -2
  146. package/renderer/dist/assets/{chunk-HTAEGDNF-DWDeEhLU.js → chunk-HTAEGDNF-CMEBy1Td.js} +1 -1
  147. package/renderer/dist/assets/{chunk-JWPE2WC7-Dsqwv3eW.js → chunk-JWPE2WC7-BJ2ObmV-.js} +1 -1
  148. package/renderer/dist/assets/{chunk-KQW6MTUR-CE86ANL2.js → chunk-KQW6MTUR-CGWOYXUE.js} +1 -1
  149. package/renderer/dist/assets/{chunk-XXDRQBXY-CoNTASfs.js → chunk-XXDRQBXY-CiZp07XC.js} +1 -1
  150. package/renderer/dist/assets/{classDiagram-v2-K4WV4PDN-2wprLqtw.js → classDiagram-v2-K4WV4PDN-DJNIX719.js} +1 -1
  151. package/renderer/dist/assets/cornerTag-CPgvu-q3.js +1 -0
  152. package/renderer/dist/assets/cornerTag-oMfEjzCO.css +1 -0
  153. package/renderer/dist/assets/{cose-bilkent-JH36ORCC-enqMiYbn.js → cose-bilkent-JH36ORCC-CbkyZOUH.js} +1 -1
  154. package/renderer/dist/assets/{cynefin-EF2NZ3EQ-DHngLxvQ.js → cynefin-EF2NZ3EQ-78iOroZO.js} +1 -1
  155. package/renderer/dist/assets/{cynefinDiagram-3GCD6N5R-C0rZZIl3.js → cynefinDiagram-3GCD6N5R-GcCopMs7.js} +1 -1
  156. package/renderer/dist/assets/{dagre-W4DXFKR2-DQnaEWO7.js → dagre-W4DXFKR2-DHLlXLkz.js} +1 -1
  157. package/renderer/dist/assets/{diagram-2UJZ2QOL-CS8AlGPx.js → diagram-2UJZ2QOL-DuZSUHcH.js} +1 -1
  158. package/renderer/dist/assets/{diagram-OVF4WLC6-yiDMHIkY.js → diagram-OVF4WLC6-Ckxu3cqH.js} +1 -1
  159. package/renderer/dist/assets/{diagram-PFPMY2P6-XbQKzbBA.js → diagram-PFPMY2P6-CsTw9Ycn.js} +1 -1
  160. package/renderer/dist/assets/{diagram-UMYRVEAY-dhVvlfl_.js → diagram-UMYRVEAY-CTXd8qVg.js} +1 -1
  161. package/renderer/dist/assets/{diagram-YEKJPTXX-DZHe8SCf.js → diagram-YEKJPTXX-CJs1T_9m.js} +1 -1
  162. package/renderer/dist/assets/{diagram-ZIFT7M5P-B5h6aXVR.js → diagram-ZIFT7M5P-CvjI23mf.js} +1 -1
  163. package/renderer/dist/assets/{ebnfDiagram-VR2GEFS7-PR9ScDco.js → ebnfDiagram-VR2GEFS7-d_IeAzOJ.js} +1 -1
  164. package/renderer/dist/assets/{elk-IJKZMXRS-Cg-yQXPd.js → elk-IJKZMXRS-zo9KFP3N.js} +1 -1
  165. package/renderer/dist/assets/{erDiagram-O2IAPWRE-omOrJMxu.js → erDiagram-O2IAPWRE-DqfYf5Dt.js} +1 -1
  166. package/renderer/dist/assets/{flowDiagram-OXPTDLAJ-aOX2hzvT.js → flowDiagram-OXPTDLAJ-DAWsMLmo.js} +1 -1
  167. package/renderer/dist/assets/{ganttDiagram-R7TSEDQI-B1H3pWyI.js → ganttDiagram-R7TSEDQI-4ml_bhwR.js} +1 -1
  168. package/renderer/dist/assets/{gitGraphDiagram-XJZIOB7I-Cvw304HC.js → gitGraphDiagram-XJZIOB7I-B_WcqSId.js} +1 -1
  169. package/renderer/dist/assets/{infoDiagram-5W2HQ5XZ-_ZXcNViH.js → infoDiagram-5W2HQ5XZ-CI-jYqzc.js} +1 -1
  170. package/renderer/dist/assets/{ishikawaDiagram-K3B6WC7H-C7Mx_qQk.js → ishikawaDiagram-K3B6WC7H-B56VWRlV.js} +1 -1
  171. package/renderer/dist/assets/{journeyDiagram-COXZFDF6-fr62QoAt.js → journeyDiagram-COXZFDF6-D1-p09Lr.js} +1 -1
  172. package/renderer/dist/assets/{kanban-definition-P3RFRI5V-J8zsabCe.js → kanban-definition-P3RFRI5V-Cv3w7JoN.js} +1 -1
  173. package/renderer/dist/assets/{linear-BmNdEtIi.js → linear-C35V2Spi.js} +1 -1
  174. package/renderer/dist/assets/main-BcoBiGwv.css +32 -0
  175. package/renderer/dist/assets/main-CLnIOulD.js +1191 -0
  176. package/renderer/dist/assets/{mermaid.core-CnYzvFkz.js → mermaid.core-BzGT5Vo9.js} +4 -4
  177. package/renderer/dist/assets/{mindmap-definition-LZFPQGKD-Bfcxc7PM.js → mindmap-definition-LZFPQGKD-BZUfuymC.js} +1 -1
  178. package/renderer/dist/assets/{pegDiagram-BGZESJAR-CwUJOq6X.js → pegDiagram-BGZESJAR-DFh9XNGe.js} +1 -1
  179. package/renderer/dist/assets/{pieDiagram-CAPJLFHJ-BrwMmqfC.js → pieDiagram-CAPJLFHJ-C65tPVsy.js} +1 -1
  180. package/renderer/dist/assets/{product-name-CTKLYNWY.js → product-name-CSNW6d7s.js} +1 -1
  181. package/renderer/dist/assets/{quadrantDiagram-GDMTTRAM-BN4Stoj-.js → quadrantDiagram-GDMTTRAM-Cushj_nk.js} +1 -1
  182. package/renderer/dist/assets/{railroadDiagram-SM67HX2B-CPZ5bbeR.js → railroadDiagram-SM67HX2B-DZGebGx5.js} +1 -1
  183. package/renderer/dist/assets/{requirementDiagram-X7JNWC4A-CgRnimVe.js → requirementDiagram-X7JNWC4A-DpAB0MNo.js} +1 -1
  184. package/renderer/dist/assets/{sankeyDiagram-UM26HJRW-Bt2rej__.js → sankeyDiagram-UM26HJRW-D-29rHra.js} +1 -1
  185. package/renderer/dist/assets/{sequenceDiagram-ZO4K6R2Y-Dd5nKe9G.js → sequenceDiagram-ZO4K6R2Y-FfOQAZol.js} +1 -1
  186. package/renderer/dist/assets/{sizeCapture-INFHLROL-usyNyXyh.js → sizeCapture-INFHLROL-C_n6fDBY.js} +1 -1
  187. package/renderer/dist/assets/{stateDiagram-v2-TBUQTH76-CRzUBb0u.js → stateDiagram-v2-TBUQTH76-BZjenzJG.js} +1 -1
  188. package/renderer/dist/assets/{swimlanes-N4OXWK64-C1GJvMS0.js → swimlanes-N4OXWK64-DxaMU9vX.js} +1 -1
  189. package/renderer/dist/assets/swimlanesDiagram-K3J5GTZL-Cb2kM6rr.js +8 -0
  190. package/renderer/dist/assets/{timeline-definition-YOQAKGHF-caeyPlcc.js → timeline-definition-YOQAKGHF-DTg5HJKz.js} +1 -1
  191. package/renderer/dist/assets/{usecaseDiagram-VIAY4XPW-BN_SV6PC.js → usecaseDiagram-VIAY4XPW-Bc3MZDsl.js} +1 -1
  192. package/renderer/dist/assets/{vennDiagram-BLWOH2XV-BLGuaUX-.js → vennDiagram-BLWOH2XV-GIVGk9Id.js} +1 -1
  193. package/renderer/dist/assets/{wardleyDiagram-YMQ3BMBF-Da0cJeNc.js → wardleyDiagram-YMQ3BMBF-NmJnbQOg.js} +1 -1
  194. package/renderer/dist/assets/{xychartDiagram-TAQBALBS-cGfUffMk.js → xychartDiagram-TAQBALBS-p-kfGfnW.js} +1 -1
  195. package/renderer/dist/corner-tag.html +3 -3
  196. package/renderer/dist/index.html +3 -3
  197. package/scripts/after-install.mjs +30 -8
  198. package/scripts/cloud-shim.pl +57 -0
  199. package/shared/account-names.d.mts +6 -0
  200. package/shared/account-names.mjs +15 -0
  201. package/shared/agent-hours.mjs +136 -0
  202. package/shared/agent-import.mjs +60 -34
  203. package/shared/agents.mjs +126 -522
  204. package/shared/analytics-events.mjs +12 -0
  205. package/shared/approval-card.mjs +36 -0
  206. package/shared/bridge-map.mjs +27 -1
  207. package/shared/claude-code-shape.mjs +6 -0
  208. package/shared/claude-usage.d.mts +1 -0
  209. package/shared/claude-usage.mjs +42 -1
  210. package/shared/cloud-hand-back.d.mts +7 -0
  211. package/shared/cloud-hand-back.mjs +20 -0
  212. package/shared/cloud-kit.d.mts +219 -0
  213. package/shared/cloud-kit.mjs +341 -0
  214. package/shared/cloud-login-name.mjs +4 -0
  215. package/shared/cloud-start.mjs +17 -0
  216. package/shared/cloud-versions.mjs +23 -0
  217. package/shared/codex-import.mjs +2 -2
  218. package/shared/codex-modes.d.mts +22 -9
  219. package/shared/codex-modes.mjs +67 -11
  220. package/shared/codex-usage.mjs +108 -2
  221. package/shared/corner-tag.d.mts +23 -1
  222. package/shared/corner-tag.mjs +284 -29
  223. package/shared/dead-run-trace.mjs +19 -2
  224. package/shared/engines.mjs +70 -309
  225. package/shared/feedback.d.mts +7 -0
  226. package/shared/feedback.mjs +25 -0
  227. package/shared/first-run-practice.mjs +17 -24
  228. package/shared/harness-definitions.mjs +8 -0
  229. package/shared/instruction-defaults.json +2 -2
  230. package/shared/key-caps.d.mts +14 -0
  231. package/shared/key-caps.mjs +68 -0
  232. package/shared/message-edits.d.mts +7 -0
  233. package/shared/message-edits.mjs +35 -0
  234. package/shared/move-thread.d.mts +24 -0
  235. package/shared/move-thread.mjs +112 -0
  236. package/shared/named-threads.mjs +72 -0
  237. package/shared/not-shipped.d.mts +22 -0
  238. package/shared/not-shipped.mjs +89 -0
  239. package/shared/notify-rules.d.mts +6 -0
  240. package/shared/notify-rules.mjs +36 -8
  241. package/shared/phone-files.mjs +28 -0
  242. package/shared/phone-settings.mjs +118 -0
  243. package/shared/phone-snapshot.d.mts +16 -0
  244. package/shared/phone-snapshot.mjs +348 -0
  245. package/shared/picture-formats.d.mts +1 -0
  246. package/shared/picture-formats.mjs +13 -0
  247. package/shared/rank.d.mts +2 -1
  248. package/shared/rank.mjs +32 -19
  249. package/shared/repeats.d.mts +8 -0
  250. package/shared/repeats.mjs +33 -2
  251. package/shared/room-cards.mjs +167 -0
  252. package/shared/room-links.d.mts +4 -0
  253. package/shared/room-links.mjs +21 -0
  254. package/shared/runs-on.d.mts +3 -3
  255. package/shared/runs-on.mjs +8 -5
  256. package/shared/shipped-note.d.mts +4 -0
  257. package/shared/shipped-note.mjs +6 -0
  258. package/shared/shortcuts.mjs +14 -6
  259. package/shared/spawn-trouble.d.mts +4 -0
  260. package/shared/spawn-trouble.mjs +443 -40
  261. package/shared/team-rules.mjs +9 -2
  262. package/shared/teammates.d.mts +19 -0
  263. package/shared/teammates.mjs +756 -0
  264. package/shared/terminal-focus.d.mts +1 -0
  265. package/shared/terminal-focus.mjs +13 -0
  266. package/shared/thread-cards.mjs +4 -1
  267. package/shared/usage.d.mts +9 -0
  268. package/shared/usage.mjs +49 -3
  269. package/shared/websites.d.mts +15 -0
  270. package/shared/websites.mjs +61 -0
  271. package/shared/work-items.mjs +127 -30
  272. package/shared/work-lines.mjs +92 -244
  273. package/renderer/dist/assets/channel-BlT2g9Sz.js +0 -1
  274. package/renderer/dist/assets/cornerTag-BLrxiDE5.css +0 -1
  275. package/renderer/dist/assets/cornerTag-BOT6u3Tn.js +0 -1
  276. package/renderer/dist/assets/main-ChNdnUvt.js +0 -1132
  277. package/renderer/dist/assets/main-nj0QR5kg.css +0 -32
  278. package/renderer/dist/assets/swimlanesDiagram-K3J5GTZL-Cy4Av2_p.js +0 -8
package/main/settings.mjs CHANGED
@@ -12,27 +12,32 @@
12
12
  // place a grant is reviewed; what changed is that she edits them as fields on
13
13
  // the project they belong to instead of in a text editor.
14
14
 
15
+ import { teammatesOn } from '../shared/teammates.mjs';
16
+ import { phoneChoiceOf, phoneProjectsOf, withPhoneAll, withPhoneProject, phoneEligible } from '../shared/phone-snapshot.mjs';
15
17
  import fs from 'node:fs';
16
18
  import { harnessFor } from './harnesses.mjs';
17
19
  import os from 'node:os';
18
20
  import path from 'node:path';
19
21
  import { codexChoiceToOpen, saveConfig } from './config.mjs';
20
22
  import { forgetClaudeBin, INSTALL_URL } from './claude-bin.mjs';
23
+ import { lookAgain } from './engine-bin.mjs';
21
24
  import { AGENT_MODES } from '../shared/agents.mjs';
22
25
  import { analyticsKey, diagnosticsOn } from './analytics.mjs';
23
26
  import { CLAUDE_PERMISSION_MODES } from '../shared/work-items.mjs';
24
27
  import { accountSentence, engineTroubleNote, refineCause } from '../shared/spawn-trouble.mjs';
25
28
  import { readPlan } from './claude-plan.mjs';
26
- import { effectiveProfiles } from './account-discovery.mjs';
29
+ import { effectiveProfiles, troubleForProfile } from './account-discovery.mjs';
27
30
  import { machineSlots, machineNote, autoAgents, MAX_SLOTS } from './machine.mjs';
28
31
  import { shortPath } from './agent-files.mjs';
29
32
  import { NAME, Name } from '../shared/product-name.mjs';
30
33
  import { autoSlots } from './memory-gate.mjs';
31
34
  import { accountIdentity, claudeLoginCommand, duplicateAccountNote, linkAccountTooling, makeClaudeHome } from './account-tooling.mjs';
32
35
  import { isEngine } from '../shared/engines.mjs';
33
- import { codexAccount, codexLoginCommand, makeCodexHome } from './codex-account.mjs';
34
- import { codexDefaultModel, codexModels } from './codex-models.mjs';
36
+ import { codexAccount, codexFreePlan, codexLoginCommand, makeCodexHome } from './codex-account.mjs';
37
+ import { codexDefaultModel, codexModelsAcross } from './codex-models.mjs';
35
38
  import { CODEX_DEFAULT_MODE, isCodexMode } from '../shared/codex-modes.mjs';
39
+ import { CLOUD_SAME, CLOUD_CLAUDE_DEFAULT, CLOUD_CODEX_DEFAULT } from './cloud-permission.mjs';
40
+ import { isPackagedElectron } from './team/session.mjs';
36
41
  import { claudeModels } from './claude-models.mjs';
37
42
  import { forgetCodexBin, INSTALL_URL as CODEX_INSTALL_URL } from './codex-bin.mjs';
38
43
 
@@ -215,6 +220,8 @@ export function buildSessionArgs(base, mode) {
215
220
  return [...model, ...(tools.length ? ['--allowedTools', ...tools] : []), ...grant, ...parsed.other];
216
221
  }
217
222
 
223
+ export { cloudPermissionArgs } from './cloud-permission.mjs';
224
+
218
225
  // THE MODEL, WRITTEN BACK INTO THE SAME LIST buildSessionArgs READS FROM.The
219
226
  // screen had no control over this at all; the flag was already there and only
220
227
  // a text editor could change it.
@@ -247,10 +254,31 @@ export function setModelArg(base, model) {
247
254
 
248
255
  const lineCount = (text) => (text.trim() ? text.trim().split('\n').length : 0);
249
256
 
257
+ // What launch found, or the last Check again, in the finder's own shape. For a
258
+ // read nobody is looking at: the search starts a login shell on the window's
259
+ // thread, and the phone reads settings every minute.
260
+ function knownEngine(config, engine) {
261
+ if (engine === 'claude') {
262
+ return {
263
+ path: config.claudeBin ?? null,
264
+ found: !!config.claudeFound,
265
+ certain: config.claudeCertain !== false,
266
+ from: config.claudeBinConfigured ? 'settings' : (config.claudeFrom ?? null),
267
+ };
268
+ }
269
+ // recheckCodex moves codexBin and not codexFound, so the path is the answer.
270
+ return {
271
+ path: config.codexBin ?? null,
272
+ found: !!config.codexBin,
273
+ certain: config.codexCertain !== false,
274
+ from: config.codexBinConfigured ? 'settings' : (config.codexFrom ?? null),
275
+ };
276
+ }
277
+
250
278
  // Claude Code: the path, whether it is really there, and where to get it when
251
279
  // it is not. One reader, here, so the screen and the config cannot disagree.
252
- export function claudeState(config) {
253
- const found = harnessFor('claude').discover(config.claudeBinConfigured ?? null);
280
+ export function claudeState(config, { search = true } = {}) {
281
+ const found = search ? harnessFor('claude').discover(config.claudeBinConfigured ?? null) : knownEngine(config, 'claude');
254
282
  return {
255
283
  claudeBin: found.path ?? config.claudeBin,
256
284
  claudeFound: found.found,
@@ -274,6 +302,20 @@ export function claudeState(config) {
274
302
  // `forgetClaudeBin` exists for.
275
303
  export function recheckClaude(config) {
276
304
  forgetClaudeBin();
305
+ return takeClaude(config);
306
+ }
307
+
308
+ /**
309
+ * Check again without holding the window: the shell is asked in the background
310
+ * and this settles once its answer is on the config. For every caller that can
311
+ * wait (the buttons, setup, the update check).
312
+ */
313
+ export async function lookAgainFor(engine, config) {
314
+ await lookAgain(engine);
315
+ return engine === 'claude' ? takeClaude(config) : takeCodex(config);
316
+ }
317
+
318
+ function takeClaude(config) {
277
319
  const state = claudeState(config);
278
320
  // The config carries the path everything else spawns from, so a search that
279
321
  // has just found Claude Code updates it rather than leaving the rest of the
@@ -282,7 +324,10 @@ export function recheckClaude(config) {
282
324
  // And whether it is here at all, which is what decides that a Mac with only
283
325
  // Codex runs on Codex (`Supervisor#_enginesFound`). Only a certain answer
284
326
  // moves it, so an unsure search never takes Claude Code away from anybody.
285
- if (state.claudeFound || state.claudeCertain) config.claudeFound = state.claudeFound;
327
+ if (state.claudeFound || state.claudeCertain) {
328
+ config.claudeFound = state.claudeFound;
329
+ config.claudeCertain = state.claudeCertain;
330
+ }
286
331
  return state;
287
332
  }
288
333
 
@@ -316,8 +361,8 @@ export function recheckClaude(config) {
316
361
  * checked by uninstalling Codex from the machine running the suite is a card
317
362
  * whose unsure state is not checked. Nothing in the app passes it.
318
363
  */
319
- export function codexState(config, where = {}) {
320
- const found = harnessFor('codex').discover(config.codexBinConfigured ?? null, where);
364
+ export function codexState(config, where = {}, { search = true } = {}) {
365
+ const found = search ? harnessFor('codex').discover(config.codexBinConfigured ?? null, where) : knownEngine(config, 'codex');
321
366
  return {
322
367
  // Empty rather than a path when there is nothing there, which is the same
323
368
  // asymmetry `config.codexBin` already keeps (main/config.mjs): a configured
@@ -335,8 +380,8 @@ export function codexState(config, where = {}) {
335
380
  }
336
381
 
337
382
  /** `codexState` under the names the walk's last card reads beside Claude's. */
338
- export function codexFoundState(config, where = {}) {
339
- const state = codexState(config, where);
383
+ export function codexFoundState(config, where = {}, how = {}) {
384
+ const state = codexState(config, where, how);
340
385
  return { codexFound: state.found, codexCertain: state.certain, codexInstallUrl: state.url };
341
386
  }
342
387
 
@@ -348,8 +393,13 @@ export function codexFoundState(config, where = {}) {
348
393
  * without a restart. */
349
394
  export function recheckCodex(config) {
350
395
  forgetCodexBin();
396
+ return takeCodex(config);
397
+ }
398
+
399
+ function takeCodex(config) {
351
400
  const state = codexState(config);
352
401
  config.codexBin = state.found ? state.bin : null;
402
+ config.codexCertain = state.certain;
353
403
  // Found while the app is open, by this button or the plan setup: the choice
354
404
  // opens now, as it would have at the next launch (main/config.mjs).
355
405
  const opened = codexChoiceToOpen(config, state.found);
@@ -438,7 +488,19 @@ export function searchForEngineBin(config, engine) {
438
488
  return { ok: true, state };
439
489
  }
440
490
 
441
- export function readSettings({ config, supervisor, store }) {
491
+ // THE ALPHA FEATURES SWITCHES (w-3d0fa23ffb). Off unless someone turned them
492
+ // on in Settings; only a real `true` counts. Multiplayer, the team version, is
493
+ // the exception in a checkout, where it was always on.
494
+ export function alphaFeatures(config, { packaged = isPackagedElectron() } = {}) {
495
+ return {
496
+ rooms: config?.alphaRooms === true,
497
+ teammates: teammatesOn(config),
498
+ multiplayer: packaged ? config?.alphaMultiplayer === true : config?.alphaMultiplayer !== false,
499
+ };
500
+ }
501
+
502
+ // `search: false` is for a read on a timer (`knownEngine`).
503
+ export function readSettings({ config, supervisor, store }, { search = true } = {}) {
442
504
  const products = store.listProducts();
443
505
  const status = supervisor.status();
444
506
  const sessions = [...supervisor.sessions.values()];
@@ -469,10 +531,17 @@ export function readSettings({ config, supervisor, store }) {
469
531
  // waiting, because a page she chose to open interrupts nobody.
470
532
  const troubles = status.accountTrouble ?? {};
471
533
  const accounts = (profiles.length ? profiles : ['default']).map((profile) => {
472
- const plan = readPlan(profile);
534
+ // THE HOME THE WORKSPACE IS CONFIGURED WITH, not this process's own. Both
535
+ // of these read a login out of a folder, and both of them defaulted to
536
+ // `os.homedir()` while the list of folders above came from `config.home`,
537
+ // so a workspace pointed anywhere else drew rows for its own folders and
538
+ // read somebody else's login into them.
539
+ const plan = readPlan(profile, { home: config.home });
473
540
  // A reason filed before an ended subscription had its own name still reads
474
541
  // as an admin's block; the login's file says which it is.
475
- const filed = troubles[profile] ?? null;
542
+ // THE SUBSCRIPTION'S TROUBLE, not the folder's: one row stands for every
543
+ // folder holding this account (account-discovery.mjs says why).
544
+ const filed = troubleForProfile(troubles, profile, { home: config.home });
476
545
  const trouble = filed ? { ...filed, cause: refineCause(filed.cause, plan) } : null;
477
546
  const resting = (supervisor._profileCooldown?.[profile] ?? 0) >= now;
478
547
  // WHOSE SUBSCRIPTION THIS ROW IS, not merely which folder it lives in.
@@ -480,14 +549,18 @@ export function readSettings({ config, supervisor, store }) {
480
549
  // person that one of their accounts had been replaced by the other;
481
550
  // main/account-tooling.mjs has how that happens. Null when the
482
551
  // folder holds no login, and then the row reads as it always did.
483
- const identity = accountIdentity(profile === 'default' ? null : profile);
552
+ const identity = accountIdentity(profile === 'default' ? null : profile, { home: config.home });
484
553
  return {
485
554
  profile,
486
555
  email: identity?.email ?? null,
487
556
  accountUuid: identity?.accountUuid ?? null,
488
- // WHICH ONE RUNS, when she has picked one. False on every row while she
489
- // has not, and then every account runs as it always has.
490
- chosen: (config.activeAccount?.claude ?? null) === profile,
557
+ // WHICH ONE RUNS, AND ONE OF THEM ALWAYS DOES (w-dac993a554). This was
558
+ // false on every row until somebody picked, because until then every
559
+ // account really did take a share of the work. One account runs it now,
560
+ // so the supervisor is asked which rather than the config file: with
561
+ // nothing picked that is the primary login, and the page says so instead
562
+ // of leaving a person to guess which of their two plans is being spent.
563
+ chosen: (supervisor._profilesFor?.('claude') ?? [])[0] === profile,
491
564
  // The default profile is whatever ~/.claude holds; anything else is a
492
565
  // second logged-in home directory, and its path is the only name it has.
493
566
  label: profile === 'default' ? 'default' : path.basename(profile),
@@ -519,6 +592,8 @@ export function readSettings({ config, supervisor, store }) {
519
592
  };
520
593
  });
521
594
 
595
+ // On her phone: every project unless she kept it here (shared/phone-snapshot.mjs).
596
+ const phoneSlugs = new Set(phoneProjectsOf(config.phoneProducts, process.env.AGENTBOX_PERSON_ID, phoneEligible(products)));
522
597
  const projects = products.map((product) => {
523
598
  let instructions = '';
524
599
  try { instructions = supervisor.readProjectInstructions(product.slug); } catch {}
@@ -540,6 +615,9 @@ export function readSettings({ config, supervisor, store }) {
540
615
  // workspace default and never a strip of Claude Code jargon on a page
541
616
  // she opens to change her rules.
542
617
  autonomous: (config.autonomousProducts ?? []).includes(product.slug),
618
+ // ON HER PHONE WITH THE MAC SHUT (docs/cloud/PHONE-PLAN.md): its threads
619
+ // go up to her own rows online on every sync (main/phone-inbox.mjs).
620
+ onPhone: phoneSlugs.has(product.slug),
543
621
  permission: override ? permissionMode(override) : 'workspace',
544
622
  permissionArgs: override ?? null,
545
623
  codexMode: config.projectCodexMode?.[product.slug] ?? 'workspace',
@@ -564,6 +642,8 @@ export function readSettings({ config, supervisor, store }) {
564
642
  return {
565
643
  archivedProjects,
566
644
  workspace: {
645
+ // THE PHONE AS A WHOLE: on unless she turned it off (shared/phone-snapshot.mjs).
646
+ phoneAll: phoneChoiceOf(config.phoneProducts, process.env.AGENTBOX_PERSON_ID, phoneEligible(products)).all,
567
647
  agentsRunning: !supervisor.paused,
568
648
  // The number picked on the menu, for the whole computer, or what is
569
649
  // running as the limit now when nothing was picked.
@@ -608,9 +688,11 @@ export function readSettings({ config, supervisor, store }) {
608
688
  // comes back with ONE entry and this screen draws exactly what it drew
609
689
  // before. A page that derived its own list would offer her a choice the
610
690
  // supervisor is about to refuse.
611
- ...engineSettings(supervisor, config),
691
+ ...engineSettings(supervisor, config, { search }),
612
692
  permission: permissionMode(workspaceArgs),
613
693
  permissionArgs: workspaceArgs,
694
+ cloudPermission: config.cloudPermission ?? CLOUD_CLAUDE_DEFAULT,
695
+ cloudCodexMode: config.cloudCodexMode ?? CLOUD_CODEX_DEFAULT,
614
696
  // ONE SWITCH FOR EVERYTHING THAT LEAVES THE MACHINE, and it is on when
615
697
  // Agentbox is installed (legal/privacy.html, section 10). Off stops the
616
698
  // counts AND the crash reports; there is deliberately no partial mode and
@@ -623,6 +705,8 @@ export function readSettings({ config, supervisor, store }) {
623
705
  // ADHD mode: whether the ADHD rules ride under hers (w-5737fe67cf). Off
624
706
  // unless she turned it on, so only `true` means on.
625
707
  adhdMode: config.adhdMode === true,
708
+ importNew: config.importNew === true,
709
+ alpha: alphaFeatures(config),
626
710
  // The corner tag over other apps (w-dafae58a23). On unless she turned it
627
711
  // off here, which is the only place it turns off for good.
628
712
  cornerTag: config.cornerTag !== false,
@@ -650,11 +734,11 @@ export function readSettings({ config, supervisor, store }) {
650
734
  // Looked up again on every read of this screen, not taken from boot.
651
735
  // Someone who reads "install it, then open this screen again" and does
652
736
  // exactly that has to see it turn found, without restarting the app.
653
- ...claudeState(config),
737
+ ...claudeState(config, { search }),
654
738
  // AND WHETHER CODEX IS, because the app needs one of the two and not
655
739
  // both: the last card of the walk only shuts the inbox when neither is
656
740
  // here (renderer/src/App.tsx).
657
- ...codexFoundState(config),
741
+ ...codexFoundState(config, {}, { search }),
658
742
  // AND WHAT THIS MAC'S CLAUDE CODE CALLS ITS MODELS.
659
743
  //
660
744
  // In the same trip, and for the same reason the line above is looked up
@@ -706,7 +790,7 @@ function engineTroubleFor(supervisor, engine) {
706
790
  return trouble ? engineTroubleNote(trouble.cause) : null;
707
791
  }
708
792
 
709
- function engineSettings(supervisor, config) {
793
+ function engineSettings(supervisor, config, { search = true } = {}) {
710
794
  const choices = supervisor.engineChoices();
711
795
  const engine = supervisor.engineFacts().workspace;
712
796
  // WHETHER THIS MAC HAS ASKED TO HEAR ABOUT CODEX AT ALL, which is a different
@@ -731,7 +815,7 @@ function engineSettings(supervisor, config) {
731
815
  // links the install, which is the question that person had.
732
816
  const codexIsHome = engine === 'codex';
733
817
  const codex = {
734
- ...codexState(config),
818
+ ...codexState(config, {}, { search }),
735
819
  trouble: engineTroubleFor(supervisor, 'codex'),
736
820
  account: codexAccount(supervisor._codexHome()),
737
821
  // EVERY CODEX LOGIN ON THE MAC, NOT JUST THE FIRST. The supervisor has
@@ -746,6 +830,7 @@ function engineSettings(supervisor, config) {
746
830
  return { engine, engineChoices: choices, codex, codexModels: [], codexModelDefault: null, codexModel: null };
747
831
  }
748
832
  const home = supervisor._codexHome();
833
+ const offered = supervisor._codexOfferHomes();
749
834
  return {
750
835
  engine,
751
836
  engineChoices: choices,
@@ -754,9 +839,12 @@ function engineSettings(supervisor, config) {
754
839
  // strip in the model drawer draws the picked model's list, so they travel
755
840
  // beside the name rather than as a list of their own that could disagree
756
841
  // with it.
757
- codexModels: codexModels({ home }).map((m) => ({
842
+ codexModels: codexModelsAcross(offered).map((m) => ({
758
843
  id: m.id, label: m.label, levels: m.levels.map((l) => l.id), defaultLevel: m.defaultLevel,
759
844
  })),
845
+ // Set when every login offered is on ChatGPT's free plan, so the menu can
846
+ // say why Codex lists so few models.
847
+ codexFreePlan: codexFreePlan(offered),
760
848
  // What her own `codex` in a terminal runs, so the card's word and her
761
849
  // terminal cannot disagree. Null is a real answer and the card says
762
850
  // "Codex's own" for it rather than guessing (renderer/src/models.ts).
@@ -786,12 +874,15 @@ const withSlug = (list, slug, on) => {
786
874
  // `paused` and `driven` were the other three and all three are gone from the
787
875
  // app: the first two because she could not tell what they did and would never
788
876
  // have used them, the third because the self-driving it belonged to is deleted.
789
- export function setProjectSetting({ config, supervisor }, { product, key, value }) {
877
+ export function setProjectSetting({ config, supervisor, store }, { product, key, value }) {
790
878
  if (!product) throw new Error('no project');
791
879
  switch (key) {
792
880
  case 'autonomous':
793
881
  saveConfig(config, { autonomousProducts: withSlug(config.autonomousProducts, product, !!value) });
794
882
  break;
883
+ case 'phone':
884
+ saveConfig(config, { phoneProducts: withPhoneProject(config.phoneProducts, process.env.AGENTBOX_PERSON_ID, product, !!value, phoneEligible(store?.listProducts?.() ?? [])) });
885
+ break;
795
886
  // WHICH OF HER CLAUDE CODE AGENTS THIS PROJECT TOOK. Names only: the files
796
887
  // stay where their author put them and Agentbox never copies or moves one,
797
888
  // so a list here that has gone stale costs nothing and an agent she
@@ -869,7 +960,9 @@ export function setProjectSetting({ config, supervisor }, { product, key, value
869
960
  * not signed in.
870
961
  */
871
962
  function codexAccountRows(supervisor) {
872
- const chosen = supervisor.config.activeAccount?.codex ?? null;
963
+ // THE ONE THAT RUNS, the same way the Claude rows answer it: the supervisor's
964
+ // own pick, which is the chosen account or the primary login (w-dac993a554).
965
+ const chosen = supervisor._profilesFor?.('codex')?.[0] ?? null;
873
966
  return supervisor._codexProfiles().map((profile) => {
874
967
  const home = supervisor._codexProfileHome(profile);
875
968
  const id = codexAccount(home);
@@ -881,8 +974,7 @@ function codexAccountRows(supervisor) {
881
974
  planNamed: id?.planNamed ?? false,
882
975
  accountId: id?.accountId ?? null,
883
976
  signedIn: !!id,
884
- // WHICH ONE RUNS. Null when she has never picked, and then every account
885
- // runs and the card says so rather than marking one at random.
977
+ // WHICH ONE RUNS, and one of them always does (`chosen` above).
886
978
  chosen: chosen === profile,
887
979
  };
888
980
  });
@@ -927,9 +1019,12 @@ export function addCodexAccount({ config, supervisor }) {
927
1019
  * ordinary reason for wanting it: a work login and a personal login, both
928
1020
  * live, on one Mac.
929
1021
  *
930
- * Everything else is the Codex flow exactly. Main makes the folder and
931
- * registers the profile, so the row appears immediately reading "Not signed
932
- * in"; the terminal is left with the browser half, which is genuinely hers.
1022
+ * Main makes the folder and the terminal is left with the browser half, which
1023
+ * is genuinely hers. UNLIKE CODEX, NOTHING IS WRITTEN INTO THE CONFIG: the
1024
+ * folder is the shape main/account-discovery.mjs finds, so the account appears
1025
+ * the moment its sign-in lands and never before. Registering it first put an
1026
+ * abandoned sign-in in Settings as a "Not signed in" account and handed it
1027
+ * every other task (tests/an-account-shows-once-and-only-once-it-is-signed-in).
933
1028
  *
934
1029
  * THE TOOLING IS LINKED AT CREATION, which the Codex side has no equivalent of.
935
1030
  * `linkAccountTooling` otherwise runs at the first spawn, and the first thing
@@ -939,9 +1034,6 @@ export function addCodexAccount({ config, supervisor }) {
939
1034
  */
940
1035
  export function addClaudeAccount({ config, supervisor }) {
941
1036
  const made = makeClaudeHome({ home: config.home });
942
- const existing = (config.authProfiles ?? []).map((x) => x || 'default');
943
- const list = existing.length ? existing : ['default'];
944
- saveConfig(config, { authProfiles: [...list, made.profile] });
945
1037
  // A failure here is a folder without her skills in it, which is a smaller
946
1038
  // thing than a sign in that does not happen: the links are retried at every
947
1039
  // spawn anyway.
@@ -1026,22 +1118,26 @@ export function leftoverSettings({ config, supervisor }) {
1026
1118
  // Codex, 2026-10-05).
1027
1119
  if (!on) {
1028
1120
  if (total && stoppable) {
1029
- now = `Right now finished agents have left ${total} program${total === 1 ? '' : 's'} running; turning this on stops ${stoppable === total ? (total === 1 ? 'it' : 'them') : `${stoppable} of them`}, two hours from then.`;
1121
+ now = `Right now finished agents have left ${total} program${total === 1 ? '' : 's'} running; turning this on stops ${stoppable === total ? (total === 1 ? 'it' : 'them') : `${stoppable} of them`} when you close their tasks.`;
1030
1122
  }
1031
1123
  return { on, now };
1032
1124
  }
1033
1125
  {
1034
1126
  if (!total) now = 'Nothing left running by finished agents.';
1035
1127
  else {
1036
- const next = list.filter((l) => l.programs && l.stopsAt).map((l) => l.stopsAt).sort((a, b) => a - b)[0];
1128
+ const timed = list.filter((l) => l.programs && l.stopsAt);
1129
+ const next = timed.map((l) => l.stopsAt).sort((a, b) => a - b)[0];
1130
+ const soon = timed.reduce((n, l) => n + l.programs, 0);
1131
+ const open = stoppable - soon;
1037
1132
  const when = (ms) => {
1038
1133
  const m = Math.max(1, Math.round((ms - Date.now()) / 60_000));
1039
1134
  return m >= 60 ? `${Math.floor(m / 60)} h${m % 60 ? ` ${m % 60} m` : ''}` : `${m} m`;
1040
1135
  };
1041
- now = `Finished agents have left ${total} program${total === 1 ? '' : 's'} running.`;
1042
- if (stoppable) now += ` ${stoppable} ${next && next > Date.now() ? `stop in ${when(next)}` : 'are stopping'}`;
1043
- if (kept) now += `${stoppable ? ';' : ''} ${kept} ${kept === 1 ? 'is' : 'are'} kept`;
1044
- now += '.';
1136
+ const parts = [];
1137
+ if (soon) parts.push(`${soon} ${next > Date.now() ? `stop${soon === 1 ? 's' : ''} in ${when(next)}` : `${soon === 1 ? 'is' : 'are'} stopping`}`);
1138
+ if (open) parts.push(`${open} stop${open === 1 ? 's' : ''} when you close ${open === 1 ? 'its task' : 'their tasks'}`);
1139
+ if (kept) parts.push(`${kept} ${kept === 1 ? 'is' : 'are'} kept`);
1140
+ now = `Finished agents have left ${total} program${total === 1 ? '' : 's'} running. ${parts.join('; ')}.`;
1045
1141
  const survivors = s?.survivors?.length ?? 0;
1046
1142
  if (survivors) now += ` ${survivors} did not stop when asked.`;
1047
1143
  }
@@ -1077,8 +1173,31 @@ export function strayFolderSettings({ supervisor }, home = os.homedir()) {
1077
1173
  return { count, now };
1078
1174
  }
1079
1175
 
1080
- export function setWorkspaceSetting({ config, supervisor }, { key, value }) {
1176
+ export function cornerTagTurnedOff({ key, value } = {}) {
1177
+ return key === 'cornerTag' && !value;
1178
+ }
1179
+
1180
+ export function countsTurnedOff({ key, value } = {}) {
1181
+ return key === 'diagnostics' && !value;
1182
+ }
1183
+
1184
+ export function setWorkspaceSetting({ config, supervisor, store }, { key, value }) {
1081
1185
  switch (key) {
1186
+ // EVERY PROJECT ON HER PHONE, or none (shared/phone-snapshot.mjs). Which
1187
+ // ones she keeps here is remembered either way.
1188
+ case 'phoneAll':
1189
+ saveConfig(config, { phoneProducts: withPhoneAll(config.phoneProducts, process.env.AGENTBOX_PERSON_ID, !!value, phoneEligible(store?.listProducts?.() ?? [])) });
1190
+ break;
1191
+ // THE DROPDOWN'S WHOLE ANSWER AT ONCE: on or off, and which projects stay
1192
+ // on this computer. Only project slugs that exist are kept.
1193
+ case 'phoneProjects': {
1194
+ const person = process.env.AGENTBOX_PERSON_ID;
1195
+ if (!person) throw new Error('sign in first');
1196
+ const every = phoneEligible(store?.listProducts?.() ?? []);
1197
+ const except = Array.isArray(value?.except) ? value.except.filter((s) => every.includes(s)) : [];
1198
+ saveConfig(config, { phoneProducts: { owner: person, all: value?.all !== false, except } });
1199
+ break;
1200
+ }
1082
1201
  case 'agentsRunning':
1083
1202
  supervisor.paused = !value;
1084
1203
  supervisor.onChange?.();
@@ -1139,6 +1258,43 @@ export function setWorkspaceSetting({ config, supervisor }, { key, value }) {
1139
1258
  break;
1140
1259
  // STOP WHAT FINISHED AGENTS LEAVE RUNNING (main/leftovers.mjs). Turning it
1141
1260
  // on records the moment, which is the earliest the clock may start from.
1261
+ // WHERE THREADS RUN (renderer/src/cloud-menu.ts): 'mac' turns cloud runs
1262
+ // off, 'full' sends what does not fit here, 'all' sends everything first.
1263
+ // Read by the supervisor per call, so it takes effect on the next tick.
1264
+ case 'cloudRuns': {
1265
+ const map = { mac: false, full: null, all: 'all' };
1266
+ if (!(value in map)) throw new Error(`unknown cloud mode: ${value}`);
1267
+ // Turning the cloud on to one meaning makes that the one C goes back to.
1268
+ const patch = value === 'mac' ? { cloudRuns: false } : { cloudRuns: map[value], cloudWhenOn: value };
1269
+ saveConfig(config, patch);
1270
+ Object.assign(config, patch);
1271
+ supervisor.wake?.();
1272
+ supervisor.onChange?.();
1273
+ break;
1274
+ }
1275
+ // WHAT "ON" MEANS (renderer/src/cloud-menu.ts): kept while the cloud is
1276
+ // off, and taking effect at once while it is on.
1277
+ case 'cloudWhenOn': {
1278
+ if (value !== 'full' && value !== 'all') throw new Error(`unknown meaning of on: ${value}`);
1279
+ const patch = config.cloudRuns === false ? { cloudWhenOn: value } : { cloudWhenOn: value, cloudRuns: value === 'all' ? 'all' : null };
1280
+ saveConfig(config, patch);
1281
+ Object.assign(config, patch);
1282
+ supervisor.wake?.();
1283
+ supervisor.onChange?.();
1284
+ break;
1285
+ }
1286
+ // THE CLOUD'S OWN MODE PER ENGINE, CLOUD_SAME for this computer's, or null
1287
+ // for the cloud's default (main/cloud-permission.mjs).
1288
+ case 'cloudPermission':
1289
+ case 'cloudCodexMode': {
1290
+ const known = key === 'cloudPermission' ? CLAUDE_MODES.includes(value) : isCodexMode(value);
1291
+ if (value != null && value !== CLOUD_SAME && !known) throw new Error(`unknown permission mode: ${value}`);
1292
+ const patch = { [key]: value ?? null };
1293
+ saveConfig(config, patch);
1294
+ Object.assign(config, patch);
1295
+ supervisor.onChange?.();
1296
+ break;
1297
+ }
1142
1298
  case 'cleanupLeftovers':
1143
1299
  saveConfig(config, value ? { cleanupLeftovers: true, cleanupLeftoversSince: Date.now() } : { cleanupLeftovers: false });
1144
1300
  supervisor.setLeftoverCleanup?.(!!value)?.catch?.((e) => console.warn('zero: leftovers:', e.message));
@@ -1162,6 +1318,26 @@ export function setWorkspaceSetting({ config, supervisor }, { key, value }) {
1162
1318
  case 'adhdMode':
1163
1319
  saveConfig(config, { adhdMode: !!value });
1164
1320
  break;
1321
+ // New chats from Claude Code and Codex come in on their own
1322
+ // (main/new-chats-watch.mjs), only those started after it went on.
1323
+ case 'importNew':
1324
+ if (!value) saveConfig(config, { importNew: false });
1325
+ else if (config.importNew !== true) saveConfig(config, { importNew: true, importNewSince: Date.now() });
1326
+ break;
1327
+ // Rooms is read on every snapshot.
1328
+ case 'alphaRooms':
1329
+ saveConfig(config, { alphaRooms: !!value });
1330
+ supervisor.onChange?.();
1331
+ break;
1332
+ case 'alphaTeammates':
1333
+ saveConfig(config, { alphaTeammates: !!value });
1334
+ supervisor.onChange?.();
1335
+ supervisor.wake?.();
1336
+ break;
1337
+ case 'alphaMultiplayer':
1338
+ saveConfig(config, { alphaMultiplayer: !!value });
1339
+ supervisor.onChange?.();
1340
+ break;
1165
1341
  // THE CORNER TAG (w-dafae58a23). Turning it back on also ends any hide, so
1166
1342
  // the switch does what it says the moment she flips it.
1167
1343
  case 'cornerTag':
@@ -1175,15 +1351,15 @@ export function setWorkspaceSetting({ config, supervisor }, { key, value }) {
1175
1351
  // in one object keyed by engine is what stops a Codex pick being read as a
1176
1352
  // Claude one, which is the collision `_accountKey` exists to prevent.
1177
1353
  //
1178
- // NULL CLEARS IT, and clearing means every account runs again, which is what
1179
- // this machine did before she ever picked. `Supervisor#_narrowToChosen` also
1180
- // ignores a name that no longer exists, so a login she removes cannot wedge
1181
- // the fleet.
1354
+ // NULL CLEARS IT, and clearing means the primary login runs the work again.
1355
+ // `Supervisor#_theOneAccount` also ignores a name that no longer exists, so
1356
+ // a login she removes cannot wedge the fleet.
1182
1357
  case 'activeAccount': {
1183
1358
  const engineId = value?.engine;
1184
1359
  if (!isEngine(engineId)) throw new Error(`unknown coding agent: ${engineId}`);
1185
1360
  const profile = typeof value?.profile === 'string' && value.profile ? value.profile : null;
1186
1361
  saveConfig(config, { activeAccount: { ...(config.activeAccount ?? {}), [engineId]: profile } });
1362
+ supervisor.accountChosen?.(engineId, profile);
1187
1363
  supervisor.onChange?.();
1188
1364
  break;
1189
1365
  }