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/main.mjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// The app: the agent inbox. Electron shell around a keyboard-first renderer, a
|
|
2
2
|
// file-derived store, and a supervisor of headless sessions.
|
|
3
3
|
|
|
4
|
-
import { app, BrowserWindow, Menu, Notification, clipboard, crashReporter, dialog, ipcMain, nativeImage, net, powerMonitor, protocol, screen as electronScreen, shell, session, safeStorage } from 'electron';
|
|
4
|
+
import { app, BrowserWindow, Menu, Notification, clipboard, crashReporter, dialog, ipcMain, nativeImage, net, powerMonitor, protocol, screen as electronScreen, shell, session, safeStorage, systemPreferences } from 'electron';
|
|
5
5
|
import * as workItemsDisk from './store/work-items.mjs';
|
|
6
6
|
import { createTeamService, teamStateFile } from './team/index.mjs';
|
|
7
|
+
import { roomsSetup } from './team/room-setup.mjs';
|
|
7
8
|
import { loadCloudConfig, supabaseSession } from './team/session.mjs';
|
|
8
9
|
// MY WORKSPACE IS NOT A TEAM FEATURE ANY MORE (w-f8d123be62), even though it
|
|
9
10
|
// still lives in the team folder next to the sharing rules it has to obey.
|
|
@@ -11,34 +12,52 @@ import { ensurePersonalProject } from './team/projects.mjs';
|
|
|
11
12
|
import path from 'node:path';
|
|
12
13
|
import fs from 'node:fs';
|
|
13
14
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
14
|
-
import { configDir, loadConfig } from './config.mjs';
|
|
15
|
+
import { configDir, loadConfig, saveConfig } from './config.mjs';
|
|
15
16
|
import { installMenu, applyZoom, requestFind } from './menu.mjs';
|
|
16
17
|
import { zoomDeltaFor } from './zoom-keys.mjs';
|
|
17
18
|
import { copySelection } from './copy-selection.mjs';
|
|
18
19
|
import { screenDetailFor } from './screen-detail.mjs';
|
|
19
20
|
import { Store } from './store.mjs';
|
|
20
21
|
import { storeRootEnv } from './store/home.mjs';
|
|
22
|
+
import { keepAnswerModesIn } from './answer-modes.mjs';
|
|
21
23
|
import { Supervisor } from './supervisor.mjs';
|
|
22
24
|
import { startCodexWatch } from './codex-watch.mjs';
|
|
25
|
+
import { watchNewChatsFor } from './new-chats-watch.mjs';
|
|
26
|
+
import { readCodexThreadsOffThread } from './codex-threads.mjs';
|
|
27
|
+
import { appSessionFolders } from './agent-homes.mjs';
|
|
23
28
|
import { registerIpc } from './ipc.mjs';
|
|
29
|
+
import { stallWatch } from './stall-watch.mjs';
|
|
30
|
+
import { startFreezeRecorder } from './freeze-recorder.mjs';
|
|
31
|
+
import { applyThrough, phoneDevice } from './phone-inbox.mjs';
|
|
32
|
+
import { answerWhatOnlyTheWindowAnswered } from './serve.mjs';
|
|
24
33
|
import { carryHerBriefsAcross, joinMessageRules, setAsideShippedMessageRules, unifyAgentInstructions } from './instruction-settings.mjs';
|
|
25
34
|
import * as approvals from './approvals.mjs';
|
|
26
35
|
import { recoveryToast } from '../shared/recovery.mjs';
|
|
27
36
|
import { dataFolderName, isNewUserBuild } from '../shared/side-build.mjs';
|
|
28
37
|
import { runningAsAFreshUser } from '../shared/fresh-user-home.mjs';
|
|
38
|
+
import { newUserWindow } from './new-user-window.mjs';
|
|
29
39
|
import { openFreshUser } from './fresh-user.mjs';
|
|
30
40
|
import { installCrashReports, reportFromRenderer, pending as pendingCrashes, setTransport } from './crash-report.mjs';
|
|
31
41
|
import { createAnalytics, createDailyCount } from './analytics.mjs';
|
|
32
42
|
import { createUpdater } from './updater.mjs';
|
|
43
|
+
import { quitStep, flushBeforeQuit, quitThenExit } from './quit-sequence.mjs';
|
|
44
|
+
import { createPlace } from '../shared/where-it-runs-from.mjs';
|
|
33
45
|
import { createSourceUpdater } from './source-updater.mjs';
|
|
46
|
+
import { learnShellDataDirs, recoverShellPath } from './shell-path.mjs';
|
|
34
47
|
import { installNotifier } from './notify.mjs';
|
|
48
|
+
import { createCornerTag } from './corner-tag.mjs';
|
|
49
|
+
import { loadLiquidGlass } from './liquid-glass.mjs';
|
|
35
50
|
import { DOC_SCHEMES, DocGrants, docPath } from './doc-scheme.mjs';
|
|
36
51
|
import { quietTheFramesScrollbars } from './frame-scrollbars.mjs';
|
|
52
|
+
import { letLocalAppsShowInThePane } from './local-app-frames.mjs';
|
|
53
|
+
import { hardenAttachedWebview } from './webview-guard.mjs';
|
|
37
54
|
import { IMG_SCHEMES, imgPath, mediaResponse, mediaType, servable } from './img-scheme.mjs';
|
|
38
55
|
import { hotWindowVerdict, storeHasWork } from './dev-window.mjs';
|
|
39
56
|
import { writeHeldThenReload } from './write-before-reload.mjs';
|
|
40
57
|
import { IS_SHE_TYPING_IN_THE_PAGE, theAppKeepsThisInput, theAppKeepsThisLetterInAPage } from '../shared/artifact-keys.mjs';
|
|
41
58
|
import { NAME, Name, WAS } from '../shared/product-name.mjs';
|
|
59
|
+
import { JOIN_SCHEME, ourLink, tokenFromLink } from '../shared/room-links.mjs';
|
|
60
|
+
import { getMic } from './mic.mjs';
|
|
42
61
|
|
|
43
62
|
// HOW LONG TO WAIT AFTER THE LID OPENS, and the wait is for the network rather
|
|
44
63
|
// than for the wake. `powerMonitor`'s resume event fires while wifi is still
|
|
@@ -228,6 +247,24 @@ installCrashReports({
|
|
|
228
247
|
});
|
|
229
248
|
|
|
230
249
|
let window = null;
|
|
250
|
+
// A ROOM INVITE LINK THAT OPENED THE APP (Rooms, alpha): agentbox://join/<token>.
|
|
251
|
+
// Held until the window takes it ('zero:take-join'); a window that is up is
|
|
252
|
+
// told to come and take it, and one still starting takes it as it mounts.
|
|
253
|
+
let pendingJoin = tokenFromLink(process.argv.find((a) => a.startsWith(`${JOIN_SCHEME}://`)) ?? '');
|
|
254
|
+
function showWindow() {
|
|
255
|
+
if (!window || window.isDestroyed()) return;
|
|
256
|
+
if (window.isMinimized()) window.restore();
|
|
257
|
+
window.focus();
|
|
258
|
+
}
|
|
259
|
+
function openJoinLink(url) {
|
|
260
|
+
const token = tokenFromLink(url);
|
|
261
|
+
if (!token) return;
|
|
262
|
+
pendingJoin = token;
|
|
263
|
+
if (window && !window.isDestroyed()) {
|
|
264
|
+
window.webContents.send('zero:join-room');
|
|
265
|
+
showWindow();
|
|
266
|
+
}
|
|
267
|
+
}
|
|
231
268
|
// Set by ⌘R and read once by the renderer as it comes back up, so a reload can
|
|
232
269
|
// say so. A reload that lands on an identical screen and a chord that did
|
|
233
270
|
// nothing at all look exactly alike, and telling them apart is the whole
|
|
@@ -275,12 +312,23 @@ function reloadRenderer() {
|
|
|
275
312
|
}
|
|
276
313
|
|
|
277
314
|
async function createWindow() {
|
|
315
|
+
// Where the shell says Claude Code and Codex keep their logins and sessions,
|
|
316
|
+
// never put into this environment (main/shell-path.mjs). WAITED FOR, beside
|
|
317
|
+
// the PATH read so it costs no extra time: the folders it names are where
|
|
318
|
+
// workers sign in now (w-6d8c543a43), and a task resumed at launch before
|
|
319
|
+
// the answer landed ran on ~/.claude signed out.
|
|
320
|
+
const [shellPath] = await Promise.all([recoverShellPath(), learnShellDataDirs()]);
|
|
321
|
+
process.env.PATH = shellPath.path;
|
|
322
|
+
if (shellPath.error) console.warn('agentbox: could not load your shell PATH; using the inherited PATH:', shellPath.error);
|
|
278
323
|
const config = loadConfig(dataDir);
|
|
279
324
|
// The store modules read the app's own home variable at call time; setting it
|
|
280
325
|
// here points auth session files, sync, and every store path at its root.
|
|
281
326
|
// Written under every name this app has had, because a store server or a
|
|
282
327
|
// script from before a rename is still out there reading the old one.
|
|
283
328
|
Object.assign(process.env, storeRootEnv(config.storeRoot));
|
|
329
|
+
// What a reply may do is kept in her own folder, not that home, which every
|
|
330
|
+
// worker is granted (main/answer-modes.mjs).
|
|
331
|
+
keepAnswerModesIn({ userDir, storeRoot: config.storeRoot });
|
|
284
332
|
|
|
285
333
|
// Menu needs the config (approval hotkeys answer the oldest pending card),
|
|
286
334
|
// so it installs here rather than at whenReady. The spool watcher in ipc
|
|
@@ -294,11 +342,11 @@ async function createWindow() {
|
|
|
294
342
|
// themselves with `approvals.answer`, and on a Codex card a file is not an
|
|
295
343
|
// answer at all: the thing waiting is Agentbox itself, in this process, so
|
|
296
344
|
// nothing on that path ever reads one. Her click on Allow landed as a
|
|
297
|
-
// FORGERY -- the file appeared for a request still waiting,
|
|
298
|
-
// deleted it inside two seconds, the log said "an answer file appeared
|
|
299
|
-
// approval <id> that the founder did not write", her card came back
|
|
300
|
-
//
|
|
301
|
-
//
|
|
345
|
+
// FORGERY -- the file appeared for a request still waiting, the card's own
|
|
346
|
+
// poll deleted it inside two seconds, the log said "an answer file appeared
|
|
347
|
+
// for approval <id> that the founder did not write", and her card came back
|
|
348
|
+
// with the worker still parked on it. It also spent the one warning that is
|
|
349
|
+
// supposed to mean a worker attacked the spool.
|
|
302
350
|
//
|
|
303
351
|
// The variable is filled in the moment `registerIpc` returns, a few hundred
|
|
304
352
|
// lines down. Until then there is nothing to answer with and nothing that
|
|
@@ -337,7 +385,7 @@ async function createWindow() {
|
|
|
337
385
|
analytics.track('app_opened');
|
|
338
386
|
usedToday(Date.now());
|
|
339
387
|
} else {
|
|
340
|
-
console.log(`zero: diagnostics
|
|
388
|
+
console.log(`zero: diagnostics ${analytics.reason}, nothing is sent`);
|
|
341
389
|
}
|
|
342
390
|
|
|
343
391
|
// EVERYBODY HAS SOMEWHERE TO SEND A THREAD (w-f8d123be62, approved
|
|
@@ -362,7 +410,16 @@ async function createWindow() {
|
|
|
362
410
|
const supervisor = new Supervisor(config, store, appDir, dataDir, userDir);
|
|
363
411
|
// THAT agents start and stop work (main/analytics.mjs checks the switch).
|
|
364
412
|
supervisor.count = (name, props) => analytics.track(name, props);
|
|
365
|
-
|
|
413
|
+
const stalls = stallWatch();
|
|
414
|
+
supervisor.stalls = stalls;
|
|
415
|
+
// AND WHICH OF OUR FUNCTIONS HELD THE THREAD, each time it froze.
|
|
416
|
+
const freezes = startFreezeRecorder({
|
|
417
|
+
dir: path.join(userDir, 'memory-log'),
|
|
418
|
+
appDir,
|
|
419
|
+
onFreeze: (f) => { stalls.noteFreeze(f); console.warn(`zero: the app froze for ${f.ms} ms in ${f.where}`); },
|
|
420
|
+
});
|
|
421
|
+
quitStep(app, 'before-quit', 'freezes.stop', () => freezes.stop());
|
|
422
|
+
quitStep(app, 'before-quit', 'supervisor.killAll', () => supervisor.killAll());
|
|
366
423
|
// THE TEAM. Off entirely on a build with no team cloud (the single-person
|
|
367
424
|
// app). Otherwise it restores whoever was signed in, and from then on every
|
|
368
425
|
// line this Mac writes says who wrote it and shared projects stay in sync.
|
|
@@ -373,13 +430,16 @@ async function createWindow() {
|
|
|
373
430
|
// single-person app, which has no sign-in to keep
|
|
374
431
|
// (tests/the-installed-app-is-the-single-person-app.test.mjs).
|
|
375
432
|
const cloudConfig = loadCloudConfig(appDir, { packaged: app.isPackaged });
|
|
433
|
+
let phoneApply = null;
|
|
434
|
+
let phoneSettings = null;
|
|
435
|
+
// Every installed build has a cloud now, so the keychain is asked only once
|
|
436
|
+
// a sign-in is read or kept, not at launch.
|
|
376
437
|
const team = cloudConfig ? createTeamService({
|
|
377
438
|
session: supabaseSession({
|
|
378
439
|
cloudConfig,
|
|
379
440
|
sessionFile: path.join(config.storeRoot, '.team-session'),
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
: { encrypt: null, decrypt: null }),
|
|
441
|
+
encrypt: (text) => (safeStorage.isEncryptionAvailable() ? safeStorage.encryptString(text) : Buffer.from(text, 'utf8')),
|
|
442
|
+
decrypt: (buf) => (safeStorage.isEncryptionAvailable() ? safeStorage.decryptString(buf) : buf.toString('utf8')),
|
|
383
443
|
packaged: app.isPackaged,
|
|
384
444
|
openExternal: (url) => shell.openExternal(url),
|
|
385
445
|
}),
|
|
@@ -391,18 +451,68 @@ async function createWindow() {
|
|
|
391
451
|
// exists; until then a change has nobody to tell.
|
|
392
452
|
onChange: () => { try { pushUpdate(); } catch { /* no window yet */ } },
|
|
393
453
|
log: (line) => console.log(line),
|
|
454
|
+
// HER PHONE WITH THE MAC SHUT (main/phone-inbox.mjs). What it left is done
|
|
455
|
+
// through the window's own handlers, filed below once the window exists.
|
|
456
|
+
phone: {
|
|
457
|
+
// Her yes, with her id on it (shared/phone-snapshot.mjs phoneProjectsOf).
|
|
458
|
+
projects: () => config.phoneProducts ?? null,
|
|
459
|
+
ready: () => !!phoneApply,
|
|
460
|
+
apply: (cmd) => phoneApply(cmd),
|
|
461
|
+
// The Settings pages' model, read through the window's own handler.
|
|
462
|
+
readSettings: () => phoneSettings?.() ?? null,
|
|
463
|
+
version: app.getVersion(),
|
|
464
|
+
live: (slug, id) => supervisor.liveFor(slug, id),
|
|
465
|
+
// The cards waiting on her, each with the fingerprint her answer must carry back.
|
|
466
|
+
approvals: () => approvals.listPending(config.storeRoot).map((r) => ({ ...r, card: approvals.cardShown(config.storeRoot, r.id) })),
|
|
467
|
+
stateFile: path.join(config.storeRoot, '.phone-inbox.json'),
|
|
468
|
+
// This installation and this store together (main/phone-inbox.mjs).
|
|
469
|
+
device: () => phoneDevice(userDir, config.storeRoot),
|
|
470
|
+
// Where her phone reads it, once the site is up (cloud/team.config.json).
|
|
471
|
+
site: typeof cloudConfig.phoneSite === 'string' ? cloudConfig.phoneSite : null,
|
|
472
|
+
// No alert on her phone while she is at this Mac (main/phone-alerts.mjs).
|
|
473
|
+
idleMs: () => powerMonitor.getSystemIdleTime() * 1000,
|
|
474
|
+
// A reply she sends with the lid shut carries on in the cloud (shared/cloud-kit.mjs).
|
|
475
|
+
carrying: (c) => supervisor.phoneCarrying(c),
|
|
476
|
+
kitsFor: (slug) => supervisor.leavesKitsFor(slug),
|
|
477
|
+
adopt: ({ project, item, runId, replies }) => supervisor.adoptCloudRun({ product: project, itemId: item, runId, replies }),
|
|
478
|
+
cloudReplies: ({ project, item, replies }) => supervisor.cloudRunReplies({ product: project, itemId: item, replies }),
|
|
479
|
+
runHome: ({ project, item, runId }) => supervisor.cloudRunHome({ product: project, itemId: item, runId }),
|
|
480
|
+
// And a new thread she starts with the lid shut.
|
|
481
|
+
newThreadKits: (c) => supervisor.leaveNewThreadKits(c),
|
|
482
|
+
adoptNew: ({ project, item, ...rest }) => supervisor.adoptCloudNewThread({ product: project, itemId: item, ...rest }),
|
|
483
|
+
},
|
|
484
|
+
// ROOMS, while switched on in Alpha features (docs/team/ROOMS-PLAN.md).
|
|
485
|
+
rooms: roomsSetup({ config, store, supervisor, userDir }),
|
|
394
486
|
}) : null;
|
|
395
487
|
if (team) {
|
|
396
488
|
team.start().then(() => supervisor.wake?.()).catch((err) => console.warn(`team: ${err.message}`));
|
|
397
|
-
app
|
|
489
|
+
quitStep(app, 'before-quit', 'team.stop', () => team.stop());
|
|
398
490
|
}
|
|
399
491
|
// HER CODEX CONVERSATIONS ASK TO COME IN. Once a minute: a new one in a
|
|
400
492
|
// folder a project points at gets a row asking yes or no, and the ones she
|
|
401
493
|
// said yes to follow Codex's latest answer.
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
//
|
|
405
|
-
|
|
494
|
+
// AND IT IS WHERE A CODEX AGENT IS COUNTED, because it is the one thing that
|
|
495
|
+
// already reads them (main/codex-watch.mjs). The switch is checked by
|
|
496
|
+
// `analytics.track` itself, so this hands it over unconditionally.
|
|
497
|
+
// Every Codex folder on the machine, read fresh each minute so a login made
|
|
498
|
+
// while the app is open is followed too (main/agent-homes.mjs).
|
|
499
|
+
const codexWatch = startCodexWatch({
|
|
500
|
+
store,
|
|
501
|
+
count: (name, props) => analytics.track(name, props),
|
|
502
|
+
readThreads: (opts) => readCodexThreadsOffThread({ ...opts, codexDirs: appSessionFolders({ config, supervisor }).codexDirs }),
|
|
503
|
+
});
|
|
504
|
+
quitStep(app, 'before-quit', 'codexWatch.stop', () => codexWatch.stop());
|
|
505
|
+
// New chats from Claude Code and Codex, once asked for on setup's last
|
|
506
|
+
// screen or in Settings. The watch checks the switch every pass.
|
|
507
|
+
const newChatsWatch = watchNewChatsFor({ store, config, supervisor });
|
|
508
|
+
quitStep(app, 'before-quit', 'newChatsWatch.stop', () => newChatsWatch.stop());
|
|
509
|
+
// Whatever is still queued goes with the app rather than dying in memory,
|
|
510
|
+
// and the quit WAITS for it (main/quit-sequence.mjs). It did not: the
|
|
511
|
+
// process went as soon as this returned, so the last batch was a POST that
|
|
512
|
+
// never left, which on an install that opens the app once is everything we
|
|
513
|
+
// would ever have heard from it (w-60c8ddbab6).
|
|
514
|
+
quitStep(app, 'before-quit', 'count the quit', () => analytics.track('app_quit', { seconds: Math.round(process.uptime()) }));
|
|
515
|
+
flushBeforeQuit(app, () => analytics.flush());
|
|
406
516
|
|
|
407
517
|
// Right-click. Electron ships no context menu at all, so links could not be
|
|
408
518
|
// copied or opened by hand anywhere in the app. Built per click from what is
|
|
@@ -593,9 +703,18 @@ async function createWindow() {
|
|
|
593
703
|
window = new BrowserWindow({
|
|
594
704
|
width: 1440,
|
|
595
705
|
height: 900,
|
|
596
|
-
|
|
706
|
+
// Half of a 1440-point screen, so the window tiles; under 700 is the phone layout.
|
|
707
|
+
minWidth: 720,
|
|
597
708
|
minHeight: 600,
|
|
598
|
-
|
|
709
|
+
// A throwaway copy says which one it is and stands a shoulder clear;
|
|
710
|
+
// your own window is centred and titled as it was.
|
|
711
|
+
...newUserWindow({
|
|
712
|
+
fresh: runningAsAFreshUser(),
|
|
713
|
+
name: NAME,
|
|
714
|
+
screen: electronScreen.getPrimaryDisplay()?.workArea,
|
|
715
|
+
width: 1440,
|
|
716
|
+
height: 900,
|
|
717
|
+
}),
|
|
599
718
|
backgroundColor: '#1a1a1c',
|
|
600
719
|
titleBarStyle: 'hiddenInset',
|
|
601
720
|
webPreferences: {
|
|
@@ -606,6 +725,11 @@ async function createWindow() {
|
|
|
606
725
|
},
|
|
607
726
|
});
|
|
608
727
|
|
|
728
|
+
// Electron hands the window's title to the page's the moment one loads, and
|
|
729
|
+
// renderer/index.html carries the app's name, so a throwaway copy went back
|
|
730
|
+
// to saying "Agentbox" as soon as it drew anything.
|
|
731
|
+
window.on('page-title-updated', (e) => e.preventDefault());
|
|
732
|
+
|
|
609
733
|
// THE MENU IS A BAR INSIDE THE WINDOW on Linux and Windows. On macOS it is
|
|
610
734
|
// the system menu, so it stays. The menu itself stays everywhere: the Ctrl
|
|
611
735
|
// chords are bound to it, and taking the menu out would take them with it.
|
|
@@ -661,9 +785,16 @@ async function createWindow() {
|
|
|
661
785
|
// AND A COPY RUN FROM SOURCE watches its git branch instead of a release
|
|
662
786
|
// feed (main/source-updater.mjs), because that is how teammates run the team
|
|
663
787
|
// build and their updates are pushes to main, not releases.
|
|
788
|
+
//
|
|
789
|
+
// AND WHERE THIS COPY IS RUNNING FROM (shared/where-it-runs-from.mjs). An
|
|
790
|
+
// app run out of the disk image, or out of a read-only copy macOS made of
|
|
791
|
+
// it, can never update itself, and until 2026-10-12 nothing in the app said
|
|
792
|
+
// so: two installs sat on 0.1.11 for a week. The fact rides the updater's
|
|
793
|
+
// state so the Settings row, the sidebar card and ⌘K all read one answer.
|
|
664
794
|
let pushUpdate = () => {};
|
|
665
795
|
const updater = app.isPackaged ? createUpdater({
|
|
666
796
|
app,
|
|
797
|
+
place: createPlace({ app }),
|
|
667
798
|
onChanged: () => pushUpdate(),
|
|
668
799
|
}) : createSourceUpdater({
|
|
669
800
|
app,
|
|
@@ -673,9 +804,24 @@ async function createWindow() {
|
|
|
673
804
|
|
|
674
805
|
// The desktop door. `main/serve.mjs` is the other one and hands over plain
|
|
675
806
|
// Node stand-ins for these three; everything else about the call is the same.
|
|
807
|
+
// What the phone leaves in the cloud is done through these same handlers
|
|
808
|
+
// (main/phone-inbox.mjs), so each one is filed in a Map as Electron gets it.
|
|
809
|
+
const phoneChannels = new Map();
|
|
810
|
+
const filingIpcMain = {
|
|
811
|
+
handle(channel, fn) { ipcMain.handle(channel, stalls.time(channel, fn)); phoneChannels.set(channel, fn); },
|
|
812
|
+
};
|
|
813
|
+
// `readClipboardText` is read only by the cloud setup, and only for a
|
|
814
|
+
// Claude sign-in code (main/ipc.mjs `zero:cloud-clipboard-code`).
|
|
815
|
+
const filingHost = {
|
|
816
|
+
ipcMain: filingIpcMain, app, dialog, readClipboardText: () => clipboard.readText(),
|
|
817
|
+
// A voice note asks for the microphone on the press of its button.
|
|
818
|
+
micAccess: () => (process.platform === 'darwin'
|
|
819
|
+
? getMic({ systemPreferences, openExternal: (url) => shell.openExternal(url) })
|
|
820
|
+
: 'granted'),
|
|
821
|
+
};
|
|
676
822
|
const ipc = registerIpc({
|
|
677
823
|
store, supervisor, config, window, analytics, docGrants, updater,
|
|
678
|
-
host:
|
|
824
|
+
host: filingHost,
|
|
679
825
|
team,
|
|
680
826
|
});
|
|
681
827
|
pushUpdate = ipc.push;
|
|
@@ -683,11 +829,17 @@ async function createWindow() {
|
|
|
683
829
|
// See the `installMenu` call above for what writing the file instead did to a
|
|
684
830
|
// Codex card.
|
|
685
831
|
answerApproval = ipc.answerApproval;
|
|
832
|
+
// What the window answers itself (badge, boot info) gets the plain stand-ins
|
|
833
|
+
// a browser tab gets.
|
|
834
|
+
answerWhatOnlyTheWindowAnswered({ handle: (channel, fn) => { if (!phoneChannels.has(channel)) phoneChannels.set(channel, fn); } });
|
|
835
|
+
phoneApply = applyThrough(phoneChannels);
|
|
836
|
+
// Every minute, so no engine search: that is a login shell on this thread.
|
|
837
|
+
phoneSettings = () => phoneChannels.get('zero:settings-read')?.({ sender: null }, { search: false }) ?? null;
|
|
686
838
|
updater.start();
|
|
687
839
|
// A task the app just shipped moved main: look now rather than in half an
|
|
688
840
|
// hour, so the restart is offered while she still remembers the task.
|
|
689
841
|
supervisor.onShipped = () => { try { updater.check?.(); } catch {} };
|
|
690
|
-
app
|
|
842
|
+
quitStep(app, 'before-quit', 'updater.stop', () => updater.stop());
|
|
691
843
|
|
|
692
844
|
// Cmd+Y / Cmd+N answer the oldest approval card from ANYWHERE, including
|
|
693
845
|
// while a child web contents owns the keyboard (menu accelerators turned out
|
|
@@ -863,7 +1015,31 @@ async function createWindow() {
|
|
|
863
1015
|
// a locked screen all read the same from in there). The renderer says what
|
|
864
1016
|
// arrived; main/notify.mjs decides. tell me when I am in another app, never
|
|
865
1017
|
// while I am in Agentbox.
|
|
866
|
-
|
|
1018
|
+
// A banner and the tray never disagree: whatever a banner told you about
|
|
1019
|
+
// while you were away is in the tray until you are back (w-93b3a1a796).
|
|
1020
|
+
let cornerTag = null;
|
|
1021
|
+
const notifier = installNotifier({
|
|
1022
|
+
app, window, Notification, powerMonitor, ipcMain, nativeImage,
|
|
1023
|
+
onArrivals: (list, needsYou) => team?.phoneArrivals(list, needsYou),
|
|
1024
|
+
onChange: () => cornerTag?.refresh(),
|
|
1025
|
+
});
|
|
1026
|
+
// THE CORNER TAG (w-dafae58a23): what is ready for her, floating over
|
|
1027
|
+
// whatever app she is in. Its page is built beside the app's own, and comes
|
|
1028
|
+
// from the dev server only when the app's own page does.
|
|
1029
|
+
cornerTag = createCornerTag({
|
|
1030
|
+
BrowserWindow, screen: electronScreen, ipcMain, Menu, powerMonitor, config, saveConfig, mainWindow: window,
|
|
1031
|
+
preload: path.join(appDir, 'main', 'corner-tag-preload.cjs'),
|
|
1032
|
+
glass: loadLiquidGlass(),
|
|
1033
|
+
told: () => notifier.told(),
|
|
1034
|
+
count: (name, props) => analytics.track(name, props),
|
|
1035
|
+
// `part` is the tag itself or the list beside it, one page drawn twice.
|
|
1036
|
+
load: (tagWindow, part) => {
|
|
1037
|
+
const devTag = process.env.ZERO_DEV_URL;
|
|
1038
|
+
const builtTag = path.join(appDir, 'renderer', 'dist', 'corner-tag.html');
|
|
1039
|
+
if (devTag && !fs.existsSync(builtTag)) tagWindow.loadURL(`${devTag.replace(/\/$/, '')}/corner-tag.html?part=${part}`);
|
|
1040
|
+
else tagWindow.loadFile(builtTag, { search: `part=${part}` });
|
|
1041
|
+
},
|
|
1042
|
+
});
|
|
867
1043
|
// Asked for once by the renderer as it mounts, rather than pushed on
|
|
868
1044
|
// did-finish-load, which races the first effects and would drop the very
|
|
869
1045
|
// message it exists to deliver.
|
|
@@ -880,6 +1056,7 @@ async function createWindow() {
|
|
|
880
1056
|
// itself (it has no disk and should not have one), and 'render-process-gone'
|
|
881
1057
|
// only fires when the process DIES, which a thrown React error does not.
|
|
882
1058
|
ipcMain.handle('zero:crash', (_e, payload) => { reportFromRenderer(payload ?? {}); });
|
|
1059
|
+
ipcMain.handle('zero:take-join', () => { const token = pendingJoin; pendingJoin = null; return token; });
|
|
883
1060
|
// External links from markdown open in the real browser; local artifacts
|
|
884
1061
|
// (a demo page, a screenshot a worker saved) open in their default app, so
|
|
885
1062
|
// "see it working" is one click from the message.
|
|
@@ -889,32 +1066,57 @@ async function createWindow() {
|
|
|
889
1066
|
return { action: 'deny' };
|
|
890
1067
|
});
|
|
891
1068
|
|
|
892
|
-
//
|
|
1069
|
+
// WHAT AN EMBEDDED PAGE MAY DO IS DECIDED HERE, NOT ON THE TAG THAT ASKED.
|
|
893
1070
|
//
|
|
894
|
-
//
|
|
895
|
-
//
|
|
896
|
-
//
|
|
897
|
-
//
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
// works as before. Every webview this window attaches gets it, the junk
|
|
901
|
-
// browser included, which is what "never" asks for.
|
|
902
|
-
window.webContents.on('will-attach-webview', (_e, webPreferences) => {
|
|
903
|
-
webPreferences.autoplayPolicy = 'document-user-activation-required';
|
|
1071
|
+
// The pane draws a website now, which is the first code in this window that
|
|
1072
|
+
// nobody here wrote, so every webview is pinned below the tag: no preload,
|
|
1073
|
+
// sandboxed, context-isolated, node off, web security on, and no sound
|
|
1074
|
+
// before a click. main/webview-guard.mjs is the rule and the reasons.
|
|
1075
|
+
window.webContents.on('will-attach-webview', (_e, webPreferences, params) => {
|
|
1076
|
+
hardenAttachedWebview(webPreferences, params);
|
|
904
1077
|
});
|
|
905
1078
|
|
|
906
1079
|
// A page in the pane hides its scrollbar until you scroll, like the app's own
|
|
907
1080
|
// (frame-scrollbars.mjs). Without it, a mouse on macOS gets a white track.
|
|
908
1081
|
quietTheFramesScrollbars(window.webContents);
|
|
909
1082
|
|
|
1083
|
+
// A local app a worker names (http://localhost:3006) draws in the pane even
|
|
1084
|
+
// when it refuses to be framed, and its sign-in cookie sticks there
|
|
1085
|
+
// (main/local-app-frames.mjs).
|
|
1086
|
+
letLocalAppsShowInThePane(window.webContents);
|
|
1087
|
+
|
|
910
1088
|
// Escape must ALWAYS leave the junk browser, even when the guest page has
|
|
911
1089
|
// focus and would otherwise swallow the key. Intercept it below the page.
|
|
912
1090
|
app.on('web-contents-created', (_event, contents) => {
|
|
913
1091
|
if (contents.getType() !== 'webview') return;
|
|
1092
|
+
|
|
1093
|
+
// A LINK IN A WEBSITE THAT WANTS A NEW WINDOW GOES TO YOUR OWN BROWSER.
|
|
1094
|
+
// The pane is one page at a time; a second Electron window would be a
|
|
1095
|
+
// browser we have not designed, and `allowpopups` is off anyway
|
|
1096
|
+
// (webview-guard.mjs), so without this such a link does nothing at all.
|
|
1097
|
+
contents.setWindowOpenHandler(({ url }) => {
|
|
1098
|
+
if (/^https?:/.test(url)) shell.openExternal(url);
|
|
1099
|
+
return { action: 'deny' };
|
|
1100
|
+
});
|
|
1101
|
+
|
|
914
1102
|
contents.on('before-input-event', (e, input) => {
|
|
1103
|
+
// ESCAPE HAS TO REACH THE APP FROM INSIDE A PAGE, and a webview is not
|
|
1104
|
+
// a frame of this window, so the handler above never hears it. It comes
|
|
1105
|
+
// up the same channel a frame's does, because the renderer answers that
|
|
1106
|
+
// one and decides there what escape means (whatTheFileSentUp). It used
|
|
1107
|
+
// to be sent on `zero:escape-browser`, the junk browser's own channel,
|
|
1108
|
+
// which no renderer code has listened to since that pane went: the key
|
|
1109
|
+
// landed nowhere and the pane took two presses to close.
|
|
915
1110
|
if (input.type === 'keyDown' && input.key === 'Escape' && window && !window.isDestroyed()) {
|
|
916
|
-
|
|
917
|
-
|
|
1111
|
+
// The keyboard is left where it is, exactly as it is for a frame: the
|
|
1112
|
+
// renderer blurs the page before the pane goes. Taking focus back
|
|
1113
|
+
// here first would move `document.activeElement` off the webview, and
|
|
1114
|
+
// the renderer's own check of the same fact would then refuse the key
|
|
1115
|
+
// that this just sent.
|
|
1116
|
+
window.webContents.send('zero:key-in-the-file', {
|
|
1117
|
+
key: input.key, meta: !!input.meta, ctrl: !!input.control, alt: !!input.alt, shift: !!input.shift,
|
|
1118
|
+
fromGuest: true,
|
|
1119
|
+
});
|
|
918
1120
|
return;
|
|
919
1121
|
}
|
|
920
1122
|
// The guest page owns the keyboard while she is in the junk browser, so
|
|
@@ -997,7 +1199,9 @@ async function createWindow() {
|
|
|
997
1199
|
} catch (err) {
|
|
998
1200
|
console.error('screenshot failed:', err.message);
|
|
999
1201
|
}
|
|
1000
|
-
|
|
1202
|
+
// The picture is taken, so the run is over whether the quit works or
|
|
1203
|
+
// not. On Linux it did not, and the shell's `timeout` ended these runs.
|
|
1204
|
+
quitThenExit(app, { what: 'the screenshot run' });
|
|
1001
1205
|
}, Number(process.env.ZERO_SCREENSHOT_DELAY_MS ?? 2500));
|
|
1002
1206
|
}
|
|
1003
1207
|
|
|
@@ -1015,12 +1219,16 @@ async function createWindow() {
|
|
|
1015
1219
|
if (!app.requestSingleInstanceLock()) {
|
|
1016
1220
|
app.quit();
|
|
1017
1221
|
} else {
|
|
1018
|
-
app.on('second-instance', () => {
|
|
1222
|
+
app.on('second-instance', (_e, argv = []) => {
|
|
1019
1223
|
if (window) {
|
|
1020
1224
|
if (window.isMinimized()) window.restore();
|
|
1021
1225
|
window.focus();
|
|
1022
1226
|
}
|
|
1227
|
+
const link = argv.find((a) => String(a).startsWith(`${JOIN_SCHEME}://`));
|
|
1228
|
+
if (link) openJoinLink(link);
|
|
1023
1229
|
});
|
|
1230
|
+
// Stripe's last page links back on the app's scheme, which only needs the window.
|
|
1231
|
+
app.on('open-url', (e, url) => { e.preventDefault(); if (ourLink(url)) showWindow(); openJoinLink(url); });
|
|
1024
1232
|
app.whenReady().then(() => {
|
|
1025
1233
|
// A from-source Linux launch keeps the launcher command installed. The
|
|
1026
1234
|
// entry runs that command; this only refreshes where it points. A packaged
|
|
@@ -1036,6 +1244,9 @@ if (!app.requestSingleInstanceLock()) {
|
|
|
1036
1244
|
// THE ABOUT BOX SAYS AGENTBOX AND ITS OWN VERSION (w-db6f5e331e). Run from
|
|
1037
1245
|
// source it read the bundle's, which is Electron's: "Electron 43.0.0".
|
|
1038
1246
|
app.setAboutPanelOptions({ applicationName: NAME, applicationVersion: app.getVersion(), version: '' });
|
|
1247
|
+
// Only the installed app takes the invite scheme: run from source it would
|
|
1248
|
+
// point every link on the Mac at this checkout's Electron.
|
|
1249
|
+
if (app.isPackaged) app.setAsDefaultProtocolClient(JOIN_SCHEME);
|
|
1039
1250
|
// Serve a granted file, and nothing else. A page under this scheme is one
|
|
1040
1251
|
// of ours, but it is written by an agent and read by her, so the check is
|
|
1041
1252
|
// on every request rather than only on the one the pane asked for.
|