@rryando/arcs 4.2.0 → 5.0.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 +2 -2
- package/dist/cli/arcs-flash.d.ts +1 -1
- package/dist/cli/arcs-flash.d.ts.map +1 -1
- package/dist/cli/arcs-flash.js +6 -6
- package/dist/cli/arcs-flash.js.map +1 -1
- package/dist/cli/arcs-orchestrate.d.ts +1 -1
- package/dist/cli/arcs-orchestrate.d.ts.map +1 -1
- package/dist/cli/arcs-orchestrate.js +4 -2
- package/dist/cli/arcs-orchestrate.js.map +1 -1
- package/dist/cli/commands/index.d.ts +1 -1
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +1 -1
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/project.js +1 -30
- package/dist/cli/commands/project.js.map +1 -1
- package/dist/cli/commands/proposal-doc.d.ts +2 -0
- package/dist/cli/commands/proposal-doc.d.ts.map +1 -0
- package/dist/cli/commands/proposal-doc.js +382 -0
- package/dist/cli/commands/proposal-doc.js.map +1 -0
- package/dist/cli/commands/web.js +4 -10
- package/dist/cli/commands/web.js.map +1 -1
- package/dist/cli/dag-commands.d.ts +9 -0
- package/dist/cli/dag-commands.d.ts.map +1 -1
- package/dist/cli/dag-commands.js +35 -25
- package/dist/cli/dag-commands.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +12 -23
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/orchestrator-shared-blocks.d.ts +12 -10
- package/dist/cli/orchestrator-shared-blocks.d.ts.map +1 -1
- package/dist/cli/orchestrator-shared-blocks.js +46 -28
- package/dist/cli/orchestrator-shared-blocks.js.map +1 -1
- package/dist/utils/session-store.d.ts +24 -2
- package/dist/utils/session-store.d.ts.map +1 -1
- package/dist/utils/session-store.js +16 -7
- 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-BPDgvsyT.js → GraphCanvas-BYZE4sO9.js} +1 -1
- package/dist/web-client/assets/{MarkdownEditor-D7TLp78z.js → MarkdownEditor-BKx6M1cw.js} +1 -1
- package/dist/web-client/assets/{abnfDiagram-VRR7QNED-CyuP2N9t.js → abnfDiagram-VRR7QNED-D4kt0l2y.js} +1 -1
- package/dist/web-client/assets/architecture-TIHT7OUA-CIdGE6VO.js +1 -0
- package/dist/web-client/assets/{architectureDiagram-ZJ3FMSHR-DZ0ul9QX.js → architectureDiagram-ZJ3FMSHR-bu29SJFS.js} +1 -1
- package/dist/web-client/assets/{blockDiagram-677ZJIJ3-LLGzlc9l.js → blockDiagram-677ZJIJ3-hsu7mXKw.js} +1 -1
- package/dist/web-client/assets/{c4Diagram-LMCZKHZV-CViu3CTc.js → c4Diagram-LMCZKHZV-DMllRlT_.js} +1 -1
- package/dist/web-client/assets/channel-CBg-s-ZD.js +1 -0
- package/dist/web-client/assets/{chunk-32BRIVSS-Bw_IuJCM.js → chunk-32BRIVSS-BSzwj5eM.js} +1 -1
- package/dist/web-client/assets/{chunk-52WLFC77-C29h440W.js → chunk-52WLFC77-RDdZn6yY.js} +1 -1
- package/dist/web-client/assets/{chunk-C7G6YPKG-hhOrvw5w.js → chunk-C7G6YPKG-DQr--txT.js} +1 -1
- package/dist/web-client/assets/{chunk-EX3LRPZG-COMzol-M.js → chunk-EX3LRPZG-Bb8nc4z4.js} +1 -1
- package/dist/web-client/assets/{chunk-FWX5IMBZ-6vdX9EUn.js → chunk-FWX5IMBZ-QvBpOcOg.js} +2 -2
- package/dist/web-client/assets/{chunk-HOUHSVGY-DWDW6sxp.js → chunk-HOUHSVGY-B0mX_yjc.js} +1 -1
- package/dist/web-client/assets/{chunk-ICXQ74PX-BdMYglo2.js → chunk-ICXQ74PX-BmJSQqOH.js} +1 -1
- package/dist/web-client/assets/{chunk-MOJQB5TN-C0LAX_dC.js → chunk-MOJQB5TN-BrEI4GGn.js} +1 -1
- package/dist/web-client/assets/{chunk-OGEWGWER-CBx8MB7f.js → chunk-OGEWGWER-CrqDPOWP.js} +1 -1
- package/dist/web-client/assets/{chunk-PUDLZKDR-DKssR1nf.js → chunk-PUDLZKDR-DfPKldpG.js} +1 -1
- package/dist/web-client/assets/{chunk-Q4XR5HBZ-B3kcxFE-.js → chunk-Q4XR5HBZ-ekATI9aV.js} +1 -1
- package/dist/web-client/assets/{chunk-V7JOEXUC-CAlymndy.js → chunk-V7JOEXUC-C5APsP1t.js} +1 -1
- package/dist/web-client/assets/{chunk-VAUOI2AC-BowfsmTW.js → chunk-VAUOI2AC-BhfSWJZI.js} +1 -1
- package/dist/web-client/assets/{chunk-VR4S4FIN-BBOydgvt.js → chunk-VR4S4FIN-BGa-44J7.js} +1 -1
- package/dist/web-client/assets/{chunk-WYO6CB5R-DcymFbES.js → chunk-WYO6CB5R-By1K0guW.js} +1 -1
- package/dist/web-client/assets/{chunk-ZGVPDNZ5--uKFP-Lr.js → chunk-ZGVPDNZ5-Vnzpc76F.js} +1 -1
- package/dist/web-client/assets/classDiagram-OUVF2IWQ-ciwDjhUR.js +1 -0
- package/dist/web-client/assets/classDiagram-v2-EOCWNBFH-ciwDjhUR.js +1 -0
- package/dist/web-client/assets/{cynefin-VYW2F7L2-CjboUOMA.js → cynefin-VYW2F7L2-C6MOMOOz.js} +1 -1
- package/dist/web-client/assets/{cynefinDiagram-TSTJHNR4-BcxygBP7.js → cynefinDiagram-TSTJHNR4-Cseyu79b.js} +1 -1
- package/dist/web-client/assets/{dagre-VKFMJZFB-D-tiERQE.js → dagre-VKFMJZFB-CQJlIuNh.js} +1 -1
- package/dist/web-client/assets/{diagram-FQU43EPY-ChPXczaS.js → diagram-FQU43EPY-DpqDxhq4.js} +1 -1
- package/dist/web-client/assets/{diagram-G47NLZAW-CVL3Y91h.js → diagram-G47NLZAW-C11fYYaF.js} +1 -1
- package/dist/web-client/assets/{diagram-NH7WQ7WH-DsaNA9Lh.js → diagram-NH7WQ7WH-BiG-uRAF.js} +1 -1
- package/dist/web-client/assets/{diagram-OA4YK3LP-CXhrhdhU.js → diagram-OA4YK3LP-CIXWWjq-.js} +1 -1
- package/dist/web-client/assets/{diagram-WEI45ONY-BTVPnk4E.js → diagram-WEI45ONY-C3OgIWu9.js} +1 -1
- package/dist/web-client/assets/{ebnfDiagram-CCIWWBDH-BAyrRBtM.js → ebnfDiagram-CCIWWBDH-BHF_NA3_.js} +1 -1
- package/dist/web-client/assets/{erDiagram-Q63AITRT-Qm24Wepm.js → erDiagram-Q63AITRT-CUOJCrLy.js} +1 -1
- package/dist/web-client/assets/eventmodeling-45OFAUF4-DxfboL1J.js +1 -0
- package/dist/web-client/assets/flowDiagram-23GEKE2U-C3NzpTtI.js +1 -0
- package/dist/web-client/assets/{ganttDiagram-NO4QXBWP-D8h7l3XJ.js → ganttDiagram-NO4QXBWP-D_4BMJ-g.js} +1 -1
- package/dist/web-client/assets/{gitGraph-TEB2WS4Q-DIBml1SB.js → gitGraph-TEB2WS4Q-CBuaZBId.js} +1 -1
- package/dist/web-client/assets/{gitGraphDiagram-IHSO6WYX-CtkYoXjn.js → gitGraphDiagram-IHSO6WYX-BbztsGuO.js} +1 -1
- package/dist/web-client/assets/index-B1KVIr80.css +2 -0
- package/dist/web-client/assets/{index-DOSH4Q9H.js → index-BWd2fBNL.js} +38 -38
- package/dist/web-client/assets/{info-DKCQHKI2-DLEUtV5Q.js → info-DKCQHKI2-Bzi0Xjro.js} +1 -1
- package/dist/web-client/assets/{infoDiagram-FWYZ7A6U-BJQ7aQux.js → infoDiagram-FWYZ7A6U-BkeEKcr0.js} +1 -1
- package/dist/web-client/assets/{ishikawaDiagram-FXEZZL3T-BPM11FvG.js → ishikawaDiagram-FXEZZL3T-CVusWu0p.js} +1 -1
- package/dist/web-client/assets/{journeyDiagram-5HDEW3XC-C0aX2z3c.js → journeyDiagram-5HDEW3XC-BUxu71zw.js} +1 -1
- package/dist/web-client/assets/{kanban-definition-HUTT4EX6-C56F29Ib.js → kanban-definition-HUTT4EX6-BE8Hv4Kd.js} +1 -1
- package/dist/web-client/assets/{line-BLFHLF2N.js → line-CiAoINJS.js} +1 -1
- package/dist/web-client/assets/{mermaid-parser.core-BLC8FhgU.js → mermaid-parser.core-BW47khiS.js} +3 -3
- package/dist/web-client/assets/{mermaid.core-BBqkKuXt.js → mermaid.core-DP--Jl9R.js} +3 -3
- package/dist/web-client/assets/{mindmap-definition-LN4V7U3C-aVZbsoPc.js → mindmap-definition-LN4V7U3C-CvWJUqdq.js} +1 -1
- package/dist/web-client/assets/{packet-7NZHBO7P-D4aqSQfB.js → packet-7NZHBO7P-XtzX9SaQ.js} +1 -1
- package/dist/web-client/assets/{pegDiagram-2B236MQR-DjfyNI0U.js → pegDiagram-2B236MQR-XNo0K1ct.js} +1 -1
- package/dist/web-client/assets/{pie-RZYD4A2V-ChCwYsYj.js → pie-RZYD4A2V-B1eUd9yt.js} +1 -1
- package/dist/web-client/assets/{pieDiagram-ENE6RG2P-BeHLKkXC.js → pieDiagram-ENE6RG2P-CRSb5z-4.js} +1 -1
- package/dist/web-client/assets/{quadrantDiagram-ABIIQ3AL-stga3gvq.js → quadrantDiagram-ABIIQ3AL-DziMaQxE.js} +1 -1
- package/dist/web-client/assets/{radar-I7S5WNFK-DOGheiwT.js → radar-I7S5WNFK-BpRqZH2g.js} +1 -1
- package/dist/web-client/assets/{railroad-3IZDKUUU-_JnU7M6L.js → railroad-3IZDKUUU-FDIHW04k.js} +1 -1
- package/dist/web-client/assets/railroad-abnf-AHOZXSZD-BKj6JAhH.js +1 -0
- package/dist/web-client/assets/railroad-ebnf-EBAXGLYW-ChDM1OBv.js +1 -0
- package/dist/web-client/assets/railroad-peg-LSFZ7HO6-DvwA2e0i.js +1 -0
- package/dist/web-client/assets/{railroadDiagram-RFXS5EU6-C0CkMsOd.js → railroadDiagram-RFXS5EU6-Cs7EVBaz.js} +1 -1
- package/dist/web-client/assets/{requirementDiagram-TGXJPOKE-DuImwoRD.js → requirementDiagram-TGXJPOKE-B9_Lj1ga.js} +1 -1
- package/dist/web-client/assets/{sankeyDiagram-HTMAVEWB-kprq0XF9.js → sankeyDiagram-HTMAVEWB-DuTJTiy0.js} +1 -1
- package/dist/web-client/assets/{sequenceDiagram-DBY2YBRQ-DiXKJMF6.js → sequenceDiagram-DBY2YBRQ-vOCU5UoE.js} +1 -1
- package/dist/web-client/assets/{stateDiagram-2N3HPSRC-D5qbVStE.js → stateDiagram-2N3HPSRC-rxAnfzWn.js} +1 -1
- package/dist/web-client/assets/stateDiagram-v2-6OUMAXLB-B3EvQPEe.js +1 -0
- package/dist/web-client/assets/{swimlanes-5IMT3BWC-DCbw389c.js → swimlanes-5IMT3BWC-gdVZUnPe.js} +1 -1
- package/dist/web-client/assets/swimlanesDiagram-G3AALYLV-WcOXuCPg.js +8 -0
- package/dist/web-client/assets/{timeline-definition-FHXFAJF6-CQeaYN_9.js → timeline-definition-FHXFAJF6-Do68JyGy.js} +1 -1
- package/dist/web-client/assets/{treeView-QDETBFTQ-Cf7Sq3qo.js → treeView-QDETBFTQ-CdZkmg80.js} +1 -1
- package/dist/web-client/assets/{treemap-6X3UGDF4-BovzvoTU.js → treemap-6X3UGDF4-ub54fmpW.js} +1 -1
- package/dist/web-client/assets/{vennDiagram-L72KCM5P-CZsJy139.js → vennDiagram-L72KCM5P-D-r8NBEp.js} +1 -1
- package/dist/web-client/assets/{wardley-OPB4EBWU-DJ7MS6XZ.js → wardley-OPB4EBWU-CTleH1-J.js} +1 -1
- package/dist/web-client/assets/{wardleyDiagram-EHGQE667-rqhcmsbM.js → wardleyDiagram-EHGQE667-BU8Kw39F.js} +1 -1
- package/dist/web-client/assets/{xychartDiagram-FW5EYKEG-HuK4Seps.js → xychartDiagram-FW5EYKEG-CfNnag6i.js} +1 -1
- package/dist/web-client/index.html +2 -2
- package/dist/web-server/app.d.ts.map +1 -1
- package/dist/web-server/app.js +1 -7
- package/dist/web-server/app.js.map +1 -1
- package/dist/web-server/claude-runner.d.ts +11 -4
- package/dist/web-server/claude-runner.d.ts.map +1 -1
- package/dist/web-server/claude-runner.js +10 -14
- package/dist/web-server/claude-runner.js.map +1 -1
- package/dist/web-server/index.d.ts.map +1 -1
- package/dist/web-server/index.js +4 -1
- package/dist/web-server/index.js.map +1 -1
- package/dist/web-server/prompt-assembly.d.ts.map +1 -1
- package/dist/web-server/prompt-assembly.js +1 -2
- package/dist/web-server/prompt-assembly.js.map +1 -1
- package/dist/web-server/routes/sessions.d.ts +9 -6
- package/dist/web-server/routes/sessions.d.ts.map +1 -1
- package/dist/web-server/routes/sessions.js +315 -207
- package/dist/web-server/routes/sessions.js.map +1 -1
- package/dist/web-server/run-driver.d.ts +113 -0
- package/dist/web-server/run-driver.d.ts.map +1 -0
- package/dist/web-server/run-driver.js +214 -0
- package/dist/web-server/run-driver.js.map +1 -0
- package/dist/web-server/run-event-log.d.ts +23 -1
- package/dist/web-server/run-event-log.d.ts.map +1 -1
- package/dist/web-server/run-event-log.js +29 -5
- package/dist/web-server/run-event-log.js.map +1 -1
- package/dist/web-server/web-auth.d.ts +3 -5
- package/dist/web-server/web-auth.d.ts.map +1 -1
- package/dist/web-server/web-auth.js +6 -11
- package/dist/web-server/web-auth.js.map +1 -1
- package/dist/web-server/web-token.d.ts +1 -2
- package/dist/web-server/web-token.d.ts.map +1 -1
- package/dist/web-server/web-token.js +1 -2
- package/dist/web-server/web-token.js.map +1 -1
- package/opencode/arcs/bundle-runtime.json +3 -3
- package/opencode/arcs/prompts/arcs-docs.txt +4 -4
- package/opencode/arcs/prompts/arcs-flash.txt +41 -33
- package/opencode/arcs/prompts/arcs-orchestrate-caveman.txt +43 -27
- package/opencode/arcs/prompts/arcs-orchestrate.txt +43 -27
- package/opencode/arcs/prompts/code-reviewer.txt +4 -4
- package/opencode/arcs/prompts/graph-explorer.txt +4 -4
- package/opencode/arcs/prompts/software-engineer.txt +2 -2
- package/opencode/arcs/prompts/tech-architect.txt +4 -4
- package/opencode/arcs/skills/brainstorming/SKILL.md +4 -4
- package/opencode/arcs/skills/enriching-codegraph-proposals/SKILL.md +1 -1
- package/opencode/arcs/skills/implementation/SKILL.md +6 -6
- package/opencode/arcs/skills/init-project/SKILL.md +4 -4
- package/opencode/arcs/skills/systematic-debugging/SKILL.md +2 -2
- package/opencode/arcs/skills/test-driven-development/SKILL.md +3 -3
- package/opencode/arcs/skills/to-diagram/SKILL.md +2 -2
- package/opencode/arcs/skills/writing-knowledge/SKILL.md +2 -2
- package/opencode/arcs/skills/writing-plans/SKILL.md +2 -2
- package/opencode/arcs/skills/writing-proposals/SKILL.md +90 -0
- package/package.json +1 -1
- package/dist/cli/commands/hooks.d.ts +0 -76
- package/dist/cli/commands/hooks.d.ts.map +0 -1
- package/dist/cli/commands/hooks.js +0 -436
- package/dist/cli/commands/hooks.js.map +0 -1
- package/dist/utils/claude-code-hook-install.d.ts +0 -80
- package/dist/utils/claude-code-hook-install.d.ts.map +0 -1
- package/dist/utils/claude-code-hook-install.js +0 -212
- package/dist/utils/claude-code-hook-install.js.map +0 -1
- package/dist/utils/hook-contract.d.ts +0 -36
- package/dist/utils/hook-contract.d.ts.map +0 -1
- package/dist/utils/hook-contract.js +0 -35
- package/dist/utils/hook-contract.js.map +0 -1
- package/dist/utils/hook-token-store.d.ts +0 -63
- package/dist/utils/hook-token-store.d.ts.map +0 -1
- package/dist/utils/hook-token-store.js +0 -88
- package/dist/utils/hook-token-store.js.map +0 -1
- package/dist/web-client/assets/architecture-TIHT7OUA-Bdo2Yvm9.js +0 -1
- package/dist/web-client/assets/channel-DBNmizpo.js +0 -1
- package/dist/web-client/assets/classDiagram-OUVF2IWQ-CB3HiA1_.js +0 -1
- package/dist/web-client/assets/classDiagram-v2-EOCWNBFH-CB3HiA1_.js +0 -1
- package/dist/web-client/assets/eventmodeling-45OFAUF4-DoTBIvl5.js +0 -1
- package/dist/web-client/assets/flowDiagram-23GEKE2U-BEH23L1A.js +0 -1
- package/dist/web-client/assets/index-wSzUPvml.css +0 -2
- package/dist/web-client/assets/railroad-abnf-AHOZXSZD-nhNub7LE.js +0 -1
- package/dist/web-client/assets/railroad-ebnf-EBAXGLYW-BlQYe7Yf.js +0 -1
- package/dist/web-client/assets/railroad-peg-LSFZ7HO6-B3E8pRVN.js +0 -1
- package/dist/web-client/assets/stateDiagram-v2-6OUMAXLB-DWwTAG1r.js +0 -1
- package/dist/web-client/assets/swimlanesDiagram-G3AALYLV-DabrCsjZ.js +0 -8
- package/dist/web-server/hook-auth.d.ts +0 -12
- package/dist/web-server/hook-auth.d.ts.map +0 -1
- package/dist/web-server/hook-auth.js +0 -36
- package/dist/web-server/hook-auth.js.map +0 -1
- package/dist/web-server/routes/hook-events.d.ts +0 -43
- package/dist/web-server/routes/hook-events.d.ts.map +0 -1
- package/dist/web-server/routes/hook-events.js +0 -316
- package/dist/web-server/routes/hook-events.js.map +0 -1
- package/opencode/arcs/skills/install-claude-code-hook/SKILL.md +0 -23
- package/scripts/claude-code-session-hook.mjs +0 -146
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hook-auth.d.ts","sourceRoot":"","sources":["../../src/web-server/hook-auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAY9C,eAAO,MAAM,gBAAgB,EAAE,iBAmB9B,CAAC"}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bearer-token gate for `/api/hook/*`.
|
|
3
|
-
*
|
|
4
|
-
* Layered on top of (never instead of) the global loopback-only
|
|
5
|
-
* `secureLocalRequest`: loopback proves the caller is on this machine, the
|
|
6
|
-
* token proves it is this project's installed hook script. Browser-facing
|
|
7
|
-
* routes stay token-free — only the hook endpoint carries a shared secret,
|
|
8
|
-
* because only it is called by something that is not the ARCS web UI.
|
|
9
|
-
*/
|
|
10
|
-
import { verifyHookToken } from "../utils/hook-token-store.js";
|
|
11
|
-
import { fail, requireProjectDir } from "./respond.js";
|
|
12
|
-
const BEARER = /^Bearer\s+(\S+)$/i;
|
|
13
|
-
/** `/api/hook/:slug/...` → the slug segment, or "" when the shape is wrong. */
|
|
14
|
-
function slugFromPath(url) {
|
|
15
|
-
const segments = new URL(url).pathname.split("/");
|
|
16
|
-
return segments[1] === "api" && segments[2] === "hook" ? (segments[3] ?? "") : "";
|
|
17
|
-
}
|
|
18
|
-
export const requireHookToken = async (c, next) => {
|
|
19
|
-
const unauthorized = () => c.json(fail("hook_unauthorized", "Missing or invalid ARCS hook token"), 401);
|
|
20
|
-
const match = BEARER.exec((c.req.header("authorization") ?? "").trim());
|
|
21
|
-
if (!match)
|
|
22
|
-
return unauthorized();
|
|
23
|
-
let projectDir;
|
|
24
|
-
try {
|
|
25
|
-
projectDir = requireProjectDir(slugFromPath(c.req.url));
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
// Deliberately 401, not 404: an unauthenticated caller must not be able to
|
|
29
|
-
// probe which project slugs exist on this machine.
|
|
30
|
-
return unauthorized();
|
|
31
|
-
}
|
|
32
|
-
if (!(await verifyHookToken(projectDir, match[1])))
|
|
33
|
-
return unauthorized();
|
|
34
|
-
await next();
|
|
35
|
-
};
|
|
36
|
-
//# sourceMappingURL=hook-auth.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hook-auth.js","sourceRoot":"","sources":["../../src/web-server/hook-auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEvD,MAAM,MAAM,GAAG,mBAAmB,CAAC;AAEnC,+EAA+E;AAC/E,SAAS,YAAY,CAAC,GAAW;IAC/B,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClD,OAAO,QAAQ,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACpF,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAsB,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;IACnE,MAAM,YAAY,GAAG,GAAG,EAAE,CACxB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,oCAAoC,CAAC,EAAE,GAAG,CAAC,CAAC;IAE/E,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACxE,IAAI,CAAC,KAAK;QAAE,OAAO,YAAY,EAAE,CAAC;IAElC,IAAI,UAAkB,CAAC;IACvB,IAAI,CAAC;QACH,UAAU,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC;QACP,2EAA2E;QAC3E,mDAAmD;QACnD,OAAO,YAAY,EAAE,CAAC;IACxB,CAAC;IAED,IAAI,CAAC,CAAC,MAAM,eAAe,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,YAAY,EAAE,CAAC;IAE1E,MAAM,IAAI,EAAE,CAAC;AACf,CAAC,CAAC"}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude Code session-bridge endpoint.
|
|
3
|
-
*
|
|
4
|
-
* Claude Code has no live-injection channel: hooks are stateless, fire per
|
|
5
|
-
* event, and hold no persistent connection. So the session drives the bridge —
|
|
6
|
-
* it announces itself at `SessionStart`, checkpoints at every
|
|
7
|
-
* `UserPromptSubmit`, closes out at `SessionEnd`, and reports its transcript
|
|
8
|
-
* at `Stop` (the last checkpoint before teardown).
|
|
9
|
-
*
|
|
10
|
-
* Those checkpoints are also the only liveness signal an observed session ever
|
|
11
|
-
* emits, so each one stamps `lastCheckpointAt` — the field the session's derived
|
|
12
|
-
* phase reads to decide whether a terminal is still working.
|
|
13
|
-
*
|
|
14
|
-
* `SessionStart` additionally answers with `stagedContext`: the same staged
|
|
15
|
-
* environment an ARCS-owned headless run carries on `--append-system-prompt`,
|
|
16
|
-
* so a terminal a human drives knows its project, its workspace and its DAG
|
|
17
|
-
* position without the human setting the stage by hand. See
|
|
18
|
-
* `sessionStartContext` for what differs from the owned path.
|
|
19
|
-
*
|
|
20
|
-
* The response stays ARCS-shaped (`{sessionId, stagedContext?}`); turning that
|
|
21
|
-
* into Claude Code's `hookSpecificOutput` envelope is the hook script's job, so
|
|
22
|
-
* a change to Claude Code's wire format never reaches the server.
|
|
23
|
-
*
|
|
24
|
-
* Unlike every other route here this one is not browser-facing, so it sits
|
|
25
|
-
* behind `requireHookToken` in addition to the global loopback check.
|
|
26
|
-
*/
|
|
27
|
-
import { Hono } from "hono";
|
|
28
|
-
export declare const hookEventsRoute: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
29
|
-
/**
|
|
30
|
-
* Ceiling on the block a SessionStart mirrors into a terminal, in characters.
|
|
31
|
-
*
|
|
32
|
-
* Deliberately far below `STAGE_SOFT_CAP` (6000): that budget is spent inside a
|
|
33
|
-
* headless `claude -p` process nobody is watching, whereas this text lands at
|
|
34
|
-
* the head of a live session a human is about to type into. Anything wider buys
|
|
35
|
-
* context nobody asked for at the cost of the window they did.
|
|
36
|
-
*
|
|
37
|
-
* Enforced by SELECTION, never by clipping — see `sessionStartContext`.
|
|
38
|
-
* `scripts/claude-code-session-hook.mjs` carries its own, wider refusal bound
|
|
39
|
-
* (`MAX_CONTEXT_CHARS`), pinned against this constant by
|
|
40
|
-
* `test/claude-code-hook-script.test.ts`.
|
|
41
|
-
*/
|
|
42
|
-
export declare const SESSION_START_STAGE_CAP = 2500;
|
|
43
|
-
//# sourceMappingURL=hook-events.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hook-events.d.ts","sourceRoot":"","sources":["../../../src/web-server/routes/hook-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAiB5B,eAAO,MAAM,eAAe,4EAAa,CAAC;AAqI1C;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,uBAAuB,OAAO,CAAC"}
|
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude Code session-bridge endpoint.
|
|
3
|
-
*
|
|
4
|
-
* Claude Code has no live-injection channel: hooks are stateless, fire per
|
|
5
|
-
* event, and hold no persistent connection. So the session drives the bridge —
|
|
6
|
-
* it announces itself at `SessionStart`, checkpoints at every
|
|
7
|
-
* `UserPromptSubmit`, closes out at `SessionEnd`, and reports its transcript
|
|
8
|
-
* at `Stop` (the last checkpoint before teardown).
|
|
9
|
-
*
|
|
10
|
-
* Those checkpoints are also the only liveness signal an observed session ever
|
|
11
|
-
* emits, so each one stamps `lastCheckpointAt` — the field the session's derived
|
|
12
|
-
* phase reads to decide whether a terminal is still working.
|
|
13
|
-
*
|
|
14
|
-
* `SessionStart` additionally answers with `stagedContext`: the same staged
|
|
15
|
-
* environment an ARCS-owned headless run carries on `--append-system-prompt`,
|
|
16
|
-
* so a terminal a human drives knows its project, its workspace and its DAG
|
|
17
|
-
* position without the human setting the stage by hand. See
|
|
18
|
-
* `sessionStartContext` for what differs from the owned path.
|
|
19
|
-
*
|
|
20
|
-
* The response stays ARCS-shaped (`{sessionId, stagedContext?}`); turning that
|
|
21
|
-
* into Claude Code's `hookSpecificOutput` envelope is the hook script's job, so
|
|
22
|
-
* a change to Claude Code's wire format never reaches the server.
|
|
23
|
-
*
|
|
24
|
-
* Unlike every other route here this one is not browser-facing, so it sits
|
|
25
|
-
* behind `requireHookToken` in addition to the global loopback check.
|
|
26
|
-
*/
|
|
27
|
-
import { join } from "node:path";
|
|
28
|
-
import { Hono } from "hono";
|
|
29
|
-
import { z } from "zod";
|
|
30
|
-
import { mirrorSessionTranscript } from "../../utils/claude-transcript.js";
|
|
31
|
-
import { HOOK_EVENTS } from "../../utils/hook-contract.js";
|
|
32
|
-
import { readJsonSafe } from "../../utils/json.js";
|
|
33
|
-
import { readPlanIndex } from "../../utils/plan-store.js";
|
|
34
|
-
import { getSession, updateSession, upsertSession, } from "../../utils/session-store.js";
|
|
35
|
-
import { listTasks } from "../../utils/task-store.js";
|
|
36
|
-
import { deriveOperatingBrief } from "../../utils/workflow-policy.js";
|
|
37
|
-
import { buildStagedEnvironment, stripStageDelimiters } from "../prompt-assembly.js";
|
|
38
|
-
import { parseBody, requireProjectDir, respond } from "../respond.js";
|
|
39
|
-
export const hookEventsRoute = new Hono();
|
|
40
|
-
/**
|
|
41
|
-
* Claude Code's native stdin fields, forwarded verbatim by the hook script.
|
|
42
|
-
* Unknown extra fields are ignored rather than rejected — Claude Code adds
|
|
43
|
-
* fields between releases and a hook must not start failing because of it.
|
|
44
|
-
*
|
|
45
|
-
* The accepted event names come straight from the bridge contract: the server
|
|
46
|
-
* cannot end up rejecting an event the installer registered the hook for.
|
|
47
|
-
*/
|
|
48
|
-
const hookEventSchema = z.object({
|
|
49
|
-
hook_event_name: z.enum(HOOK_EVENTS),
|
|
50
|
-
session_id: z.string().min(1),
|
|
51
|
-
cwd: z.string().optional(),
|
|
52
|
-
source: z.string().optional(),
|
|
53
|
-
prompt: z.string().optional(),
|
|
54
|
-
reason: z.string().optional(),
|
|
55
|
-
transcript_path: z.string().optional(),
|
|
56
|
-
control: z.string().optional(),
|
|
57
|
-
});
|
|
58
|
-
/**
|
|
59
|
-
* Builds the metadata persisted on the session. Claude Code's `cwd` lands under
|
|
60
|
-
* the `directory` key: that is the metadata key the sessions UI already reads,
|
|
61
|
-
* so every session renders its worktree the same way.
|
|
62
|
-
* `transcript_path` is persisted under `transcriptPath` (the sessions UI reads
|
|
63
|
-
* that key) so headless-run write-backs can resolve the transcript without the
|
|
64
|
-
* client resupplying it, and `control` is persisted verbatim for back-compat
|
|
65
|
-
* with readers that still display it — it no longer decides anything here, the
|
|
66
|
-
* session's persisted `origin` does.
|
|
67
|
-
*/
|
|
68
|
-
function sessionMetadata(event) {
|
|
69
|
-
const metadata = {
|
|
70
|
-
...(event.cwd && { directory: event.cwd }),
|
|
71
|
-
...(event.source && { source: event.source }),
|
|
72
|
-
...(event.control !== undefined && { control: event.control }),
|
|
73
|
-
...(event.transcript_path !== undefined && { transcriptPath: event.transcript_path }),
|
|
74
|
-
};
|
|
75
|
-
return Object.keys(metadata).length > 0 ? metadata : undefined;
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Registers (or refreshes) the session behind a hook event.
|
|
79
|
-
*
|
|
80
|
-
* Anything announcing itself through this endpoint is by definition a real
|
|
81
|
-
* terminal session ARCS is watching, so a record created here is `observed` —
|
|
82
|
-
* the origin that opts it into transcript mirroring. Provenance is create-only
|
|
83
|
-
* in the store, so an event arriving for an ARCS-owned thread refreshes it
|
|
84
|
-
* without demoting it.
|
|
85
|
-
*/
|
|
86
|
-
function registerSession(projectDir, event) {
|
|
87
|
-
const metadata = sessionMetadata(event);
|
|
88
|
-
return upsertSession(projectDir, {
|
|
89
|
-
runtimeType: "claude-code",
|
|
90
|
-
runtimeSessionId: event.session_id,
|
|
91
|
-
origin: "observed",
|
|
92
|
-
status: "active",
|
|
93
|
-
...(metadata && { metadata }),
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Records the checkpoint itself, plus whatever it carried.
|
|
98
|
-
*
|
|
99
|
-
* `lastCheckpointAt` is written at EVERY UserPromptSubmit and Stop, even for an
|
|
100
|
-
* event with no metadata at all: it is the only proof of life a session ARCS
|
|
101
|
-
* merely observes ever emits, and the derived phase reads nothing else for such
|
|
102
|
-
* a session. Miss one and a working terminal reads idle.
|
|
103
|
-
*
|
|
104
|
-
* ISO-8601, like every other top-level session timestamp (`metadata.run` keeps
|
|
105
|
-
* epoch ms — the two units never mix). Checkpoint-derived metadata
|
|
106
|
-
* (transcriptPath, directory…) rides the same write, so the transcript path a
|
|
107
|
-
* checkpoint carries is still never dropped.
|
|
108
|
-
*/
|
|
109
|
-
async function persistCheckpoint(projectDir, session, event) {
|
|
110
|
-
const metadata = sessionMetadata(event);
|
|
111
|
-
return updateSession(projectDir, {
|
|
112
|
-
id: session.normalizedId,
|
|
113
|
-
lastCheckpointAt: new Date().toISOString(),
|
|
114
|
-
...(metadata !== undefined && { metadata }),
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Whether a checkpoint's runtime transcript should be mirrored into the
|
|
119
|
-
* session's sidecar.
|
|
120
|
-
*
|
|
121
|
-
* Only sessions ARCS observes qualify. An `arcs`-origin record owns its sidecar
|
|
122
|
-
* through the run route's own turn appends, so mirroring a runtime transcript
|
|
123
|
-
* on top would duplicate the conversation. The rule reads the persisted origin,
|
|
124
|
-
* never `metadata.control`.
|
|
125
|
-
*/
|
|
126
|
-
function shouldMirrorTranscript(session) {
|
|
127
|
-
return session.origin === "observed";
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Resolves the session behind a checkpoint, registering it if this is the first
|
|
131
|
-
* event ARCS has seen. `resume`/`compact` can deliver a prompt for a session
|
|
132
|
-
* whose SessionStart never reached us, and dropping the checkpoint would cost
|
|
133
|
-
* the session its only proof of life.
|
|
134
|
-
*/
|
|
135
|
-
async function resolveCheckpointSession(projectDir, event) {
|
|
136
|
-
try {
|
|
137
|
-
return await getSession(projectDir, event.session_id);
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
return registerSession(projectDir, event);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
// ---------------------------------------------------------------------------
|
|
144
|
-
// SessionStart staged context
|
|
145
|
-
// ---------------------------------------------------------------------------
|
|
146
|
-
/**
|
|
147
|
-
* Ceiling on the block a SessionStart mirrors into a terminal, in characters.
|
|
148
|
-
*
|
|
149
|
-
* Deliberately far below `STAGE_SOFT_CAP` (6000): that budget is spent inside a
|
|
150
|
-
* headless `claude -p` process nobody is watching, whereas this text lands at
|
|
151
|
-
* the head of a live session a human is about to type into. Anything wider buys
|
|
152
|
-
* context nobody asked for at the cost of the window they did.
|
|
153
|
-
*
|
|
154
|
-
* Enforced by SELECTION, never by clipping — see `sessionStartContext`.
|
|
155
|
-
* `scripts/claude-code-session-hook.mjs` carries its own, wider refusal bound
|
|
156
|
-
* (`MAX_CONTEXT_CHARS`), pinned against this constant by
|
|
157
|
-
* `test/claude-code-hook-script.test.ts`.
|
|
158
|
-
*/
|
|
159
|
-
export const SESSION_START_STAGE_CAP = 2500;
|
|
160
|
-
/** Width for one value interpolated into the degraded block. */
|
|
161
|
-
const DEGRADED_FIELD_WIDTH = 160;
|
|
162
|
-
/**
|
|
163
|
-
* Normalizes one untrusted value for an ARCS-authored line: delimiter-stripped,
|
|
164
|
-
* whitespace-collapsed, width-bounded. Mirrors prompt-assembly's `field` (not
|
|
165
|
-
* exported), and applies to EVERY slot below rather than to the values that
|
|
166
|
-
* look risky — a project name and a task title are both agent- or user-authored
|
|
167
|
-
* text arriving in the controller's voice.
|
|
168
|
-
*/
|
|
169
|
-
function degradedField(value, width = DEGRADED_FIELD_WIDTH) {
|
|
170
|
-
const clean = stripStageDelimiters(value).replace(/\s+/g, " ").trim();
|
|
171
|
-
return clean.length <= width ? clean : `${clean.slice(0, width - 1)}…`;
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* The two lines a session with nothing staged for it still deserves.
|
|
175
|
-
*
|
|
176
|
-
* An observed session carries no `linkedNodeId` until a human sets one —
|
|
177
|
-
* discovery never links — so this is the COMMON case at SessionStart, not an
|
|
178
|
-
* edge. It therefore states what is true and useful (which project this
|
|
179
|
-
* workspace is, how to read its DAG, and what the operating brief says the
|
|
180
|
-
* project is currently on) instead of apologising for the missing link.
|
|
181
|
-
*
|
|
182
|
-
* No wrapper, and none needed: nothing here is a quoted body. The two variable
|
|
183
|
-
* values are stripped, collapsed and width-bounded through `degradedField`,
|
|
184
|
-
* exactly as prompt-assembly treats the same task title in its own brief block.
|
|
185
|
-
*/
|
|
186
|
-
async function degradedStagedContext(projectDir, slug) {
|
|
187
|
-
const [projectMeta, tasks, planIndex] = await Promise.all([
|
|
188
|
-
readJsonSafe(join(projectDir, "meta.json")),
|
|
189
|
-
listTasks(projectDir),
|
|
190
|
-
readPlanIndex(projectDir),
|
|
191
|
-
]);
|
|
192
|
-
const operating = deriveOperatingBrief({
|
|
193
|
-
tasks: tasks.map((t) => ({
|
|
194
|
-
id: t.id,
|
|
195
|
-
title: t.title,
|
|
196
|
-
status: t.status,
|
|
197
|
-
planId: t.planId,
|
|
198
|
-
priority: t.priority,
|
|
199
|
-
dependsOn: t.dependsOn,
|
|
200
|
-
})),
|
|
201
|
-
plans: planIndex.plans.map((p) => ({ id: p.id, title: p.title, status: p.status })),
|
|
202
|
-
});
|
|
203
|
-
return [
|
|
204
|
-
`This workspace is tracked by ARCS as project ${degradedField(slug)} ` +
|
|
205
|
-
`"${degradedField(projectMeta?.name ?? slug)}" — read its DAG with ` +
|
|
206
|
-
`\`arcs brief ${degradedField(slug)} --lean --json\`. Link this session to a task in the ` +
|
|
207
|
-
"ARCS web UI to stage that task's scope, acceptance and verify command here.",
|
|
208
|
-
`Project current focus: ${degradedField(operating.currentFocus)} · ` +
|
|
209
|
-
`Next action: ${degradedField(operating.nextAction)}`,
|
|
210
|
-
].join("\n");
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* The staged block a SessionStart answers with, or nothing at all.
|
|
214
|
-
*
|
|
215
|
-
* Same builder as an ARCS-owned headless run (`buildStagedEnvironment`), and
|
|
216
|
-
* deliberately NOT the same call:
|
|
217
|
-
* - no references — those are attached per SEND, and a session that has not
|
|
218
|
-
* started yet has none;
|
|
219
|
-
* - no argv, no permission segment — the terminal's user owns their own
|
|
220
|
-
* permissions and ARCS does not get to narrow them from here;
|
|
221
|
-
* - a much tighter cap (see SESSION_START_STAGE_CAP);
|
|
222
|
-
* - STATELESS — no fingerprint, no `metadata.stage`, no restage bookkeeping at
|
|
223
|
-
* all. The staleness machinery exists to avoid re-injecting an unchanged
|
|
224
|
-
* block across turns of one conversation; a SessionStart IS turn zero, so
|
|
225
|
-
* there is nothing to compare against and nothing to persist.
|
|
226
|
-
*
|
|
227
|
-
* The cap is enforced by SELECTION — the whole assembled text, or the whole
|
|
228
|
-
* degraded block — never by clipping the assembled text. A head truncation
|
|
229
|
-
* would keep an untrusted body's opener and sever its closer, putting every
|
|
230
|
-
* later ARCS-authored line (including the one stating the controller's own
|
|
231
|
-
* scope) inside an unterminated untrusted region. `softCap` lets the builder's
|
|
232
|
-
* own ladder degrade gracefully first; the degraded block is the floor for the
|
|
233
|
-
* DAG wide enough that even a fully degraded build does not fit.
|
|
234
|
-
*
|
|
235
|
-
* Any failure returns `undefined`: the hook script's hard rule is that a broken
|
|
236
|
-
* bridge is invisible, so a staging error must reach it as an absent field, not
|
|
237
|
-
* as a 500.
|
|
238
|
-
*
|
|
239
|
-
* ONE builder, but not one wording: prompt-assembly conditions its IDENTITY and
|
|
240
|
-
* LIMITS blocks on the session's PERSISTED origin, and provenance is CREATE-ONLY
|
|
241
|
-
* (see `registerSession`). A first sighting is created `observed`; an event
|
|
242
|
-
* arriving for an ARCS-owned thread refreshes it without demoting it, so an
|
|
243
|
-
* `arcs`-origin session reaching SessionStart keeps its origin and therefore gets
|
|
244
|
-
* the `arcs` variant. Either variant states what is true of THAT session — for
|
|
245
|
-
* the observed one, that ARCS is NOT setting its tools, permissions or lifecycle,
|
|
246
|
-
* which the bullets above are the reason for, since no argv exists to set them
|
|
247
|
-
* with. The untrusted-content half is identical on both origins; only the claim
|
|
248
|
-
* of control moves.
|
|
249
|
-
*/
|
|
250
|
-
async function sessionStartContext(projectDir, slug, session, event) {
|
|
251
|
-
try {
|
|
252
|
-
if (session.linkedNodeType && session.linkedNodeId) {
|
|
253
|
-
const staged = await buildStagedEnvironment(projectDir, slug, session, {
|
|
254
|
-
// Claude Code's own cwd: the directory this terminal is actually in,
|
|
255
|
-
// which is a truer workspace root than the project's registered first
|
|
256
|
-
// path when a project spans more than one checkout.
|
|
257
|
-
...(event.cwd && { workspaceRoot: event.cwd }),
|
|
258
|
-
softCap: SESSION_START_STAGE_CAP,
|
|
259
|
-
});
|
|
260
|
-
if (staged.text.length <= SESSION_START_STAGE_CAP)
|
|
261
|
-
return staged.text;
|
|
262
|
-
}
|
|
263
|
-
return await degradedStagedContext(projectDir, slug);
|
|
264
|
-
}
|
|
265
|
-
catch {
|
|
266
|
-
return undefined;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
async function handleHookEvent(projectDir, slug, event) {
|
|
270
|
-
if (event.hook_event_name === "SessionStart") {
|
|
271
|
-
const session = await registerSession(projectDir, event);
|
|
272
|
-
const stagedContext = await sessionStartContext(projectDir, slug, session, event);
|
|
273
|
-
return {
|
|
274
|
-
sessionId: session.normalizedId,
|
|
275
|
-
...(stagedContext !== undefined && { stagedContext }),
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
if (event.hook_event_name === "UserPromptSubmit") {
|
|
279
|
-
const session = await resolveCheckpointSession(projectDir, event);
|
|
280
|
-
const checkpoint = await persistCheckpoint(projectDir, session, event);
|
|
281
|
-
if (event.transcript_path !== undefined && shouldMirrorTranscript(checkpoint)) {
|
|
282
|
-
await mirrorSessionTranscript(projectDir, checkpoint.normalizedId, event.transcript_path);
|
|
283
|
-
}
|
|
284
|
-
return { sessionId: checkpoint.normalizedId };
|
|
285
|
-
}
|
|
286
|
-
if (event.hook_event_name === "Stop") {
|
|
287
|
-
// Stop is a checkpoint like UserPromptSubmit, so an unknown session is
|
|
288
|
-
// auto-registered rather than dropped.
|
|
289
|
-
const session = await resolveCheckpointSession(projectDir, event);
|
|
290
|
-
const checkpoint = await persistCheckpoint(projectDir, session, event);
|
|
291
|
-
if (event.transcript_path !== undefined && shouldMirrorTranscript(checkpoint)) {
|
|
292
|
-
await mirrorSessionTranscript(projectDir, checkpoint.normalizedId, event.transcript_path);
|
|
293
|
-
}
|
|
294
|
-
return { sessionId: checkpoint.normalizedId };
|
|
295
|
-
}
|
|
296
|
-
// SessionEnd. Every documented reason (clear|resume|logout|other) is an
|
|
297
|
-
// ordinary teardown — none of them signals a crash, so none maps to "failed".
|
|
298
|
-
const metadata = sessionMetadata(event);
|
|
299
|
-
const session = await updateSession(projectDir, {
|
|
300
|
-
id: event.session_id,
|
|
301
|
-
status: "completed",
|
|
302
|
-
...(metadata !== undefined && { metadata }),
|
|
303
|
-
});
|
|
304
|
-
if (event.transcript_path !== undefined && shouldMirrorTranscript(session)) {
|
|
305
|
-
await mirrorSessionTranscript(projectDir, session.normalizedId, event.transcript_path);
|
|
306
|
-
}
|
|
307
|
-
return { sessionId: session.normalizedId };
|
|
308
|
-
}
|
|
309
|
-
hookEventsRoute.post("/api/hook/:slug/event", async (c) => respond(c, async () => {
|
|
310
|
-
const slug = c.req.param("slug");
|
|
311
|
-
// Validates the slug before it is threaded on to the stager, which uses it
|
|
312
|
-
// both as a knowledge-selection key and as an interpolated identity value.
|
|
313
|
-
const projectDir = requireProjectDir(slug);
|
|
314
|
-
return handleHookEvent(projectDir, slug, await parseBody(c, hookEventSchema));
|
|
315
|
-
}));
|
|
316
|
-
//# sourceMappingURL=hook-events.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hook-events.js","sourceRoot":"","sources":["../../../src/web-server/routes/hook-events.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: install-claude-code-hook
|
|
3
|
-
description: Install the ARCS session-bridge hook into an existing Claude Code workspace
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Install Claude Code Hook
|
|
7
|
-
|
|
8
|
-
## Boundary
|
|
9
|
-
|
|
10
|
-
Claude Code only. If the current harness is not Claude Code, stop. The hook changes `.claude/settings.local.json`, so obtain explicit confirmation before using `--write`.
|
|
11
|
-
|
|
12
|
-
## Method
|
|
13
|
-
|
|
14
|
-
1. Run `arcs hooks status <slug> --json`.
|
|
15
|
-
2. If already installed for this slug, report a no-op.
|
|
16
|
-
3. Explain the file written, registered events, local token, and that a new Claude Code session is required.
|
|
17
|
-
4. If the hook points at another slug, warn that installation will repoint it and confirm that effect.
|
|
18
|
-
5. After explicit confirmation, run `arcs hooks install-claude-code <slug> --write --json` once.
|
|
19
|
-
6. Report `settingsPath`, events, and next-session requirement.
|
|
20
|
-
|
|
21
|
-
Do not hand-edit Claude settings. A malformed settings file is a stop condition: surface the CLI error and do not repair, reformat, or delete it. Do not rerun installation for reassurance because it may rotate the token.
|
|
22
|
-
|
|
23
|
-
Without confirmation, offer the snippet-only command without `--write`.
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* ARCS ↔ Claude Code session-bridge hook.
|
|
4
|
-
*
|
|
5
|
-
* Registered four times in settings.json (SessionStart, UserPromptSubmit,
|
|
6
|
-
* SessionEnd, Stop) and dispatches internally on the `hook_event_name` field
|
|
7
|
-
* Claude Code writes to stdin. Install with `arcs hooks install-claude-code
|
|
8
|
-
* <slug>`, which generates the token and prints the snippet to paste.
|
|
9
|
-
*
|
|
10
|
-
* One of the four can put text in front of the model: SessionStart mirrors
|
|
11
|
-
* ARCS's staged environment (project, workspace, DAG position) into the new
|
|
12
|
-
* session, emitting Claude Code's `hookSpecificOutput` envelope on stdout; the
|
|
13
|
-
* other three print nothing.
|
|
14
|
-
*
|
|
15
|
-
* HARD RULE: this script never blocks the session. Any failure — ARCS not
|
|
16
|
-
* running, token rejected, timeout, malformed JSON — is swallowed, nothing is
|
|
17
|
-
* printed, and the exit code stays 0. Exit code 2 (the "block" signal) is never
|
|
18
|
-
* produced. A broken bridge must be invisible, never an obstacle to the user's
|
|
19
|
-
* actual Claude Code session.
|
|
20
|
-
*
|
|
21
|
-
* Config comes from the environment, assigned inline in the settings.json
|
|
22
|
-
* command string:
|
|
23
|
-
* ARCS_HOOK_TOKEN per-project token (required)
|
|
24
|
-
* ARCS_HOOK_SLUG ARCS project slug (required)
|
|
25
|
-
* ARCS_HOOK_URL ARCS web server URL (default http://127.0.0.1:4173)
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
// DEFAULT_URL and EVENTS are literals on purpose: this file runs standalone out
|
|
29
|
-
// of the user's settings.json and importing ARCS would give the HARD RULE above
|
|
30
|
-
// a way to fail. `src/utils/hook-contract.ts` owns the same two values for the
|
|
31
|
-
// TypeScript side, and `test/hook-contract-parity.test.ts` parses THIS source
|
|
32
|
-
// and fails if the two ever diverge — so keep the shapes greppable: a
|
|
33
|
-
// double-quoted DEFAULT_URL, and a flat `new Set([...])` of string literals.
|
|
34
|
-
const DEFAULT_URL = "http://127.0.0.1:4173";
|
|
35
|
-
/** Short by design: a hung ARCS server must not stall prompt submission. */
|
|
36
|
-
const TIMEOUT_MS = 1500;
|
|
37
|
-
const EVENTS = new Set(["SessionStart", "UserPromptSubmit", "SessionEnd", "Stop"]);
|
|
38
|
-
/**
|
|
39
|
-
* Refusal bound on a context block the server sends, in characters.
|
|
40
|
-
*
|
|
41
|
-
* The server caps the SessionStart block at 2500 (`SESSION_START_STAGE_CAP` in
|
|
42
|
-
* `src/web-server/routes/hook-events.ts`); this is the CLIENT's own limit, so a
|
|
43
|
-
* misbehaving, mismatched or hostile ARCS cannot shove an unbounded body into
|
|
44
|
-
* the head of the user's live session. Over the bound the block is dropped
|
|
45
|
-
* whole rather than clipped — a clip would sever a wrapper's closing delimiter.
|
|
46
|
-
* `test/claude-code-hook-script.test.ts` parses this literal and fails if the
|
|
47
|
-
* server's cap ever climbs above it, so the two cannot silently cross.
|
|
48
|
-
*/
|
|
49
|
-
const MAX_CONTEXT_CHARS = 4000;
|
|
50
|
-
|
|
51
|
-
/** Never rejects: an unreadable stdin yields "" and the run turns into a no-op. */
|
|
52
|
-
function readStdin() {
|
|
53
|
-
return new Promise((resolveStdin) => {
|
|
54
|
-
let raw = "";
|
|
55
|
-
let settled = false;
|
|
56
|
-
const finish = () => {
|
|
57
|
-
if (settled) return;
|
|
58
|
-
settled = true;
|
|
59
|
-
clearTimeout(timer);
|
|
60
|
-
process.stdin.destroy();
|
|
61
|
-
resolveStdin(raw);
|
|
62
|
-
};
|
|
63
|
-
const timer = setTimeout(finish, TIMEOUT_MS);
|
|
64
|
-
|
|
65
|
-
process.stdin.setEncoding("utf-8");
|
|
66
|
-
process.stdin.on("data", (chunk) => {
|
|
67
|
-
raw += chunk;
|
|
68
|
-
});
|
|
69
|
-
process.stdin.on("end", finish);
|
|
70
|
-
process.stdin.on("error", finish);
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async function main() {
|
|
75
|
-
const raw = await readStdin();
|
|
76
|
-
if (!raw.trim()) return;
|
|
77
|
-
|
|
78
|
-
const event = JSON.parse(raw);
|
|
79
|
-
const eventName = event?.hook_event_name;
|
|
80
|
-
const sessionId = event?.session_id;
|
|
81
|
-
if (!EVENTS.has(eventName) || typeof sessionId !== "string" || !sessionId) return;
|
|
82
|
-
|
|
83
|
-
const token = process.env.ARCS_HOOK_TOKEN;
|
|
84
|
-
const slug = process.env.ARCS_HOOK_SLUG;
|
|
85
|
-
if (!token || !slug) return;
|
|
86
|
-
const baseUrl = (process.env.ARCS_HOOK_URL || DEFAULT_URL).replace(/\/+$/, "");
|
|
87
|
-
|
|
88
|
-
const response = await fetch(`${baseUrl}/api/hook/${encodeURIComponent(slug)}/event`, {
|
|
89
|
-
method: "POST",
|
|
90
|
-
headers: {
|
|
91
|
-
"content-type": "application/json",
|
|
92
|
-
authorization: `Bearer ${token}`,
|
|
93
|
-
},
|
|
94
|
-
body: JSON.stringify({
|
|
95
|
-
hook_event_name: eventName,
|
|
96
|
-
session_id: sessionId,
|
|
97
|
-
...(typeof event.cwd === "string" && { cwd: event.cwd }),
|
|
98
|
-
...(typeof event.source === "string" && { source: event.source }),
|
|
99
|
-
...(typeof event.reason === "string" && { reason: event.reason }),
|
|
100
|
-
...(typeof event.transcript_path === "string" && { transcript_path: event.transcript_path }),
|
|
101
|
-
}),
|
|
102
|
-
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
103
|
-
});
|
|
104
|
-
if (!response.ok) return;
|
|
105
|
-
|
|
106
|
-
// Only SessionStart can inject context: it mirrors ARCS's staged environment
|
|
107
|
-
// into the fresh session. UserPromptSubmit, SessionEnd and Stop are pure
|
|
108
|
-
// notifications and answer with empty stdout, so only SessionStart reads the
|
|
109
|
-
// response body at all.
|
|
110
|
-
if (eventName !== "SessionStart") return;
|
|
111
|
-
|
|
112
|
-
const envelope = await response.json();
|
|
113
|
-
|
|
114
|
-
const staged = envelope?.data?.stagedContext;
|
|
115
|
-
// Every rejection here is a silent no-op, never a repair: an absent field,
|
|
116
|
-
// a non-string, an empty string and an oversized body all mean "ARCS has
|
|
117
|
-
// nothing usable to stage", and the session proceeds exactly as if the
|
|
118
|
-
// bridge were not installed.
|
|
119
|
-
if (typeof staged !== "string" || staged === "" || staged.length > MAX_CONTEXT_CHARS) return;
|
|
120
|
-
|
|
121
|
-
process.stdout.write(
|
|
122
|
-
JSON.stringify({
|
|
123
|
-
hookSpecificOutput: {
|
|
124
|
-
hookEventName: "SessionStart",
|
|
125
|
-
additionalContext: staged,
|
|
126
|
-
},
|
|
127
|
-
}),
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Belt and braces around the hard rule: even a bug in this file (or a stray
|
|
132
|
-
// async rejection) must not surface as a non-zero exit for the user.
|
|
133
|
-
process.on("uncaughtException", () => {
|
|
134
|
-
process.exitCode = 0;
|
|
135
|
-
});
|
|
136
|
-
process.on("unhandledRejection", () => {
|
|
137
|
-
process.exitCode = 0;
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// No process.exit(): letting the event loop drain guarantees stdout is flushed
|
|
141
|
-
// before the process ends, and the default exit code is already 0.
|
|
142
|
-
main()
|
|
143
|
-
.catch(() => {})
|
|
144
|
-
.finally(() => {
|
|
145
|
-
process.exitCode = 0;
|
|
146
|
-
});
|