agentbox-app 0.1.12 → 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.
- package/README.md +24 -9
- package/bin/agentbox.mjs +23 -1
- package/briefs/message-rules.md +36 -8
- package/briefs/worker.md +46 -23
- package/main/account-discovery.mjs +122 -30
- package/main/account-tooling.mjs +29 -1
- package/main/account-usage.mjs +46 -0
- package/main/acp.mjs +296 -0
- package/main/agent-homes.mjs +158 -0
- package/main/agent-sessions.mjs +311 -260
- package/main/agent-updates.mjs +9 -22
- package/main/agents.mjs +179 -466
- package/main/analytics.mjs +42 -2
- package/main/answer-modes.mjs +103 -37
- package/main/approval-prompt-core.mjs +197 -0
- package/main/approval-prompt-server.mjs +4 -138
- package/main/approvals.mjs +101 -297
- package/main/artifact-path.mjs +47 -18
- package/main/claude-bin.mjs +45 -311
- package/main/claude-input.mjs +57 -7
- package/main/claude-launch-env.mjs +54 -0
- package/main/claude-models.mjs +39 -7
- package/main/claude-plan.mjs +64 -16
- package/main/claude-session-open.mjs +28 -0
- package/main/claude-usage-process.mjs +40 -0
- package/main/claude-usage.mjs +94 -59
- package/main/cloud/account.mjs +179 -0
- package/main/cloud/aws.mjs +127 -0
- package/main/cloud/browser-return.mjs +58 -0
- package/main/cloud/clients.mjs +15 -0
- package/main/cloud/codex-cloud.mjs +53 -0
- package/main/cloud/config.mjs +107 -0
- package/main/cloud/docs.mjs +219 -0
- package/main/cloud/exec.mjs +27 -0
- package/main/cloud/host.mjs +165 -0
- package/main/cloud/kit.mjs +80 -0
- package/main/cloud/logins.mjs +543 -0
- package/main/cloud/managed.mjs +115 -0
- package/main/cloud/marker.mjs +104 -0
- package/main/cloud/org.mjs +53 -0
- package/main/cloud/reuse.mjs +208 -0
- package/main/cloud/run-cli.mjs +177 -0
- package/main/cloud/run.mjs +1934 -0
- package/main/cloud/usage.mjs +76 -0
- package/main/cloud-permission.mjs +51 -0
- package/main/codex-account.mjs +78 -0
- package/main/codex-app-server.mjs +276 -409
- package/main/codex-approvals.mjs +148 -433
- package/main/codex-bin.mjs +51 -249
- package/main/codex-models.mjs +20 -2
- package/main/codex-session.mjs +246 -506
- package/main/codex-threads-worker.mjs +12 -0
- package/main/codex-threads.mjs +112 -11
- package/main/codex-usage-file.mjs +5 -3
- package/main/codex-usage.mjs +56 -7
- package/main/codex-watch.mjs +83 -5
- package/main/codex.mjs +95 -363
- package/main/config.mjs +37 -5
- package/main/corner-tag.mjs +810 -0
- package/main/crash-report.mjs +26 -3
- package/main/dev-window.mjs +1 -1
- package/main/engine-bin.mjs +545 -0
- package/main/engine-setup.mjs +25 -24
- package/main/feedback.mjs +14 -31
- package/main/folder-pictures.mjs +2 -2
- package/main/freeze-recorder-thread.mjs +86 -0
- package/main/freeze-recorder.mjs +146 -0
- package/main/fresh-user.mjs +20 -9
- package/main/git-change-offthread.mjs +17 -3
- package/main/git-change-thread.mjs +5 -2
- package/main/harnesses/claude-stream.mjs +208 -0
- package/main/harnesses/claude.mjs +105 -0
- package/main/harnesses/codex.mjs +72 -0
- package/main/harnesses/common.mjs +78 -0
- package/main/harnesses/instructions-file.mjs +116 -0
- package/main/harnesses/opencode.mjs +234 -0
- package/main/harnesses.mjs +65 -0
- package/main/importable-threads.mjs +96 -0
- package/main/ipc.mjs +520 -135
- package/main/leftovers.mjs +117 -25
- package/main/liquid-glass.mjs +26 -0
- package/main/live-replies.mjs +10 -4
- package/main/local-app-frames.mjs +82 -0
- package/main/main-went-red.mjs +330 -0
- package/main/main.mjs +248 -37
- package/main/memory-gate-history.mjs +85 -20
- package/main/memory-gate-server.mjs +129 -11
- package/main/memory-gate.mjs +62 -8
- package/main/memory-log.mjs +124 -0
- package/main/menu.mjs +4 -2
- package/main/message-priority.mjs +2 -2
- package/main/mic.mjs +38 -0
- package/main/native/liquid-glass/build/liquid-glass.node +0 -0
- package/main/new-chats-watch.mjs +110 -0
- package/main/new-user-window.mjs +25 -0
- package/main/notify.mjs +64 -5
- package/main/opencode-server.mjs +271 -0
- package/main/opencode.mjs +287 -0
- package/main/phone-alerts.mjs +117 -0
- package/main/phone-inbox.mjs +625 -0
- package/main/phone-link.mjs +571 -0
- package/main/phone-uploads.mjs +476 -0
- package/main/picture-shape.mjs +114 -0
- package/main/quit-sequence.mjs +143 -0
- package/main/refresh-agent-models.mjs +15 -2
- package/main/relay-address.mjs +28 -0
- package/main/relay-client.mjs +314 -0
- package/main/repeats.mjs +10 -4
- package/main/row-label.mjs +18 -47
- package/main/run-change.mjs +13 -0
- package/main/run-ledger.mjs +135 -0
- package/main/runs-on.mjs +32 -35
- package/main/save-attachments.mjs +41 -0
- package/main/serve.mjs +155 -9
- package/main/settings.mjs +364 -50
- package/main/shell-path.mjs +234 -0
- package/main/ship-conflict-brief.mjs +119 -0
- package/main/ship-queue.mjs +134 -20
- package/main/sign-in-files.mjs +3 -7
- package/main/source-updater.mjs +45 -11
- package/main/stage-attachment.mjs +68 -0
- package/main/stall-watch.mjs +50 -0
- package/main/start-hold.mjs +73 -0
- package/main/store/home.mjs +87 -232
- package/main/store/paths.mjs +11 -0
- package/main/store/teammates-files.mjs +99 -0
- package/main/store/work-items.mjs +231 -13
- package/main/store.mjs +227 -53
- package/main/supervisor.mjs +3865 -699
- package/main/task-commands.mjs +13 -17
- package/main/task-folders-offthread.mjs +6 -1
- package/main/task-folders.mjs +897 -105
- package/main/task-terminals.mjs +147 -41
- package/main/team/index.mjs +114 -10
- package/main/team/memory-cloud.mjs +183 -1
- package/main/team/room-hours.mjs +48 -0
- package/main/team/room-setup.mjs +31 -0
- package/main/team/rooms-memory.mjs +454 -0
- package/main/team/rooms-shape.mjs +42 -0
- package/main/team/rooms-supabase.mjs +324 -0
- package/main/team/rooms.mjs +575 -0
- package/main/team/session.mjs +96 -26
- package/main/team/supabase-backend.mjs +180 -0
- package/main/team/sync.mjs +109 -1
- package/main/teammates.mjs +580 -0
- package/main/terminal-host.mjs +143 -0
- package/main/terminal-hosts.mjs +261 -0
- package/main/transcript-search.mjs +80 -0
- package/main/updater.mjs +71 -9
- package/main/webview-guard.mjs +45 -0
- package/main/worktree-include.mjs +365 -0
- package/mcp/core/documents.mjs +3 -1
- package/mcp/core/repeats.mjs +88 -0
- package/mcp/core/teammates.mjs +222 -0
- package/mcp/core/work.mjs +76 -4
- package/mcp/stdio.mjs +24 -11
- package/mcp/tools.mjs +116 -8
- package/package.json +30 -5
- package/renderer/dist/assets/abnfDiagram-YUKMZFIV-CoWB6YUK.js +1 -0
- package/renderer/dist/assets/arc-Ch0NrCul.js +1 -0
- package/renderer/dist/assets/architectureDiagram-47P4ROYG-CXz9M5tQ.js +36 -0
- package/renderer/dist/assets/blockDiagram-E7TT5TSB-DchGUuHH.js +140 -0
- package/renderer/dist/assets/c4Diagram-CRA5TL53-Cip-zNyr.js +38 -0
- package/renderer/dist/assets/channel-BQuQSL--.js +1 -0
- package/renderer/dist/assets/chunk-2Q5K7J3B-BoXid_2r.js +1 -0
- package/renderer/dist/assets/chunk-5VM5RSS4-Cpez1rRz.js +15 -0
- package/renderer/dist/assets/chunk-7TKQ45FW-DKA84YkE.js +1 -0
- package/renderer/dist/assets/chunk-AW2ZBBNX-Dg-SumPG.js +88 -0
- package/renderer/dist/assets/chunk-FVRAUYC3-06TCvPm1.js +2 -0
- package/renderer/dist/assets/chunk-HTAEGDNF-CMEBy1Td.js +1 -0
- package/renderer/dist/assets/chunk-JWPE2WC7-BJ2ObmV-.js +1 -0
- package/renderer/dist/assets/chunk-KQW6MTUR-CGWOYXUE.js +1 -0
- package/renderer/dist/assets/chunk-XXDRQBXY-CiZp07XC.js +1 -0
- package/renderer/dist/assets/classDiagram-v2-K4WV4PDN-DJNIX719.js +217 -0
- package/renderer/dist/assets/cornerTag-CPgvu-q3.js +1 -0
- package/renderer/dist/assets/cornerTag-oMfEjzCO.css +1 -0
- package/renderer/dist/assets/cose-bilkent-JH36ORCC-CbkyZOUH.js +1 -0
- package/renderer/dist/assets/cynefin-EF2NZ3EQ-78iOroZO.js +141 -0
- package/renderer/dist/assets/cynefinDiagram-3GCD6N5R-GcCopMs7.js +62 -0
- package/renderer/dist/assets/cytoscape.esm-C5JX3QLV.js +331 -0
- package/renderer/dist/assets/dagre-W4DXFKR2-DHLlXLkz.js +4 -0
- package/renderer/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/renderer/dist/assets/diagram-2UJZ2QOL-DuZSUHcH.js +200 -0
- package/renderer/dist/assets/diagram-OVF4WLC6-Ckxu3cqH.js +24 -0
- package/renderer/dist/assets/diagram-PFPMY2P6-CsTw9Ycn.js +30 -0
- package/renderer/dist/assets/diagram-UMYRVEAY-CTXd8qVg.js +24 -0
- package/renderer/dist/assets/diagram-YEKJPTXX-CJs1T_9m.js +41 -0
- package/renderer/dist/assets/diagram-ZIFT7M5P-CvjI23mf.js +3 -0
- package/renderer/dist/assets/ebnfDiagram-VR2GEFS7-d_IeAzOJ.js +1 -0
- package/renderer/dist/assets/elk-IJKZMXRS-zo9KFP3N.js +27 -0
- package/renderer/dist/assets/erDiagram-O2IAPWRE-DqfYf5Dt.js +99 -0
- package/renderer/dist/assets/flowDiagram-OXPTDLAJ-DAWsMLmo.js +213 -0
- package/renderer/dist/assets/ganttDiagram-R7TSEDQI-4ml_bhwR.js +292 -0
- package/renderer/dist/assets/gitGraphDiagram-XJZIOB7I-B_WcqSId.js +106 -0
- package/renderer/dist/assets/graph-DGbsTEsI.js +1 -0
- package/renderer/dist/assets/infoDiagram-5W2HQ5XZ-CI-jYqzc.js +2 -0
- package/renderer/dist/assets/init-Gi6I4Gst.js +1 -0
- package/renderer/dist/assets/ishikawaDiagram-K3B6WC7H-B56VWRlV.js +70 -0
- package/renderer/dist/assets/journeyDiagram-COXZFDF6-D1-p09Lr.js +139 -0
- package/renderer/dist/assets/kanban-definition-P3RFRI5V-Cv3w7JoN.js +89 -0
- package/renderer/dist/assets/katex-C5jXJg4s.js +257 -0
- package/renderer/dist/assets/linear-C35V2Spi.js +1 -0
- package/renderer/dist/assets/main-BcoBiGwv.css +32 -0
- package/renderer/dist/assets/main-CLnIOulD.js +1191 -0
- package/renderer/dist/assets/mermaid.core-BzGT5Vo9.js +314 -0
- package/renderer/dist/assets/mindmap-definition-LZFPQGKD-BZUfuymC.js +96 -0
- package/renderer/dist/assets/ordinal-Cboi1Yqb.js +1 -0
- package/renderer/dist/assets/pegDiagram-BGZESJAR-DFh9XNGe.js +1 -0
- package/renderer/dist/assets/pieDiagram-CAPJLFHJ-C65tPVsy.js +39 -0
- package/renderer/dist/assets/product-name-CSNW6d7s.js +40 -0
- package/renderer/dist/assets/quadrantDiagram-GDMTTRAM-Cushj_nk.js +7 -0
- package/renderer/dist/assets/railroadDiagram-SM67HX2B-DZGebGx5.js +1 -0
- package/renderer/dist/assets/requirementDiagram-X7JNWC4A-DpAB0MNo.js +84 -0
- package/renderer/dist/assets/sankeyDiagram-UM26HJRW-D-29rHra.js +40 -0
- package/renderer/dist/assets/sequenceDiagram-ZO4K6R2Y-FfOQAZol.js +169 -0
- package/renderer/dist/assets/sizeCapture-INFHLROL-C_n6fDBY.js +1 -0
- package/renderer/dist/assets/stateDiagram-v2-TBUQTH76-BZjenzJG.js +291 -0
- package/renderer/dist/assets/swimlanes-N4OXWK64-DxaMU9vX.js +1 -0
- package/renderer/dist/assets/swimlanesDiagram-K3J5GTZL-Cb2kM6rr.js +8 -0
- package/renderer/dist/assets/timeline-definition-YOQAKGHF-DTg5HJKz.js +120 -0
- package/renderer/dist/assets/usecaseDiagram-VIAY4XPW-Bc3MZDsl.js +370 -0
- package/renderer/dist/assets/vennDiagram-BLWOH2XV-GIVGk9Id.js +34 -0
- package/renderer/dist/assets/wardleyDiagram-YMQ3BMBF-NmJnbQOg.js +78 -0
- package/renderer/dist/assets/xychartDiagram-TAQBALBS-p-kfGfnW.js +7 -0
- package/renderer/dist/corner-tag.html +13 -0
- package/renderer/dist/emulator/audio-rules.mjs +74 -0
- package/renderer/dist/emulator/data/compression/README.md +11 -0
- package/renderer/dist/emulator/data/compression/extract7z.js +1 -0
- package/renderer/dist/emulator/data/compression/extractzip.js +1 -0
- package/renderer/dist/emulator/data/compression/libunrar.js +519 -0
- package/renderer/dist/emulator/data/compression/libunrar.wasm +0 -0
- package/renderer/dist/emulator/data/cores/README.md +22 -0
- package/renderer/dist/emulator/data/cores/mgba-legacy-wasm.data +0 -0
- package/renderer/dist/emulator/data/cores/mgba-thread-legacy-wasm.data +0 -0
- package/renderer/dist/emulator/data/cores/mgba-thread-wasm.data +0 -0
- package/renderer/dist/emulator/data/cores/mgba-wasm.data +0 -0
- package/renderer/dist/emulator/data/cores/package.json +65 -0
- package/renderer/dist/emulator/data/cores/reports/mgba.json +1 -0
- package/renderer/dist/emulator/data/emulator.css +1614 -0
- package/renderer/dist/emulator/data/loader.js +170 -0
- package/renderer/dist/emulator/data/localization/README.md +63 -0
- package/renderer/dist/emulator/data/localization/af-FR.json +339 -0
- package/renderer/dist/emulator/data/localization/ar-AR.json +301 -0
- package/renderer/dist/emulator/data/localization/ben-BEN.json +301 -0
- package/renderer/dist/emulator/data/localization/de-GER.json +301 -0
- package/renderer/dist/emulator/data/localization/el-GR.json +301 -0
- package/renderer/dist/emulator/data/localization/en-US.json +339 -0
- package/renderer/dist/emulator/data/localization/es-ES.json +310 -0
- package/renderer/dist/emulator/data/localization/fa-AF.json +310 -0
- package/renderer/dist/emulator/data/localization/hi-HI.json +301 -0
- package/renderer/dist/emulator/data/localization/it-IT.json +302 -0
- package/renderer/dist/emulator/data/localization/ja-JA.json +301 -0
- package/renderer/dist/emulator/data/localization/jv-JV.json +301 -0
- package/renderer/dist/emulator/data/localization/ko-KO.json +336 -0
- package/renderer/dist/emulator/data/localization/pt-BR.json +361 -0
- package/renderer/dist/emulator/data/localization/retroarch.json +617 -0
- package/renderer/dist/emulator/data/localization/ro-RO.json +310 -0
- package/renderer/dist/emulator/data/localization/ru-RU.json +301 -0
- package/renderer/dist/emulator/data/localization/tr-TR.json +310 -0
- package/renderer/dist/emulator/data/localization/vi-VN.json +302 -0
- package/renderer/dist/emulator/data/localization/zh-CN.json +351 -0
- package/renderer/dist/emulator/data/src/GameManager.js +464 -0
- package/renderer/dist/emulator/data/src/compression.js +142 -0
- package/renderer/dist/emulator/data/src/emulator.js +6158 -0
- package/renderer/dist/emulator/data/src/gamepad.js +167 -0
- package/renderer/dist/emulator/data/src/nipplejs.js +1 -0
- package/renderer/dist/emulator/data/src/shaders.js +236 -0
- package/renderer/dist/emulator/data/src/socket.io.min.js +7 -0
- package/renderer/dist/emulator/data/src/storage.js +125 -0
- package/renderer/dist/emulator/data/version.json +5 -0
- package/renderer/dist/emulator/host.js +297 -0
- package/renderer/dist/emulator/index.html +28 -0
- package/renderer/dist/emulator/provenance.json +6 -0
- package/renderer/dist/index.html +16 -3
- package/scripts/after-install.mjs +30 -8
- package/scripts/approval-server.sh +24 -5
- package/scripts/before-publish.mjs +12 -10
- package/scripts/cloud-shim.pl +57 -0
- package/shared/account-names.d.mts +6 -0
- package/shared/account-names.mjs +15 -0
- package/shared/agent-hours.mjs +136 -0
- package/shared/agent-import.mjs +62 -34
- package/shared/agents.d.mts +1 -0
- package/shared/agents.mjs +126 -522
- package/shared/analytics-events.mjs +12 -0
- package/shared/approval-card.mjs +36 -0
- package/shared/bridge-map.mjs +45 -1
- package/shared/claude-code-shape.mjs +6 -0
- package/shared/claude-commands.generated.mjs +6 -4
- package/shared/claude-models.generated.mjs +6 -4
- package/shared/claude-usage.d.mts +1 -0
- package/shared/claude-usage.mjs +42 -1
- package/shared/cloud-hand-back.d.mts +7 -0
- package/shared/cloud-hand-back.mjs +20 -0
- package/shared/cloud-kit.d.mts +219 -0
- package/shared/cloud-kit.mjs +341 -0
- package/shared/cloud-login-name.mjs +4 -0
- package/shared/cloud-start.mjs +17 -0
- package/shared/cloud-versions.mjs +23 -0
- package/shared/codex-import.mjs +2 -2
- package/shared/codex-modes.d.mts +22 -9
- package/shared/codex-modes.mjs +67 -11
- package/shared/codex-usage.mjs +108 -2
- package/shared/corner-tag.d.mts +36 -0
- package/shared/corner-tag.mjs +396 -0
- package/shared/dead-run-trace.mjs +19 -2
- package/shared/engines.mjs +76 -300
- package/shared/feedback.d.mts +7 -0
- package/shared/feedback.mjs +25 -0
- package/shared/first-run-practice.mjs +17 -24
- package/shared/harness-definitions.mjs +111 -0
- package/shared/instruction-defaults.json +2 -2
- package/shared/key-caps.d.mts +14 -0
- package/shared/key-caps.mjs +68 -0
- package/shared/message-edits.d.mts +7 -0
- package/shared/message-edits.mjs +35 -0
- package/shared/move-thread.d.mts +24 -0
- package/shared/move-thread.mjs +112 -0
- package/shared/named-threads.mjs +72 -0
- package/shared/not-shipped.d.mts +22 -0
- package/shared/not-shipped.mjs +89 -0
- package/shared/notify-rules.d.mts +31 -0
- package/shared/notify-rules.mjs +55 -8
- package/shared/phone-files.mjs +28 -0
- package/shared/phone-settings.mjs +118 -0
- package/shared/phone-snapshot.d.mts +16 -0
- package/shared/phone-snapshot.mjs +348 -0
- package/shared/picture-formats.d.mts +1 -0
- package/shared/picture-formats.mjs +13 -0
- package/shared/provider-commands.mjs +10 -2
- package/shared/rank.d.mts +4 -1
- package/shared/rank.mjs +82 -19
- package/shared/relay-address.mjs +6 -0
- package/shared/relay-crypto.mjs +165 -0
- package/shared/repeats.d.mts +8 -0
- package/shared/repeats.mjs +33 -2
- package/shared/room-cards.mjs +167 -0
- package/shared/room-links.d.mts +4 -0
- package/shared/room-links.mjs +21 -0
- package/shared/runs-on.d.mts +3 -13
- package/shared/runs-on.mjs +31 -52
- package/shared/shipped-note.d.mts +4 -0
- package/shared/shipped-note.mjs +6 -0
- package/shared/shortcuts.mjs +24 -10
- package/shared/spawn-trouble.d.mts +4 -0
- package/shared/spawn-trouble.mjs +484 -30
- package/shared/team-rules.mjs +9 -2
- package/shared/teammates.d.mts +19 -0
- package/shared/teammates.mjs +756 -0
- package/shared/terminal-focus.d.mts +1 -0
- package/shared/terminal-focus.mjs +13 -0
- package/shared/terminal-input.d.mts +1 -0
- package/shared/terminal-input.mjs +30 -0
- package/shared/terminal-keys.d.mts +1 -0
- package/shared/terminal-keys.mjs +16 -0
- package/shared/terminal-size.d.mts +4 -0
- package/shared/terminal-size.mjs +29 -0
- package/shared/thread-cards.mjs +4 -1
- package/shared/usage.d.mts +12 -0
- package/shared/usage.mjs +56 -3
- package/shared/websites.d.mts +15 -0
- package/shared/websites.mjs +61 -0
- package/shared/where-it-runs-from.d.mts +43 -0
- package/shared/where-it-runs-from.mjs +155 -0
- package/shared/work-items.mjs +150 -29
- package/shared/work-lines.mjs +93 -245
- package/shared/xterm-invalid-range.d.mts +2 -0
- package/shared/xterm-invalid-range.mjs +58 -0
- package/renderer/dist/assets/index-ChKsQkRw.js +0 -1169
- package/renderer/dist/assets/index-ClBXnq3B.css +0 -32
package/main/settings.mjs
CHANGED
|
@@ -12,27 +12,34 @@
|
|
|
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';
|
|
18
|
+
import { harnessFor } from './harnesses.mjs';
|
|
16
19
|
import os from 'node:os';
|
|
17
20
|
import path from 'node:path';
|
|
18
21
|
import { codexChoiceToOpen, saveConfig } from './config.mjs';
|
|
19
|
-
import {
|
|
22
|
+
import { forgetClaudeBin, INSTALL_URL } from './claude-bin.mjs';
|
|
23
|
+
import { lookAgain } from './engine-bin.mjs';
|
|
20
24
|
import { AGENT_MODES } from '../shared/agents.mjs';
|
|
21
25
|
import { analyticsKey, diagnosticsOn } from './analytics.mjs';
|
|
22
26
|
import { CLAUDE_PERMISSION_MODES } from '../shared/work-items.mjs';
|
|
23
|
-
import { accountSentence, engineTroubleNote } from '../shared/spawn-trouble.mjs';
|
|
27
|
+
import { accountSentence, engineTroubleNote, refineCause } from '../shared/spawn-trouble.mjs';
|
|
24
28
|
import { readPlan } from './claude-plan.mjs';
|
|
25
|
-
import { effectiveProfiles } from './account-discovery.mjs';
|
|
29
|
+
import { effectiveProfiles, troubleForProfile } from './account-discovery.mjs';
|
|
26
30
|
import { machineSlots, machineNote, autoAgents, MAX_SLOTS } from './machine.mjs';
|
|
27
|
-
import {
|
|
31
|
+
import { shortPath } from './agent-files.mjs';
|
|
32
|
+
import { NAME, Name } from '../shared/product-name.mjs';
|
|
28
33
|
import { autoSlots } from './memory-gate.mjs';
|
|
29
34
|
import { accountIdentity, claudeLoginCommand, duplicateAccountNote, linkAccountTooling, makeClaudeHome } from './account-tooling.mjs';
|
|
30
35
|
import { isEngine } from '../shared/engines.mjs';
|
|
31
|
-
import { codexAccount, codexLoginCommand, makeCodexHome } from './codex-account.mjs';
|
|
32
|
-
import { codexDefaultModel,
|
|
36
|
+
import { codexAccount, codexFreePlan, codexLoginCommand, makeCodexHome } from './codex-account.mjs';
|
|
37
|
+
import { codexDefaultModel, codexModelsAcross } from './codex-models.mjs';
|
|
33
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';
|
|
34
41
|
import { claudeModels } from './claude-models.mjs';
|
|
35
|
-
import {
|
|
42
|
+
import { forgetCodexBin, INSTALL_URL as CODEX_INSTALL_URL } from './codex-bin.mjs';
|
|
36
43
|
|
|
37
44
|
// Her Claude Code sessions in her inbox: all of them, only the ones stopped on
|
|
38
45
|
// a question, or none. One reader, here, so the settings screen and the
|
|
@@ -213,6 +220,8 @@ export function buildSessionArgs(base, mode) {
|
|
|
213
220
|
return [...model, ...(tools.length ? ['--allowedTools', ...tools] : []), ...grant, ...parsed.other];
|
|
214
221
|
}
|
|
215
222
|
|
|
223
|
+
export { cloudPermissionArgs } from './cloud-permission.mjs';
|
|
224
|
+
|
|
216
225
|
// THE MODEL, WRITTEN BACK INTO THE SAME LIST buildSessionArgs READS FROM.The
|
|
217
226
|
// screen had no control over this at all; the flag was already there and only
|
|
218
227
|
// a text editor could change it.
|
|
@@ -245,16 +254,42 @@ export function setModelArg(base, model) {
|
|
|
245
254
|
|
|
246
255
|
const lineCount = (text) => (text.trim() ? text.trim().split('\n').length : 0);
|
|
247
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
|
+
|
|
248
278
|
// Claude Code: the path, whether it is really there, and where to get it when
|
|
249
279
|
// it is not. One reader, here, so the screen and the config cannot disagree.
|
|
250
|
-
export function claudeState(config) {
|
|
251
|
-
const found =
|
|
280
|
+
export function claudeState(config, { search = true } = {}) {
|
|
281
|
+
const found = search ? harnessFor('claude').discover(config.claudeBinConfigured ?? null) : knownEngine(config, 'claude');
|
|
252
282
|
return {
|
|
253
283
|
claudeBin: found.path ?? config.claudeBin,
|
|
254
284
|
claudeFound: found.found,
|
|
255
285
|
// Whether the search got an answer at all.
|
|
256
286
|
claudeCertain: found.certain !== false,
|
|
257
287
|
claudeInstallUrl: INSTALL_URL,
|
|
288
|
+
// WHETHER SOMEBODY POINTED AT THIS FILE THEMSELVES, which is the one thing
|
|
289
|
+
// the card cannot work out from the path alone. A chosen path is never
|
|
290
|
+
// searched around, so the row that offers the search back has to know
|
|
291
|
+
// (`pointAtEngineBin` below).
|
|
292
|
+
claudeChosen: found.from === 'settings',
|
|
258
293
|
};
|
|
259
294
|
}
|
|
260
295
|
|
|
@@ -267,6 +302,20 @@ export function claudeState(config) {
|
|
|
267
302
|
// `forgetClaudeBin` exists for.
|
|
268
303
|
export function recheckClaude(config) {
|
|
269
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) {
|
|
270
319
|
const state = claudeState(config);
|
|
271
320
|
// The config carries the path everything else spawns from, so a search that
|
|
272
321
|
// has just found Claude Code updates it rather than leaving the rest of the
|
|
@@ -275,7 +324,10 @@ export function recheckClaude(config) {
|
|
|
275
324
|
// And whether it is here at all, which is what decides that a Mac with only
|
|
276
325
|
// Codex runs on Codex (`Supervisor#_enginesFound`). Only a certain answer
|
|
277
326
|
// moves it, so an unsure search never takes Claude Code away from anybody.
|
|
278
|
-
if (state.claudeFound || state.claudeCertain)
|
|
327
|
+
if (state.claudeFound || state.claudeCertain) {
|
|
328
|
+
config.claudeFound = state.claudeFound;
|
|
329
|
+
config.claudeCertain = state.claudeCertain;
|
|
330
|
+
}
|
|
279
331
|
return state;
|
|
280
332
|
}
|
|
281
333
|
|
|
@@ -309,8 +361,8 @@ export function recheckClaude(config) {
|
|
|
309
361
|
* checked by uninstalling Codex from the machine running the suite is a card
|
|
310
362
|
* whose unsure state is not checked. Nothing in the app passes it.
|
|
311
363
|
*/
|
|
312
|
-
export function codexState(config, where = {}) {
|
|
313
|
-
const found =
|
|
364
|
+
export function codexState(config, where = {}, { search = true } = {}) {
|
|
365
|
+
const found = search ? harnessFor('codex').discover(config.codexBinConfigured ?? null, where) : knownEngine(config, 'codex');
|
|
314
366
|
return {
|
|
315
367
|
// Empty rather than a path when there is nothing there, which is the same
|
|
316
368
|
// asymmetry `config.codexBin` already keeps (main/config.mjs): a configured
|
|
@@ -322,12 +374,14 @@ export function codexState(config, where = {}) {
|
|
|
322
374
|
// Whether the search got an answer at all.
|
|
323
375
|
certain: found.certain !== false,
|
|
324
376
|
url: CODEX_INSTALL_URL,
|
|
377
|
+
// Whether somebody pointed at this file themselves. See `claudeState`.
|
|
378
|
+
chosen: found.from === 'settings',
|
|
325
379
|
};
|
|
326
380
|
}
|
|
327
381
|
|
|
328
382
|
/** `codexState` under the names the walk's last card reads beside Claude's. */
|
|
329
|
-
export function codexFoundState(config, where = {}) {
|
|
330
|
-
const state = codexState(config, where);
|
|
383
|
+
export function codexFoundState(config, where = {}, how = {}) {
|
|
384
|
+
const state = codexState(config, where, how);
|
|
331
385
|
return { codexFound: state.found, codexCertain: state.certain, codexInstallUrl: state.url };
|
|
332
386
|
}
|
|
333
387
|
|
|
@@ -339,8 +393,13 @@ export function codexFoundState(config, where = {}) {
|
|
|
339
393
|
* without a restart. */
|
|
340
394
|
export function recheckCodex(config) {
|
|
341
395
|
forgetCodexBin();
|
|
396
|
+
return takeCodex(config);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function takeCodex(config) {
|
|
342
400
|
const state = codexState(config);
|
|
343
401
|
config.codexBin = state.found ? state.bin : null;
|
|
402
|
+
config.codexCertain = state.certain;
|
|
344
403
|
// Found while the app is open, by this button or the plan setup: the choice
|
|
345
404
|
// opens now, as it would have at the next launch (main/config.mjs).
|
|
346
405
|
const opened = codexChoiceToOpen(config, state.found);
|
|
@@ -348,7 +407,100 @@ export function recheckCodex(config) {
|
|
|
348
407
|
return state;
|
|
349
408
|
}
|
|
350
409
|
|
|
351
|
-
|
|
410
|
+
/* ------------------- POINTING AT IT YOURSELF, AND BACK -------------------- */
|
|
411
|
+
/**
|
|
412
|
+
* THE WAY OUT OF A SEARCH THAT MISSED, AND IT IS NOT A RELEASE (w-ce8c1a9275).
|
|
413
|
+
*
|
|
414
|
+
* The note this came from: "It has a really hard time finding the install on the
|
|
415
|
+
* person's computer, and we keep having bug reports and then patching that
|
|
416
|
+
* specific case." Asking the login shell first (main/engine-bin.mjs) covers
|
|
417
|
+
* every installer a person's own PATH knows about, which is most of them. It
|
|
418
|
+
* cannot cover a wrapper script somewhere nobody would guess, a tool on a
|
|
419
|
+
* volume, or a machine whose login shell will not start at all -- and for those,
|
|
420
|
+
* every fix used to be a path WE ship and a release THEY wait for.
|
|
421
|
+
*
|
|
422
|
+
* `claudeBin` in zero.config.json already won over the search and always has.
|
|
423
|
+
* What was missing is that nobody is told about that file and the app gave no
|
|
424
|
+
* way to edit it. These two functions are that door, and the second one matters
|
|
425
|
+
* as much as the first: a wrong choice that could only be undone by hand-editing
|
|
426
|
+
* a file nobody has heard of is not a door, it is a trap.
|
|
427
|
+
*
|
|
428
|
+
* THE REFUSALS ARE MOST OF THE WORK. Each thing refused here was possible by
|
|
429
|
+
* hand before and each one becomes a spawn that fails once per row, naming a
|
|
430
|
+
* file nobody meant to name. The sentence comes back to the screen instead.
|
|
431
|
+
*
|
|
432
|
+
* NO PATH FROM THE WINDOW IS EVER TRUSTED: main/ipc.mjs opens the picker and
|
|
433
|
+
* calls this in the same trip, so the only path that reaches here is one the
|
|
434
|
+
* open panel itself produced. The sibling rule is
|
|
435
|
+
* tests/where-codex-runs-from-is-not-a-file-a-worker-can-write.test.mjs.
|
|
436
|
+
*/
|
|
437
|
+
const BIN_KEY = { claude: 'claudeBin', codex: 'codexBin' };
|
|
438
|
+
|
|
439
|
+
/** The sentence, or null when the file really is one we could run. */
|
|
440
|
+
function whyNotAnAgent(chosen) {
|
|
441
|
+
if (typeof chosen !== 'string' || !path.isAbsolute(chosen)) {
|
|
442
|
+
return `${Name} needs the file itself, picked from your computer.`;
|
|
443
|
+
}
|
|
444
|
+
let stat;
|
|
445
|
+
try { stat = fs.statSync(chosen); } catch { stat = null; }
|
|
446
|
+
if (!stat) return `${Name} could not find anything there. It may have moved since.`;
|
|
447
|
+
if (stat.isDirectory()) return 'That is a folder. Open it and pick the file inside.';
|
|
448
|
+
try { fs.accessSync(chosen, fs.constants.X_OK); } catch {
|
|
449
|
+
return 'That file cannot be run, so it is not the one.';
|
|
450
|
+
}
|
|
451
|
+
return null;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Take a file somebody picked for one coding agent.
|
|
456
|
+
*
|
|
457
|
+
* Written to zero.config.json so it survives a restart AND set on the live
|
|
458
|
+
* config, because every consumer reads `config.*` per call and a setting that
|
|
459
|
+
* waits for a relaunch is the same failure as a fix that is not running. The
|
|
460
|
+
* recheck afterwards is what puts the path the fleet spawns from in step with
|
|
461
|
+
* it, the same way the Check again button does.
|
|
462
|
+
*/
|
|
463
|
+
export function pointAtEngineBin(config, engine, chosen) {
|
|
464
|
+
const key = BIN_KEY[engine];
|
|
465
|
+
if (!key) return { ok: false, say: `${Name} does not know a coding agent called that.` };
|
|
466
|
+
const why = whyNotAnAgent(chosen);
|
|
467
|
+
if (why) return { ok: false, say: why };
|
|
468
|
+
if (!config.appDir) return { ok: false, say: `${Name} has nowhere to save that.` };
|
|
469
|
+
saveConfig(config, { [key]: chosen });
|
|
470
|
+
config[`${engine}BinConfigured`] = chosen;
|
|
471
|
+
const state = engine === 'claude' ? recheckClaude(config) : recheckCodex(config);
|
|
472
|
+
return { ok: true, state };
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Give the choice back, so the search is in charge again. The key is REMOVED
|
|
477
|
+
* from the file rather than emptied: `saveConfig` reads an explicit undefined as
|
|
478
|
+
* a deletion, and an empty string left behind would read as a setting that means
|
|
479
|
+
* something else (main/config.mjs only treats a non-empty string as chosen).
|
|
480
|
+
*/
|
|
481
|
+
export function searchForEngineBin(config, engine) {
|
|
482
|
+
const key = BIN_KEY[engine];
|
|
483
|
+
if (!key) return { ok: false, say: `${Name} does not know a coding agent called that.` };
|
|
484
|
+
if (!config.appDir) return { ok: false, say: `${Name} has nowhere to save that.` };
|
|
485
|
+
saveConfig(config, { [key]: undefined });
|
|
486
|
+
config[`${engine}BinConfigured`] = null;
|
|
487
|
+
const state = engine === 'claude' ? recheckClaude(config) : recheckCodex(config);
|
|
488
|
+
return { ok: true, state };
|
|
489
|
+
}
|
|
490
|
+
|
|
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 } = {}) {
|
|
352
504
|
const products = store.listProducts();
|
|
353
505
|
const status = supervisor.status();
|
|
354
506
|
const sessions = [...supervisor.sessions.values()];
|
|
@@ -379,21 +531,36 @@ export function readSettings({ config, supervisor, store }) {
|
|
|
379
531
|
// waiting, because a page she chose to open interrupts nobody.
|
|
380
532
|
const troubles = status.accountTrouble ?? {};
|
|
381
533
|
const accounts = (profiles.length ? profiles : ['default']).map((profile) => {
|
|
382
|
-
|
|
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 });
|
|
540
|
+
// A reason filed before an ended subscription had its own name still reads
|
|
541
|
+
// as an admin's block; the login's file says which it is.
|
|
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 });
|
|
545
|
+
const trouble = filed ? { ...filed, cause: refineCause(filed.cause, plan) } : null;
|
|
383
546
|
const resting = (supervisor._profileCooldown?.[profile] ?? 0) >= now;
|
|
384
547
|
// WHOSE SUBSCRIPTION THIS ROW IS, not merely which folder it lives in.
|
|
385
548
|
// The page named its rows after folders, so nothing on it could tell a
|
|
386
549
|
// person that one of their accounts had been replaced by the other;
|
|
387
550
|
// main/account-tooling.mjs has how that happens. Null when the
|
|
388
551
|
// folder holds no login, and then the row reads as it always did.
|
|
389
|
-
const identity = accountIdentity(profile === 'default' ? null : profile);
|
|
552
|
+
const identity = accountIdentity(profile === 'default' ? null : profile, { home: config.home });
|
|
390
553
|
return {
|
|
391
554
|
profile,
|
|
392
555
|
email: identity?.email ?? null,
|
|
393
556
|
accountUuid: identity?.accountUuid ?? null,
|
|
394
|
-
// WHICH ONE RUNS,
|
|
395
|
-
//
|
|
396
|
-
|
|
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,
|
|
397
564
|
// The default profile is whatever ~/.claude holds; anything else is a
|
|
398
565
|
// second logged-in home directory, and its path is the only name it has.
|
|
399
566
|
label: profile === 'default' ? 'default' : path.basename(profile),
|
|
@@ -421,10 +588,12 @@ export function readSettings({ config, supervisor, store }) {
|
|
|
421
588
|
// Read here rather than kept, because Claude Code refreshes its own
|
|
422
589
|
// profile as it runs and this page is opened by hand a few times a day.
|
|
423
590
|
// `null` when the file cannot be read, and then no screen says anything.
|
|
424
|
-
plan:
|
|
591
|
+
plan: plan.known ? { label: plan.label, max: plan.max } : null,
|
|
425
592
|
};
|
|
426
593
|
});
|
|
427
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)));
|
|
428
597
|
const projects = products.map((product) => {
|
|
429
598
|
let instructions = '';
|
|
430
599
|
try { instructions = supervisor.readProjectInstructions(product.slug); } catch {}
|
|
@@ -446,6 +615,9 @@ export function readSettings({ config, supervisor, store }) {
|
|
|
446
615
|
// workspace default and never a strip of Claude Code jargon on a page
|
|
447
616
|
// she opens to change her rules.
|
|
448
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),
|
|
449
621
|
permission: override ? permissionMode(override) : 'workspace',
|
|
450
622
|
permissionArgs: override ?? null,
|
|
451
623
|
codexMode: config.projectCodexMode?.[product.slug] ?? 'workspace',
|
|
@@ -470,8 +642,12 @@ export function readSettings({ config, supervisor, store }) {
|
|
|
470
642
|
return {
|
|
471
643
|
archivedProjects,
|
|
472
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,
|
|
473
647
|
agentsRunning: !supervisor.paused,
|
|
474
|
-
|
|
648
|
+
// The number picked on the menu, for the whole computer, or what is
|
|
649
|
+
// running as the limit now when nothing was picked.
|
|
650
|
+
sessionsAtOnce: typeof config.agentsAtOnce === 'number' ? config.agentsAtOnce : status.capacity,
|
|
475
651
|
// AUTOMATIC, AND WHAT IT WORKS OUT TO (w-e5225b62ba). `agentsAuto` is who
|
|
476
652
|
// is deciding; `agentsTotal` is what the whole Mac is running at once,
|
|
477
653
|
// which is the number the page shows, because the per-account one is
|
|
@@ -499,6 +675,7 @@ export function readSettings({ config, supervisor, store }) {
|
|
|
499
675
|
machineNote: machineNote(slotsHere, config.maxConcurrentSessions),
|
|
500
676
|
memoryGate: memoryGateSettings({ config, supervisor }),
|
|
501
677
|
leftovers: leftoverSettings({ config, supervisor }),
|
|
678
|
+
strayFolders: strayFolderSettings({ supervisor }),
|
|
502
679
|
capacity: status.capacity,
|
|
503
680
|
running: sessions.length,
|
|
504
681
|
model: parseSessionArgs(workspaceArgs).model,
|
|
@@ -511,9 +688,11 @@ export function readSettings({ config, supervisor, store }) {
|
|
|
511
688
|
// comes back with ONE entry and this screen draws exactly what it drew
|
|
512
689
|
// before. A page that derived its own list would offer her a choice the
|
|
513
690
|
// supervisor is about to refuse.
|
|
514
|
-
...engineSettings(supervisor, config),
|
|
691
|
+
...engineSettings(supervisor, config, { search }),
|
|
515
692
|
permission: permissionMode(workspaceArgs),
|
|
516
693
|
permissionArgs: workspaceArgs,
|
|
694
|
+
cloudPermission: config.cloudPermission ?? CLOUD_CLAUDE_DEFAULT,
|
|
695
|
+
cloudCodexMode: config.cloudCodexMode ?? CLOUD_CODEX_DEFAULT,
|
|
517
696
|
// ONE SWITCH FOR EVERYTHING THAT LEAVES THE MACHINE, and it is on when
|
|
518
697
|
// Agentbox is installed (legal/privacy.html, section 10). Off stops the
|
|
519
698
|
// counts AND the crash reports; there is deliberately no partial mode and
|
|
@@ -526,6 +705,11 @@ export function readSettings({ config, supervisor, store }) {
|
|
|
526
705
|
// ADHD mode: whether the ADHD rules ride under hers (w-5737fe67cf). Off
|
|
527
706
|
// unless she turned it on, so only `true` means on.
|
|
528
707
|
adhdMode: config.adhdMode === true,
|
|
708
|
+
importNew: config.importNew === true,
|
|
709
|
+
alpha: alphaFeatures(config),
|
|
710
|
+
// The corner tag over other apps (w-dafae58a23). On unless she turned it
|
|
711
|
+
// off here, which is the only place it turns off for good.
|
|
712
|
+
cornerTag: config.cornerTag !== false,
|
|
529
713
|
// How much of her own Claude Code goes in her inbox: all / waiting / off.
|
|
530
714
|
// All by default, because the machine nobody has opened this page on is
|
|
531
715
|
// the one with thirteen forgotten sessions on it.
|
|
@@ -550,11 +734,11 @@ export function readSettings({ config, supervisor, store }) {
|
|
|
550
734
|
// Looked up again on every read of this screen, not taken from boot.
|
|
551
735
|
// Someone who reads "install it, then open this screen again" and does
|
|
552
736
|
// exactly that has to see it turn found, without restarting the app.
|
|
553
|
-
...claudeState(config),
|
|
737
|
+
...claudeState(config, { search }),
|
|
554
738
|
// AND WHETHER CODEX IS, because the app needs one of the two and not
|
|
555
739
|
// both: the last card of the walk only shuts the inbox when neither is
|
|
556
740
|
// here (renderer/src/App.tsx).
|
|
557
|
-
...codexFoundState(config),
|
|
741
|
+
...codexFoundState(config, {}, { search }),
|
|
558
742
|
// AND WHAT THIS MAC'S CLAUDE CODE CALLS ITS MODELS.
|
|
559
743
|
//
|
|
560
744
|
// In the same trip, and for the same reason the line above is looked up
|
|
@@ -606,7 +790,7 @@ function engineTroubleFor(supervisor, engine) {
|
|
|
606
790
|
return trouble ? engineTroubleNote(trouble.cause) : null;
|
|
607
791
|
}
|
|
608
792
|
|
|
609
|
-
function engineSettings(supervisor, config) {
|
|
793
|
+
function engineSettings(supervisor, config, { search = true } = {}) {
|
|
610
794
|
const choices = supervisor.engineChoices();
|
|
611
795
|
const engine = supervisor.engineFacts().workspace;
|
|
612
796
|
// WHETHER THIS MAC HAS ASKED TO HEAR ABOUT CODEX AT ALL, which is a different
|
|
@@ -631,7 +815,7 @@ function engineSettings(supervisor, config) {
|
|
|
631
815
|
// links the install, which is the question that person had.
|
|
632
816
|
const codexIsHome = engine === 'codex';
|
|
633
817
|
const codex = {
|
|
634
|
-
...codexState(config),
|
|
818
|
+
...codexState(config, {}, { search }),
|
|
635
819
|
trouble: engineTroubleFor(supervisor, 'codex'),
|
|
636
820
|
account: codexAccount(supervisor._codexHome()),
|
|
637
821
|
// EVERY CODEX LOGIN ON THE MAC, NOT JUST THE FIRST. The supervisor has
|
|
@@ -646,6 +830,7 @@ function engineSettings(supervisor, config) {
|
|
|
646
830
|
return { engine, engineChoices: choices, codex, codexModels: [], codexModelDefault: null, codexModel: null };
|
|
647
831
|
}
|
|
648
832
|
const home = supervisor._codexHome();
|
|
833
|
+
const offered = supervisor._codexOfferHomes();
|
|
649
834
|
return {
|
|
650
835
|
engine,
|
|
651
836
|
engineChoices: choices,
|
|
@@ -654,9 +839,12 @@ function engineSettings(supervisor, config) {
|
|
|
654
839
|
// strip in the model drawer draws the picked model's list, so they travel
|
|
655
840
|
// beside the name rather than as a list of their own that could disagree
|
|
656
841
|
// with it.
|
|
657
|
-
codexModels:
|
|
842
|
+
codexModels: codexModelsAcross(offered).map((m) => ({
|
|
658
843
|
id: m.id, label: m.label, levels: m.levels.map((l) => l.id), defaultLevel: m.defaultLevel,
|
|
659
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),
|
|
660
848
|
// What her own `codex` in a terminal runs, so the card's word and her
|
|
661
849
|
// terminal cannot disagree. Null is a real answer and the card says
|
|
662
850
|
// "Codex's own" for it rather than guessing (renderer/src/models.ts).
|
|
@@ -686,12 +874,15 @@ const withSlug = (list, slug, on) => {
|
|
|
686
874
|
// `paused` and `driven` were the other three and all three are gone from the
|
|
687
875
|
// app: the first two because she could not tell what they did and would never
|
|
688
876
|
// have used them, the third because the self-driving it belonged to is deleted.
|
|
689
|
-
export function setProjectSetting({ config, supervisor }, { product, key, value }) {
|
|
877
|
+
export function setProjectSetting({ config, supervisor, store }, { product, key, value }) {
|
|
690
878
|
if (!product) throw new Error('no project');
|
|
691
879
|
switch (key) {
|
|
692
880
|
case 'autonomous':
|
|
693
881
|
saveConfig(config, { autonomousProducts: withSlug(config.autonomousProducts, product, !!value) });
|
|
694
882
|
break;
|
|
883
|
+
case 'phone':
|
|
884
|
+
saveConfig(config, { phoneProducts: withPhoneProject(config.phoneProducts, process.env.AGENTBOX_PERSON_ID, product, !!value, phoneEligible(store?.listProducts?.() ?? [])) });
|
|
885
|
+
break;
|
|
695
886
|
// WHICH OF HER CLAUDE CODE AGENTS THIS PROJECT TOOK. Names only: the files
|
|
696
887
|
// stay where their author put them and Agentbox never copies or moves one,
|
|
697
888
|
// so a list here that has gone stale costs nothing and an agent she
|
|
@@ -769,7 +960,9 @@ export function setProjectSetting({ config, supervisor }, { product, key, value
|
|
|
769
960
|
* not signed in.
|
|
770
961
|
*/
|
|
771
962
|
function codexAccountRows(supervisor) {
|
|
772
|
-
|
|
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;
|
|
773
966
|
return supervisor._codexProfiles().map((profile) => {
|
|
774
967
|
const home = supervisor._codexProfileHome(profile);
|
|
775
968
|
const id = codexAccount(home);
|
|
@@ -781,8 +974,7 @@ function codexAccountRows(supervisor) {
|
|
|
781
974
|
planNamed: id?.planNamed ?? false,
|
|
782
975
|
accountId: id?.accountId ?? null,
|
|
783
976
|
signedIn: !!id,
|
|
784
|
-
// WHICH ONE RUNS
|
|
785
|
-
// runs and the card says so rather than marking one at random.
|
|
977
|
+
// WHICH ONE RUNS, and one of them always does (`chosen` above).
|
|
786
978
|
chosen: chosen === profile,
|
|
787
979
|
};
|
|
788
980
|
});
|
|
@@ -827,9 +1019,12 @@ export function addCodexAccount({ config, supervisor }) {
|
|
|
827
1019
|
* ordinary reason for wanting it: a work login and a personal login, both
|
|
828
1020
|
* live, on one Mac.
|
|
829
1021
|
*
|
|
830
|
-
*
|
|
831
|
-
*
|
|
832
|
-
*
|
|
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).
|
|
833
1028
|
*
|
|
834
1029
|
* THE TOOLING IS LINKED AT CREATION, which the Codex side has no equivalent of.
|
|
835
1030
|
* `linkAccountTooling` otherwise runs at the first spawn, and the first thing
|
|
@@ -839,9 +1034,6 @@ export function addCodexAccount({ config, supervisor }) {
|
|
|
839
1034
|
*/
|
|
840
1035
|
export function addClaudeAccount({ config, supervisor }) {
|
|
841
1036
|
const made = makeClaudeHome({ home: config.home });
|
|
842
|
-
const existing = (config.authProfiles ?? []).map((x) => x || 'default');
|
|
843
|
-
const list = existing.length ? existing : ['default'];
|
|
844
|
-
saveConfig(config, { authProfiles: [...list, made.profile] });
|
|
845
1037
|
// A failure here is a folder without her skills in it, which is a smaller
|
|
846
1038
|
// thing than a sign in that does not happen: the links are retried at every
|
|
847
1039
|
// spawn anyway.
|
|
@@ -891,6 +1083,9 @@ export function memoryGateSettings({ config, supervisor }) {
|
|
|
891
1083
|
export function memoryReading({ config, supervisor }) {
|
|
892
1084
|
const out = { heavy: null, waiting: null, pressure: null, usedPct: null, asked: null, waited: null, refused: null };
|
|
893
1085
|
if (!config.memoryGate) return out;
|
|
1086
|
+
// The supervisor's own hold on new agents (main/start-hold.mjs), which does
|
|
1087
|
+
// not depend on which copy of the app is coordinating the command queue.
|
|
1088
|
+
try { out.holding = !!supervisor.startHoldStatus?.()?.holding; } catch { out.holding = false; }
|
|
894
1089
|
let s = null;
|
|
895
1090
|
try { s = supervisor.memoryGateStatus?.() ?? null; } catch { return out; }
|
|
896
1091
|
if (!s || s.role === 'standby') return out;
|
|
@@ -923,22 +1118,26 @@ export function leftoverSettings({ config, supervisor }) {
|
|
|
923
1118
|
// Codex, 2026-10-05).
|
|
924
1119
|
if (!on) {
|
|
925
1120
|
if (total && stoppable) {
|
|
926
|
-
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`}
|
|
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.`;
|
|
927
1122
|
}
|
|
928
1123
|
return { on, now };
|
|
929
1124
|
}
|
|
930
1125
|
{
|
|
931
1126
|
if (!total) now = 'Nothing left running by finished agents.';
|
|
932
1127
|
else {
|
|
933
|
-
const
|
|
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;
|
|
934
1132
|
const when = (ms) => {
|
|
935
1133
|
const m = Math.max(1, Math.round((ms - Date.now()) / 60_000));
|
|
936
1134
|
return m >= 60 ? `${Math.floor(m / 60)} h${m % 60 ? ` ${m % 60} m` : ''}` : `${m} m`;
|
|
937
1135
|
};
|
|
938
|
-
|
|
939
|
-
if (
|
|
940
|
-
if (
|
|
941
|
-
|
|
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('; ')}.`;
|
|
942
1141
|
const survivors = s?.survivors?.length ?? 0;
|
|
943
1142
|
if (survivors) now += ` ${survivors} did not stop when asked.`;
|
|
944
1143
|
}
|
|
@@ -946,8 +1145,59 @@ export function leftoverSettings({ config, supervisor }) {
|
|
|
946
1145
|
return { on, now };
|
|
947
1146
|
}
|
|
948
1147
|
|
|
949
|
-
|
|
1148
|
+
/**
|
|
1149
|
+
* COPIES OF A PROJECT THE APP DID NOT MAKE, SAID OUT LOUD (w-330eea6c66).
|
|
1150
|
+
*
|
|
1151
|
+
* MEASURED 2026-10-07: thirteen worktrees of one repository sat outside the
|
|
1152
|
+
* folder the app keeps its own in, about 740 MB, and nothing in the app could
|
|
1153
|
+
* list, show or sweep one. That is the same invisibility that stranded 26 GB on
|
|
1154
|
+
* 2026-09-22, and the half that fixes it for a person is being told.
|
|
1155
|
+
*
|
|
1156
|
+
* NO BUTTON, DELIBERATELY. A folder the app did not make is not the app's to
|
|
1157
|
+
* remove: it is the only copy of whatever is uncommitted inside it, and somebody
|
|
1158
|
+
* made it on purpose. So this is a sentence and nothing else, and it is absent
|
|
1159
|
+
* entirely when there is nothing to say, because a row that is usually quiet
|
|
1160
|
+
* trains the reaction it exists to prevent.
|
|
1161
|
+
*/
|
|
1162
|
+
export function strayFolderSettings({ supervisor }, home = os.homedir()) {
|
|
1163
|
+
let list = [];
|
|
1164
|
+
try { list = supervisor?.strayFolders?.() ?? []; } catch { list = []; }
|
|
1165
|
+
if (!list.length) return null;
|
|
1166
|
+
const count = list.length;
|
|
1167
|
+
const one = count === 1;
|
|
1168
|
+
const projects = [...new Set(list.map((w) => w.project).filter(Boolean))];
|
|
1169
|
+
const named = list.slice(0, 3).map((w) => shortPath(w.path, home));
|
|
1170
|
+
const rest = count - named.length;
|
|
1171
|
+
const of = projects.length ? ` of ${projects.slice(0, 2).join(' and ')}${projects.length > 2 ? ' and other projects' : ''}` : '';
|
|
1172
|
+
const now = `${count} ${one ? 'copy' : 'copies'}${of} ${one ? 'was' : 'were'} made by hand outside the folder ${NAME} keeps its own in, and ${one ? 'is' : 'are'} holding disk until you remove ${one ? 'it' : 'them'}: ${named.join(', ')}${rest > 0 ? ` and ${rest} more` : ''}. ${NAME} never removes a folder it did not make.`;
|
|
1173
|
+
return { count, now };
|
|
1174
|
+
}
|
|
1175
|
+
|
|
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 }) {
|
|
950
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
|
+
}
|
|
951
1201
|
case 'agentsRunning':
|
|
952
1202
|
supervisor.paused = !value;
|
|
953
1203
|
supervisor.onChange?.();
|
|
@@ -979,7 +1229,9 @@ export function setWorkspaceSetting({ config, supervisor }, { key, value }) {
|
|
|
979
1229
|
const n = Math.max(1, Math.min(MAX_SLOTS, Math.round(Number(value) || 1)));
|
|
980
1230
|
// Setting a number by hand IS taking the decision back, so the page never
|
|
981
1231
|
// shows a stepper that the supervisor is quietly ignoring.
|
|
982
|
-
|
|
1232
|
+
// FOR THE WHOLE COMPUTER (w-ec27ff1a51), under its own key, so a number
|
|
1233
|
+
// written per login before 5 Oct can never be read as this choice.
|
|
1234
|
+
saveConfig(config, { agentsAtOnce: n, agentsAuto: false });
|
|
983
1235
|
// An explicit choice replaces the startup plan suggestion for BOTH
|
|
984
1236
|
// engines. Leaving this marker set makes Codex ignore the new number
|
|
985
1237
|
// until loadConfig runs again at restart. It is derived, not persisted.
|
|
@@ -1006,6 +1258,43 @@ export function setWorkspaceSetting({ config, supervisor }, { key, value }) {
|
|
|
1006
1258
|
break;
|
|
1007
1259
|
// STOP WHAT FINISHED AGENTS LEAVE RUNNING (main/leftovers.mjs). Turning it
|
|
1008
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
|
+
}
|
|
1009
1298
|
case 'cleanupLeftovers':
|
|
1010
1299
|
saveConfig(config, value ? { cleanupLeftovers: true, cleanupLeftoversSince: Date.now() } : { cleanupLeftovers: false });
|
|
1011
1300
|
supervisor.setLeftoverCleanup?.(!!value)?.catch?.((e) => console.warn('zero: leftovers:', e.message));
|
|
@@ -1029,6 +1318,31 @@ export function setWorkspaceSetting({ config, supervisor }, { key, value }) {
|
|
|
1029
1318
|
case 'adhdMode':
|
|
1030
1319
|
saveConfig(config, { adhdMode: !!value });
|
|
1031
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;
|
|
1341
|
+
// THE CORNER TAG (w-dafae58a23). Turning it back on also ends any hide, so
|
|
1342
|
+
// the switch does what it says the moment she flips it.
|
|
1343
|
+
case 'cornerTag':
|
|
1344
|
+
saveConfig(config, value ? { cornerTag: true, cornerTagHiddenUntil: 0 } : { cornerTag: false });
|
|
1345
|
+
break;
|
|
1032
1346
|
// WHICH ACCOUNT HER WORK RUNS ON.
|
|
1033
1347
|
//
|
|
1034
1348
|
// ONE KEY HOLDS BOTH ENGINES, because a profile word means different things
|
|
@@ -1037,15 +1351,15 @@ export function setWorkspaceSetting({ config, supervisor }, { key, value }) {
|
|
|
1037
1351
|
// in one object keyed by engine is what stops a Codex pick being read as a
|
|
1038
1352
|
// Claude one, which is the collision `_accountKey` exists to prevent.
|
|
1039
1353
|
//
|
|
1040
|
-
// NULL CLEARS IT, and clearing means
|
|
1041
|
-
//
|
|
1042
|
-
//
|
|
1043
|
-
// 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.
|
|
1044
1357
|
case 'activeAccount': {
|
|
1045
1358
|
const engineId = value?.engine;
|
|
1046
1359
|
if (!isEngine(engineId)) throw new Error(`unknown coding agent: ${engineId}`);
|
|
1047
1360
|
const profile = typeof value?.profile === 'string' && value.profile ? value.profile : null;
|
|
1048
1361
|
saveConfig(config, { activeAccount: { ...(config.activeAccount ?? {}), [engineId]: profile } });
|
|
1362
|
+
supervisor.accountChosen?.(engineId, profile);
|
|
1049
1363
|
supervisor.onChange?.();
|
|
1050
1364
|
break;
|
|
1051
1365
|
}
|