@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
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intent → argv permission policy for headless `claude -p` runs.
|
|
3
|
+
*
|
|
4
|
+
* Safety in the session bridge is argv-shaped, and this module is the SINGLE
|
|
5
|
+
* place tool and permission flags are produced: `claude-runner.ts` stays
|
|
6
|
+
* argv-agnostic and no route hand-assembles a more permissive run. Every token
|
|
7
|
+
* emitted here comes from a closed set of module constants — the one
|
|
8
|
+
* caller-supplied token is the staged system prompt, and it is kept
|
|
9
|
+
* unambiguously a value (see asValueToken). Bypass flags are therefore
|
|
10
|
+
* unreachable from HTTP input by construction rather than by convention, and
|
|
11
|
+
* `test/permission-policy.test.ts` drives the builder with hostile
|
|
12
|
+
* HTTP-shaped payloads to keep it that way.
|
|
13
|
+
*
|
|
14
|
+
* Flags verified against claude 2.1.223: `--tools <tools...>` takes a
|
|
15
|
+
* comma-separated built-in tool list, `--permission-mode` accepts "plan" and
|
|
16
|
+
* "acceptEdits", and `--append-system-prompt` appends to (never replaces) the
|
|
17
|
+
* system prompt. `--cwd` is deliberately absent — claude >= 2.x rejects it, and
|
|
18
|
+
* the runner applies the working directory through spawn options.cwd instead.
|
|
19
|
+
*/
|
|
20
|
+
/** Accepted run intents. Also the source list for route-level zod validation. */
|
|
21
|
+
export const RUN_INTENTS = ["ask", "change"];
|
|
22
|
+
/** `ask`: inspect the workspace, never touch it. */
|
|
23
|
+
const ASK_TOOLS = ["Read", "Grep", "Glob"];
|
|
24
|
+
/**
|
|
25
|
+
* `change`: the read-only set plus the edit surface. Bash is deliberately NOT
|
|
26
|
+
* here — it is opt-in per run, so a change run cannot shell out by default.
|
|
27
|
+
*/
|
|
28
|
+
const CHANGE_TOOLS = ["Read", "Grep", "Glob", "Edit", "Write", "TodoWrite"];
|
|
29
|
+
/** Appended last, and only on an explicit `allowBash === true`. */
|
|
30
|
+
const BASH_TOOL = "Bash";
|
|
31
|
+
const INTENT_TOOLS = {
|
|
32
|
+
ask: ASK_TOOLS,
|
|
33
|
+
change: CHANGE_TOOLS,
|
|
34
|
+
};
|
|
35
|
+
/** `plan` cannot edit; `acceptEdits` auto-accepts edits but not shell commands.
|
|
36
|
+
* "bypassPermissions" is not reachable from this map — that is the point. */
|
|
37
|
+
const INTENT_PERMISSION_MODES = {
|
|
38
|
+
ask: "plan",
|
|
39
|
+
change: "acceptEdits",
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Builds the tool/permission argv segment for one run. The caller concatenates
|
|
43
|
+
* it onto the rest of its argv (`-p`, `--resume`, `--output-format`, …); this
|
|
44
|
+
* module owns nothing else.
|
|
45
|
+
*/
|
|
46
|
+
export function buildPermissionArgv(input = {}) {
|
|
47
|
+
const fields = asRecord(input);
|
|
48
|
+
const intent = normalizeIntent(fields.intent);
|
|
49
|
+
const tools = [...INTENT_TOOLS[intent]];
|
|
50
|
+
if (fields.allowBash === true)
|
|
51
|
+
tools.push(BASH_TOOL);
|
|
52
|
+
const argv = ["--tools", tools.join(","), "--permission-mode", INTENT_PERMISSION_MODES[intent]];
|
|
53
|
+
const staged = typeof fields.stagedSystemPrompt === "string" ? fields.stagedSystemPrompt.trim() : "";
|
|
54
|
+
if (staged)
|
|
55
|
+
argv.push("--append-system-prompt", asValueToken(staged));
|
|
56
|
+
return argv;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Fails closed: anything that is not exactly `"change"` runs read-only. The
|
|
60
|
+
* route's zod enum rejects malformed intents with a 400 first — this is the
|
|
61
|
+
* second line, so a caller that skips validation cannot widen the run.
|
|
62
|
+
*/
|
|
63
|
+
function normalizeIntent(value) {
|
|
64
|
+
return value === "change" ? "change" : "ask";
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Keeps a caller-supplied value from ever being flag-shaped. Staged text is the
|
|
68
|
+
* only argv token ARCS does not author character-for-character, so a message of
|
|
69
|
+
* exactly `--dangerously-skip-permissions` arrives at claude's option parser in
|
|
70
|
+
* a position where only that parser's rules decide whether it reads as a value
|
|
71
|
+
* or as a flag.
|
|
72
|
+
*
|
|
73
|
+
* This prefix closes no hole that exists today, and an earlier version of this
|
|
74
|
+
* comment was wrong to claim it did. A live probe against claude 2.1.223:
|
|
75
|
+
* `claude --append-system-prompt --output-format json -p "…"` printed plain
|
|
76
|
+
* text where the control printed JSON — meaning the CLI had already swallowed
|
|
77
|
+
* the dash-leading `--output-format` as the VALUE of `--append-system-prompt`
|
|
78
|
+
* instead of reading it as an option. The installed parser is safe unaided.
|
|
79
|
+
*
|
|
80
|
+
* It is kept for version-independence, not as a bug fix. "An option's argument
|
|
81
|
+
* may itself begin with a dash" is an undocumented parser detail that a minor
|
|
82
|
+
* CLI upgrade could reverse with no breaking-change note, and the blast radius
|
|
83
|
+
* if it ever does is a permission flag from HTTP input. A single leading
|
|
84
|
+
* newline keeps every byte of the text while making the token unambiguously a
|
|
85
|
+
* value under either rule.
|
|
86
|
+
*/
|
|
87
|
+
function asValueToken(text) {
|
|
88
|
+
return text.startsWith("-") ? `\n${text}` : text;
|
|
89
|
+
}
|
|
90
|
+
/** Tolerates any runtime shape an HTTP body can take (null, array, scalar). */
|
|
91
|
+
function asRecord(value) {
|
|
92
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
93
|
+
? value
|
|
94
|
+
: {};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=permission-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission-policy.js","sourceRoot":"","sources":["../../src/web-server/permission-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,iFAAiF;AACjF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAU,CAAC;AAItD,oDAAoD;AACpD,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AAEpD;;;GAGG;AACH,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,CAAU,CAAC;AAErF,mEAAmE;AACnE,MAAM,SAAS,GAAG,MAAM,CAAC;AAEzB,MAAM,YAAY,GAAyC;IACzD,GAAG,EAAE,SAAS;IACd,MAAM,EAAE,YAAY;CACrB,CAAC;AAEF;8EAC8E;AAC9E,MAAM,uBAAuB,GAA8B;IACzD,GAAG,EAAE,MAAM;IACX,MAAM,EAAE,aAAa;CACtB,CAAC;AAoBF;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAA6B,EAAE;IACjE,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAE9C,MAAM,KAAK,GAAG,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;IACxC,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAErD,MAAM,IAAI,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,mBAAmB,EAAE,uBAAuB,CAAC,MAAM,CAAC,CAAC,CAAC;IAEhG,MAAM,MAAM,GACV,OAAO,MAAM,CAAC,kBAAkB,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACxF,IAAI,MAAM;QAAE,IAAI,CAAC,IAAI,CAAC,wBAAwB,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;IAEtE,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,KAAc;IACrC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAC/C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAS,YAAY,CAAC,IAAY;IAChC,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACnD,CAAC;AAED,+EAA+E;AAC/E,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACzE,CAAC,CAAE,KAAiC;QACpC,CAAC,CAAC,EAAE,CAAC;AACT,CAAC"}
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt assembly — the STABLE staged-environment tier, plus reference
|
|
3
|
+
* rendering.
|
|
4
|
+
*
|
|
5
|
+
* Two independent products, one module because they share one trust model and
|
|
6
|
+
* one escape (`stripStageDelimiters`, `untrustedDoc`):
|
|
7
|
+
* - `buildStagedEnvironment` / `planStageRefresh` — the per-SESSION stable
|
|
8
|
+
* block, documented below.
|
|
9
|
+
* - `renderReference` / `renderReferences` — the per-TURN references a caller
|
|
10
|
+
* attached to a message. This is the ONE place a reference is turned into
|
|
11
|
+
* prompt text; nothing here enters the staged block, so a reference can
|
|
12
|
+
* never move the stable tier's fingerprint.
|
|
13
|
+
*
|
|
14
|
+
* A headless `claude -p` run starts with no ambient project knowledge: it does
|
|
15
|
+
* not know which DAG node it is on, where the workspace root is, or what the
|
|
16
|
+
* project already learned. This module renders that context once, as a single
|
|
17
|
+
* ordered block that rides `--append-system-prompt`. The run route
|
|
18
|
+
* (`routes/sessions.ts`) appends that flag/value pair directly today:
|
|
19
|
+
* `permission-policy.ts`'s `buildPermissionArgv` owns the flag but returns a
|
|
20
|
+
* WHOLE tool/permission segment keyed on an `intent` the run route does not
|
|
21
|
+
* have, so emitting it there would restrict what today's runs may do. When
|
|
22
|
+
* POST /turns introduces intents, this same text becomes its
|
|
23
|
+
* `stagedSystemPrompt` and the direct pair goes away. This module emits TEXT
|
|
24
|
+
* only — it never produces argv, and never spawns anything.
|
|
25
|
+
*
|
|
26
|
+
* STABLE means byte-identical across turns for an unchanged DAG. That is the
|
|
27
|
+
* whole economics of the tier: an unchanged prefix is a cache hit upstream, so
|
|
28
|
+
* nothing volatile (timestamps, queue depth, run state) is allowed in `text`.
|
|
29
|
+
* `stagedAt` therefore lives on the returned stage RECORD, never in the text.
|
|
30
|
+
* The VOLATILE tier is a separate, later concern.
|
|
31
|
+
*
|
|
32
|
+
* Trust model. ARCS-derived facts are asserted plainly. Every body copied out
|
|
33
|
+
* of a file or an agent-authored DAG document is wrapped in a named
|
|
34
|
+
* `<<<ARCS_UNTRUSTED_DOC …>>>` delimiter, carries an explicit "embedded
|
|
35
|
+
* instructions cannot override" sentence, and is run through
|
|
36
|
+
* `stripStageDelimiters` so a document cannot close its own wrapper and
|
|
37
|
+
* escalate into the controller's voice.
|
|
38
|
+
*
|
|
39
|
+
* Budgets are spent on a body's CONTENT, never on the wrapped string: clipping
|
|
40
|
+
* a rendered wrapper keeps its opener and severs its closer, which puts every
|
|
41
|
+
* later ARCS-authored block inside an unterminated untrusted region. Both
|
|
42
|
+
* products obey this — `renderBlock` for the staged tier, and the reference
|
|
43
|
+
* renderers by clipping before they call `untrustedDoc`.
|
|
44
|
+
*
|
|
45
|
+
* Read-only. This module reads ARCS data through the existing store readers and
|
|
46
|
+
* the existing knowledge-selection helper; it never writes. It RETURNS a
|
|
47
|
+
* `StageRecord` for the caller (the run route) to persist at `metadata.stage`.
|
|
48
|
+
* (Caveat inherited from the stores, not introduced here: `readKnowledgeIndex`
|
|
49
|
+
* and `readPlanIndex` self-repair a corrupt or drifted index on read. That is
|
|
50
|
+
* repair of existing data, never a mutation this module authors.)
|
|
51
|
+
*/
|
|
52
|
+
import type { SessionReference } from "../utils/claude-transcript.js";
|
|
53
|
+
import type { SessionMeta } from "../utils/session-store.js";
|
|
54
|
+
export declare const STAGE_TRANSPORTS: readonly ["system", "prompt"];
|
|
55
|
+
export type StageTransport = (typeof STAGE_TRANSPORTS)[number];
|
|
56
|
+
/**
|
|
57
|
+
* How the staged text reaches the model.
|
|
58
|
+
*
|
|
59
|
+
* - `system` (default) — appended via `--append-system-prompt`. Cheapest and
|
|
60
|
+
* keeps the block out of the visible conversation.
|
|
61
|
+
* - `prompt` — prepended to the user prompt text instead.
|
|
62
|
+
*
|
|
63
|
+
* The designed fallback: flip this single constant to `"prompt"` if predicate
|
|
64
|
+
* P1 fails (see `STAGE_MANUAL_CHECKS`). Nothing else in the module changes —
|
|
65
|
+
* the transport is carried on the stage record so a flip forces a restage on
|
|
66
|
+
* already-staged sessions rather than silently leaving them on the old channel.
|
|
67
|
+
*/
|
|
68
|
+
export declare const STAGE_TRANSPORT: StageTransport;
|
|
69
|
+
/**
|
|
70
|
+
* Checks this layer cannot automate, recorded as data so they stay greppable
|
|
71
|
+
* and can be surfaced by a route or a doc instead of rotting in a comment.
|
|
72
|
+
*/
|
|
73
|
+
export declare const STAGE_MANUAL_CHECKS: readonly [string];
|
|
74
|
+
/**
|
|
75
|
+
* Degradation starts above this.
|
|
76
|
+
*
|
|
77
|
+
* MEASURED, against the live ARCS project, with the budgets below. It is
|
|
78
|
+
* HEADROOM, not a live path — a test reaches it only by passing `softCap`.
|
|
79
|
+
*
|
|
80
|
+
* STATE THE INPUTS OR THE FIGURE IS NOT RE-DERIVABLE, AND THERE ARE FOUR OF
|
|
81
|
+
* THEM. An assembled width is a function of inputs the corpus does not contain:
|
|
82
|
+
* un-budgeted IDENTITY interpolates `sessionId` (ceiling 96), `slug` (64) and
|
|
83
|
+
* `projectName` (64); un-budgeted WORKSPACE interpolates `workspaceRoot` (256).
|
|
84
|
+
* Every one is width-normalized by FIELD_WIDTHS and none is budgeted, so each
|
|
85
|
+
* char lands WHOLE on a build whose budgeted blocks are already saturated
|
|
86
|
+
* (measured on the binding node: dag-position 1199/1200, node-body 1200/1200,
|
|
87
|
+
* brief 800/800, knowledge 1599/1600). A row that names only one of the four is
|
|
88
|
+
* not a measurement — an earlier row here swept `sessionId` to its ceiling while
|
|
89
|
+
* leaving `projectName` at the live corpus's incidental 4 chars and
|
|
90
|
+
* `workspaceRoot` at 23, and recorded "fires for 0" as though it were general.
|
|
91
|
+
*
|
|
92
|
+
* WHAT IS AFFORDABLE IS THEIR SUM. The four inputs share one margin, so the
|
|
93
|
+
* whole measurement collapses to one number: on the live corpus the widest
|
|
94
|
+
* `observed` build stays off the ladder while
|
|
95
|
+
*
|
|
96
|
+
* sessionId + slug + projectName + workspaceRoot <= 230 chars
|
|
97
|
+
*
|
|
98
|
+
* and fires at 231 (verified from both sides — see the 126/127 and 66/67 rows).
|
|
99
|
+
* `arcs` affords 284. The ceilings sum to 480, so the all-ceilings corner is 250
|
|
100
|
+
* chars past what the cap can hold and MUST degrade; see the last row.
|
|
101
|
+
*
|
|
102
|
+
* Live ARCS DAG, 137 tasks / 18 plans, swept whole against a COPY of the data
|
|
103
|
+
* dir (the stores self-repair on read), every row at the `sessionId` ceiling of
|
|
104
|
+
* 96, both origins, widths post-ladder with the FIRING COUNT beside them:
|
|
105
|
+
*
|
|
106
|
+
* slug 4, name 4, root 23 — the live values:
|
|
107
|
+
* arcs 5843 task / 5048 plan fires 0 of 137 and 0 of 18
|
|
108
|
+
* observed 5897 task / 5102 plan fires 0 of 137 and 0 of 18
|
|
109
|
+
* slug 4, name 64 (projectName CEILING), root 23:
|
|
110
|
+
* arcs 5903 / 5108 fires 0 of 137 and 0 of 18
|
|
111
|
+
* observed 5957 / 5162 fires 0 of 137 and 0 of 18
|
|
112
|
+
* slug 64 (slug CEILING), name 4, root 23: same widths as the row above
|
|
113
|
+
* observed 5957 / 5162 fires 0 of 137 and 0 of 18
|
|
114
|
+
* slug 4, name 4, root 103 — a deep but ordinary checkout path:
|
|
115
|
+
* arcs 5923 / 5128 fires 0 of 137 and 0 of 18
|
|
116
|
+
* observed 5977 / 5182 fires 0 of 137 and 0 of 18
|
|
117
|
+
* slug 4, name 4, root 126 / 127 — the crossing, from both sides:
|
|
118
|
+
* observed 6000 / 5205 fires 0 of 137 (126: on the cap)
|
|
119
|
+
* observed 6000 / 5206 fires 11 of 137 (127: over it)
|
|
120
|
+
* slug 4, name 64, root 66 / 67 — the same crossing with the name at ceiling:
|
|
121
|
+
* observed 6000 fires 0 of 137 | 6000 fires 11 of 137
|
|
122
|
+
* slug 64, name 64, root 256 — ALL FOUR AT THEIR CEILINGS:
|
|
123
|
+
* arcs 5991 / 5401 fires 49 of 137 and 0 of 18
|
|
124
|
+
* observed 5998 / 5455 fires 54 of 137 and 0 of 18
|
|
125
|
+
* knowledge is the only payer (digest 6 entries -> 3); IDENTITY, WORKSPACE
|
|
126
|
+
* and LIMITS render whole, and no build exceeds the cap.
|
|
127
|
+
*
|
|
128
|
+
* THE CORPUS SIZE IS ONE OF THE INPUTS, so a re-take on a different one is DRIFT,
|
|
129
|
+
* not a regression: the live DAG is already 139 tasks, which moves only the
|
|
130
|
+
* `observed` ceiling row from 54 to 55. Every row above names its inputs so the
|
|
131
|
+
* next taker re-derives them rather than comparing a count across two corpora.
|
|
132
|
+
*
|
|
133
|
+
* THE CEILING ROW FIRES BY CONSTRUCTION, NOT BY REGRESSION. Un-budgeted blocks
|
|
134
|
+
* at their widest cost 915 chars (STAGE_HARD_CAP's arithmetic) against the 663
|
|
135
|
+
* this cap leaves them, so no wording can make that row zero: it is 252 chars
|
|
136
|
+
* over before a single word is written. Same corner on the pre-origin-conditioned
|
|
137
|
+
* module, same 137-task corpus: 51 of 137 (arcs) and 53 of 137 (observed), 0 of
|
|
138
|
+
* 18 plans, knowledge the only payer. ONE number cannot cover both origins there
|
|
139
|
+
* either — HEAD's IDENTITY line already interpolates `origin`, 4 chars for `arcs`
|
|
140
|
+
* against 8 for `observed` — which is this file's own rule again: a row that names
|
|
141
|
+
* only one of its inputs is not a measurement. Note the direction, too: HEAD
|
|
142
|
+
* degrades MORE than this module does on `arcs` (51 against 49). Zero there is
|
|
143
|
+
* reachable only by raising this cap or budgeting IDENTITY/WORKSPACE, and both are
|
|
144
|
+
* larger decisions than a reword. What the row guarantees is that the DEGRADATION
|
|
145
|
+
* is bounded and paid by the cheapest budgeted block.
|
|
146
|
+
*
|
|
147
|
+
* REALISTIC vs CEILING, and which is which: a `workspaceRoot` is a real checkout
|
|
148
|
+
* path (this repo's is 23 chars, a deep one ~103), so the 23/66/103/126 rows are
|
|
149
|
+
* the reachable ones and 256 is the guarantee row. A `projectName` and a `slug`
|
|
150
|
+
* at 64 are entirely reachable — that is why the name-at-ceiling row exists, and
|
|
151
|
+
* why the un-budgeted wording that pushed its crossing down to a 57-char project
|
|
152
|
+
* name was reverted rather than re-measured.
|
|
153
|
+
*
|
|
154
|
+
* Earlier rows, kept for shape only — none of them names all four inputs, so
|
|
155
|
+
* none is comparable with the table above:
|
|
156
|
+
* 130 tasks: 5812 task / 5011 plan, fires 0 of 130, id width unrecorded.
|
|
157
|
+
* 133 tasks: 5807 / 5006 at a 15-char id; 5888 / 5087 re-derived at the id
|
|
158
|
+
* ceiling. Fires 0 of 133 either way. Taken when `renderBlock` moved
|
|
159
|
+
* the budget clip onto a body's CONTENT — both maxima are UNCHANGED
|
|
160
|
+
* by that move (a clipped block is still bounded by the same budget:
|
|
161
|
+
* the wrapper's tags are paid out of it, not added to it).
|
|
162
|
+
*
|
|
163
|
+
* All of this is a measurement, not a property, and it is what to re-take when a
|
|
164
|
+
* budget, an input width or a block's content changes. It has already caught two.
|
|
165
|
+
* Staging the owning plan for task-linked sessions put real content into a
|
|
166
|
+
* node-body block whose 1800-char budget had been sized for content that never
|
|
167
|
+
* existed, which took the widest real node to 6412 and made the ladder fire for
|
|
168
|
+
* 62 of 130 — paying for the plan by DELETING the whole knowledge digest; the
|
|
169
|
+
* budget was sized to the content instead (STAGE_BLOCK_BUDGETS["node-body"]).
|
|
170
|
+
* And 55 chars of un-budgeted wording moved the affordance from 234 to 179,
|
|
171
|
+
* which fired the ladder for 15 of 137 at nothing worse than a 57-char project
|
|
172
|
+
* name; 51 of those chars were given back (see LIMITS_OBSERVED) and the
|
|
173
|
+
* affordance is 230. The residual 4 is the `observed` IDENTITY sentence, which
|
|
174
|
+
* buys a true statement on a path where the old one was false — and `arcs` is 46
|
|
175
|
+
* chars NARROWER than it was, having dropped a supersede notice nothing emits.
|
|
176
|
+
*
|
|
177
|
+
* Re-take it with a sweep over the WHOLE corpus, both origins, naming ALL FOUR
|
|
178
|
+
* input widths, and report the ladder-FIRING COUNT beside every width. A width
|
|
179
|
+
* alone is satisfied by the degradation it is supposed to detect — that is how
|
|
180
|
+
* the 15-of-137 regression passed every cap assertion in the suite.
|
|
181
|
+
* `test/prompt-assembly-stable.test.ts` describe (g) pins the count.
|
|
182
|
+
*/
|
|
183
|
+
export declare const STAGE_SOFT_CAP = 6000;
|
|
184
|
+
/**
|
|
185
|
+
* Never exceeded. Held by construction, and the arithmetic is:
|
|
186
|
+
* budgeted blocks (STAGE_BLOCK_BUDGETS) = 4800
|
|
187
|
+
* + un-budgeted blocks at their widest (identity 347,
|
|
188
|
+
* workspace 353, limits 215 — width-normalized at
|
|
189
|
+
* input by FIELD_WIDTHS, never truncated) = 915
|
|
190
|
+
* + envelope, preamble, headings and joiners = 537
|
|
191
|
+
* ------
|
|
192
|
+
* = 6252
|
|
193
|
+
* which leaves 1748 chars of slack under this cap.
|
|
194
|
+
*
|
|
195
|
+
* READ THIS AGAINST STAGE_SOFT_CAP, because the two disagree ON PURPOSE. The
|
|
196
|
+
* un-budgeted blocks are allowed 915 chars here and the soft cap leaves them
|
|
197
|
+
* 663 (6000 - 4800 - 537), so a build with every bounded input at its ceiling
|
|
198
|
+
* is 252 chars over the SOFT cap and degrades. That is the ladder doing its job,
|
|
199
|
+
* not a defect — but it is also why a reword of an un-budgeted block is a
|
|
200
|
+
* measurement, not an edit: it is spent out of a margin this cap does not
|
|
201
|
+
* protect. STAGE_SOFT_CAP records the sweep that says how much margin is left.
|
|
202
|
+
*
|
|
203
|
+
* `identity` and `limits` are ORIGIN-CONDITIONED, and the two numbers above are
|
|
204
|
+
* the `observed` variant — still the wider of the pair on both blocks (`arcs`
|
|
205
|
+
* measures 320 and 188), though limits is now 215 rather than 266: it lost a
|
|
206
|
+
* 32-char lead-in and traded a refresh promise it cannot keep for a 31-char
|
|
207
|
+
* capture statement. A ceiling taken from one origin is not a ceiling, which is
|
|
208
|
+
* why `test/prompt-assembly-stable.test.ts` builds both and asserts the observed
|
|
209
|
+
* one is the larger before pinning it.
|
|
210
|
+
*
|
|
211
|
+
* The un-budgeted numbers are otherwise the widths their fields are bounded to,
|
|
212
|
+
* so they cannot grow without a FIELD_WIDTHS constant moving — or without
|
|
213
|
+
* someone rewording an authored block, which is the change these figures exist
|
|
214
|
+
* to catch.
|
|
215
|
+
*/
|
|
216
|
+
export declare const STAGE_HARD_CAP = 8000;
|
|
217
|
+
export type StageBlockId = "identity" | "workspace" | "dag-position" | "node-body" | "brief" | "knowledge" | "limits";
|
|
218
|
+
/**
|
|
219
|
+
* The blocks the ladder may degrade and a per-block budget applies to.
|
|
220
|
+
*
|
|
221
|
+
* `identity`, `workspace` and `limits` are deliberately NOT here and carry no
|
|
222
|
+
* budget at all: they are never degraded, and their variable fields are
|
|
223
|
+
* width-normalized at input (FIELD_WIDTHS) instead, which bounds them by
|
|
224
|
+
* construction. Budgets for them used to exist and were inert — excluded from
|
|
225
|
+
* every code path that reads a budget, and all three exceeded the numbers they
|
|
226
|
+
* stated (324/353/234 against 120/120/200), so the invariant they documented
|
|
227
|
+
* was false as written.
|
|
228
|
+
*/
|
|
229
|
+
export type StageBudgetedBlockId = "dag-position" | "node-body" | "brief" | "knowledge";
|
|
230
|
+
/** Render order. Fixed — the prefix must be stable for the cache to hit. */
|
|
231
|
+
export declare const STAGE_BLOCK_ORDER: readonly StageBlockId[];
|
|
232
|
+
/**
|
|
233
|
+
* Per-block character budgets. Keyed by StageBudgetedBlockId, so a block with
|
|
234
|
+
* no budget cannot be given an inert one. Sum = 4800; see STAGE_HARD_CAP for
|
|
235
|
+
* the full ceiling arithmetic this feeds.
|
|
236
|
+
*
|
|
237
|
+
* `node-body` is 1200, not the 1800 it carried while the block was empty for
|
|
238
|
+
* every task-linked run. 1800 is what the widest real DAG cannot afford: it
|
|
239
|
+
* takes the largest task-linked block to 6412 and makes the soft-cap ladder fire
|
|
240
|
+
* for 62 of 130 real nodes, whose first two rungs zero the knowledge digest — a
|
|
241
|
+
* curated 6-entry index traded for 600 more chars of one plan document. At 1200
|
|
242
|
+
* the widest real node is 5812 and the ladder fires for none, so both blocks
|
|
243
|
+
* survive. Measured across the whole live DAG at 1800/1500/1400/1300/1200:
|
|
244
|
+
* 62/34/14/0/0 nodes degraded.
|
|
245
|
+
*
|
|
246
|
+
* A budget bounds the block AS RENDERED, wrapper tags included: `renderBlock`
|
|
247
|
+
* pays the open/close tags out of the budget and spends what is left on the
|
|
248
|
+
* body's content. So a number here is not "chars of document" — a wide `source`
|
|
249
|
+
* buys less document, and a budget below the tag cost drops the body for a
|
|
250
|
+
* one-line pointer rather than emitting an opener it cannot close.
|
|
251
|
+
*/
|
|
252
|
+
export declare const STAGE_BLOCK_BUDGETS: Record<StageBudgetedBlockId, number>;
|
|
253
|
+
/**
|
|
254
|
+
* Fixed truncation precedence — exactly the budgeted blocks, cheapest-to-lose
|
|
255
|
+
* first. The DAG position survives longest because it carries what the run must
|
|
256
|
+
* satisfy to finish (its scope, acceptance and verify command) alongside its
|
|
257
|
+
* edges; everything above it can be re-read on demand from the DAG or the repo.
|
|
258
|
+
*/
|
|
259
|
+
export declare const STAGE_TRUNCATION_PRECEDENCE: readonly StageBudgetedBlockId[];
|
|
260
|
+
/**
|
|
261
|
+
* Neutralizes ARCS delimiter tokens in untrusted content. Applied to EVERY
|
|
262
|
+
* injected value — bodies, titles, summaries, ids — so there is no per-field
|
|
263
|
+
* exception to reason about.
|
|
264
|
+
*/
|
|
265
|
+
export declare function stripStageDelimiters(text: string): string;
|
|
266
|
+
/**
|
|
267
|
+
* Files whose mtime means "the DAG may have moved". Cheap: four stats, no
|
|
268
|
+
* parsing. Store-mediated edits to a plan/knowledge BODY also land here,
|
|
269
|
+
* because every store write rewrites the owning index alongside the document.
|
|
270
|
+
*/
|
|
271
|
+
export declare const STAGE_PROBE_FILES: readonly string[];
|
|
272
|
+
/**
|
|
273
|
+
* Deliberately NOT probed. Session heartbeat, status and run-metadata writes
|
|
274
|
+
* touch `sessions/index.json` on essentially every poll — including the very
|
|
275
|
+
* write that persists `metadata.stage`. Probing it would make every stage
|
|
276
|
+
* permanently stale and defeat the whole cache.
|
|
277
|
+
*/
|
|
278
|
+
export declare const STAGE_PROBE_EXCLUDED: readonly string[];
|
|
279
|
+
/**
|
|
280
|
+
* The markdown document STAGED for the linked node, as a project-relative path.
|
|
281
|
+
* It must name the same file `readSources` copies into the node-body block, or
|
|
282
|
+
* an edit to that file would not invalidate the stage.
|
|
283
|
+
*
|
|
284
|
+
* Plans own `plans/<id>.md`. A task owns no document at all, so the block stages
|
|
285
|
+
* the plan that owns the TASK — and this therefore resolves to that same
|
|
286
|
+
* `plans/<planId>.md` rather than to the aggregate `tasks.md` it used to name
|
|
287
|
+
* (`tasks.md` was never load-bearing: it is rewritten by the same store write
|
|
288
|
+
* that rewrites the already-probed `tasks/index.json`).
|
|
289
|
+
*
|
|
290
|
+
* DELIBERATE COST, chosen over a silent staleness hole: resolving a task's plan
|
|
291
|
+
* needs the task index, so this is no longer derivable from the session alone
|
|
292
|
+
* and the probe is no longer stats-only. The read is one 192 KB JSON parse on
|
|
293
|
+
* the live ARCS project (~2 ms), paid ONCE PER RUN — the probe runs at spawn
|
|
294
|
+
* time, not per poll — against a `claude -p` subprocess that costs three orders
|
|
295
|
+
* of magnitude more. The alternative (persist the path on the stage record and
|
|
296
|
+
* read it back) removes the read but points the probe at the PREVIOUS build's
|
|
297
|
+
* file, which is a subtler thing to reason about for a saving that is invisible
|
|
298
|
+
* next to the spawn.
|
|
299
|
+
*
|
|
300
|
+
* `readJsonSafe`, never `listTasks`: the store readers self-repair a drifted
|
|
301
|
+
* index on read, and a probe that can WRITE a file it probes is a
|
|
302
|
+
* self-invalidating cache (the same failure `STAGE_PROBE_EXCLUDED` exists for).
|
|
303
|
+
*
|
|
304
|
+
* The one gap left: a hand-edited `plans/index.json` whose `file` does not
|
|
305
|
+
* follow `plans/<normalizedId>.md`. Every store-written index does, and a
|
|
306
|
+
* store-mediated body edit rewrites the probed index anyway.
|
|
307
|
+
*/
|
|
308
|
+
export declare function linkedNodeMarkdownPath(projectDir: string, session: SessionMeta): Promise<string | undefined>;
|
|
309
|
+
/**
|
|
310
|
+
* Max mtime (epoch ms) across the probe set plus the linked node's markdown.
|
|
311
|
+
* Returns 0 when nothing in the set exists.
|
|
312
|
+
*/
|
|
313
|
+
export declare function probeDagMtimeMs(projectDir: string, session: SessionMeta): Promise<number>;
|
|
314
|
+
export interface StageRecord {
|
|
315
|
+
/** sha256 hex of the staged text. */
|
|
316
|
+
fingerprint: string;
|
|
317
|
+
/**
|
|
318
|
+
* Epoch MILLISECONDS. Deliberately not ISO: it is compared numerically
|
|
319
|
+
* against `fs.Stats.mtimeMs`, and it sits under `metadata` next to
|
|
320
|
+
* `metadata.run`, which is already epoch ms. (Top-level SessionMeta
|
|
321
|
+
* timestamps are ISO; `metadata.*` timestamps are epoch ms. This follows its
|
|
322
|
+
* neighbours, not its grandparent.)
|
|
323
|
+
*
|
|
324
|
+
* On the path that persists it (`planStageRefresh`) this is the OBSERVED
|
|
325
|
+
* PROBE WATERMARK, never the wall clock — see that function's clause 2.
|
|
326
|
+
*/
|
|
327
|
+
stagedAt: number;
|
|
328
|
+
transport: StageTransport;
|
|
329
|
+
}
|
|
330
|
+
/** Reads and validates `session.metadata.stage`, which is untyped on disk. */
|
|
331
|
+
export declare function readStageRecord(session: SessionMeta): StageRecord | undefined;
|
|
332
|
+
export interface StageTruncation {
|
|
333
|
+
block: StageBudgetedBlockId;
|
|
334
|
+
/** `block-budget` — the block exceeded its own budget. `soft-cap` — the
|
|
335
|
+
* assembled text exceeded STAGE_SOFT_CAP and this block paid for it. */
|
|
336
|
+
reason: "block-budget" | "soft-cap";
|
|
337
|
+
droppedChars: number;
|
|
338
|
+
}
|
|
339
|
+
export interface StagedEnvironment {
|
|
340
|
+
text: string;
|
|
341
|
+
chars: number;
|
|
342
|
+
truncated: StageTruncation[];
|
|
343
|
+
/** Ready to persist at `metadata.stage`. This module never writes it. */
|
|
344
|
+
stage: StageRecord;
|
|
345
|
+
}
|
|
346
|
+
export interface StageOptions {
|
|
347
|
+
/** Absolute workspace root. Falls back to the project's first
|
|
348
|
+
* `workspacePaths` entry, so P2 holds even when the caller passes nothing. */
|
|
349
|
+
workspaceRoot?: string;
|
|
350
|
+
/** Knowledge audience filter. Default `implementer`. */
|
|
351
|
+
audience?: string;
|
|
352
|
+
transport?: StageTransport;
|
|
353
|
+
/**
|
|
354
|
+
* Epoch ms for `stage.stagedAt`. Tests pin it; nothing else should —
|
|
355
|
+
* `planStageRefresh` OVERRIDES it with the probe watermark, because a record
|
|
356
|
+
* it returns is a record a caller persists and compares against mtimes.
|
|
357
|
+
*/
|
|
358
|
+
now?: number;
|
|
359
|
+
/**
|
|
360
|
+
* Overrides STAGE_SOFT_CAP. Exists so the truncation precedence can be driven
|
|
361
|
+
* end-to-end at a cap the block budgets can actually breach — a caller on a
|
|
362
|
+
* tighter model budget may also lower it. STAGE_HARD_CAP is not overridable.
|
|
363
|
+
*/
|
|
364
|
+
softCap?: number;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Builds the STABLE tier for one session.
|
|
368
|
+
*
|
|
369
|
+
* Deterministic: for an unchanged DAG the returned `text` is byte-identical
|
|
370
|
+
* across turns. Nothing volatile is rendered — `stage.stagedAt` is on the
|
|
371
|
+
* record, not in the text.
|
|
372
|
+
*/
|
|
373
|
+
export declare function buildStagedEnvironment(projectDir: string, slug: string, session: SessionMeta, opts?: StageOptions): Promise<StagedEnvironment>;
|
|
374
|
+
export declare function fingerprintStagedText(text: string): string;
|
|
375
|
+
export type StageRefreshReason = "unstaged" | "transport-changed" | "fresh" | "unchanged" | "changed";
|
|
376
|
+
export interface StageRefresh {
|
|
377
|
+
reason: StageRefreshReason;
|
|
378
|
+
/** The staged text changed and must be re-injected. */
|
|
379
|
+
restage: boolean;
|
|
380
|
+
/** The caller should write `stage` to `metadata.stage`. */
|
|
381
|
+
persist: boolean;
|
|
382
|
+
stage?: StageRecord;
|
|
383
|
+
/** Absent only when `reason === "fresh"` — the cheap path never assembles. */
|
|
384
|
+
staged?: StagedEnvironment;
|
|
385
|
+
/** Max mtime observed by the probe, for logging. */
|
|
386
|
+
probedAt: number;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Two-phase staleness decision, verbatim:
|
|
390
|
+
*
|
|
391
|
+
* probe = max mtimeMs over tasks/index.json, plans/index.json,
|
|
392
|
+
* knowledge/index.json, meta.json and the linked node's markdown.
|
|
393
|
+
* Missing files contribute 0. sessions/index.json is DELIBERATELY
|
|
394
|
+
* EXCLUDED — heartbeat writes would make every stage permanently stale.
|
|
395
|
+
* 1. no stage record -> restage (reason "unstaged")
|
|
396
|
+
* 2. stage.transport !== active transport-> restage (reason "transport-changed")
|
|
397
|
+
* 3. probe <= stage.stagedAt -> NO rebuild (reason "fresh") [cheap exit]
|
|
398
|
+
* 4. otherwise rebuild, fingerprint = sha256(text):
|
|
399
|
+
* fingerprint === stage.fingerprint -> no restage (reason "unchanged")
|
|
400
|
+
* but persist a bumped stagedAt so
|
|
401
|
+
* the cheap exit works again
|
|
402
|
+
* else -> restage (reason "changed")
|
|
403
|
+
*
|
|
404
|
+
* Step 4's stagedAt bump writes to sessions/index.json, which is exactly why
|
|
405
|
+
* that file must stay out of the probe set: otherwise the bump would invalidate
|
|
406
|
+
* itself on the next call. That exclusion is clause 1 of the pattern, and it is
|
|
407
|
+
* NOT sufficient alone.
|
|
408
|
+
*
|
|
409
|
+
* Clause 2 — STAMP FROM THE PROBE, NOT THE CLOCK. `stagedAt` is the `probedAt`
|
|
410
|
+
* watermark this function observed, so step 3 compares two values from the same
|
|
411
|
+
* measurement. Stamping `Date.now()` instead mixes two clocks that need not
|
|
412
|
+
* agree: anywhere mtime can exceed wall clock (NFS, container skew, an
|
|
413
|
+
* mtime-preserving restore) `probe <= stagedAt` never holds, the cheap exit
|
|
414
|
+
* never fires, and step 4 re-assembles and re-persists on EVERY turn despite a
|
|
415
|
+
* perfectly correct exclusion set.
|
|
416
|
+
*
|
|
417
|
+
* It also closes a read-then-stamp TOCTOU window. The probe runs before
|
|
418
|
+
* `readSources`; a wall clock sampled after would absorb a write landing in
|
|
419
|
+
* between and leave the stage stale until the NEXT write. Stamping the
|
|
420
|
+
* watermark leaves that write above the stamp, so the next call rebuilds and
|
|
421
|
+
* the fingerprint compare decides.
|
|
422
|
+
*/
|
|
423
|
+
export declare function planStageRefresh(projectDir: string, slug: string, session: SessionMeta, opts?: StageOptions): Promise<StageRefresh>;
|
|
424
|
+
/**
|
|
425
|
+
* Per-reference caps.
|
|
426
|
+
*
|
|
427
|
+
* A reference belongs to the ONE turn a caller attached it to: it is rendered
|
|
428
|
+
* here and never reaches `buildStagedEnvironment`, so no value below can move
|
|
429
|
+
* the stable tier's fingerprint, its budgets or its truncation ladder.
|
|
430
|
+
*/
|
|
431
|
+
export declare const REFERENCE_BUDGETS: {
|
|
432
|
+
/** A doc section is what the user actually selected, so it is quoted — but
|
|
433
|
+
* bounded, because a selection can be a whole chapter. */
|
|
434
|
+
readonly doc: 1600;
|
|
435
|
+
/** A file excerpt is an ANCHOR for a pointer, never the content: the agent
|
|
436
|
+
* reads the live file, so a long excerpt buys only tokens and staleness. */
|
|
437
|
+
readonly fileExcerpt: 400;
|
|
438
|
+
};
|
|
439
|
+
/**
|
|
440
|
+
* ONE reference as prompt text.
|
|
441
|
+
*
|
|
442
|
+
* Deterministic: the same payload renders the same bytes — no timestamps, no
|
|
443
|
+
* counters, no ambient state. Every injected value goes through the same
|
|
444
|
+
* delimiter escape the staged tier uses, so a reference body cannot close its
|
|
445
|
+
* own wrapper and speak in the controller's voice, and every quoted body is
|
|
446
|
+
* introduced by an open tag carrying the governing note.
|
|
447
|
+
*/
|
|
448
|
+
export declare function renderReference(reference: SessionReference): string;
|
|
449
|
+
/**
|
|
450
|
+
* The turn's whole reference block, or `""` when there is nothing to render —
|
|
451
|
+
* a turn without references must add no bytes at all.
|
|
452
|
+
*/
|
|
453
|
+
export declare function renderReferences(references: readonly SessionReference[]): string;
|
|
454
|
+
//# sourceMappingURL=prompt-assembly.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-assembly.d.ts","sourceRoot":"","sources":["../../src/web-server/prompt-assembly.ts"],"names":[],"mappings":"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"}
|