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/source-updater.mjs
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
import { execFile, execFileSync, spawn } from 'node:child_process';
|
|
34
34
|
import fs from 'node:fs';
|
|
35
35
|
import { describe } from './updater.mjs';
|
|
36
|
+
import { loginShell } from './shell-path.mjs';
|
|
36
37
|
|
|
37
38
|
const FIRST_CHECK_MS = 20_000;
|
|
38
39
|
const EVERY_MS = 30 * 60 * 1000;
|
|
@@ -55,7 +56,13 @@ const SAY = {
|
|
|
55
56
|
// on this Mac, and the restart below runs that build. Counted as her changes,
|
|
56
57
|
// they made every update after the first say "changes of your own" for good
|
|
57
58
|
// (tests/a-build-does-not-stop-the-next-update.test.mjs).
|
|
58
|
-
|
|
59
|
+
//
|
|
60
|
+
// THE LOCKFILE IS NPM'S, TOO (2026-10-07). The restart's `npm install` rewrote
|
|
61
|
+
// package-lock.json (this npm drops its `libc` lines), and the card never came
|
|
62
|
+
// back while main ran 21 commits ahead. An edit to the dependencies themselves
|
|
63
|
+
// is in package.json, which still blocks
|
|
64
|
+
// (tests/a-package-install-does-not-stop-the-next-update.test.mjs).
|
|
65
|
+
const isBuildOutput = (file) => file === 'package-lock.json' || /^shared\/[^/]+\.generated\.[cm]?[jt]s$/.test(file);
|
|
59
66
|
// The status code is one or two letters and `gitIn` trims the output, which
|
|
60
67
|
// takes the leading space off the first line, so it is matched, not sliced.
|
|
61
68
|
const changedPaths = (porcelain) => String(porcelain ?? '').split('\n').filter(Boolean).map((l) => l.replace(/^[ MADRCUT?!]{1,2} /, '').replace(/^"|"$/g, ''));
|
|
@@ -97,19 +104,26 @@ function collect(bin, args, { cwd, timeout }) {
|
|
|
97
104
|
|
|
98
105
|
// WHICH npm. Started with `npm start`, the process carries npm's own path in
|
|
99
106
|
// its environment, so that one is used and nvm or a version manager never
|
|
100
|
-
// matters. Started any other way,
|
|
101
|
-
// main/claude-bin.mjs finds Claude Code
|
|
102
|
-
//
|
|
107
|
+
// matters. Started any other way, their login shell is asked, the way
|
|
108
|
+
// main/claude-bin.mjs finds Claude Code, and only a shell this machine has: a
|
|
109
|
+
// Linux launcher start carries no SHELL, so the old `|| '/bin/zsh'` was a path
|
|
110
|
+
// to nothing and every update on a box without zsh failed in two seconds. With
|
|
111
|
+
// no shell at all, npm on PATH is the better guess. The arguments are fixed
|
|
112
|
+
// strings from this file, never anything read from disk.
|
|
113
|
+
export function npmCommand(args, { env = process.env, exists = fs.existsSync } = {}) {
|
|
114
|
+
const node = env.npm_node_execpath;
|
|
115
|
+
const cli = env.npm_execpath;
|
|
116
|
+
if (node && cli && exists(node) && exists(cli)) return [node, [cli, ...args]];
|
|
117
|
+
const shell = loginShell(env, exists);
|
|
118
|
+
if (!exists(shell)) return ['npm', args];
|
|
119
|
+
return [shell, ['-lic', `npm ${args.join(' ')}`]];
|
|
120
|
+
}
|
|
121
|
+
|
|
103
122
|
export function defaultNpm(appDir, env = process.env) {
|
|
104
123
|
return (args) => {
|
|
105
124
|
const timeout = args[0] === 'install' ? INSTALL_MS : BUILD_MS;
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
if (node && cli && fs.existsSync(node) && fs.existsSync(cli)) {
|
|
109
|
-
return collect(node, [cli, ...args], { cwd: appDir, timeout });
|
|
110
|
-
}
|
|
111
|
-
const shell = env.SHELL || '/bin/zsh';
|
|
112
|
-
return collect(shell, ['-lic', `npm ${args.join(' ')}`], { cwd: appDir, timeout });
|
|
125
|
+
const [bin, argv] = npmCommand(args, { env });
|
|
126
|
+
return collect(bin, argv, { cwd: appDir, timeout });
|
|
113
127
|
};
|
|
114
128
|
}
|
|
115
129
|
|
|
@@ -128,6 +142,18 @@ export function createSourceUpdater({
|
|
|
128
142
|
log = console,
|
|
129
143
|
onChanged = () => {},
|
|
130
144
|
npm = defaultNpm(appDir),
|
|
145
|
+
// THE STEP `npm start` DOES AND THIS DID NOT. A from-source run gets its
|
|
146
|
+
// name, icon and bundle id from scripts/brand-electron.mjs, which npm runs
|
|
147
|
+
// before Electron. An update does not go through npm: it builds and calls
|
|
148
|
+
// app.relaunch(), which re-executes the same binary. So the branding had
|
|
149
|
+
// never once run on a self-restart, and a fix to it could sit on disk for
|
|
150
|
+
// days without reaching the bundle (measured 2026-10-09, with the
|
|
151
|
+
// Info.plist four days older than the fix meant to change it).
|
|
152
|
+
// Imported here and not at the top of the file: scripts/ is deliberately not
|
|
153
|
+
// in the downloadable build (`build.files`, and a test holds it there), and
|
|
154
|
+
// a static import would stop that build booting at all. This path only ever
|
|
155
|
+
// runs from source, where the script is on disk.
|
|
156
|
+
brand = async () => (await import('../scripts/brand-electron.mjs')).brandElectron(),
|
|
131
157
|
relaunch = () => { app?.relaunch(); app?.quit(); },
|
|
132
158
|
} = {}) {
|
|
133
159
|
const git = gitIn(appDir);
|
|
@@ -251,12 +277,20 @@ export function createSourceUpdater({
|
|
|
251
277
|
set({ phase: 'ready', error: `The new packages would not install: ${failureLine(installed.out)}` });
|
|
252
278
|
return;
|
|
253
279
|
}
|
|
280
|
+
// What the install rewrote goes back, so the folder is left as main has
|
|
281
|
+
// it and anything else that fast-forwards it cannot trip on the file.
|
|
282
|
+
await git(['checkout', '--', 'package-lock.json']);
|
|
254
283
|
}
|
|
255
284
|
const built = await npm(['run', 'build']);
|
|
256
285
|
if (built.code !== 0) {
|
|
257
286
|
set({ phase: 'ready', error: `The new code would not build: ${failureLine(built.out)}` });
|
|
258
287
|
return;
|
|
259
288
|
}
|
|
289
|
+
// Before the relaunch, never after: the next launch is the one that reads
|
|
290
|
+
// the Info.plist. And never fatally, for the reason brand-electron.mjs
|
|
291
|
+
// opens with about itself — an app that does not come back up is worse
|
|
292
|
+
// than one wearing the wrong icon.
|
|
293
|
+
try { await brand(); } catch (e) { log.warn?.('[source-updater] could not rebrand the bundle:', e?.message ?? e); }
|
|
260
294
|
log.info?.('[source-updater] built', state.newVersion, '- relaunching');
|
|
261
295
|
relaunch();
|
|
262
296
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// STAGING A FILE FOR A REPLY BOX, before it is sent: the bytes of a paste, or
|
|
2
|
+
// a copy of a picture dropped in, written into the account's .staging folder,
|
|
3
|
+
// which the window may draw from (main/ipc.mjs `zero:stage-attachment` says
|
|
4
|
+
// why). A picture the window cannot draw is turned into one that it can here,
|
|
5
|
+
// so the box, the message and the teammate all get a picture.
|
|
6
|
+
import { execFile } from 'node:child_process';
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { turnedName } from '../shared/picture-formats.mjs';
|
|
10
|
+
|
|
11
|
+
const WEEK = 7 * 24 * 60 * 60 * 1000;
|
|
12
|
+
const SIPS_MS = 30_000;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Answers `{ path }`, and `name` too when the file was turned into another
|
|
16
|
+
* format, which is the name it goes on under.
|
|
17
|
+
*/
|
|
18
|
+
export async function stageAttachment(dir, { name, dataBase64, srcPath } = {}, { turn = turnIntoPicture } = {}) {
|
|
19
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
20
|
+
// Sweep on the way in rather than on a timer: an abandoned paste is only
|
|
21
|
+
// ever discovered by the next one, and a week is longer than any draft has
|
|
22
|
+
// been left open. Failure to sweep must never fail the paste.
|
|
23
|
+
try {
|
|
24
|
+
const week = Date.now() - WEEK;
|
|
25
|
+
for (const f of fs.readdirSync(dir)) {
|
|
26
|
+
const p = path.join(dir, f);
|
|
27
|
+
try { if (fs.statSync(p).mtimeMs < week) fs.unlinkSync(p); } catch { /* leave it */ }
|
|
28
|
+
}
|
|
29
|
+
} catch { /* a sweep that cannot run is not a paste that failed */ }
|
|
30
|
+
const safe = String(name ?? 'pasted.png').replace(/[^\w.-]+/g, '-').slice(0, 80);
|
|
31
|
+
const abs = path.join(dir, `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}-${safe}`);
|
|
32
|
+
// A path is a drag, bytes are a paste. Already inside the folder we serve
|
|
33
|
+
// from is left alone: copying it would only make a second file to sweep.
|
|
34
|
+
if (typeof srcPath === 'string' && srcPath) {
|
|
35
|
+
if (path.resolve(srcPath) === path.resolve(path.join(dir, path.basename(srcPath)))) return { path: srcPath };
|
|
36
|
+
fs.copyFileSync(srcPath, abs);
|
|
37
|
+
} else {
|
|
38
|
+
fs.writeFileSync(abs, Buffer.from(String(dataBase64 ?? ''), 'base64'));
|
|
39
|
+
}
|
|
40
|
+
const as = turnedName(name ?? safe);
|
|
41
|
+
if (!as) return { path: abs };
|
|
42
|
+
// One that cannot be turned goes as the file it is, which is how every TIFF went before.
|
|
43
|
+
const drawn = await Promise.resolve().then(() => turn(abs)).catch(() => null);
|
|
44
|
+
if (!drawn) return { path: abs };
|
|
45
|
+
try { fs.unlinkSync(abs); } catch { /* swept within the week */ }
|
|
46
|
+
return { path: drawn, name: as };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Turns a TIFF or HEIC into a PNG or JPEG beside it with the Mac's own sips,
|
|
51
|
+
* and answers the new file's path. Null off a Mac, for any other file, or
|
|
52
|
+
* when sips fails or writes nothing.
|
|
53
|
+
*/
|
|
54
|
+
export async function turnIntoPicture(file, { platform = process.platform, run = sips } = {}) {
|
|
55
|
+
const as = turnedName(path.basename(file));
|
|
56
|
+
if (!as || platform !== 'darwin') return null;
|
|
57
|
+
const out = path.join(path.dirname(file), as);
|
|
58
|
+
try {
|
|
59
|
+
await run(['-s', 'format', as.endsWith('.png') ? 'png' : 'jpeg', file, '--out', out]);
|
|
60
|
+
return fs.statSync(out).size > 0 ? out : null;
|
|
61
|
+
} catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const sips = (args) => new Promise((resolve, reject) => {
|
|
67
|
+
execFile('/usr/bin/sips', args, { timeout: SIPS_MS }, (err) => (err ? reject(err) : resolve()));
|
|
68
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// WHICH REQUEST HELD THE APP. A spinning wheel on a Mac is the main process
|
|
2
|
+
// not answering, and nothing used to record what it was doing instead. This
|
|
3
|
+
// times every request the window makes and keeps the longest freeze; the
|
|
4
|
+
// memory log writes both into its minute line (main/memory-log.mjs).
|
|
5
|
+
//
|
|
6
|
+
// Only the synchronous part of a handler is timed. That is the part that holds
|
|
7
|
+
// the process: once a handler waits on a promise the window is free again.
|
|
8
|
+
import { monitorEventLoopDelay, performance } from 'node:perf_hooks';
|
|
9
|
+
|
|
10
|
+
export const SLOW_MS = 100;
|
|
11
|
+
|
|
12
|
+
export function stallWatch({ clock = () => performance.now(), loop = monitorEventLoopDelay({ resolution: 20 }) } = {}) {
|
|
13
|
+
loop.enable();
|
|
14
|
+
let slow = new Map();
|
|
15
|
+
let freezes = [];
|
|
16
|
+
return {
|
|
17
|
+
/** A freeze main/freeze-recorder.mjs caught, with the function that held it. */
|
|
18
|
+
noteFreeze({ ms, where }) {
|
|
19
|
+
freezes.push({ ms, where });
|
|
20
|
+
},
|
|
21
|
+
time(channel, fn) {
|
|
22
|
+
return (...args) => {
|
|
23
|
+
const start = clock();
|
|
24
|
+
try {
|
|
25
|
+
return fn(...args);
|
|
26
|
+
} finally {
|
|
27
|
+
const ms = Math.round(clock() - start);
|
|
28
|
+
if (ms >= SLOW_MS) {
|
|
29
|
+
const seen = slow.get(channel) ?? { channel, times: 0, maxMs: 0 };
|
|
30
|
+
seen.times += 1;
|
|
31
|
+
seen.maxMs = Math.max(seen.maxMs, ms);
|
|
32
|
+
slow.set(channel, seen);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
/** The minute so far, and a fresh start. */
|
|
38
|
+
take() {
|
|
39
|
+
const out = {
|
|
40
|
+
longestStallMs: Math.round(loop.max / 1e6),
|
|
41
|
+
slowRequests: [...slow.values()].sort((a, b) => b.maxMs - a.maxMs).slice(0, 5),
|
|
42
|
+
...(freezes.length ? { freezes: freezes.sort((a, b) => b.ms - a.ms).slice(0, 5) } : {}),
|
|
43
|
+
};
|
|
44
|
+
loop.reset();
|
|
45
|
+
slow = new Map();
|
|
46
|
+
freezes = [];
|
|
47
|
+
return out;
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// NO NEW AGENT STARTS WHILE MEMORY IS SHORT (w-ec27ff1a51).
|
|
2
|
+
//
|
|
3
|
+
// 2026-10-11, a 16 GB Mac ran out of application memory with Agentbox at
|
|
4
|
+
// 22 GB and six agents running. The memory check (main/memory-gate.mjs) held
|
|
5
|
+
// tests and builds back, but nothing asked memory before STARTING an agent, so
|
|
6
|
+
// the fleet filled every slot it had into a Mac that was already short.
|
|
7
|
+
//
|
|
8
|
+
// So while the memory switch is on and the Mac reads tight or very short, a new
|
|
9
|
+
// agent waits. That is the whole rule. Everything else here is a way out of it,
|
|
10
|
+
// because the founder's condition was that urgent work still comes first and
|
|
11
|
+
// that nothing sits stuck for long on a misread:
|
|
12
|
+
//
|
|
13
|
+
// - NOTHING RUNNING, ONE STARTS. Whatever is filling memory then is not us,
|
|
14
|
+
// and an app with no agent running at all is broken rather than careful.
|
|
15
|
+
// - AN URGENT ROW, OR ONE SHE ASKED FOR BY NAME, starts while tight and waits
|
|
16
|
+
// only while very short: the command gate's rule for urgent commands.
|
|
17
|
+
// - A SWAP IS NOT A NEW AGENT. A row something was paused for (an Urgent row
|
|
18
|
+
// taking a lesser session's slot, or Run now) always starts, so urgent work
|
|
19
|
+
// still takes over while memory is very short, by replacing, not adding.
|
|
20
|
+
// - A READING THAT IS MISSING, UNREADABLE OR OLDER THAN A MINUTE IS NOT A
|
|
21
|
+
// REASON TO HOLD. The hold acts only on a reading it actually has.
|
|
22
|
+
// - TEN MINUTES HELD, ONE STARTS ANYWAY, and the ten minutes start again from
|
|
23
|
+
// it. A reading stuck on "tight" by mistake costs a slow queue, never a
|
|
24
|
+
// stopped one.
|
|
25
|
+
//
|
|
26
|
+
// Pure, so every one of those is a test (tests/no-new-agent-starts-while-memory-is-short).
|
|
27
|
+
|
|
28
|
+
import { execFileSync } from 'node:child_process';
|
|
29
|
+
import { pressureFrom } from './memory-gate.mjs';
|
|
30
|
+
|
|
31
|
+
/** One reading, synchronously, for the moment before a restart brings the
|
|
32
|
+
* fleet back. Nulls (so no hold) when it cannot be read. */
|
|
33
|
+
export function readMacPressureNow() {
|
|
34
|
+
let level = null;
|
|
35
|
+
let freePct = null;
|
|
36
|
+
try {
|
|
37
|
+
const out = execFileSync('/usr/sbin/sysctl', ['-n', 'kern.memorystatus_vm_pressure_level', 'kern.memorystatus_level'],
|
|
38
|
+
{ timeout: 2_000, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
39
|
+
[level, freePct] = out.trim().split(/\s+/).map(Number);
|
|
40
|
+
} catch { /* not a Mac, or sysctl did not answer */ }
|
|
41
|
+
return { level: Number.isFinite(level) ? level : null, freePct: Number.isFinite(freePct) ? freePct : null, at: Date.now() };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** A reading older than this is not acted on. */
|
|
45
|
+
export const STALE_MS = 60_000;
|
|
46
|
+
/** The longest new work waits on memory before one agent starts anyway. */
|
|
47
|
+
export const MAX_HOLD_MS = 10 * 60_000;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Whether one more agent may start now, and why. `reading` is
|
|
51
|
+
* `{ level, freePct, at }` from `readMacPressure`, stamped when it arrived.
|
|
52
|
+
* `heldSince` is when the current hold began (null when nothing is held);
|
|
53
|
+
* `lastStartAt` is when an agent last started.
|
|
54
|
+
*/
|
|
55
|
+
export function startDecision({
|
|
56
|
+
on, reading, now, running,
|
|
57
|
+
urgent = false, asked = false, swap = false,
|
|
58
|
+
lastStartAt = 0, heldSince = null,
|
|
59
|
+
staleMs = STALE_MS, maxHoldMs = MAX_HOLD_MS,
|
|
60
|
+
}) {
|
|
61
|
+
if (!on) return { start: true, why: 'off' };
|
|
62
|
+
if (!(running > 0)) return { start: true, why: 'nothing-running' };
|
|
63
|
+
if (swap) return { start: true, why: 'swap' };
|
|
64
|
+
const at = Number(reading?.at);
|
|
65
|
+
const known = reading && (Number.isFinite(reading.level) || Number.isFinite(reading.freePct));
|
|
66
|
+
if (!known || !Number.isFinite(at) || Math.abs(now - at) > staleMs) return { start: true, why: 'no-reading' };
|
|
67
|
+
const pressure = pressureFrom(reading);
|
|
68
|
+
if (pressure === 'normal') return { start: true, why: 'normal' };
|
|
69
|
+
if (pressure === 'tight' && (urgent || asked)) return { start: true, why: 'urgent' };
|
|
70
|
+
const waitingSince = Math.max(heldSince ?? now, Number(lastStartAt) || 0);
|
|
71
|
+
if (now - waitingSince >= maxHoldMs) return { start: true, why: 'overdue' };
|
|
72
|
+
return { start: false, why: pressure };
|
|
73
|
+
}
|