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,136 @@
|
|
|
1
|
+
// AGENT HOURS: the level, the week, the streak (w-3d0fa23ffb).
|
|
2
|
+
//
|
|
3
|
+
// Pure. A run is `{key, at, start, item, product, engine, seconds, failed,
|
|
4
|
+
// began}`: `at` is when it ended, and a run is counted on the local day it
|
|
5
|
+
// ended. Every run whose agent actually began counts its wall time, failed or
|
|
6
|
+
// not, and overlapping runs each count.
|
|
7
|
+
|
|
8
|
+
export const MASTERY_HOURS = 10_000;
|
|
9
|
+
const MAX_RUN_SECONDS = 24 * 3600;
|
|
10
|
+
const DAY_MS = 86_400_000;
|
|
11
|
+
|
|
12
|
+
// Up to 99, hours grow as level^2.5: level 2 in minutes, 99 at MASTERY_HOURS.
|
|
13
|
+
// Not RuneScape's curve, which spends half its hours on the last seven levels
|
|
14
|
+
// and so reads 82 after one heavy month. Past 99 there is no ceiling and each
|
|
15
|
+
// level costs 5% more than the last, starting from the curve's pace at 99 so
|
|
16
|
+
// no level ever costs less than the one before.
|
|
17
|
+
const RISE = 2.5;
|
|
18
|
+
const PAST = Math.log(1.05);
|
|
19
|
+
const PACE_AT_99 = (MASTERY_HOURS * RISE) / 98;
|
|
20
|
+
// A level starts at its exact hours, not one float step later.
|
|
21
|
+
const EPS = 1e-10;
|
|
22
|
+
|
|
23
|
+
export function hoursForLevel(level) {
|
|
24
|
+
const L = Number(level);
|
|
25
|
+
if (!(L > 1)) return 0;
|
|
26
|
+
if (L <= 99) return MASTERY_HOURS * ((L - 1) / 98) ** RISE;
|
|
27
|
+
return MASTERY_HOURS + (PACE_AT_99 * Math.expm1((L - 99) * PAST)) / PAST;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function levelFor(hours) {
|
|
31
|
+
const h = Number(hours);
|
|
32
|
+
if (!Number.isFinite(h) || h <= 0) return 1;
|
|
33
|
+
if (h < MASTERY_HOURS) return 1 + Math.floor(98 * (h / MASTERY_HOURS) ** (1 / RISE) + EPS);
|
|
34
|
+
return 99 + Math.floor(Math.log1p(((h - MASTERY_HOURS) * PAST) / PACE_AT_99) / PAST + EPS);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
38
|
+
export const localDate = (ms) => { const d = new Date(ms); return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`; };
|
|
39
|
+
const localMonth = (ms) => localDate(ms).slice(0, 7);
|
|
40
|
+
|
|
41
|
+
function mondayOf(ms) {
|
|
42
|
+
const d = new Date(ms);
|
|
43
|
+
d.setHours(0, 0, 0, 0);
|
|
44
|
+
d.setDate(d.getDate() - ((d.getDay() + 6) % 7));
|
|
45
|
+
return d.getTime();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function startOfDay(ms) {
|
|
49
|
+
const d = new Date(ms);
|
|
50
|
+
d.setHours(0, 0, 0, 0);
|
|
51
|
+
return d.getTime();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const counts = (r) => r && r.began !== false && Number.isFinite(r.at) && Number(r.seconds) > 0;
|
|
55
|
+
|
|
56
|
+
// One line per key. The line written when the run ended beats one read back
|
|
57
|
+
// from its log, which may have been read while the run was still going.
|
|
58
|
+
export function dedupeRuns(runs) {
|
|
59
|
+
const seen = new Map();
|
|
60
|
+
for (const r of runs ?? []) {
|
|
61
|
+
if (!r || typeof r !== 'object' || typeof r.key !== 'string' || !r.key) continue;
|
|
62
|
+
if (!Number.isFinite(r.at) || !(Number(r.seconds) > 0)) continue;
|
|
63
|
+
const had = seen.get(r.key);
|
|
64
|
+
if (!had || (had.backfilled && !r.backfilled)) seen.set(r.key, r);
|
|
65
|
+
}
|
|
66
|
+
return [...seen.values()];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Days in a row with a run, counted back from today, or from yesterday when
|
|
70
|
+
// today has none yet. `dates` are local YYYY-MM-DD strings, from any number of
|
|
71
|
+
// Macs.
|
|
72
|
+
export function streakOf(dates, now = Date.now()) {
|
|
73
|
+
const have = new Set(dates);
|
|
74
|
+
let cursor = startOfDay(now);
|
|
75
|
+
if (!have.has(localDate(cursor))) cursor -= DAY_MS / 2;
|
|
76
|
+
let n = 0;
|
|
77
|
+
while (have.has(localDate(cursor))) {
|
|
78
|
+
n += 1;
|
|
79
|
+
// Half a day back and then to the start of that day survives a DST change.
|
|
80
|
+
cursor = startOfDay(startOfDay(cursor) - DAY_MS / 2);
|
|
81
|
+
}
|
|
82
|
+
return n;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function summarizeRuns(runs, { now = Date.now() } = {}) {
|
|
86
|
+
const weekStartMs = mondayOf(now);
|
|
87
|
+
const dayStartMs = startOfDay(now);
|
|
88
|
+
let total = 0;
|
|
89
|
+
let week = 0;
|
|
90
|
+
let today = 0;
|
|
91
|
+
const active = new Set();
|
|
92
|
+
const months = new Map();
|
|
93
|
+
const first = new Date(now);
|
|
94
|
+
first.setDate(1);
|
|
95
|
+
for (let i = 11; i >= 0; i -= 1) {
|
|
96
|
+
const d = new Date(first.getFullYear(), first.getMonth() - i, 1);
|
|
97
|
+
months.set(`${d.getFullYear()}-${pad(d.getMonth() + 1)}`, 0);
|
|
98
|
+
}
|
|
99
|
+
for (const r of dedupeRuns(runs)) {
|
|
100
|
+
if (!counts(r) || r.at > now) continue;
|
|
101
|
+
const h = Math.min(Number(r.seconds), MAX_RUN_SECONDS) / 3600;
|
|
102
|
+
total += h;
|
|
103
|
+
if (r.at >= weekStartMs) week += h;
|
|
104
|
+
if (r.at >= dayStartMs) today += h;
|
|
105
|
+
active.add(localDate(r.at));
|
|
106
|
+
const m = localMonth(r.at);
|
|
107
|
+
if (months.has(m)) months.set(m, months.get(m) + h);
|
|
108
|
+
}
|
|
109
|
+
const activeDays = [...active].sort().slice(-60);
|
|
110
|
+
return {
|
|
111
|
+
total,
|
|
112
|
+
week,
|
|
113
|
+
weekStart: localDate(weekStartMs),
|
|
114
|
+
today,
|
|
115
|
+
day: localDate(dayStartMs),
|
|
116
|
+
streak: streakOf(activeDays, now),
|
|
117
|
+
activeDays,
|
|
118
|
+
byMonth: [...months].map(([month, hours]) => ({ month, hours })),
|
|
119
|
+
level: levelFor(total),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// One run read back from its trace log, `sessions/<item>/<startedAtMs>.log`:
|
|
124
|
+
// the start is the file's name, the end the `# exited (code) <ISO>` footer,
|
|
125
|
+
// else the file's last write.
|
|
126
|
+
export function runFromTrace({ name, text = '', mtimeMs, item, product }) {
|
|
127
|
+
const m = /^(\d{12,14})\.log$/.exec(String(name ?? ''));
|
|
128
|
+
if (!m) return null;
|
|
129
|
+
const start = Number(m[1]);
|
|
130
|
+
const footer = /# exited \((-?\d+|null)\) (\S+)(?: · [^\n]*)?\s*$/m.exec(String(text));
|
|
131
|
+
const end = footer ? Date.parse(footer[2]) : Number(mtimeMs);
|
|
132
|
+
if (!Number.isFinite(end) || end <= start) return null;
|
|
133
|
+
const seconds = Math.round((end - start) / 1000);
|
|
134
|
+
if (seconds > MAX_RUN_SECONDS) return null;
|
|
135
|
+
return { key: `${item}:${start}`, at: end, start, item, product, engine: null, seconds, failed: footer ? footer[1] !== '0' : null };
|
|
136
|
+
}
|
package/shared/agent-import.mjs
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
/**
|
|
19
19
|
* The label every one of these rows carries, so a second walk through the
|
|
20
20
|
* first run can tell which agents already have a row and file nothing twice. */
|
|
21
|
-
import { NAME
|
|
21
|
+
import { NAME } from '../shared/product-name.mjs';
|
|
22
22
|
export const IMPORT_LABEL = 'agent-import';
|
|
23
23
|
|
|
24
24
|
/**
|
|
@@ -107,11 +107,11 @@ export function agentsNeedingRows(chosen, existingItems = []) {
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
/* --------------------------- AND THE THREADS ----------------------------- */
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
//
|
|
110
|
+
// A picked thread becomes a row that carries the conversation on. It first
|
|
111
|
+
// did not: the body said the reply started fresh, and somebody importing a
|
|
112
|
+
// hundred half-finished sessions was asked to restate every one of them
|
|
113
|
+
// (GitHub #44). The row is still only a row here; the resume happens on the
|
|
114
|
+
// first reply, in `Supervisor#importedThreadFor`.
|
|
115
115
|
//
|
|
116
116
|
// Everything else is the agent import's shape, for the same reasons: one row per
|
|
117
117
|
// thing the user ticked, a label so a second press files nothing twice, and a
|
|
@@ -125,6 +125,53 @@ export const THREAD_LABEL = 'thread-import';
|
|
|
125
125
|
* which is stable across renames and is what the transcript is filed under. */
|
|
126
126
|
export const threadLabel = (id) => `thread:${String(id ?? '').trim()}`;
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* WHETHER A CHAT ENDED WAITING ON YOU, read off the agent's last reply.
|
|
130
|
+
*
|
|
131
|
+
* Waiting means the reply's last line is a question, or a question followed by
|
|
132
|
+
* the choices it offers. `ask` is that question, cut from the front when it is
|
|
133
|
+
* long, because the question is at the end of the line. */
|
|
134
|
+
const ASK_CHARS = 140;
|
|
135
|
+
const SHORT_ASK = 40;
|
|
136
|
+
const CHOICE = /^(\d+[.)]|[-*+]|[a-z][.)])\s+/i;
|
|
137
|
+
const NOT_WAITING = Object.freeze({ waiting: false, ask: '' });
|
|
138
|
+
|
|
139
|
+
function plainLine(line) {
|
|
140
|
+
return String(line)
|
|
141
|
+
.replace(/^(>\s*)+/, '')
|
|
142
|
+
.replace(/^#{1,6}\s+/, '')
|
|
143
|
+
.replace(/[*`]+/g, '')
|
|
144
|
+
// An underscore between two letters is part of a name (account_id).
|
|
145
|
+
.replace(/(?<![A-Za-z0-9])_+|_+(?![A-Za-z0-9])/g, '')
|
|
146
|
+
.replace(/^[("'“‘\s]+/, '')
|
|
147
|
+
.replace(/[)"'”’\s]+$/, '')
|
|
148
|
+
.trim();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function shortAsk(line) {
|
|
152
|
+
if (line.length <= ASK_CHARS) return line;
|
|
153
|
+
const sentences = line.split(/(?<=[.!?])\s+/);
|
|
154
|
+
let last = sentences.pop();
|
|
155
|
+
// "Shall I do that?" says nothing without the sentence it follows.
|
|
156
|
+
while (last.length < SHORT_ASK && sentences.length && sentences.at(-1).length + 1 + last.length <= ASK_CHARS) {
|
|
157
|
+
last = `${sentences.pop()} ${last}`;
|
|
158
|
+
}
|
|
159
|
+
if (last.length <= ASK_CHARS) return last;
|
|
160
|
+
const tail = line.slice(-(ASK_CHARS - 1));
|
|
161
|
+
const sp = tail.indexOf(' ');
|
|
162
|
+
return `…${sp > 0 && sp < 40 ? tail.slice(sp + 1) : tail}`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function howTheChatEnded(said) {
|
|
166
|
+
const lines = String(said ?? '').replace(/\r/g, '').split('\n').map((l) => l.trim()).filter(Boolean);
|
|
167
|
+
let i = lines.length - 1;
|
|
168
|
+
while (i >= 0 && CHOICE.test(lines[i])) i -= 1;
|
|
169
|
+
if (i < 0) return { ...NOT_WAITING };
|
|
170
|
+
const line = plainLine(lines[i].replace(CHOICE, ''));
|
|
171
|
+
if (!line.endsWith('?')) return { ...NOT_WAITING };
|
|
172
|
+
return { waiting: true, ask: shortAsk(line) };
|
|
173
|
+
}
|
|
174
|
+
|
|
128
175
|
/**
|
|
129
176
|
* WHEN SHE HAD IT, in the words a person uses about this week.
|
|
130
177
|
*
|
|
@@ -154,37 +201,16 @@ export function startedIn(source) {
|
|
|
154
201
|
}
|
|
155
202
|
|
|
156
203
|
/**
|
|
157
|
-
* ONE IMPORTED THREAD'S WORDS
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
|
|
162
|
-
* a list that has to be read past to find which is which.
|
|
163
|
-
*
|
|
164
|
-
* The last paragraph is the honest one. Agentbox read the top of the transcript
|
|
165
|
-
* to find this name and nothing else, and the reply starts a fresh session. A
|
|
166
|
-
* row that let her believe otherwise would be the same empty promise the agent
|
|
167
|
-
* import had before 08-23, in a new place. */
|
|
168
|
-
export function threadImportRow(thread, { projectName = null, now = Date.now() } = {}) {
|
|
204
|
+
* ONE IMPORTED THREAD'S WORDS, the chat as it was: the title Claude Code gave
|
|
205
|
+
* it, your first message as the body and the agent's last reply as the
|
|
206
|
+
* result, so the thread opens on the question it ended with. The reply
|
|
207
|
+
* carries the conversation on (`Supervisor#importedThreadFor`). */
|
|
208
|
+
export function threadImportRow(thread) {
|
|
169
209
|
const title = String(thread?.title || '').trim();
|
|
170
|
-
const where = String(thread?.short || thread?.folder || '').trim();
|
|
171
|
-
const when = whenWords(thread?.when, now);
|
|
172
|
-
const started = [
|
|
173
|
-
'You started this',
|
|
174
|
-
startedIn(thread?.source),
|
|
175
|
-
when,
|
|
176
|
-
where ? `in ${where}` : '',
|
|
177
|
-
].filter(Boolean).join(' ');
|
|
178
|
-
const inProject = projectName ? ` here in ${projectName}` : '';
|
|
179
|
-
const body = [
|
|
180
|
-
'**Say what you want done next in this thread.**',
|
|
181
|
-
`${started}.`,
|
|
182
|
-
`Reply with the job and ${NAME} runs it${inProject}, answering you here.`,
|
|
183
|
-
`${Name} has not read the conversation, only the line above that names it, and replying starts a fresh session rather than carrying the old one on. So say what you need in the reply.`,
|
|
184
|
-
].join('\n\n');
|
|
185
210
|
return {
|
|
186
211
|
title,
|
|
187
|
-
body,
|
|
212
|
+
body: String(thread?.firstSaid || '').trim() || title,
|
|
213
|
+
result: String(thread?.lastSaid || '').trim(),
|
|
188
214
|
kind: 'question',
|
|
189
215
|
priority: 3,
|
|
190
216
|
labels: [THREAD_LABEL, threadLabel(thread?.id)],
|