@rryando/arcs 3.11.0 → 4.1.0
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 +1 -1
- package/dist/cli/commands/hooks.d.ts +46 -6
- package/dist/cli/commands/hooks.d.ts.map +1 -1
- package/dist/cli/commands/hooks.js +190 -52
- package/dist/cli/commands/hooks.js.map +1 -1
- package/dist/cli/commands/web.js +14 -4
- package/dist/cli/commands/web.js.map +1 -1
- package/dist/cli/config.d.ts +14 -3
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +39 -38
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/instructions.d.ts +13 -1
- package/dist/cli/instructions.d.ts.map +1 -1
- package/dist/cli/instructions.js +38 -3
- package/dist/cli/instructions.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +76 -11
- package/dist/cli/setup.js.map +1 -1
- package/dist/shared/session-vocabulary.d.ts +88 -0
- package/dist/shared/session-vocabulary.d.ts.map +1 -0
- package/dist/shared/session-vocabulary.js +114 -0
- package/dist/shared/session-vocabulary.js.map +1 -0
- package/dist/utils/claude-code-hook-install.d.ts +1 -1
- package/dist/utils/claude-code-hook-install.d.ts.map +1 -1
- package/dist/utils/claude-code-hook-install.js +71 -5
- package/dist/utils/claude-code-hook-install.js.map +1 -1
- package/dist/utils/claude-transcript.d.ts +81 -2
- package/dist/utils/claude-transcript.d.ts.map +1 -1
- package/dist/utils/claude-transcript.js +33 -2
- package/dist/utils/claude-transcript.js.map +1 -1
- package/dist/utils/git.d.ts +21 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +65 -1
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/hook-contract.d.ts +36 -0
- package/dist/utils/hook-contract.d.ts.map +1 -0
- package/dist/utils/hook-contract.js +35 -0
- package/dist/utils/hook-contract.js.map +1 -0
- package/dist/utils/hook-token-store.d.ts +44 -3
- package/dist/utils/hook-token-store.d.ts.map +1 -1
- package/dist/utils/hook-token-store.js +51 -6
- package/dist/utils/hook-token-store.js.map +1 -1
- package/dist/utils/session-store.d.ts +207 -29
- package/dist/utils/session-store.d.ts.map +1 -1
- package/dist/utils/session-store.js +236 -44
- package/dist/utils/session-store.js.map +1 -1
- package/dist/utils/storage-utils.d.ts +1 -1
- package/dist/utils/storage-utils.d.ts.map +1 -1
- package/dist/utils/storage-utils.js +1 -1
- package/dist/utils/storage-utils.js.map +1 -1
- package/dist/web-client/assets/{GraphCanvas-dNyZ458L.js → GraphCanvas-BPDgvsyT.js} +1 -1
- package/dist/web-client/assets/{MarkdownEditor-BmU9mdkN.js → MarkdownEditor-D7TLp78z.js} +1 -1
- package/dist/web-client/assets/{abnfDiagram-VRR7QNED-D1BFBoeF.js → abnfDiagram-VRR7QNED-CyuP2N9t.js} +1 -1
- package/dist/web-client/assets/architecture-TIHT7OUA-Bdo2Yvm9.js +1 -0
- package/dist/web-client/assets/{architectureDiagram-ZJ3FMSHR-CA8hTWUK.js → architectureDiagram-ZJ3FMSHR-DZ0ul9QX.js} +1 -1
- package/dist/web-client/assets/{blockDiagram-677ZJIJ3-CQpb_KwX.js → blockDiagram-677ZJIJ3-LLGzlc9l.js} +1 -1
- package/dist/web-client/assets/{c4Diagram-LMCZKHZV-BhpHX84V.js → c4Diagram-LMCZKHZV-CViu3CTc.js} +1 -1
- package/dist/web-client/assets/channel-DBNmizpo.js +1 -0
- package/dist/web-client/assets/{chunk-32BRIVSS-BUusQQa_.js → chunk-32BRIVSS-Bw_IuJCM.js} +1 -1
- package/dist/web-client/assets/{chunk-52WLFC77-nNYwlftl.js → chunk-52WLFC77-C29h440W.js} +1 -1
- package/dist/web-client/assets/{chunk-C7G6YPKG-D0a-yqnK.js → chunk-C7G6YPKG-hhOrvw5w.js} +1 -1
- package/dist/web-client/assets/{chunk-EX3LRPZG-IDuRMN-4.js → chunk-EX3LRPZG-COMzol-M.js} +1 -1
- package/dist/web-client/assets/{chunk-FWX5IMBZ-D_spTcqi.js → chunk-FWX5IMBZ-6vdX9EUn.js} +2 -2
- package/dist/web-client/assets/{chunk-HOUHSVGY-C-bcxwZS.js → chunk-HOUHSVGY-DWDW6sxp.js} +1 -1
- package/dist/web-client/assets/{chunk-ICXQ74PX-CjmK2bAM.js → chunk-ICXQ74PX-BdMYglo2.js} +1 -1
- package/dist/web-client/assets/{chunk-MOJQB5TN-Bkc08KWY.js → chunk-MOJQB5TN-C0LAX_dC.js} +1 -1
- package/dist/web-client/assets/{chunk-OGEWGWER-BAAYYvG9.js → chunk-OGEWGWER-CBx8MB7f.js} +1 -1
- package/dist/web-client/assets/{chunk-PUDLZKDR-WXbPY7NM.js → chunk-PUDLZKDR-DKssR1nf.js} +1 -1
- package/dist/web-client/assets/{chunk-Q4XR5HBZ-DcbnjxQE.js → chunk-Q4XR5HBZ-B3kcxFE-.js} +1 -1
- package/dist/web-client/assets/{chunk-V7JOEXUC-C6t75PAp.js → chunk-V7JOEXUC-CAlymndy.js} +1 -1
- package/dist/web-client/assets/{chunk-VAUOI2AC-DVrJ0Ic7.js → chunk-VAUOI2AC-BowfsmTW.js} +1 -1
- package/dist/web-client/assets/{chunk-VR4S4FIN-MOOFvGS0.js → chunk-VR4S4FIN-BBOydgvt.js} +1 -1
- package/dist/web-client/assets/{chunk-WYO6CB5R-sK7Y2NZD.js → chunk-WYO6CB5R-DcymFbES.js} +1 -1
- package/dist/web-client/assets/{chunk-ZGVPDNZ5-a13RQsku.js → chunk-ZGVPDNZ5--uKFP-Lr.js} +1 -1
- package/dist/web-client/assets/classDiagram-OUVF2IWQ-CB3HiA1_.js +1 -0
- package/dist/web-client/assets/classDiagram-v2-EOCWNBFH-CB3HiA1_.js +1 -0
- package/dist/web-client/assets/{cynefin-VYW2F7L2-D8xaH-wO.js → cynefin-VYW2F7L2-CjboUOMA.js} +1 -1
- package/dist/web-client/assets/{cynefinDiagram-TSTJHNR4-Bt__EqJW.js → cynefinDiagram-TSTJHNR4-BcxygBP7.js} +1 -1
- package/dist/web-client/assets/{dagre-VKFMJZFB-Bwgjwflz.js → dagre-VKFMJZFB-D-tiERQE.js} +1 -1
- package/dist/web-client/assets/{diagram-FQU43EPY-CaPDVUq2.js → diagram-FQU43EPY-ChPXczaS.js} +1 -1
- package/dist/web-client/assets/{diagram-G47NLZAW-BQLB9YYA.js → diagram-G47NLZAW-CVL3Y91h.js} +1 -1
- package/dist/web-client/assets/{diagram-NH7WQ7WH-BWo84w8Y.js → diagram-NH7WQ7WH-DsaNA9Lh.js} +1 -1
- package/dist/web-client/assets/{diagram-OA4YK3LP-bKn6Pz5s.js → diagram-OA4YK3LP-CXhrhdhU.js} +1 -1
- package/dist/web-client/assets/{diagram-WEI45ONY-BRqV5Oy6.js → diagram-WEI45ONY-BTVPnk4E.js} +1 -1
- package/dist/web-client/assets/{ebnfDiagram-CCIWWBDH-DhUXL1-7.js → ebnfDiagram-CCIWWBDH-BAyrRBtM.js} +1 -1
- package/dist/web-client/assets/{erDiagram-Q63AITRT-HXAQQ-_F.js → erDiagram-Q63AITRT-Qm24Wepm.js} +1 -1
- package/dist/web-client/assets/eventmodeling-45OFAUF4-DoTBIvl5.js +1 -0
- package/dist/web-client/assets/flowDiagram-23GEKE2U-BEH23L1A.js +1 -0
- package/dist/web-client/assets/{ganttDiagram-NO4QXBWP-D-Ddf_Ii.js → ganttDiagram-NO4QXBWP-D8h7l3XJ.js} +1 -1
- package/dist/web-client/assets/{gitGraph-TEB2WS4Q-BmHzs0uF.js → gitGraph-TEB2WS4Q-DIBml1SB.js} +1 -1
- package/dist/web-client/assets/{gitGraphDiagram-IHSO6WYX-YnQWrlh_.js → gitGraphDiagram-IHSO6WYX-CtkYoXjn.js} +1 -1
- package/dist/web-client/assets/{index-DCWxuIeQ.js → index-DOSH4Q9H.js} +38 -36
- package/dist/web-client/assets/index-wSzUPvml.css +2 -0
- package/dist/web-client/assets/{info-DKCQHKI2-DCT_B7RN.js → info-DKCQHKI2-DLEUtV5Q.js} +1 -1
- package/dist/web-client/assets/{infoDiagram-FWYZ7A6U-D-le1Zhq.js → infoDiagram-FWYZ7A6U-BJQ7aQux.js} +1 -1
- package/dist/web-client/assets/{ishikawaDiagram-FXEZZL3T-Jr1x2VJB.js → ishikawaDiagram-FXEZZL3T-BPM11FvG.js} +1 -1
- package/dist/web-client/assets/{journeyDiagram-5HDEW3XC-BF9ELxj-.js → journeyDiagram-5HDEW3XC-C0aX2z3c.js} +1 -1
- package/dist/web-client/assets/{kanban-definition-HUTT4EX6-C4fJqAxu.js → kanban-definition-HUTT4EX6-C56F29Ib.js} +1 -1
- package/dist/web-client/assets/{line-7N7ikFxa.js → line-BLFHLF2N.js} +1 -1
- package/dist/web-client/assets/{mermaid-parser.core-QbC1icPt.js → mermaid-parser.core-BLC8FhgU.js} +3 -3
- package/dist/web-client/assets/{mermaid.core-C26d_UJm.js → mermaid.core-BBqkKuXt.js} +3 -3
- package/dist/web-client/assets/{mindmap-definition-LN4V7U3C-D6TV1JDf.js → mindmap-definition-LN4V7U3C-aVZbsoPc.js} +1 -1
- package/dist/web-client/assets/{packet-7NZHBO7P-CR1vrGj3.js → packet-7NZHBO7P-D4aqSQfB.js} +1 -1
- package/dist/web-client/assets/{pegDiagram-2B236MQR-xOMBBtfV.js → pegDiagram-2B236MQR-DjfyNI0U.js} +1 -1
- package/dist/web-client/assets/{pie-RZYD4A2V-BbWuhjwy.js → pie-RZYD4A2V-ChCwYsYj.js} +1 -1
- package/dist/web-client/assets/{pieDiagram-ENE6RG2P-MsfnsqgW.js → pieDiagram-ENE6RG2P-BeHLKkXC.js} +1 -1
- package/dist/web-client/assets/{quadrantDiagram-ABIIQ3AL-BoI7zKXF.js → quadrantDiagram-ABIIQ3AL-stga3gvq.js} +1 -1
- package/dist/web-client/assets/{radar-I7S5WNFK-CbYXKToJ.js → radar-I7S5WNFK-DOGheiwT.js} +1 -1
- package/dist/web-client/assets/{railroad-3IZDKUUU-6LxHDkLe.js → railroad-3IZDKUUU-_JnU7M6L.js} +1 -1
- package/dist/web-client/assets/railroad-abnf-AHOZXSZD-nhNub7LE.js +1 -0
- package/dist/web-client/assets/railroad-ebnf-EBAXGLYW-BlQYe7Yf.js +1 -0
- package/dist/web-client/assets/railroad-peg-LSFZ7HO6-B3E8pRVN.js +1 -0
- package/dist/web-client/assets/{railroadDiagram-RFXS5EU6-D6RUoUki.js → railroadDiagram-RFXS5EU6-C0CkMsOd.js} +1 -1
- package/dist/web-client/assets/{requirementDiagram-TGXJPOKE-B6k4BDpE.js → requirementDiagram-TGXJPOKE-DuImwoRD.js} +1 -1
- package/dist/web-client/assets/{sankeyDiagram-HTMAVEWB-BUDF-UFr.js → sankeyDiagram-HTMAVEWB-kprq0XF9.js} +1 -1
- package/dist/web-client/assets/{sequenceDiagram-DBY2YBRQ-D6GqcsUi.js → sequenceDiagram-DBY2YBRQ-DiXKJMF6.js} +1 -1
- package/dist/web-client/assets/{stateDiagram-2N3HPSRC-WfJCQAK5.js → stateDiagram-2N3HPSRC-D5qbVStE.js} +1 -1
- package/dist/web-client/assets/stateDiagram-v2-6OUMAXLB-DWwTAG1r.js +1 -0
- package/dist/web-client/assets/{swimlanes-5IMT3BWC-BtMo82mC.js → swimlanes-5IMT3BWC-DCbw389c.js} +1 -1
- package/dist/web-client/assets/swimlanesDiagram-G3AALYLV-DabrCsjZ.js +8 -0
- package/dist/web-client/assets/{timeline-definition-FHXFAJF6-CoAmv2Sn.js → timeline-definition-FHXFAJF6-CQeaYN_9.js} +1 -1
- package/dist/web-client/assets/{treeView-QDETBFTQ-BWsKzE1s.js → treeView-QDETBFTQ-Cf7Sq3qo.js} +1 -1
- package/dist/web-client/assets/{treemap-6X3UGDF4-i_qGtB3o.js → treemap-6X3UGDF4-BovzvoTU.js} +1 -1
- package/dist/web-client/assets/{vennDiagram-L72KCM5P-DYkiLe-P.js → vennDiagram-L72KCM5P-CZsJy139.js} +1 -1
- package/dist/web-client/assets/{wardley-OPB4EBWU-Daaqr1Vp.js → wardley-OPB4EBWU-DJ7MS6XZ.js} +1 -1
- package/dist/web-client/assets/{wardleyDiagram-EHGQE667-Bofbsg3J.js → wardleyDiagram-EHGQE667-rqhcmsbM.js} +1 -1
- package/dist/web-client/assets/{xychartDiagram-FW5EYKEG-KNF4VTfL.js → xychartDiagram-FW5EYKEG-HuK4Seps.js} +1 -1
- package/dist/web-client/index.html +2 -2
- package/dist/web-server/app.d.ts +4 -1
- package/dist/web-server/app.d.ts.map +1 -1
- package/dist/web-server/app.js +19 -3
- package/dist/web-server/app.js.map +1 -1
- package/dist/web-server/claude-runner.d.ts +109 -7
- package/dist/web-server/claude-runner.d.ts.map +1 -1
- package/dist/web-server/claude-runner.js +329 -50
- package/dist/web-server/claude-runner.js.map +1 -1
- package/dist/web-server/index.d.ts +2 -2
- package/dist/web-server/index.d.ts.map +1 -1
- package/dist/web-server/index.js +3 -2
- package/dist/web-server/index.js.map +1 -1
- package/dist/web-server/permission-policy.d.ts +46 -0
- package/dist/web-server/permission-policy.d.ts.map +1 -0
- package/dist/web-server/permission-policy.js +96 -0
- package/dist/web-server/permission-policy.js.map +1 -0
- package/dist/web-server/prompt-assembly.d.ts +454 -0
- package/dist/web-server/prompt-assembly.d.ts.map +1 -0
- package/dist/web-server/prompt-assembly.js +1122 -0
- package/dist/web-server/prompt-assembly.js.map +1 -0
- package/dist/web-server/routes/hook-events.d.ts +28 -4
- package/dist/web-server/routes/hook-events.d.ts.map +1 -1
- package/dist/web-server/routes/hook-events.js +218 -37
- package/dist/web-server/routes/hook-events.js.map +1 -1
- package/dist/web-server/routes/sessions.d.ts +8 -8
- package/dist/web-server/routes/sessions.d.ts.map +1 -1
- package/dist/web-server/routes/sessions.js +1007 -261
- package/dist/web-server/routes/sessions.js.map +1 -1
- package/dist/web-server/routes/workspace.d.ts +27 -0
- package/dist/web-server/routes/workspace.d.ts.map +1 -0
- package/dist/web-server/routes/workspace.js +280 -0
- package/dist/web-server/routes/workspace.js.map +1 -0
- package/dist/web-server/run-event-log.d.ts +167 -0
- package/dist/web-server/run-event-log.d.ts.map +1 -0
- package/dist/web-server/run-event-log.js +468 -0
- package/dist/web-server/run-event-log.js.map +1 -0
- package/dist/web-server/session-reconciler.d.ts +162 -0
- package/dist/web-server/session-reconciler.d.ts.map +1 -0
- package/dist/web-server/session-reconciler.js +363 -0
- package/dist/web-server/session-reconciler.js.map +1 -0
- package/dist/web-server/static.d.ts +7 -0
- package/dist/web-server/static.d.ts.map +1 -1
- package/dist/web-server/static.js +46 -3
- package/dist/web-server/static.js.map +1 -1
- package/dist/web-server/web-auth.d.ts +17 -0
- package/dist/web-server/web-auth.d.ts.map +1 -0
- package/dist/web-server/web-auth.js +33 -0
- package/dist/web-server/web-auth.js.map +1 -0
- package/dist/web-server/web-token.d.ts +39 -0
- package/dist/web-server/web-token.d.ts.map +1 -0
- package/dist/web-server/web-token.js +71 -0
- package/dist/web-server/web-token.js.map +1 -0
- package/opencode/arcs/manifest.json +8 -8
- package/package.json +1 -1
- package/scripts/claude-code-session-hook.mjs +37 -16
- package/scripts/deploy-claudecode-bundle.mjs +24 -3
- package/dist/web-client/assets/architecture-TIHT7OUA-CJqI5wNI.js +0 -1
- package/dist/web-client/assets/channel-C8DlmyVe.js +0 -1
- package/dist/web-client/assets/classDiagram-OUVF2IWQ-p32N1P_G.js +0 -1
- package/dist/web-client/assets/classDiagram-v2-EOCWNBFH-p32N1P_G.js +0 -1
- package/dist/web-client/assets/eventmodeling-45OFAUF4-Bj5P8mZJ.js +0 -1
- package/dist/web-client/assets/flowDiagram-23GEKE2U-37BztFri.js +0 -1
- package/dist/web-client/assets/index-3mNPVkix.css +0 -2
- package/dist/web-client/assets/railroad-abnf-AHOZXSZD-2Dg9wu0J.js +0 -1
- package/dist/web-client/assets/railroad-ebnf-EBAXGLYW-C_E2ot0R.js +0 -1
- package/dist/web-client/assets/railroad-peg-LSFZ7HO6-Bs9UQR1b.js +0 -1
- package/dist/web-client/assets/stateDiagram-v2-6OUMAXLB-BCMWGnsJ.js +0 -1
- package/dist/web-client/assets/swimlanesDiagram-G3AALYLV-DmudmLcK.js +0 -8
- package/dist/web-server/opencode-client.d.ts +0 -123
- package/dist/web-server/opencode-client.d.ts.map +0 -1
- package/dist/web-server/opencode-client.js +0 -514
- package/dist/web-server/opencode-client.js.map +0 -1
package/dist/utils/git.js
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
|
-
import { execSync } from "node:child_process";
|
|
1
|
+
import { execFile, execSync } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
const execFileAsync = promisify(execFile);
|
|
4
|
+
/**
|
|
5
|
+
* Ceiling on one async git invocation. A `git` that never returns — a
|
|
6
|
+
* network-backed worktree, an index.lock held by another process — must fail
|
|
7
|
+
* closed to "no revision" rather than pin a request open forever. Generous
|
|
8
|
+
* enough that a cold `rev-parse` on a large repo still answers.
|
|
9
|
+
*
|
|
10
|
+
* Exported for the tests that assert the deadline is actually honoured.
|
|
11
|
+
*/
|
|
12
|
+
export const GIT_ASYNC_TIMEOUT_MS = 2000;
|
|
13
|
+
/** Slack the raced deadline allows the child's own kill path before giving up
|
|
14
|
+
* on it, so a child that DOES die on signal reports its real failure. */
|
|
15
|
+
const GIT_DEADLINE_GRACE_MS = 100;
|
|
2
16
|
function exec(cmd, cwd) {
|
|
3
17
|
try {
|
|
4
18
|
return execSync(cmd, {
|
|
@@ -11,12 +25,62 @@ function exec(cmd, cwd) {
|
|
|
11
25
|
return null;
|
|
12
26
|
}
|
|
13
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Async: run `git` with an argv array, never a shell, and never a sync spawn.
|
|
30
|
+
* Same contract as `exec` above — trimmed stdout, or `null` for any failure —
|
|
31
|
+
* so an async caller reads the same values a sync one would.
|
|
32
|
+
*
|
|
33
|
+
* The deadline is RACED, not delegated to `timeout`. Node's `timeout` option
|
|
34
|
+
* guarantees a kill ATTEMPT, not a settlement: it signals the child and then
|
|
35
|
+
* waits for `close`, so a child that cannot act on the signal never fires the
|
|
36
|
+
* callback and the promise stays pending forever — a request that hangs holding
|
|
37
|
+
* its connection even though the timeout fired. The realistic instance is
|
|
38
|
+
* D-state I/O on a stalled NFS/FUSE mount, which is exactly the wedged-worktree
|
|
39
|
+
* case this budget exists for; `killSignal: "SIGKILL"` narrows the window (it
|
|
40
|
+
* beats a child that merely ignores SIGTERM) but does not close it, since
|
|
41
|
+
* SIGKILL does not touch uninterruptible sleep either. Racing our own timer is
|
|
42
|
+
* what actually bounds the caller, and `unref` keeps a pending timer from
|
|
43
|
+
* holding the process open on the way out.
|
|
44
|
+
*
|
|
45
|
+
* What this does NOT do is reap the child: nothing can until the I/O returns.
|
|
46
|
+
* A caller that retries against a stalled mount still accumulates live children
|
|
47
|
+
* — bound that separately if it ever matters here.
|
|
48
|
+
*/
|
|
49
|
+
function execAsync(args, cwd) {
|
|
50
|
+
const ran = execFileAsync("git", args, {
|
|
51
|
+
encoding: "utf-8",
|
|
52
|
+
cwd,
|
|
53
|
+
timeout: GIT_ASYNC_TIMEOUT_MS,
|
|
54
|
+
killSignal: "SIGKILL",
|
|
55
|
+
windowsHide: true,
|
|
56
|
+
})
|
|
57
|
+
.then(({ stdout }) => stdout.trim())
|
|
58
|
+
.catch(() => null);
|
|
59
|
+
const expired = new Promise((resolve) => {
|
|
60
|
+
setTimeout(() => resolve(null), GIT_ASYNC_TIMEOUT_MS + GIT_DEADLINE_GRACE_MS).unref();
|
|
61
|
+
});
|
|
62
|
+
return Promise.race([ran, expired]);
|
|
63
|
+
}
|
|
14
64
|
export function isGitRepo(cwd) {
|
|
15
65
|
return exec("git rev-parse --is-inside-work-tree", cwd) === "true";
|
|
16
66
|
}
|
|
17
67
|
export function getHeadCommit(cwd) {
|
|
18
68
|
return exec("git rev-parse --short HEAD", cwd);
|
|
19
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Async twin of `getHeadCommit`, for callers on a request path.
|
|
72
|
+
*
|
|
73
|
+
* The sync export stays as it is — its callers are CLI, where blocking costs
|
|
74
|
+
* nothing. A server is the opposite case: `execSync` holds the whole event
|
|
75
|
+
* loop for the child's entire lifetime, so one file view stalls every other
|
|
76
|
+
* in-flight request and every open SSE stream. Use this one from a handler.
|
|
77
|
+
*
|
|
78
|
+
* Settles within `GIT_ASYNC_TIMEOUT_MS` plus a small grace no matter what the
|
|
79
|
+
* child does — see `execAsync` for why that needs a race rather than a timeout.
|
|
80
|
+
*/
|
|
81
|
+
export async function getHeadCommitAsync(cwd) {
|
|
82
|
+
return execAsync(["rev-parse", "--short", "HEAD"], cwd);
|
|
83
|
+
}
|
|
20
84
|
export function getGitLog(cwd, options) {
|
|
21
85
|
const limit = options?.limit ?? 50;
|
|
22
86
|
const since = options?.since;
|
package/dist/utils/git.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wire contract shared by everything on the Claude Code session bridge:
|
|
3
|
+
* the event names the hook is registered under, and the address it posts to.
|
|
4
|
+
*
|
|
5
|
+
* These values are duplicated across process boundaries by necessity — the
|
|
6
|
+
* server validates them, the installer writes them into settings.json, and
|
|
7
|
+
* `scripts/claude-code-session-hook.mjs` runs standalone under Claude Code with
|
|
8
|
+
* no ARCS import available. Every duplicate that CAN import derives from here;
|
|
9
|
+
* the one that cannot (the `.mjs`, which must stay dependency-free so a broken
|
|
10
|
+
* bridge is inert rather than fatal) keeps its own literals and is pinned to
|
|
11
|
+
* this module by `test/hook-contract-parity.test.ts`, which fails on any
|
|
12
|
+
* divergence in either direction.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* The four Claude Code events the bridge registers for. One script is installed
|
|
16
|
+
* under all of them; it dispatches internally on `hook_event_name`.
|
|
17
|
+
*
|
|
18
|
+
* A readonly tuple so `z.enum()` consumes it directly — the route's validation
|
|
19
|
+
* and the installer's registration can never drift apart. Adding a fifth event
|
|
20
|
+
* here without adding it to the hook script breaks the parity test.
|
|
21
|
+
*/
|
|
22
|
+
export declare const HOOK_EVENTS: readonly ["SessionStart", "UserPromptSubmit", "SessionEnd", "Stop"];
|
|
23
|
+
export type HookEventName = (typeof HOOK_EVENTS)[number];
|
|
24
|
+
/** Loopback only: `arcs web` refuses to bind anything else. */
|
|
25
|
+
export declare const DEFAULT_WEB_HOST = "127.0.0.1";
|
|
26
|
+
/** Default `arcs web` port, and therefore the port every hook is installed with. */
|
|
27
|
+
export declare const DEFAULT_WEB_PORT = 4173;
|
|
28
|
+
/**
|
|
29
|
+
* Where an installed hook posts when `--url` was not given.
|
|
30
|
+
*
|
|
31
|
+
* Baked into the settings.json command string at install time, so changing it
|
|
32
|
+
* only affects hooks installed afterwards — an already-installed hook keeps
|
|
33
|
+
* posting to the URL it was written with.
|
|
34
|
+
*/
|
|
35
|
+
export declare const DEFAULT_SERVER_URL = "http://127.0.0.1:4173";
|
|
36
|
+
//# sourceMappingURL=hook-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-contract.d.ts","sourceRoot":"","sources":["../../src/utils/hook-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,qEAAsE,CAAC;AAE/F,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,+DAA+D;AAC/D,eAAO,MAAM,gBAAgB,cAAc,CAAC;AAE5C,oFAAoF;AACpF,eAAO,MAAM,gBAAgB,OAAO,CAAC;AAErC;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,0BAAmD,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wire contract shared by everything on the Claude Code session bridge:
|
|
3
|
+
* the event names the hook is registered under, and the address it posts to.
|
|
4
|
+
*
|
|
5
|
+
* These values are duplicated across process boundaries by necessity — the
|
|
6
|
+
* server validates them, the installer writes them into settings.json, and
|
|
7
|
+
* `scripts/claude-code-session-hook.mjs` runs standalone under Claude Code with
|
|
8
|
+
* no ARCS import available. Every duplicate that CAN import derives from here;
|
|
9
|
+
* the one that cannot (the `.mjs`, which must stay dependency-free so a broken
|
|
10
|
+
* bridge is inert rather than fatal) keeps its own literals and is pinned to
|
|
11
|
+
* this module by `test/hook-contract-parity.test.ts`, which fails on any
|
|
12
|
+
* divergence in either direction.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* The four Claude Code events the bridge registers for. One script is installed
|
|
16
|
+
* under all of them; it dispatches internally on `hook_event_name`.
|
|
17
|
+
*
|
|
18
|
+
* A readonly tuple so `z.enum()` consumes it directly — the route's validation
|
|
19
|
+
* and the installer's registration can never drift apart. Adding a fifth event
|
|
20
|
+
* here without adding it to the hook script breaks the parity test.
|
|
21
|
+
*/
|
|
22
|
+
export const HOOK_EVENTS = ["SessionStart", "UserPromptSubmit", "SessionEnd", "Stop"];
|
|
23
|
+
/** Loopback only: `arcs web` refuses to bind anything else. */
|
|
24
|
+
export const DEFAULT_WEB_HOST = "127.0.0.1";
|
|
25
|
+
/** Default `arcs web` port, and therefore the port every hook is installed with. */
|
|
26
|
+
export const DEFAULT_WEB_PORT = 4173;
|
|
27
|
+
/**
|
|
28
|
+
* Where an installed hook posts when `--url` was not given.
|
|
29
|
+
*
|
|
30
|
+
* Baked into the settings.json command string at install time, so changing it
|
|
31
|
+
* only affects hooks installed afterwards — an already-installed hook keeps
|
|
32
|
+
* posting to the URL it was written with.
|
|
33
|
+
*/
|
|
34
|
+
export const DEFAULT_SERVER_URL = `http://${DEFAULT_WEB_HOST}:${DEFAULT_WEB_PORT}`;
|
|
35
|
+
//# sourceMappingURL=hook-contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-contract.js","sourceRoot":"","sources":["../../src/utils/hook-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,cAAc,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,CAAU,CAAC;AAI/F,+DAA+D;AAC/D,MAAM,CAAC,MAAM,gBAAgB,GAAG,WAAW,CAAC;AAE5C,oFAAoF;AACpF,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAErC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,UAAU,gBAAgB,IAAI,gBAAgB,EAAE,CAAC"}
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
* Per-project auth token for the Claude Code session-bridge hook endpoint.
|
|
3
3
|
*
|
|
4
4
|
* Loopback-only is not enough on its own: every process on the machine shares
|
|
5
|
-
* localhost, so any local program could otherwise register sessions
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* localhost, so any local program could otherwise register sessions, write
|
|
6
|
+
* checkpoints, and hit the SessionStart path — whose answer is injected into a
|
|
7
|
+
* live agent session as `additionalContext`. The token proves the caller is
|
|
8
|
+
* the hook script that `arcs hooks install-claude-code` provisioned for this
|
|
9
|
+
* project.
|
|
8
10
|
*
|
|
9
11
|
* Intentionally not a CRUD store — one token per project, rotated by rerunning
|
|
10
12
|
* the install command. No index, no markdown mirror, no lock (a rotation races
|
|
@@ -12,6 +14,45 @@
|
|
|
12
14
|
*/
|
|
13
15
|
export declare function hookTokenPath(projectDir: string): string;
|
|
14
16
|
export declare function readHookToken(projectDir: string): Promise<string | undefined>;
|
|
17
|
+
/**
|
|
18
|
+
* Rotates the on-disk token, owner-only.
|
|
19
|
+
*
|
|
20
|
+
* Unlike the web token there is no in-memory copy to verify against — the hook
|
|
21
|
+
* subprocess re-reads this file at every checkpoint, so the FILE is the
|
|
22
|
+
* credential and its mode is the whole control. `writeJson` stages a temp file
|
|
23
|
+
* and renames it into place with no mode argument, so the token lands 0644
|
|
24
|
+
* (world-readable) on a default umask — and it lands that way on EVERY write,
|
|
25
|
+
* not just the first: the rename swaps in the freshly created temp inode, whose
|
|
26
|
+
* mode came from the umask, and the previous file's mode is discarded with the
|
|
27
|
+
* inode it belonged to. (A mode passed at open() would in fact have covered this
|
|
28
|
+
* writer, precisely because every write creates the destination inode; the
|
|
29
|
+
* "applies only at create" caveat bites a direct non-atomic open(path,"w",mode)
|
|
30
|
+
* over an existing file, which is not this path.) The chmod is nonetheless
|
|
31
|
+
* unconditional rather than conditional on the mode read back, so the 0600
|
|
32
|
+
* guarantee survives a future switch away from the atomic writer.
|
|
33
|
+
*
|
|
34
|
+
* The directory is narrowed too: the staged temp file is a fresh inode born
|
|
35
|
+
* under the umask, so it is briefly world-readable between write and rename.
|
|
36
|
+
* 0o700 on the enclosing directory — which holds nothing but this token —
|
|
37
|
+
* denies another account the traversal needed to reach that window at all.
|
|
38
|
+
*
|
|
39
|
+
* What this buys, stated honestly: 0o600 is a cross-user control. It keeps
|
|
40
|
+
* other UNIX accounts out; it is NOT a defense against a process running as
|
|
41
|
+
* THIS user, which can read the file at any mode. Nor is this the token's only
|
|
42
|
+
* copy — `arcs hooks install-claude-code --write` embeds the same value in the
|
|
43
|
+
* workspace's .claude/settings.local.json, which is now created 0o600 and
|
|
44
|
+
* chmodded 0o600 unconditionally too (claude-code-hook-install.ts), though that
|
|
45
|
+
* copy is inlined into the hook command string and so still leaks to `ps` on
|
|
46
|
+
* every hook fire. So this is a floor on ARCS's own copy, not a guarantee about
|
|
47
|
+
* the secret.
|
|
48
|
+
*
|
|
49
|
+
* A chmod failure propagates and fails the install command. That is
|
|
50
|
+
* deliberate — the caller (`arcs hooks install-claude-code`) has not printed
|
|
51
|
+
* the snippet yet, so the run fails closed and the user reruns to rotate,
|
|
52
|
+
* rather than silently installing a token this process could not protect. The
|
|
53
|
+
* hook's own read path (readHookToken/verifyHookToken) is untouched by this and
|
|
54
|
+
* still never throws.
|
|
55
|
+
*/
|
|
15
56
|
export declare function writeHookToken(projectDir: string, token: string): Promise<void>;
|
|
16
57
|
/**
|
|
17
58
|
* Constant-time token comparison. Returns false when the project has no token
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-token-store.d.ts","sourceRoot":"","sources":["../../src/utils/hook-token-store.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"hook-token-store.d.ts","sourceRoot":"","sources":["../../src/utils/hook-token-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAaH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAGnF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrF;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ7F"}
|
|
@@ -2,16 +2,19 @@
|
|
|
2
2
|
* Per-project auth token for the Claude Code session-bridge hook endpoint.
|
|
3
3
|
*
|
|
4
4
|
* Loopback-only is not enough on its own: every process on the machine shares
|
|
5
|
-
* localhost, so any local program could otherwise register sessions
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* localhost, so any local program could otherwise register sessions, write
|
|
6
|
+
* checkpoints, and hit the SessionStart path — whose answer is injected into a
|
|
7
|
+
* live agent session as `additionalContext`. The token proves the caller is
|
|
8
|
+
* the hook script that `arcs hooks install-claude-code` provisioned for this
|
|
9
|
+
* project.
|
|
8
10
|
*
|
|
9
11
|
* Intentionally not a CRUD store — one token per project, rotated by rerunning
|
|
10
12
|
* the install command. No index, no markdown mirror, no lock (a rotation races
|
|
11
13
|
* only with itself, and the loser simply has to rerun install).
|
|
12
14
|
*/
|
|
13
15
|
import { timingSafeEqual } from "node:crypto";
|
|
14
|
-
import {
|
|
16
|
+
import { chmod } from "node:fs/promises";
|
|
17
|
+
import { dirname, join } from "node:path";
|
|
15
18
|
import { readJsonSafe } from "./json.js";
|
|
16
19
|
import { ensureDir, nowISO, writeJson } from "./storage-utils.js";
|
|
17
20
|
export function hookTokenPath(projectDir) {
|
|
@@ -21,9 +24,51 @@ export async function readHookToken(projectDir) {
|
|
|
21
24
|
const file = await readJsonSafe(hookTokenPath(projectDir));
|
|
22
25
|
return typeof file?.token === "string" && file.token ? file.token : undefined;
|
|
23
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Rotates the on-disk token, owner-only.
|
|
29
|
+
*
|
|
30
|
+
* Unlike the web token there is no in-memory copy to verify against — the hook
|
|
31
|
+
* subprocess re-reads this file at every checkpoint, so the FILE is the
|
|
32
|
+
* credential and its mode is the whole control. `writeJson` stages a temp file
|
|
33
|
+
* and renames it into place with no mode argument, so the token lands 0644
|
|
34
|
+
* (world-readable) on a default umask — and it lands that way on EVERY write,
|
|
35
|
+
* not just the first: the rename swaps in the freshly created temp inode, whose
|
|
36
|
+
* mode came from the umask, and the previous file's mode is discarded with the
|
|
37
|
+
* inode it belonged to. (A mode passed at open() would in fact have covered this
|
|
38
|
+
* writer, precisely because every write creates the destination inode; the
|
|
39
|
+
* "applies only at create" caveat bites a direct non-atomic open(path,"w",mode)
|
|
40
|
+
* over an existing file, which is not this path.) The chmod is nonetheless
|
|
41
|
+
* unconditional rather than conditional on the mode read back, so the 0600
|
|
42
|
+
* guarantee survives a future switch away from the atomic writer.
|
|
43
|
+
*
|
|
44
|
+
* The directory is narrowed too: the staged temp file is a fresh inode born
|
|
45
|
+
* under the umask, so it is briefly world-readable between write and rename.
|
|
46
|
+
* 0o700 on the enclosing directory — which holds nothing but this token —
|
|
47
|
+
* denies another account the traversal needed to reach that window at all.
|
|
48
|
+
*
|
|
49
|
+
* What this buys, stated honestly: 0o600 is a cross-user control. It keeps
|
|
50
|
+
* other UNIX accounts out; it is NOT a defense against a process running as
|
|
51
|
+
* THIS user, which can read the file at any mode. Nor is this the token's only
|
|
52
|
+
* copy — `arcs hooks install-claude-code --write` embeds the same value in the
|
|
53
|
+
* workspace's .claude/settings.local.json, which is now created 0o600 and
|
|
54
|
+
* chmodded 0o600 unconditionally too (claude-code-hook-install.ts), though that
|
|
55
|
+
* copy is inlined into the hook command string and so still leaks to `ps` on
|
|
56
|
+
* every hook fire. So this is a floor on ARCS's own copy, not a guarantee about
|
|
57
|
+
* the secret.
|
|
58
|
+
*
|
|
59
|
+
* A chmod failure propagates and fails the install command. That is
|
|
60
|
+
* deliberate — the caller (`arcs hooks install-claude-code`) has not printed
|
|
61
|
+
* the snippet yet, so the run fails closed and the user reruns to rotate,
|
|
62
|
+
* rather than silently installing a token this process could not protect. The
|
|
63
|
+
* hook's own read path (readHookToken/verifyHookToken) is untouched by this and
|
|
64
|
+
* still never throws.
|
|
65
|
+
*/
|
|
24
66
|
export async function writeHookToken(projectDir, token) {
|
|
25
|
-
|
|
26
|
-
await
|
|
67
|
+
const path = hookTokenPath(projectDir);
|
|
68
|
+
await ensureDir(dirname(path));
|
|
69
|
+
await chmod(dirname(path), 0o700);
|
|
70
|
+
await writeJson(path, { token, createdAt: nowISO() });
|
|
71
|
+
await chmod(path, 0o600);
|
|
27
72
|
}
|
|
28
73
|
/**
|
|
29
74
|
* Constant-time token comparison. Returns false when the project has no token
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-token-store.js","sourceRoot":"","sources":["../../src/utils/hook-token-store.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"hook-token-store.js","sourceRoot":"","sources":["../../src/utils/hook-token-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAOlE,MAAM,UAAU,aAAa,CAAC,UAAkB;IAC9C,OAAO,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,wBAAwB,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAkB;IACpD,MAAM,IAAI,GAAG,MAAM,YAAY,CAAgB,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC;IAC1E,OAAO,OAAO,IAAI,EAAE,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAChF,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,UAAkB,EAAE,KAAa;IACpE,MAAM,IAAI,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IACvC,MAAM,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/B,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;IAClC,MAAM,SAAS,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;IACtD,MAAM,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,UAAkB,EAAE,SAAiB;IACzE,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,UAAU,CAAC,CAAC;IAC9C,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS;QAAE,OAAO,KAAK,CAAC;IAEvC,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC/C,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACpD,OAAO,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -1,18 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Session CRUD storage for ARCS projects.
|
|
3
3
|
*
|
|
4
|
-
* Tracks agent runtime sessions
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Tracks agent runtime sessions attached to a project. Unlike
|
|
5
|
+
* tasks/plans/knowledge these records are volatile runtime state: they carry no
|
|
6
|
+
* markdown mirror and never invalidate the graph cache.
|
|
7
7
|
*/
|
|
8
8
|
export type { SessionLinkedNodeType, SessionRuntimeType, SessionStatus, } from "./storage-utils.js";
|
|
9
9
|
export { SESSION_LINKED_NODE_TYPES, SESSION_RUNTIME_TYPES, SESSION_STATUSES, } from "./storage-utils.js";
|
|
10
|
+
/**
|
|
11
|
+
* Where a session record came from — its provenance, not its state.
|
|
12
|
+
*
|
|
13
|
+
* - `observed` — a runtime session ARCS merely watches: a terminal `claude`
|
|
14
|
+
* session announcing itself through the hook bridge. Something outside ARCS
|
|
15
|
+
* drives it.
|
|
16
|
+
* - `arcs` — a record ARCS minted for itself (the headless oneshot/stable
|
|
17
|
+
* threads). No terminal is attached; it is driven by headless runs only.
|
|
18
|
+
*
|
|
19
|
+
* Declared here rather than in storage-utils alongside the other session enums
|
|
20
|
+
* because origin is derived by this module (legacy promotion below) and every
|
|
21
|
+
* consumer already imports the session enums through this file.
|
|
22
|
+
*/
|
|
23
|
+
export declare const SESSION_ORIGINS: readonly ["observed", "arcs"];
|
|
24
|
+
export type SessionOrigin = (typeof SESSION_ORIGINS)[number];
|
|
10
25
|
export interface SessionMeta {
|
|
11
26
|
id: string;
|
|
12
27
|
normalizedId: string;
|
|
13
28
|
runtimeType: import("./storage-utils.js").SessionRuntimeType;
|
|
14
|
-
/** Runtime-native session id, verbatim (e.g.
|
|
29
|
+
/** Runtime-native session id, verbatim (e.g. a claude-code session uuid). */
|
|
15
30
|
runtimeSessionId: string;
|
|
31
|
+
/**
|
|
32
|
+
* Provenance of the record. Persisted, never client-settable, and never
|
|
33
|
+
* rewritten by an upsert — whoever created the record fixed it. Always
|
|
34
|
+
* present on a value read through this module even when the stored record
|
|
35
|
+
* predates the field (see `withDerivedOrigin`).
|
|
36
|
+
*/
|
|
37
|
+
origin: SessionOrigin;
|
|
16
38
|
status: import("./storage-utils.js").SessionStatus;
|
|
17
39
|
startedAt: string;
|
|
18
40
|
lastMessageAt?: string;
|
|
@@ -26,11 +48,41 @@ export interface SessionMeta {
|
|
|
26
48
|
/** Normalized task/plan id — never a diagram node id (T001…). */
|
|
27
49
|
linkedNodeId?: string;
|
|
28
50
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
51
|
+
* Id of the headless run currently claimed on this record — written when the
|
|
52
|
+
* run is spawned and cleared when it settles (`beginSessionRun` /
|
|
53
|
+
* `settleSessionRun`). Its presence IS the claim: a record carrying one is
|
|
54
|
+
* believed to have a live `claude` child behind it.
|
|
55
|
+
*
|
|
56
|
+
* Written for the runs ARCS drives itself, so in practice every `arcs`-origin
|
|
57
|
+
* thread; an `observed` record only carries one while a headless run targets
|
|
58
|
+
* it. Deliberately absent from `UpdateSessionInput`: a claim is a fact about
|
|
59
|
+
* a process, never something a caller hands in.
|
|
32
60
|
*/
|
|
33
|
-
|
|
61
|
+
currentRunId?: string;
|
|
62
|
+
/**
|
|
63
|
+
* OS pid of the claimed run's child. Persisted because in-memory liveness
|
|
64
|
+
* dies with the server and the restart case is exactly the one that has to be
|
|
65
|
+
* recoverable — the startup sweep probes this pid to tell a live run from an
|
|
66
|
+
* orphaned claim.
|
|
67
|
+
*/
|
|
68
|
+
currentRunPid?: number;
|
|
69
|
+
/**
|
|
70
|
+
* ISO-8601 proof of life for the claimed run. Same unit as every other
|
|
71
|
+
* top-level timestamp on this record; `metadata.run.*` keeps epoch ms and the
|
|
72
|
+
* two never mix.
|
|
73
|
+
*
|
|
74
|
+
* SHORTCUT: nothing refreshes this mid-run yet, so it equals the run's spawn
|
|
75
|
+
* time and RUN_HEARTBEAT_TTL_MS has to cover a whole run; upgrade to a
|
|
76
|
+
* periodic touch (and a far shorter TTL) when the runner grows a heartbeat.
|
|
77
|
+
*/
|
|
78
|
+
heartbeatAt?: string;
|
|
79
|
+
/**
|
|
80
|
+
* ISO-8601 time of the last runtime checkpoint ARCS observed — Claude Code's
|
|
81
|
+
* `UserPromptSubmit` and `Stop` hooks. The only liveness evidence an
|
|
82
|
+
* `observed` session ever produces: nothing else reports that a terminal
|
|
83
|
+
* session is still working.
|
|
84
|
+
*/
|
|
85
|
+
lastCheckpointAt?: string;
|
|
34
86
|
metadata?: Record<string, unknown>;
|
|
35
87
|
}
|
|
36
88
|
export interface SessionIndex {
|
|
@@ -39,6 +91,13 @@ export interface SessionIndex {
|
|
|
39
91
|
export interface CreateSessionInput {
|
|
40
92
|
runtimeType: import("./storage-utils.js").SessionRuntimeType;
|
|
41
93
|
runtimeSessionId: string;
|
|
94
|
+
/**
|
|
95
|
+
* Provenance, set once at creation and defaulting to `observed`. Only the
|
|
96
|
+
* ARCS-minted headless threads pass `arcs`. Deliberately absent from every
|
|
97
|
+
* request schema: provenance is a fact about who created the record, never
|
|
98
|
+
* something a client hands in.
|
|
99
|
+
*/
|
|
100
|
+
origin?: SessionOrigin;
|
|
42
101
|
status?: import("./storage-utils.js").SessionStatus;
|
|
43
102
|
startedAt?: string;
|
|
44
103
|
lastMessageAt?: string;
|
|
@@ -51,6 +110,12 @@ export interface UpdateSessionInput {
|
|
|
51
110
|
status?: import("./storage-utils.js").SessionStatus;
|
|
52
111
|
/** Pass `null` to clear; pass an ISO timestamp to set. */
|
|
53
112
|
lastMessageAt?: string | null;
|
|
113
|
+
/**
|
|
114
|
+
* ISO timestamp of a runtime checkpoint just observed (`null` clears it).
|
|
115
|
+
* Settable here — unlike the run claim — because a checkpoint is a report the
|
|
116
|
+
* hook bridge relays, not a process ARCS owns.
|
|
117
|
+
*/
|
|
118
|
+
lastCheckpointAt?: string | null;
|
|
54
119
|
/** Pass `null` to clear; pass a string to set. */
|
|
55
120
|
userEmail?: string | null;
|
|
56
121
|
/** Pass `null` to clear; merged shallowly into the existing metadata. */
|
|
@@ -62,12 +127,6 @@ export interface UpdateSessionInput {
|
|
|
62
127
|
linkedNodeType?: import("./storage-utils.js").SessionLinkedNodeType | null;
|
|
63
128
|
/** Normalized task/plan id — validated against the task/plan store. */
|
|
64
129
|
linkedNodeId?: string | null;
|
|
65
|
-
/**
|
|
66
|
-
* Whole-queue replacement (`null` clears it). Appending/draining goes through
|
|
67
|
-
* `enqueueSessionMessage`/`drainSessionMessageQueue` instead — a shallow merge
|
|
68
|
-
* cannot express those safely under concurrent access.
|
|
69
|
-
*/
|
|
70
|
-
messageQueue?: string[] | null;
|
|
71
130
|
now?: string;
|
|
72
131
|
}
|
|
73
132
|
export interface SessionFilters {
|
|
@@ -75,6 +134,78 @@ export interface SessionFilters {
|
|
|
75
134
|
runtimeType?: import("./storage-utils.js").SessionRuntimeType;
|
|
76
135
|
}
|
|
77
136
|
export declare function readSessionIndex(projectDir: string): Promise<SessionIndex>;
|
|
137
|
+
/**
|
|
138
|
+
* What a session is doing right now, as a reader of the UI would say it.
|
|
139
|
+
*
|
|
140
|
+
* DERIVED, never stored: there is no `phase` field on `SessionMeta` and no way
|
|
141
|
+
* to write one through this module. A stored phase is a second source of truth
|
|
142
|
+
* that goes stale the instant a process dies without telling anyone — which is
|
|
143
|
+
* precisely the "stuck on running forever" failure this replaces.
|
|
144
|
+
*/
|
|
145
|
+
export declare const SESSION_PHASES: readonly ["running", "idle", "failed", "ended"];
|
|
146
|
+
export type SessionPhase = (typeof SESSION_PHASES)[number];
|
|
147
|
+
/**
|
|
148
|
+
* Outcome vocabulary persisted on `metadata.run.outcome`. A superset of the
|
|
149
|
+
* runner's own `RunOutcome` ("success" | "error" | "timeout"): `interrupted` is
|
|
150
|
+
* never produced BY a run, it is written FOR a run whose process disappeared
|
|
151
|
+
* without ever settling — a restart's orphan. Declared here rather than
|
|
152
|
+
* imported from the web server because `utils/` must not depend on
|
|
153
|
+
* `web-server/`; claude-runner's union stays exactly what a child can return.
|
|
154
|
+
*/
|
|
155
|
+
export declare const SESSION_RUN_OUTCOMES: readonly ["success", "error", "timeout", "interrupted"];
|
|
156
|
+
export type SessionRunOutcome = (typeof SESSION_RUN_OUTCOMES)[number];
|
|
157
|
+
/**
|
|
158
|
+
* How long a run claim's heartbeat counts as proof of life. Sized to the
|
|
159
|
+
* runner's default 10-minute run ceiling because nothing refreshes the
|
|
160
|
+
* heartbeat mid-run yet (see `SessionMeta.heartbeatAt`) — a shorter window
|
|
161
|
+
* would demote a perfectly healthy long run to `idle`.
|
|
162
|
+
*/
|
|
163
|
+
export declare const RUN_HEARTBEAT_TTL_MS: number;
|
|
164
|
+
/**
|
|
165
|
+
* How long a runtime checkpoint counts as proof of life for an observed
|
|
166
|
+
* session. Deliberately shorter than the run TTL: checkpoints arrive at every
|
|
167
|
+
* prompt and every turn end, so a terminal that has produced neither in five
|
|
168
|
+
* minutes is waiting on a human, not working.
|
|
169
|
+
*/
|
|
170
|
+
export declare const CHECKPOINT_TTL_MS: number;
|
|
171
|
+
export interface SessionPhaseOptions {
|
|
172
|
+
/** Clock in epoch ms; defaults to `Date.now()`. */
|
|
173
|
+
now?: number;
|
|
174
|
+
heartbeatTtlMs?: number;
|
|
175
|
+
checkpointTtlMs?: number;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* The record's run claim, or `undefined` when it holds none. Validated rather
|
|
179
|
+
* than trusted: a hand-edited index can carry anything under this key.
|
|
180
|
+
*/
|
|
181
|
+
export declare function sessionRunClaim(session: SessionMeta): string | undefined;
|
|
182
|
+
/**
|
|
183
|
+
* Derives a session's phase from its own persisted evidence, in one place.
|
|
184
|
+
*
|
|
185
|
+
* Precedence, strongest first:
|
|
186
|
+
* 1. a terminal `status` — `failed` is `failed`, `completed`/`disconnected`
|
|
187
|
+
* are `ended`. Nothing observed later reopens a session that is over.
|
|
188
|
+
* 2. a run claim (`currentRunId`) — ARCS spawned a child for this record, so
|
|
189
|
+
* its `heartbeatAt` is the freshest evidence there is. Stale means the
|
|
190
|
+
* claim outlived its proof of life, which reads `idle`, not `failed`: the
|
|
191
|
+
* run is settled by the reconciler, not guessed at here.
|
|
192
|
+
* 3. `lastCheckpointAt` — the only signal an observed terminal session emits.
|
|
193
|
+
*
|
|
194
|
+
* `metadata.run.outcome` is deliberately NOT an input. That field is run-level
|
|
195
|
+
* history (rendered next to the run), while phase answers "is this session live
|
|
196
|
+
* right now" — a run that failed an hour ago leaves the session idle and ready
|
|
197
|
+
* for the next one, not permanently `failed`.
|
|
198
|
+
*
|
|
199
|
+
* Pure: a record plus a clock, no I/O, no process probing. Liveness that needs
|
|
200
|
+
* the world (a pid, `claude agents`) belongs to the reconciler, which starts
|
|
201
|
+
* from this value and can only ever demote it.
|
|
202
|
+
*
|
|
203
|
+
* SHORTCUT: checkpoint freshness cannot tell `UserPromptSubmit` (turn started)
|
|
204
|
+
* from `Stop` (turn ended), so a session reads `running` for the TTL after its
|
|
205
|
+
* last turn; upgrade to a persisted checkpoint kind when the panel needs
|
|
206
|
+
* turn-level precision.
|
|
207
|
+
*/
|
|
208
|
+
export declare function deriveSessionPhase(session: SessionMeta, options?: SessionPhaseOptions): SessionPhase;
|
|
78
209
|
export declare function createSession(projectDir: string, input: CreateSessionInput): Promise<SessionMeta>;
|
|
79
210
|
/**
|
|
80
211
|
* Create-or-update by runtime session id. Used by runtime discovery bridges,
|
|
@@ -88,26 +219,73 @@ export declare function upsertSession(projectDir: string, input: CreateSessionIn
|
|
|
88
219
|
export declare function listSessions(projectDir: string, filters?: SessionFilters): Promise<SessionMeta[]>;
|
|
89
220
|
export declare function getSession(projectDir: string, sessionId: string): Promise<SessionMeta>;
|
|
90
221
|
export declare function updateSession(projectDir: string, input: UpdateSessionInput): Promise<SessionMeta>;
|
|
222
|
+
export interface BeginSessionRunInput {
|
|
223
|
+
/** Caller-minted id for this run — the claim's identity. */
|
|
224
|
+
runId: string;
|
|
225
|
+
/** OS pid of the spawned child; absent/`null` when the spawn produced none. */
|
|
226
|
+
pid?: number | null;
|
|
227
|
+
/** ISO override for the heartbeat and `updatedAt` stamps (tests). */
|
|
228
|
+
now?: string;
|
|
229
|
+
}
|
|
230
|
+
export interface SettleSessionRunInput {
|
|
231
|
+
/**
|
|
232
|
+
* Settles only when it matches the persisted claim. Omit to settle whatever
|
|
233
|
+
* claim is there (the startup sweep passes the id it read, so a run that
|
|
234
|
+
* started in between is never settled out from under itself).
|
|
235
|
+
*/
|
|
236
|
+
runId?: string;
|
|
237
|
+
outcome: SessionRunOutcome;
|
|
238
|
+
error?: string;
|
|
239
|
+
/** Epoch ms for `metadata.run.endedAt` — defaults to now. */
|
|
240
|
+
endedAt?: number;
|
|
241
|
+
/**
|
|
242
|
+
* Extra `metadata.run` fields stamped in the SAME write as the outcome: what
|
|
243
|
+
* the RUNNER measured and no claim could have known at spawn (the pid and
|
|
244
|
+
* startedAt the child actually reported, the run's mode, the stream
|
|
245
|
+
* observations). Merged UNDER the settle's own fields, so `outcome`/`endedAt`/
|
|
246
|
+
* `error` can never be smuggled past the settle that owns them.
|
|
247
|
+
*/
|
|
248
|
+
run?: Record<string, unknown>;
|
|
249
|
+
/**
|
|
250
|
+
* Sibling `metadata` keys written in the same read-modify-write, shallow
|
|
251
|
+
* merged as `updateSession` merges. The seed-decision repair rides here: a
|
|
252
|
+
* settle that released the claim in one write and repaired the record in a
|
|
253
|
+
* second is readable in between as "this run failed" while still carrying the
|
|
254
|
+
* seed state that failed it — and the second write can land AFTER a newer run
|
|
255
|
+
* has already claimed the record, clobbering its live `metadata.run`. Merged
|
|
256
|
+
* UNDER `run`, so `run` can never be rewritten through this door.
|
|
257
|
+
*/
|
|
258
|
+
metadata?: Record<string, unknown>;
|
|
259
|
+
/** ISO override for `updatedAt` (tests). */
|
|
260
|
+
now?: string;
|
|
261
|
+
}
|
|
91
262
|
/**
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* Deliberately not part of `updateSession`: the generic path shallow-merges
|
|
95
|
-
* whatever the caller passes, which would let two concurrent senders read the
|
|
96
|
-
* same array and write back a queue missing one message. Append happens inside
|
|
97
|
-
* the store lock, so the read-modify-write is atomic.
|
|
263
|
+
* Claims a session for a headless run: persists the run id, the child's pid and
|
|
264
|
+
* the first heartbeat, all of which survive the server process that made them.
|
|
98
265
|
*
|
|
99
|
-
* The
|
|
100
|
-
*
|
|
266
|
+
* The claim is what makes a run recoverable. In-memory liveness (the runner's
|
|
267
|
+
* `liveRuns` map) dies with the server, so without a persisted claim a run
|
|
268
|
+
* interrupted by a restart would leave the session reading `running` forever
|
|
269
|
+
* with nothing left that could ever settle it.
|
|
101
270
|
*/
|
|
102
|
-
export declare function
|
|
271
|
+
export declare function beginSessionRun(projectDir: string, sessionId: string, input: BeginSessionRunInput): Promise<SessionMeta>;
|
|
103
272
|
/**
|
|
104
|
-
*
|
|
273
|
+
* Releases a session's run claim, records how the run ended on `metadata.run`,
|
|
274
|
+
* and applies whatever the settle repaired — in ONE lock acquisition.
|
|
275
|
+
*
|
|
276
|
+
* Read-modify-write has to be atomic: `metadata.run` is replaced wholesale by
|
|
277
|
+
* every writer, so settling through the generic `updateSession` would race the
|
|
278
|
+
* route's own write-back and could drop the run's pid/startedAt.
|
|
105
279
|
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
280
|
+
* Everything a settle concludes therefore goes in HERE rather than in a
|
|
281
|
+
* follow-up `updateSession`. The claim is the only thing serializing a run
|
|
282
|
+
* against the next one, and releasing it is the LAST thing this write does — so
|
|
283
|
+
* a conclusion left to a second write is both observable in the gap (the record
|
|
284
|
+
* reads settled while still carrying the state the run just disproved) and
|
|
285
|
+
* unguarded outside it: the `input.runId` check above holds only for the
|
|
286
|
+
* duration of this lock, and a newer run can claim the record the moment it is
|
|
287
|
+
* released.
|
|
110
288
|
*/
|
|
111
|
-
export declare function
|
|
289
|
+
export declare function settleSessionRun(projectDir: string, sessionId: string, input: SettleSessionRunInput): Promise<SessionMeta>;
|
|
112
290
|
export declare function deleteSession(projectDir: string, sessionId: string): Promise<void>;
|
|
113
291
|
//# sourceMappingURL=session-store.d.ts.map
|