agentbox-app 0.1.13 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/agent-sessions.mjs +282 -268
- package/main/agents.mjs +179 -466
- package/main/analytics.mjs +12 -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-input.mjs +48 -4
- package/main/claude-plan.mjs +48 -0
- package/main/claude-session-open.mjs +28 -0
- package/main/claude-usage-process.mjs +40 -0
- package/main/claude-usage.mjs +18 -40
- 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-models.mjs +20 -2
- package/main/codex-session.mjs +212 -507
- package/main/codex-threads-worker.mjs +12 -0
- package/main/codex-threads.mjs +71 -3
- package/main/codex-usage-file.mjs +5 -3
- package/main/codex-usage.mjs +56 -7
- package/main/codex-watch.mjs +17 -3
- package/main/codex.mjs +95 -363
- package/main/config.mjs +11 -1
- package/main/corner-tag.mjs +340 -19
- package/main/dev-window.mjs +1 -1
- package/main/engine-bin.mjs +232 -282
- package/main/engine-setup.mjs +21 -9
- package/main/feedback.mjs +3 -25
- 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.mjs +32 -11
- package/main/harnesses/codex.mjs +9 -2
- package/main/importable-threads.mjs +64 -6
- package/main/ipc.mjs +362 -111
- package/main/leftovers.mjs +117 -25
- package/main/liquid-glass.mjs +26 -0
- package/main/live-replies.mjs +10 -4
- package/main/main-went-red.mjs +330 -0
- package/main/main.mjs +199 -84
- package/main/memory-gate-history.mjs +36 -10
- package/main/memory-gate-server.mjs +62 -0
- package/main/memory-gate.mjs +14 -1
- 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 +24 -8
- package/main/phone-alerts.mjs +117 -0
- package/main/phone-inbox.mjs +625 -0
- package/main/phone-link.mjs +29 -9
- 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-client.mjs +69 -1
- package/main/repeats.mjs +10 -4
- package/main/row-label.mjs +12 -41
- package/main/run-change.mjs +13 -0
- package/main/run-ledger.mjs +135 -0
- package/main/save-attachments.mjs +41 -0
- package/main/serve.mjs +45 -3
- package/main/settings.mjs +220 -44
- package/main/shell-path.mjs +185 -37
- package/main/ship-conflict-brief.mjs +119 -0
- package/main/ship-queue.mjs +115 -19
- package/main/source-updater.mjs +18 -10
- package/main/stage-attachment.mjs +68 -0
- package/main/stall-watch.mjs +50 -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 +226 -52
- package/main/supervisor.mjs +3103 -341
- package/main/task-folders.mjs +430 -30
- package/main/task-terminals.mjs +110 -34
- 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/webview-guard.mjs +45 -0
- package/main/worktree-include.mjs +90 -219
- 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 +21 -5
- package/renderer/dist/assets/{abnfDiagram-YUKMZFIV-DPPuMWt-.js → abnfDiagram-YUKMZFIV-CoWB6YUK.js} +1 -1
- package/renderer/dist/assets/{arc-HmFfdseH.js → arc-Ch0NrCul.js} +1 -1
- package/renderer/dist/assets/{architectureDiagram-47P4ROYG-DxJ3zHrH.js → architectureDiagram-47P4ROYG-CXz9M5tQ.js} +1 -1
- package/renderer/dist/assets/{blockDiagram-E7TT5TSB-CbTXzOqQ.js → blockDiagram-E7TT5TSB-DchGUuHH.js} +1 -1
- package/renderer/dist/assets/{c4Diagram-CRA5TL53-X5ItFyLn.js → c4Diagram-CRA5TL53-Cip-zNyr.js} +1 -1
- package/renderer/dist/assets/channel-BQuQSL--.js +1 -0
- package/renderer/dist/assets/{chunk-2Q5K7J3B-DC12Ho_L.js → chunk-2Q5K7J3B-BoXid_2r.js} +1 -1
- package/renderer/dist/assets/{chunk-5VM5RSS4-ClVtfPd0.js → chunk-5VM5RSS4-Cpez1rRz.js} +1 -1
- package/renderer/dist/assets/{chunk-7TKQ45FW-DgcOm0HT.js → chunk-7TKQ45FW-DKA84YkE.js} +1 -1
- package/renderer/dist/assets/{chunk-AW2ZBBNX-C01s4yoF.js → chunk-AW2ZBBNX-Dg-SumPG.js} +1 -1
- package/renderer/dist/assets/{chunk-FVRAUYC3-Bj0zxhR4.js → chunk-FVRAUYC3-06TCvPm1.js} +2 -2
- package/renderer/dist/assets/{chunk-HTAEGDNF-DWDeEhLU.js → chunk-HTAEGDNF-CMEBy1Td.js} +1 -1
- package/renderer/dist/assets/{chunk-JWPE2WC7-Dsqwv3eW.js → chunk-JWPE2WC7-BJ2ObmV-.js} +1 -1
- package/renderer/dist/assets/{chunk-KQW6MTUR-CE86ANL2.js → chunk-KQW6MTUR-CGWOYXUE.js} +1 -1
- package/renderer/dist/assets/{chunk-XXDRQBXY-CoNTASfs.js → chunk-XXDRQBXY-CiZp07XC.js} +1 -1
- package/renderer/dist/assets/{classDiagram-v2-K4WV4PDN-2wprLqtw.js → classDiagram-v2-K4WV4PDN-DJNIX719.js} +1 -1
- 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-enqMiYbn.js → cose-bilkent-JH36ORCC-CbkyZOUH.js} +1 -1
- package/renderer/dist/assets/{cynefin-EF2NZ3EQ-DHngLxvQ.js → cynefin-EF2NZ3EQ-78iOroZO.js} +1 -1
- package/renderer/dist/assets/{cynefinDiagram-3GCD6N5R-C0rZZIl3.js → cynefinDiagram-3GCD6N5R-GcCopMs7.js} +1 -1
- package/renderer/dist/assets/{dagre-W4DXFKR2-DQnaEWO7.js → dagre-W4DXFKR2-DHLlXLkz.js} +1 -1
- package/renderer/dist/assets/{diagram-2UJZ2QOL-CS8AlGPx.js → diagram-2UJZ2QOL-DuZSUHcH.js} +1 -1
- package/renderer/dist/assets/{diagram-OVF4WLC6-yiDMHIkY.js → diagram-OVF4WLC6-Ckxu3cqH.js} +1 -1
- package/renderer/dist/assets/{diagram-PFPMY2P6-XbQKzbBA.js → diagram-PFPMY2P6-CsTw9Ycn.js} +1 -1
- package/renderer/dist/assets/{diagram-UMYRVEAY-dhVvlfl_.js → diagram-UMYRVEAY-CTXd8qVg.js} +1 -1
- package/renderer/dist/assets/{diagram-YEKJPTXX-DZHe8SCf.js → diagram-YEKJPTXX-CJs1T_9m.js} +1 -1
- package/renderer/dist/assets/{diagram-ZIFT7M5P-B5h6aXVR.js → diagram-ZIFT7M5P-CvjI23mf.js} +1 -1
- package/renderer/dist/assets/{ebnfDiagram-VR2GEFS7-PR9ScDco.js → ebnfDiagram-VR2GEFS7-d_IeAzOJ.js} +1 -1
- package/renderer/dist/assets/{elk-IJKZMXRS-Cg-yQXPd.js → elk-IJKZMXRS-zo9KFP3N.js} +1 -1
- package/renderer/dist/assets/{erDiagram-O2IAPWRE-omOrJMxu.js → erDiagram-O2IAPWRE-DqfYf5Dt.js} +1 -1
- package/renderer/dist/assets/{flowDiagram-OXPTDLAJ-aOX2hzvT.js → flowDiagram-OXPTDLAJ-DAWsMLmo.js} +1 -1
- package/renderer/dist/assets/{ganttDiagram-R7TSEDQI-B1H3pWyI.js → ganttDiagram-R7TSEDQI-4ml_bhwR.js} +1 -1
- package/renderer/dist/assets/{gitGraphDiagram-XJZIOB7I-Cvw304HC.js → gitGraphDiagram-XJZIOB7I-B_WcqSId.js} +1 -1
- package/renderer/dist/assets/{infoDiagram-5W2HQ5XZ-_ZXcNViH.js → infoDiagram-5W2HQ5XZ-CI-jYqzc.js} +1 -1
- package/renderer/dist/assets/{ishikawaDiagram-K3B6WC7H-C7Mx_qQk.js → ishikawaDiagram-K3B6WC7H-B56VWRlV.js} +1 -1
- package/renderer/dist/assets/{journeyDiagram-COXZFDF6-fr62QoAt.js → journeyDiagram-COXZFDF6-D1-p09Lr.js} +1 -1
- package/renderer/dist/assets/{kanban-definition-P3RFRI5V-J8zsabCe.js → kanban-definition-P3RFRI5V-Cv3w7JoN.js} +1 -1
- package/renderer/dist/assets/{linear-BmNdEtIi.js → linear-C35V2Spi.js} +1 -1
- package/renderer/dist/assets/main-BcoBiGwv.css +32 -0
- package/renderer/dist/assets/main-CLnIOulD.js +1191 -0
- package/renderer/dist/assets/{mermaid.core-CnYzvFkz.js → mermaid.core-BzGT5Vo9.js} +4 -4
- package/renderer/dist/assets/{mindmap-definition-LZFPQGKD-Bfcxc7PM.js → mindmap-definition-LZFPQGKD-BZUfuymC.js} +1 -1
- package/renderer/dist/assets/{pegDiagram-BGZESJAR-CwUJOq6X.js → pegDiagram-BGZESJAR-DFh9XNGe.js} +1 -1
- package/renderer/dist/assets/{pieDiagram-CAPJLFHJ-BrwMmqfC.js → pieDiagram-CAPJLFHJ-C65tPVsy.js} +1 -1
- package/renderer/dist/assets/{product-name-CTKLYNWY.js → product-name-CSNW6d7s.js} +1 -1
- package/renderer/dist/assets/{quadrantDiagram-GDMTTRAM-BN4Stoj-.js → quadrantDiagram-GDMTTRAM-Cushj_nk.js} +1 -1
- package/renderer/dist/assets/{railroadDiagram-SM67HX2B-CPZ5bbeR.js → railroadDiagram-SM67HX2B-DZGebGx5.js} +1 -1
- package/renderer/dist/assets/{requirementDiagram-X7JNWC4A-CgRnimVe.js → requirementDiagram-X7JNWC4A-DpAB0MNo.js} +1 -1
- package/renderer/dist/assets/{sankeyDiagram-UM26HJRW-Bt2rej__.js → sankeyDiagram-UM26HJRW-D-29rHra.js} +1 -1
- package/renderer/dist/assets/{sequenceDiagram-ZO4K6R2Y-Dd5nKe9G.js → sequenceDiagram-ZO4K6R2Y-FfOQAZol.js} +1 -1
- package/renderer/dist/assets/{sizeCapture-INFHLROL-usyNyXyh.js → sizeCapture-INFHLROL-C_n6fDBY.js} +1 -1
- package/renderer/dist/assets/{stateDiagram-v2-TBUQTH76-CRzUBb0u.js → stateDiagram-v2-TBUQTH76-BZjenzJG.js} +1 -1
- package/renderer/dist/assets/{swimlanes-N4OXWK64-C1GJvMS0.js → swimlanes-N4OXWK64-DxaMU9vX.js} +1 -1
- package/renderer/dist/assets/swimlanesDiagram-K3J5GTZL-Cb2kM6rr.js +8 -0
- package/renderer/dist/assets/{timeline-definition-YOQAKGHF-caeyPlcc.js → timeline-definition-YOQAKGHF-DTg5HJKz.js} +1 -1
- package/renderer/dist/assets/{usecaseDiagram-VIAY4XPW-BN_SV6PC.js → usecaseDiagram-VIAY4XPW-Bc3MZDsl.js} +1 -1
- package/renderer/dist/assets/{vennDiagram-BLWOH2XV-BLGuaUX-.js → vennDiagram-BLWOH2XV-GIVGk9Id.js} +1 -1
- package/renderer/dist/assets/{wardleyDiagram-YMQ3BMBF-Da0cJeNc.js → wardleyDiagram-YMQ3BMBF-NmJnbQOg.js} +1 -1
- package/renderer/dist/assets/{xychartDiagram-TAQBALBS-cGfUffMk.js → xychartDiagram-TAQBALBS-p-kfGfnW.js} +1 -1
- package/renderer/dist/corner-tag.html +3 -3
- package/renderer/dist/index.html +3 -3
- package/scripts/after-install.mjs +30 -8
- 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 +60 -34
- 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 +27 -1
- package/shared/claude-code-shape.mjs +6 -0
- 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 +23 -1
- package/shared/corner-tag.mjs +284 -29
- package/shared/dead-run-trace.mjs +19 -2
- package/shared/engines.mjs +70 -309
- 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 +8 -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 +6 -0
- package/shared/notify-rules.mjs +36 -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/rank.d.mts +2 -1
- package/shared/rank.mjs +32 -19
- 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 -3
- package/shared/runs-on.mjs +8 -5
- package/shared/shipped-note.d.mts +4 -0
- package/shared/shipped-note.mjs +6 -0
- package/shared/shortcuts.mjs +14 -6
- package/shared/spawn-trouble.d.mts +4 -0
- package/shared/spawn-trouble.mjs +443 -40
- 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/thread-cards.mjs +4 -1
- package/shared/usage.d.mts +9 -0
- package/shared/usage.mjs +49 -3
- package/shared/websites.d.mts +15 -0
- package/shared/websites.mjs +61 -0
- package/shared/work-items.mjs +127 -30
- package/shared/work-lines.mjs +92 -244
- package/renderer/dist/assets/channel-BlT2g9Sz.js +0 -1
- package/renderer/dist/assets/cornerTag-BLrxiDE5.css +0 -1
- package/renderer/dist/assets/cornerTag-BOT6u3Tn.js +0 -1
- package/renderer/dist/assets/main-ChNdnUvt.js +0 -1132
- package/renderer/dist/assets/main-nj0QR5kg.css +0 -32
- package/renderer/dist/assets/swimlanesDiagram-K3J5GTZL-Cy4Av2_p.js +0 -8
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// WHAT THE CLOUD RUNS USED, KEPT ON THE MAC (tests/a-cloud-run-records-what-it-really-used).
|
|
2
|
+
//
|
|
3
|
+
// One line per run in ~/.agentbox/cloud-usage.jsonl, beside cloud.json: when,
|
|
4
|
+
// which row, which engine, and what the sandbox measured (cloud/sandbox/usage.mjs).
|
|
5
|
+
// The plan limits are set from these lines, so nothing here is estimated
|
|
6
|
+
// except the cost, and that says so in its name.
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import os from 'node:os';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
|
|
11
|
+
// AgentCore Runtime's published rates (us-east-1, 2026-10), per vCPU-hour of
|
|
12
|
+
// CPU actually used and per GB-hour of memory. Runtime v1, which this account
|
|
13
|
+
// runs; v2 is $0.1276 and $0.0169.
|
|
14
|
+
export const AGENTCORE_RATES = { vcpuHour: 0.0895, gbHour: 0.00945 };
|
|
15
|
+
|
|
16
|
+
export function cloudUsagePath({ home = os.homedir() } = {}) {
|
|
17
|
+
return path.join(home || os.homedir(), '.agentbox', 'cloud-usage.jsonl');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function appendCloudUsage({ runId, item, engine, exitCode, usage }, { home, now = Date.now } = {}) {
|
|
21
|
+
const file = cloudUsagePath({ home });
|
|
22
|
+
const line = {
|
|
23
|
+
at: new Date(now()).toISOString(),
|
|
24
|
+
runId: runId ?? null,
|
|
25
|
+
item: item ?? null,
|
|
26
|
+
engine: engine ?? null,
|
|
27
|
+
exitCode: Number.isInteger(exitCode) ? exitCode : null,
|
|
28
|
+
wallSeconds: usage?.wallSeconds ?? null,
|
|
29
|
+
cpuSeconds: usage?.cpuSeconds ?? null,
|
|
30
|
+
peakMemoryBytes: usage?.peakMemoryBytes ?? null,
|
|
31
|
+
source: usage?.source ?? null,
|
|
32
|
+
};
|
|
33
|
+
// Once per run: a homecoming retried after a failed import reads the same
|
|
34
|
+
// done.json again.
|
|
35
|
+
if (line.runId && readCloudUsage({ home }).some((l) => l.runId === line.runId)) return null;
|
|
36
|
+
try {
|
|
37
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
38
|
+
fs.appendFileSync(file, JSON.stringify(line) + '\n');
|
|
39
|
+
} catch { /* a record that cannot be written never fails the run */ }
|
|
40
|
+
return line;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function readCloudUsage({ home, file = cloudUsagePath({ home }) } = {}) {
|
|
44
|
+
let text;
|
|
45
|
+
try { text = fs.readFileSync(file, 'utf8'); } catch { return []; }
|
|
46
|
+
const out = [];
|
|
47
|
+
for (const l of text.split('\n')) {
|
|
48
|
+
if (!l.trim()) continue;
|
|
49
|
+
try { out.push(JSON.parse(l)); } catch { /* one broken line loses only itself */ }
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Agent-hours since `since`, and the cost of the runs that measured
|
|
55
|
+
// themselves. Memory is billed on its high-water mark for the whole run, the
|
|
56
|
+
// way Runtime v1 bills it.
|
|
57
|
+
export function summarizeCloudUsage(lines, { since = 0 } = {}) {
|
|
58
|
+
let runs = 0; let seconds = 0; let measured = 0; let cost = 0;
|
|
59
|
+
for (const l of lines) {
|
|
60
|
+
if (Date.parse(l.at) < since) continue;
|
|
61
|
+
runs += 1;
|
|
62
|
+
seconds += l.wallSeconds || 0;
|
|
63
|
+
if (l.wallSeconds && l.cpuSeconds != null && l.peakMemoryBytes != null) {
|
|
64
|
+
measured += l.wallSeconds;
|
|
65
|
+
cost += (l.cpuSeconds / 3600) * AGENTCORE_RATES.vcpuHour
|
|
66
|
+
+ (l.peakMemoryBytes / 1024 ** 3) * (l.wallSeconds / 3600) * AGENTCORE_RATES.gbHour;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
runs,
|
|
71
|
+
agentHours: Math.round((seconds / 3600) * 100) / 100,
|
|
72
|
+
measuredHours: Math.round((measured / 3600) * 100) / 100,
|
|
73
|
+
estimatedCost: cost,
|
|
74
|
+
costPerAgentHour: measured ? cost / (measured / 3600) : null,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// THE CLOUD'S OWN PERMISSION MODE, put on a cloud run's arguments. Its own file
|
|
2
|
+
// because the Claude harness and the settings both need it, and the settings
|
|
3
|
+
// already import the harnesses.
|
|
4
|
+
import { CLAUDE_PERMISSION_MODES } from '../shared/work-items.mjs';
|
|
5
|
+
import { isCodexMode } from '../shared/codex-modes.mjs';
|
|
6
|
+
|
|
7
|
+
const SKIP_FLAGS = ['--dangerously-skip-permissions'];
|
|
8
|
+
|
|
9
|
+
// Unset, a cloud run does not ask: the sandbox is thrown away after the run,
|
|
10
|
+
// holds no key that can push, and nobody is there to answer a card.
|
|
11
|
+
export const CLOUD_SAME = 'same';
|
|
12
|
+
export const CLOUD_CLAUDE_DEFAULT = 'bypassPermissions';
|
|
13
|
+
export const CLOUD_CODEX_DEFAULT = 'full-access';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The Claude Code mode a cloud run starts in, or null to keep the flag the run
|
|
17
|
+
* already has: this computer's, or the mode set on the thread itself, which
|
|
18
|
+
* the cloud must not loosen.
|
|
19
|
+
*/
|
|
20
|
+
export function cloudClaudeMode(setting, threadMode = null) {
|
|
21
|
+
if (CLAUDE_PERMISSION_MODES.includes(threadMode) || setting === CLOUD_SAME) return null;
|
|
22
|
+
return CLAUDE_PERMISSION_MODES.includes(setting) ? setting : CLOUD_CLAUDE_DEFAULT;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** The Codex mode a cloud run starts in, by the same rule. */
|
|
26
|
+
export function cloudCodexMode(setting, threadMode, here) {
|
|
27
|
+
if (isCodexMode(threadMode)) return threadMode;
|
|
28
|
+
if (setting === CLOUD_SAME) return here;
|
|
29
|
+
return isCodexMode(setting) ? setting : CLOUD_CODEX_DEFAULT;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Only the permission flag changes, in place, so nothing else moves. Null
|
|
34
|
+
* leaves the run on this computer's mode. With no flag to replace it goes
|
|
35
|
+
* first, where a list flag such as --allowedTools cannot take it as a value.
|
|
36
|
+
*/
|
|
37
|
+
export function cloudPermissionArgs(args, mode) {
|
|
38
|
+
if (mode == null) return args;
|
|
39
|
+
if (!CLAUDE_PERMISSION_MODES.includes(mode)) throw new Error(`unknown permission mode: ${mode}`);
|
|
40
|
+
const out = [];
|
|
41
|
+
let at = -1;
|
|
42
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
43
|
+
const arg = String(args[i]);
|
|
44
|
+
const flag = arg === '--permission-mode' || arg.startsWith('--permission-mode=') || SKIP_FLAGS.includes(arg);
|
|
45
|
+
if (!flag) { out.push(args[i]); continue; }
|
|
46
|
+
if (at < 0) at = out.length;
|
|
47
|
+
if (arg === '--permission-mode') i += 1;
|
|
48
|
+
}
|
|
49
|
+
out.splice(at < 0 ? 0 : at, 0, '--permission-mode', mode);
|
|
50
|
+
return out;
|
|
51
|
+
}
|
package/main/codex-account.mjs
CHANGED
|
@@ -113,6 +113,71 @@ export function codexAccount(home = null, { file = null } = {}) {
|
|
|
113
113
|
return { email, name, plan, planNamed: planIsNamed(chatgpt?.chatgpt_plan_type), mode, accountId };
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
/**
|
|
117
|
+
* WHEN THIS LOGIN'S PAID CHATGPT PLAN ENDED, in ms, or null.
|
|
118
|
+
*
|
|
119
|
+
* A lapsed plan reads `chatgpt_plan_type: "free"` and keeps the old
|
|
120
|
+
* subscription's `chatgpt_subscription_active_until`. Only that pair is read as
|
|
121
|
+
* an ending: a paid type with a past date is a token minted before a renewal,
|
|
122
|
+
* and a free login that never paid has no date.
|
|
123
|
+
*/
|
|
124
|
+
export function codexPlanEnded(home = null, { file = null, now = Date.now() } = {}) {
|
|
125
|
+
let auth = null;
|
|
126
|
+
try { auth = JSON.parse(fs.readFileSync(file ?? codexAuthFile(home), 'utf8')); } catch { return null; }
|
|
127
|
+
const chatgpt = claims(auth?.tokens?.id_token)?.[AUTH_CLAIM];
|
|
128
|
+
if (String(chatgpt?.chatgpt_plan_type ?? '').trim().toLowerCase() !== 'free') return null;
|
|
129
|
+
const until = Date.parse(chatgpt?.chatgpt_subscription_active_until ?? '');
|
|
130
|
+
return Number.isFinite(until) && until <= now ? until : null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* WHETHER THE FREE PLAN IS WHY CODEX OFFERS FEW MODELS: `{ endedAt }` when every
|
|
135
|
+
* one of these logins reads Free, with the latest paid plan's end or null, and
|
|
136
|
+
* null when any login is paid or cannot say.
|
|
137
|
+
*/
|
|
138
|
+
export function codexFreePlan(homes, { now = Date.now() } = {}) {
|
|
139
|
+
if (!homes.length || !homes.every((h) => codexAccount(h)?.plan === PLANS.free)) return null;
|
|
140
|
+
const ended = homes.map((h) => codexPlanEnded(h, { now })).filter((t) => t != null);
|
|
141
|
+
return { endedAt: ended.length ? Math.max(...ended) : null };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* WHAT KIND OF LOGIN A CODEX HOME HOLDS: 'chatgpt' (a plan), 'apikey' (a key,
|
|
146
|
+
* metered per call), or null when it cannot say.
|
|
147
|
+
*
|
|
148
|
+
* Codex's own reading: `auth_mode` when the file has one, and an older file
|
|
149
|
+
* with no mode is a key when it carries a key and no tokens. A ChatGPT login
|
|
150
|
+
* with a key left beside its tokens is still a ChatGPT login; the mode decides.
|
|
151
|
+
*/
|
|
152
|
+
export function codexLoginMode(home = null, { file = null } = {}) {
|
|
153
|
+
let auth = null;
|
|
154
|
+
try { auth = JSON.parse(fs.readFileSync(file ?? codexAuthFile(home), 'utf8')); } catch { return null; }
|
|
155
|
+
if (!auth || typeof auth !== 'object') return null;
|
|
156
|
+
const mode = typeof auth.auth_mode === 'string' ? auth.auth_mode.trim().toLowerCase().replace(/[^a-z]/g, '') : '';
|
|
157
|
+
if (mode) return mode === 'apikey' ? 'apikey' : mode.startsWith('chatgpt') ? 'chatgpt' : mode;
|
|
158
|
+
if (auth.tokens && typeof auth.tokens === 'object') return 'chatgpt';
|
|
159
|
+
return typeof auth.OPENAI_API_KEY === 'string' && auth.OPENAI_API_KEY ? 'apikey' : null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* WHY A WORKER MAY NOT RUN ON THIS CODEX LOGIN, OR NULL WHEN IT MAY.
|
|
164
|
+
*
|
|
165
|
+
* Workers run on a subscription and never on a key, and the worker scrub
|
|
166
|
+
* keeps OPENAI_API_KEY out of their environment for it. But `codex login
|
|
167
|
+
* --with-api-key` keeps the key in auth.json, which Codex reads for itself,
|
|
168
|
+
* past the scrub: measured 2026-10-15 with codex-cli 0.160.0 on a home laid
|
|
169
|
+
* out that way (the verify skill's `codex-api-key-login` setup), every request
|
|
170
|
+
* a worker sent was signed with the key, and the task was answered as though
|
|
171
|
+
* nothing were wrong. There is no plan in such a home to fall back on, so the
|
|
172
|
+
* run is refused, in words shared/spawn-trouble.mjs files as 'api-key'. The
|
|
173
|
+
* key is never in the sentence.
|
|
174
|
+
*/
|
|
175
|
+
export function codexKeyRefusal(home = null, opts = {}) {
|
|
176
|
+
return codexLoginMode(home, opts) === 'apikey'
|
|
177
|
+
? 'Codex is signed in with an API key, which bills every call to that key. Workers only run on a ChatGPT plan: run codex login in a terminal to sign in with ChatGPT.'
|
|
178
|
+
: null;
|
|
179
|
+
}
|
|
180
|
+
|
|
116
181
|
/**
|
|
117
182
|
* A FOLDER FOR THE NEXT CODEX LOGIN, MADE BEFORE ANYTHING IS ASKED TO USE IT.
|
|
118
183
|
*
|
|
@@ -137,6 +202,19 @@ export function makeCodexHome({ home = os.homedir(), mkdir = fs.mkdirSync, exist
|
|
|
137
202
|
throw new Error('There are already a lot of Codex folders in your home directory.');
|
|
138
203
|
}
|
|
139
204
|
|
|
205
|
+
/**
|
|
206
|
+
* codex-cli refuses a `CODEX_HOME` that does not exist rather than making it,
|
|
207
|
+
* and exits 1 before anything else happens; an empty folder that exists is
|
|
208
|
+
* fine. Every spawn here names `CODEX_HOME`, so each one goes through this
|
|
209
|
+
* first (tests/codex-never-starts-on-a-home-that-is-not-there).
|
|
210
|
+
*
|
|
211
|
+
* @returns the home it was given, so it can be used inline at a spawn.
|
|
212
|
+
*/
|
|
213
|
+
export function ensureCodexHome(home, { mkdir = fs.mkdirSync } = {}) {
|
|
214
|
+
if (home) { try { mkdir(home, { recursive: true }); } catch { /* codex's own message about the folder is the better one */ } }
|
|
215
|
+
return home;
|
|
216
|
+
}
|
|
217
|
+
|
|
140
218
|
/**
|
|
141
219
|
* The one line that signs a new account in, for the terminal to run. The home
|
|
142
220
|
* is spelled out rather than left to the shell, because `~` inside a variable
|