pi-daddy 0.20.1 → 0.21.1
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/CHANGELOG.md +23 -0
- package/README.md +20 -15
- package/dist/grant-env.d.ts.map +1 -1
- package/dist/grant-env.js +1 -1
- package/dist/grant-env.js.map +1 -1
- package/dist/grant-store.d.ts +25 -10
- package/dist/grant-store.d.ts.map +1 -1
- package/dist/grant-store.js +42 -19
- package/dist/grant-store.js.map +1 -1
- package/dist/herdr-poll.js +1 -1
- package/dist/herdr-poll.js.map +1 -1
- package/dist/run-child.d.ts +1 -1
- package/dist/run-child.d.ts.map +1 -1
- package/dist/run-child.js +2 -2
- package/dist/run-child.js.map +1 -1
- package/extensions/delegation.ts +1 -1
- package/extensions/grants-command.ts +3 -3
- package/extensions/init-command.ts +9 -5
- package/extensions/session.ts +21 -7
- package/package.json +1 -1
- package/src/grant-env.ts +3 -2
- package/src/grant-store.ts +75 -21
- package/src/herdr-poll.ts +1 -1
- package/src/run-child.ts +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,29 @@ the record of how the package got here and are worth keeping; they are not worth
|
|
|
12
12
|
> the record of how the package arrived at what it does, and because the reasoning behind each one is
|
|
13
13
|
> usually the clearest statement of why the current behaviour is what it is.
|
|
14
14
|
|
|
15
|
+
## 0.21.1 — twenty-minute default child timeout (2026-09-02)
|
|
16
|
+
|
|
17
|
+
- Raise the default per-child wall-clock limit from 600 to 1200 seconds. Explicit
|
|
18
|
+
`PI_GRANTS_CHILD_TIMEOUT` values remain unchanged and inherited by descendants.
|
|
19
|
+
|
|
20
|
+
## 0.21.0 — one project init enables its ledger (2026-09-01)
|
|
21
|
+
|
|
22
|
+
- `/grants init` now atomically persists one project choice containing both the capability grant and default
|
|
23
|
+
`.pi/grants.jsonl`, then adopts both after that write succeeds. Future plain `pi` starts load both, so
|
|
24
|
+
`/grants ledger` and `/grants dashboard` need no repeated shell export.
|
|
25
|
+
- Merely installing pi-daddy still initializes nothing. `PI_GRANTS_GRANT` bypasses the project store for
|
|
26
|
+
children/CI, and `PI_GRANTS_LEDGER` overrides the stored default, including `""` for a one-run opt-out.
|
|
27
|
+
- Existing version-1 grant stores retain their no-ledger behavior until the operator explicitly reruns
|
|
28
|
+
`/grants init`; an upgrade never converts prior governance consent into recording consent.
|
|
29
|
+
- Newly generated `.pi/grants.env` files export the project ledger. Existing reviewed files remain untouched.
|
|
30
|
+
- **First-review repair:** remember whether the ledger came from the environment before publishing a stored
|
|
31
|
+
default, so a later init after a cwd change can replace pi-daddy's own old path without overriding a real
|
|
32
|
+
operator value. A second review made v1 lookalike `projectLedger` fields an explicit inert case after its
|
|
33
|
+
mutation survived the first tests. Review also exposed pre-existing malformed-store fail-open behavior
|
|
34
|
+
(R-175); it remains open and is not presented as fixed by this release.
|
|
35
|
+
- **Final-quality repair:** installed smoke now matches the active ledger export as a complete line; the old
|
|
36
|
+
commented `#export` contained the previous substring and falsely passed.
|
|
37
|
+
|
|
15
38
|
## 0.20.1 — open the dashboard with Herdr's split-pane contract (2026-09-01)
|
|
16
39
|
|
|
17
40
|
- Fix `/grants dashboard` on Herdr 0.8+: a split plugin pane targets the verified caller pane and must not
|
package/README.md
CHANGED
|
@@ -6,7 +6,8 @@ tree, so a sub-agent can never hold more of the **tool surface** than its parent
|
|
|
6
6
|
configured.
|
|
7
7
|
|
|
8
8
|
Both qualifiers are load-bearing and are not buried: a child granted `bash` can escape governance entirely
|
|
9
|
-
(ADR-0012, measured), and
|
|
9
|
+
(ADR-0012, measured), and recording is opt-in — explicitly by environment or by running `/grants init` once
|
|
10
|
+
for this project. See *What this governs, and what it does not*.
|
|
10
11
|
|
|
11
12
|
> **0.13.0 was the first published release.** Earlier versions were developed in-repo and never shipped, so
|
|
12
13
|
> the breaking changes in the changelog describe how this package arrived at its current behaviour rather
|
|
@@ -161,7 +162,7 @@ delegate_all({ children: [ {…}, {…}, {…} ] }) // several
|
|
|
161
162
|
refusal this package made was recorded by pi as a **successful** tool call. Found by the integration suite
|
|
162
163
|
on its first run.
|
|
163
164
|
- **A child cannot outlive or overwhelm you.** Output is capped (1 MiB), there is a wall-clock timeout
|
|
164
|
-
(`PI_GRANTS_CHILD_TIMEOUT`, default
|
|
165
|
+
(`PI_GRANTS_CHILD_TIMEOUT`, default 1200s) with `SIGTERM` → `SIGKILL` escalation so a child cannot ignore
|
|
165
166
|
its way past it, an abort is honoured even if it arrived before the spawn, and a child that exits
|
|
166
167
|
non-zero, times out or is cancelled comes back as a **tool error naming which** — not as an answer.
|
|
167
168
|
- **Fan-out is synchronous and bounded.** At most 8 children per call, and the subtree budget bounds the
|
|
@@ -475,9 +476,12 @@ pi # then, inside pi:
|
|
|
475
476
|
|
|
476
477
|
**`pi install`, not `npm install`** — it registers the package with pi, which is what makes the extension
|
|
477
478
|
auto-load; presence in `node_modules` alone does nothing. `/grants init` asks only about the capabilities
|
|
478
|
-
that can change your machine and applies the answer to the running session, no restart (ADR-0030).
|
|
479
|
-
|
|
480
|
-
the
|
|
479
|
+
that can change your machine and applies the answer to the running session, no restart (ADR-0030). That one
|
|
480
|
+
project opt-in now also enables `.pi/grants.jsonl` immediately and for every later plain `pi` start
|
|
481
|
+
(ADR-0037), so `/grants ledger` and `/grants dashboard` need no shell export. Merely installing the package
|
|
482
|
+
does not initialize unrelated directories. `npx pi-daddy init` does the same scaffolding from a shell, and
|
|
483
|
+
both search pi's install root as well as the project's. A pre-0.21 stored grant is not retroactive recording
|
|
484
|
+
consent; run `/grants init` once after upgrading to enable its default ledger.
|
|
481
485
|
|
|
482
486
|
```
|
|
483
487
|
found principal-pi-skills@2.3.1 — 7 skill(s), 0 declaring allowed-tools
|
|
@@ -579,23 +583,23 @@ everything below it.
|
|
|
579
583
|
|
|
580
584
|
| Variable | Default | Notes |
|
|
581
585
|
| :--- | :--- | :--- |
|
|
582
|
-
| `PI_GRANTS_GRANT` | unset → ungoverned | Presence is
|
|
586
|
+
| `PI_GRANTS_GRANT` | unset → use this directory's stored init choice, or ungoverned when none exists | Presence switches governance on and bypasses the whole cwd store; this is how children and CI stay environment-only. |
|
|
583
587
|
| `PI_GRANTS_MAX_DEPTH` | `2` | Child-depth bound. `0` disables spawning. |
|
|
584
588
|
| `PI_GRANTS_DEPTH` | `0` | This session's own depth; set by the parent, not by hand. |
|
|
585
589
|
| `PI_GRANTS_GATED` | **`tool:bash`** in a governed session | Capabilities needing human approval. Set to `""` to gate nothing. Gating is closed under subsumption, so this also covers `write`/`edit`/`read`/`grep`/`find`/`ls` (ADR-0012). |
|
|
586
590
|
| `PI_GRANTS_APPROVED` | unset | Inherited `capability@subject#sha256` entries; set by the parent, clamped to the child's own grant, and honoured only against the definition body the child itself loaded (ADR-0022). |
|
|
587
591
|
| `PI_GRANTS_APPROVAL_TIMEOUT` | `120` (seconds) | How long a dialog waits. `0` or an unreadable value means **no timeout**: waiting forever denies nothing, so it is the safe reading of a value we do not understand. |
|
|
588
|
-
| `PI_GRANTS_LEDGER` | unset → not recording |
|
|
592
|
+
| `PI_GRANTS_LEDGER` | unset → a v2 `/grants init` choice uses `<cwd>/.pi/grants.jsonl`; otherwise not recording | Presence overrides the project default; `""` disables it for one run. Any effective path is load-bearing. |
|
|
589
593
|
| `PI_GRANTS_WORKSPACE_REGISTRY` | unset | Operator-owned `{version:1, workspaces:{id:{path}}}` file, required only for workspace-routed spawns. |
|
|
590
594
|
| `PI_GRANTS_WORKSPACE_LEASE_DIR` | under `$PI_CODING_AGENT_DIR/pi-daddy/` | Kernel writer locks and ownership metadata. |
|
|
591
|
-
| `PI_GRANTS_CHILD_TIMEOUT` | `
|
|
595
|
+
| `PI_GRANTS_CHILD_TIMEOUT` | `1200` (seconds) | Wall-clock limit for a child. Inherited by descendants — an operator preference, deliberately *not* attenuating state. |
|
|
592
596
|
| `PI_GRANTS_FANOUT` | `8` | Per-call width and downward subtree budget; not a session-total counter. Malformed or `0` falls back to the default. |
|
|
593
597
|
| `PI_GRANTS_PARENT_ID` | `d0` | Readable logical tree position; set by the parent and allowed to repeat across calls. |
|
|
594
598
|
| `PI_GRANTS_EXECUTION_ID` | unset at a root | Unique governed execution occurrence; set by the parent. Lifecycle/lease joins use this, never `PI_GRANTS_PARENT_ID`. |
|
|
595
599
|
| `PI_GRANTS_HERDR` | unset ⇒ **probe** | Three-state. Unset probes for a reachable herdr and uses panes if one answers; `1` demands panes and refuses every delegation if herdr is unreachable; `0` demands captured subprocesses. Never detected from `herdr` merely being on `PATH`. |
|
|
596
600
|
| `PI_GRANTS_HERDR_WORKSPACE` | the parent's `HERDR_WORKSPACE_ID` | herdr workspace for spawned panes. Defaults to the workspace this session is in, so a child is a tab away rather than a workspace away. |
|
|
597
601
|
| `PI_GRANTS_HERDR_KEEP_PANE` | unset | `1` keeps each child's pane for inspection, and no sweep closes it. Off by default: a fan-out would flood the workspace. |
|
|
598
|
-
| `PI_CODING_AGENT_DIR` | `~/.pi/agent` | pi's own variable, not ours — but it decides where
|
|
602
|
+
| `PI_CODING_AGENT_DIR` | `~/.pi/agent` | pi's own variable, not ours — but it decides where stored project grants/ledger consent and persisted approvals live. |
|
|
599
603
|
|
|
600
604
|
**A malformed value disables spawning; it never falls back to a default.** An unreadable
|
|
601
605
|
`PI_GRANTS_MAX_DEPTH` or `PI_GRANTS_DEPTH` yields `maxDepth: 0` and a startup warning naming the
|
|
@@ -603,12 +607,13 @@ variable. Before 0.5.0 these were read with `parseInt`, which accepts numeric pr
|
|
|
603
607
|
and otherwise gives `NaN` — and since every comparison against `NaN` is false, a typo did not tighten the
|
|
604
608
|
depth limit, it **removed** it.
|
|
605
609
|
|
|
606
|
-
**Configuring a ledger makes it a precondition, not a log.**
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
is broken after
|
|
610
|
+
**Configuring a ledger makes it a precondition, not a log.** This applies equally to an explicit
|
|
611
|
+
`PI_GRANTS_LEDGER` and to the project default accepted through `/grants init`: if the write fails, delegation
|
|
612
|
+
is **refused**. Asking for an audit trail is an explicit act, and `ledger.ts` has always documented that an
|
|
613
|
+
unrecorded grant should fail closed; until 0.5.0 both call sites silently swallowed the error. Legacy v1 grant
|
|
614
|
+
stores and sessions with no ledger configured are unaffected. Concurrent appends are serialised by a lock file
|
|
615
|
+
with a short timeout — failing closed beats hanging — and a lock abandoned by a killed process is broken after
|
|
616
|
+
10s.
|
|
612
617
|
|
|
613
618
|
## The ledger
|
|
614
619
|
|
package/dist/grant-env.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grant-env.d.ts","sourceRoot":"","sources":["../src/grant-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAA0B,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAEvE;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,UAAU,EAEpD,CAAC;AAEF,0DAA0D;AAC1D,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAQ/D;AAaD,qBAAa,gBAAiB,SAAQ,KAAK;CAAG;AAE9C,mFAAmF;AACnF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI,CAU/D;AAED,gFAAgF;AAChF,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,+FAA+F;IAC/F,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,iCAAiC;IACjC,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,6GAA6G;IAC7G,QAAQ,EAAE,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;IACpC,yFAAyF;IACzF,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,sGAAsG;IACtG,kBAAkB,CAAC,EAAE,UAAU,EAAE,CAAC;IAClC,kGAAkG;IAClG,eAAe,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,UAAU,CAAA;KAAE,EAAE,CAAC;IAC5D,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"grant-env.d.ts","sourceRoot":"","sources":["../src/grant-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAA0B,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAEvE;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,UAAU,EAEpD,CAAC;AAEF,0DAA0D;AAC1D,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAQ/D;AAaD,qBAAa,gBAAiB,SAAQ,KAAK;CAAG;AAE9C,mFAAmF;AACnF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI,CAU/D;AAED,gFAAgF;AAChF,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,+FAA+F;IAC/F,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,iCAAiC;IACjC,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,6GAA6G;IAC7G,QAAQ,EAAE,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;IACpC,yFAAyF;IACzF,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,sGAAsG;IACtG,kBAAkB,CAAC,EAAE,UAAU,EAAE,CAAC;IAClC,kGAAkG;IAClG,eAAe,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,UAAU,CAAA;KAAE,EAAE,CAAC;IAC5D,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CA6G3D;AAED,qFAAqF;AACrF,eAAO,MAAM,WAAW,EAAE,UAAgC,CAAC"}
|
package/dist/grant-env.js
CHANGED
|
@@ -146,7 +146,7 @@ export function renderGrantEnv(input) {
|
|
|
146
146
|
lines.push(`# CAUTION: ${caution}`);
|
|
147
147
|
if (input.cautions.length > 0)
|
|
148
148
|
lines.push("#");
|
|
149
|
-
lines.push("# tool:delegate is what registers the delegation tools at all — withhold it and this session is a leaf.", `export PI_GRANTS_GRANT="${input.live.join(",")}"`, "", "#
|
|
149
|
+
lines.push("# tool:delegate is what registers the delegation tools at all — withhold it and this session is a leaf.", `export PI_GRANTS_GRANT="${input.live.join(",")}"`, "", "# Init enables this project ledger. It is LOAD-BEARING: a spawn that cannot be recorded is refused.", '# PI_GRANTS_LEDGER still overrides the stored default used by plain `pi` after `/grants init`.', 'export PI_GRANTS_LEDGER=".pi/grants.jsonl"', "", "# Optional. tool:bash is ALREADY gated by default, so this line only matters if you widen it:", "# gating is closed under subsumption, so gating tool:write also gates tool:bash (bash can write).", '#export PI_GRANTS_GATED="tool:bash,tool:write"', "");
|
|
150
150
|
return lines.join("\n");
|
|
151
151
|
}
|
|
152
152
|
/** The capability that must always be live, or the generated file is inert (S-5). */
|
package/dist/grant-env.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grant-env.js","sourceRoot":"","sources":["../src/grant-env.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"grant-env.js","sourceRoot":"","sources":["../src/grant-env.ts"],"names":[],"mappings":"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"}
|
package/dist/grant-store.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
2
|
+
* The init choice for a directory, stored **outside** it: its grant and, in v2, explicit project-ledger
|
|
3
|
+
* consent.
|
|
3
4
|
*
|
|
4
|
-
* `PI_GRANTS_GRANT`
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* `PI_GRANTS_GRANT` and `PI_GRANTS_LEDGER` remain the propagation channel to children — a parent writes them
|
|
6
|
+
* and every child inherits them. The store is a root-session source only, so an operator does not have to
|
|
7
|
+
* `source` a file and restart pi after making the project choice.
|
|
7
8
|
*
|
|
8
9
|
* **Outside the workspace, and that is the whole design.** A grant is a ceiling; a ceiling a governed child
|
|
9
10
|
* can rewrite is not a ceiling. `<cwd>/.pi/grants.env` is writable by any child holding `tool:write`, so
|
|
@@ -18,6 +19,14 @@
|
|
|
18
19
|
* of the decision, diffable in a PR. It is simply no longer the thing the enforcer reads.
|
|
19
20
|
*/
|
|
20
21
|
import type { Capability } from "./resolve.ts";
|
|
22
|
+
export interface StoredGrant {
|
|
23
|
+
grant: Capability[];
|
|
24
|
+
/** Whether a root session defaults to `<cwd>/.pi/grants.jsonl`. False for every legacy v1 store. */
|
|
25
|
+
projectLedger: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface SaveGrantOptions {
|
|
28
|
+
projectLedger?: boolean;
|
|
29
|
+
}
|
|
21
30
|
/**
|
|
22
31
|
* Where this directory's grant lives.
|
|
23
32
|
*
|
|
@@ -27,15 +36,17 @@ import type { Capability } from "./resolve.ts";
|
|
|
27
36
|
*/
|
|
28
37
|
export declare function grantStorePath(cwd: string): string;
|
|
29
38
|
/**
|
|
30
|
-
* Parse a store file's text into
|
|
39
|
+
* Parse a store file's text into its versioned project choice, or null.
|
|
31
40
|
*
|
|
32
41
|
* Split out from the readers so the **one** validation lives in one place: both the sync and async paths
|
|
33
42
|
* must agree, and two parsers is how they come to disagree.
|
|
34
43
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
44
|
+
* Rejects every doubt at this parser boundary — it never constructs a partial ceiling. The session currently
|
|
45
|
+
* treats absent and invalid stores alike (R-175), so do not call that wider behavior fail-closed. The `cwd`
|
|
46
|
+
* check is R-27's: a copied file describes a directory nobody authorised it for.
|
|
38
47
|
*/
|
|
48
|
+
export declare function parseStoredGrant(text: string, cwd: string): StoredGrant | null;
|
|
49
|
+
/** Compatibility view for callers that need only the capability ceiling. */
|
|
39
50
|
export declare function parseGrantFile(text: string, cwd: string): Capability[] | null;
|
|
40
51
|
/**
|
|
41
52
|
* Read this directory's stored grant, synchronously.
|
|
@@ -46,12 +57,16 @@ export declare function parseGrantFile(text: string, cwd: string): Capability[]
|
|
|
46
57
|
* decision it exists to inform, so the store would silently fail to grant delegation — the exact class of
|
|
47
58
|
* defect R-38 and R-39 were.
|
|
48
59
|
*/
|
|
60
|
+
export declare function loadStoredGrantSync(cwd: string): StoredGrant | null;
|
|
49
61
|
export declare function loadGrantSync(cwd: string): Capability[] | null;
|
|
50
62
|
/** Async twin, for callers that already have one. Same parser, so they cannot disagree. */
|
|
63
|
+
export declare function loadStoredGrant(cwd: string): Promise<StoredGrant | null>;
|
|
51
64
|
export declare function loadGrant(cwd: string): Promise<Capability[] | null>;
|
|
65
|
+
/** The one project-local default ADR-0037 binds to an explicit v2 init choice. */
|
|
66
|
+
export declare function projectLedgerPath(cwd: string): string;
|
|
52
67
|
export type SaveOutcome = "saved" | "failed" | "busy";
|
|
53
68
|
/**
|
|
54
|
-
* Write this directory's grant.
|
|
69
|
+
* Write this directory's grant and optional project-ledger consent as one atomic choice.
|
|
55
70
|
*
|
|
56
71
|
* Locked with the same lock the ledger and the approval store use, for the same reason: two sessions in one
|
|
57
72
|
* directory running `/grants init` concurrently must not interleave. A lock this cannot take yields `busy`
|
|
@@ -62,7 +77,7 @@ export type SaveOutcome = "saved" | "failed" | "busy";
|
|
|
62
77
|
* filesystem, so a reader never sees a half-written grant. Both copied from `writeFileSafely`, deliberately
|
|
63
78
|
* — a second, subtly different atomic-write is how the two come to disagree about what "safe" meant.
|
|
64
79
|
*/
|
|
65
|
-
export declare function saveGrant(cwd: string, grant: Capability[]): Promise<SaveOutcome>;
|
|
80
|
+
export declare function saveGrant(cwd: string, grant: Capability[], options?: SaveGrantOptions): Promise<SaveOutcome>;
|
|
66
81
|
/** Remove this directory's stored grant. True when a file was there to remove. */
|
|
67
82
|
export declare function clearGrant(cwd: string): Promise<boolean>;
|
|
68
83
|
//# sourceMappingURL=grant-store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grant-store.d.ts","sourceRoot":"","sources":["../src/grant-store.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"grant-store.d.ts","sourceRoot":"","sources":["../src/grant-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AASH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAoB/C,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,oGAAoG;IACpG,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAOD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIlD;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAoB9E;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,GAAG,IAAI,CAE7E;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAMnE;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,GAAG,IAAI,CAE9D;AAED,2FAA2F;AAC3F,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAM9E;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,CAEzE;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEtD;;;;;;;;;;;GAWG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,UAAU,EAAE,EACnB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,WAAW,CAAC,CAsBtB;AAED,kFAAkF;AAClF,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAS9D"}
|
package/dist/grant-store.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
2
|
+
* The init choice for a directory, stored **outside** it: its grant and, in v2, explicit project-ledger
|
|
3
|
+
* consent.
|
|
3
4
|
*
|
|
4
|
-
* `PI_GRANTS_GRANT`
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* `PI_GRANTS_GRANT` and `PI_GRANTS_LEDGER` remain the propagation channel to children — a parent writes them
|
|
6
|
+
* and every child inherits them. The store is a root-session source only, so an operator does not have to
|
|
7
|
+
* `source` a file and restart pi after making the project choice.
|
|
7
8
|
*
|
|
8
9
|
* **Outside the workspace, and that is the whole design.** A grant is a ceiling; a ceiling a governed child
|
|
9
10
|
* can rewrite is not a ceiling. `<cwd>/.pi/grants.env` is writable by any child holding `tool:write`, so
|
|
@@ -22,7 +23,7 @@ import { readFileSync } from "node:fs";
|
|
|
22
23
|
import { mkdir, readFile, rename, rm, unlink, writeFile } from "node:fs/promises";
|
|
23
24
|
import { randomUUID } from "node:crypto";
|
|
24
25
|
import { homedir } from "node:os";
|
|
25
|
-
import { basename, dirname, join } from "node:path";
|
|
26
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
26
27
|
import { withFileLock, LockTimeoutError } from "./file-lock.js";
|
|
27
28
|
/** `$PI_CODING_AGENT_DIR`, or pi's default. Same resolution as the approval store. */
|
|
28
29
|
function agentDir() {
|
|
@@ -41,19 +42,19 @@ export function grantStorePath(cwd) {
|
|
|
41
42
|
return join(agentDir(), "grants", `${slug}-${hash}.json`);
|
|
42
43
|
}
|
|
43
44
|
/**
|
|
44
|
-
* Parse a store file's text into
|
|
45
|
+
* Parse a store file's text into its versioned project choice, or null.
|
|
45
46
|
*
|
|
46
47
|
* Split out from the readers so the **one** validation lives in one place: both the sync and async paths
|
|
47
48
|
* must agree, and two parsers is how they come to disagree.
|
|
48
49
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
50
|
+
* Rejects every doubt at this parser boundary — it never constructs a partial ceiling. The session currently
|
|
51
|
+
* treats absent and invalid stores alike (R-175), so do not call that wider behavior fail-closed. The `cwd`
|
|
52
|
+
* check is R-27's: a copied file describes a directory nobody authorised it for.
|
|
52
53
|
*/
|
|
53
|
-
export function
|
|
54
|
+
export function parseStoredGrant(text, cwd) {
|
|
54
55
|
try {
|
|
55
56
|
const parsed = JSON.parse(text);
|
|
56
|
-
if (parsed.version !== 1)
|
|
57
|
+
if (parsed.version !== 1 && parsed.version !== 2)
|
|
57
58
|
return null;
|
|
58
59
|
if (parsed.cwd !== cwd)
|
|
59
60
|
return null;
|
|
@@ -61,12 +62,21 @@ export function parseGrantFile(text, cwd) {
|
|
|
61
62
|
return null;
|
|
62
63
|
if (!parsed.grant.every((c) => typeof c === "string" && c.length > 0))
|
|
63
64
|
return null;
|
|
64
|
-
|
|
65
|
+
if (parsed.version === 2 && parsed.projectLedger !== true)
|
|
66
|
+
return null;
|
|
67
|
+
return {
|
|
68
|
+
grant: parsed.grant,
|
|
69
|
+
projectLedger: parsed.version === 2,
|
|
70
|
+
};
|
|
65
71
|
}
|
|
66
72
|
catch {
|
|
67
73
|
return null;
|
|
68
74
|
}
|
|
69
75
|
}
|
|
76
|
+
/** Compatibility view for callers that need only the capability ceiling. */
|
|
77
|
+
export function parseGrantFile(text, cwd) {
|
|
78
|
+
return parseStoredGrant(text, cwd)?.grant ?? null;
|
|
79
|
+
}
|
|
70
80
|
/**
|
|
71
81
|
* Read this directory's stored grant, synchronously.
|
|
72
82
|
*
|
|
@@ -76,25 +86,35 @@ export function parseGrantFile(text, cwd) {
|
|
|
76
86
|
* decision it exists to inform, so the store would silently fail to grant delegation — the exact class of
|
|
77
87
|
* defect R-38 and R-39 were.
|
|
78
88
|
*/
|
|
79
|
-
export function
|
|
89
|
+
export function loadStoredGrantSync(cwd) {
|
|
80
90
|
try {
|
|
81
|
-
return
|
|
91
|
+
return parseStoredGrant(readFileSync(grantStorePath(cwd), "utf8"), cwd);
|
|
82
92
|
}
|
|
83
93
|
catch {
|
|
84
94
|
return null;
|
|
85
95
|
}
|
|
86
96
|
}
|
|
97
|
+
export function loadGrantSync(cwd) {
|
|
98
|
+
return loadStoredGrantSync(cwd)?.grant ?? null;
|
|
99
|
+
}
|
|
87
100
|
/** Async twin, for callers that already have one. Same parser, so they cannot disagree. */
|
|
88
|
-
export async function
|
|
101
|
+
export async function loadStoredGrant(cwd) {
|
|
89
102
|
try {
|
|
90
|
-
return
|
|
103
|
+
return parseStoredGrant(await readFile(grantStorePath(cwd), "utf8"), cwd);
|
|
91
104
|
}
|
|
92
105
|
catch {
|
|
93
106
|
return null;
|
|
94
107
|
}
|
|
95
108
|
}
|
|
109
|
+
export async function loadGrant(cwd) {
|
|
110
|
+
return (await loadStoredGrant(cwd))?.grant ?? null;
|
|
111
|
+
}
|
|
112
|
+
/** The one project-local default ADR-0037 binds to an explicit v2 init choice. */
|
|
113
|
+
export function projectLedgerPath(cwd) {
|
|
114
|
+
return resolve(cwd, ".pi", "grants.jsonl");
|
|
115
|
+
}
|
|
96
116
|
/**
|
|
97
|
-
* Write this directory's grant.
|
|
117
|
+
* Write this directory's grant and optional project-ledger consent as one atomic choice.
|
|
98
118
|
*
|
|
99
119
|
* Locked with the same lock the ledger and the approval store use, for the same reason: two sessions in one
|
|
100
120
|
* directory running `/grants init` concurrently must not interleave. A lock this cannot take yields `busy`
|
|
@@ -105,9 +125,12 @@ export async function loadGrant(cwd) {
|
|
|
105
125
|
* filesystem, so a reader never sees a half-written grant. Both copied from `writeFileSafely`, deliberately
|
|
106
126
|
* — a second, subtly different atomic-write is how the two come to disagree about what "safe" meant.
|
|
107
127
|
*/
|
|
108
|
-
export async function saveGrant(cwd, grant) {
|
|
128
|
+
export async function saveGrant(cwd, grant, options = {}) {
|
|
109
129
|
const path = grantStorePath(cwd);
|
|
110
|
-
const
|
|
130
|
+
const common = { cwd, grant: [...grant].sort(), writtenAt: new Date().toISOString() };
|
|
131
|
+
const file = options.projectLedger
|
|
132
|
+
? { version: 2, ...common, projectLedger: true }
|
|
133
|
+
: { version: 1, ...common };
|
|
111
134
|
try {
|
|
112
135
|
await mkdir(dirname(path), { recursive: true });
|
|
113
136
|
return await withFileLock(path, "grant store", async () => {
|
package/dist/grant-store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grant-store.js","sourceRoot":"","sources":["../src/grant-store.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"grant-store.js","sourceRoot":"","sources":["../src/grant-store.ts"],"names":[],"mappings":"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"}
|
package/dist/herdr-poll.js
CHANGED
|
@@ -33,7 +33,7 @@ export const DEFAULT_SNAPSHOT_LINES = 3;
|
|
|
33
33
|
export async function waitForSettled(exec, request, before, deadline, maxOutputBytes) {
|
|
34
34
|
const interval = request.pollIntervalMs ?? POLL_INTERVAL_MS;
|
|
35
35
|
// ADR-0032. The pane is read on every poll so the parent can show what the child is doing, rather than the
|
|
36
|
-
// one word `delegate` for up to
|
|
36
|
+
// one word `delegate` for up to twenty minutes by default.
|
|
37
37
|
//
|
|
38
38
|
// No cross-poll state is kept, deliberately: the previous design remembered what it had reported so it could
|
|
39
39
|
// send a diff, and that is what broke — see `tailLines`. A snapshot needs no memory.
|
package/dist/herdr-poll.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"herdr-poll.js","sourceRoot":"","sources":["../src/herdr-poll.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,UAAU,EAAkB,MAAM,gBAAgB,CAAC;AA0B5D,4GAA4G;AAC5G,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;AAEtD,2EAA2E;AAC3E,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AACpC,+GAA+G;AAC/G,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAExC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAe,EACf,OAAmB,EACnB,MAAc,EACd,QAAgB,EAChB,cAAsB;IAEtB,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,IAAI,gBAAgB,CAAC;IAC5D,2GAA2G;IAC3G,
|
|
1
|
+
{"version":3,"file":"herdr-poll.js","sourceRoot":"","sources":["../src/herdr-poll.ts"],"names":[],"mappings":"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"}
|
package/dist/run-child.d.ts
CHANGED
|
@@ -75,7 +75,7 @@ export interface ChildRunResult {
|
|
|
75
75
|
}
|
|
76
76
|
/** 1 MiB. A delegation returns a summary; anything larger is a runaway, not an answer. */
|
|
77
77
|
export declare const DEFAULT_MAX_OUTPUT_BYTES: number;
|
|
78
|
-
/**
|
|
78
|
+
/** 20 minutes. Long-running sub-agent work often exceeded ten; a hang remains bounded. */
|
|
79
79
|
export declare const DEFAULT_TIMEOUT_MS: number;
|
|
80
80
|
/** Grace between SIGTERM and SIGKILL. A child that ignores SIGTERM must not make the timeout advisory. */
|
|
81
81
|
export declare const DEFAULT_KILL_GRACE_MS = 5000;
|
package/dist/run-child.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-child.d.ts","sourceRoot":"","sources":["../src/run-child.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAeH;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAY9D;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,4BAA4B,CAAC;AAE3D,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAK9D;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,yFAAyF;IACzF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2GAA2G;IAC3G,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,mGAAmG;IACnG,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,cAAc;IAC7B,yFAAyF;IACzF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAC/B,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,0FAA0F;AAC1F,eAAO,MAAM,wBAAwB,QAAc,CAAC;AACpD,
|
|
1
|
+
{"version":3,"file":"run-child.d.ts","sourceRoot":"","sources":["../src/run-child.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAeH;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAY9D;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,4BAA4B,CAAC;AAE3D,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAK9D;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,yFAAyF;IACzF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2GAA2G;IAC3G,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,mGAAmG;IACnG,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,cAAc;IAC7B,yFAAyF;IACzF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAC/B,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,0FAA0F;AAC1F,eAAO,MAAM,wBAAwB,QAAc,CAAC;AACpD,0FAA0F;AAC1F,eAAO,MAAM,kBAAkB,QAAiB,CAAC;AACjD,0GAA0G;AAC1G,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAE1C,wBAAgB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CA6K1E"}
|
package/dist/run-child.js
CHANGED
|
@@ -63,8 +63,8 @@ export function timeoutFromEnv(raw) {
|
|
|
63
63
|
}
|
|
64
64
|
/** 1 MiB. A delegation returns a summary; anything larger is a runaway, not an answer. */
|
|
65
65
|
export const DEFAULT_MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
66
|
-
/**
|
|
67
|
-
export const DEFAULT_TIMEOUT_MS =
|
|
66
|
+
/** 20 minutes. Long-running sub-agent work often exceeded ten; a hang remains bounded. */
|
|
67
|
+
export const DEFAULT_TIMEOUT_MS = 20 * 60 * 1000;
|
|
68
68
|
/** Grace between SIGTERM and SIGKILL. A child that ignores SIGTERM must not make the timeout advisory. */
|
|
69
69
|
export const DEFAULT_KILL_GRACE_MS = 5000;
|
|
70
70
|
export function runChild(request) {
|
package/dist/run-child.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-child.js","sourceRoot":"","sources":["../src/run-child.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;AAE5E,SAAS,0BAA0B;IACjC,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,UAAU;QAAE,OAAO,SAAS,CAAC;IACnE,MAAM,OAAO,GAAI,UAA8E,CAAC,YAAY,CAAC,CAAC;IAC9G,OAAO,OAAO,EAAE,QAAQ,EAAE,CAAC;AAC7B,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,MAAc;IACpD,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3B,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,MAAM;QAAE,OAAO,IAAI,CAAC;IACnD,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,MAAM,SAAS,IAAI,IAAI,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,IAAI,GAAG,IAAI,GAAG,MAAM;YAAE,MAAM;QAChC,GAAG,IAAI,SAAS,CAAC;QACjB,IAAI,IAAI,IAAI,CAAC;IACf,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,yBAAyB,CAAC;AAE3D,iGAAiG;AACjG,MAAM,UAAU,cAAc,CAAC,GAAuB;IACpD,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAChC,mGAAmG;IACnG,uEAAuE;IACvE,OAAO,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC;AAC1G,CAAC;AA8CD,0FAA0F;AAC1F,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,GAAG,IAAI,CAAC;AACpD,
|
|
1
|
+
{"version":3,"file":"run-child.js","sourceRoot":"","sources":["../src/run-child.ts"],"names":[],"mappings":"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"}
|
package/extensions/delegation.ts
CHANGED
|
@@ -244,7 +244,7 @@ export function registerDelegationTools(pi: ExtensionAPI, session: GrantsSession
|
|
|
244
244
|
parameters: delegateParams,
|
|
245
245
|
async execute(_toolCallId, params, signal, onUpdate, ctx) {
|
|
246
246
|
// ADR-0032: one child, same block. `_onUpdate` was discarded here, so a delegation showed the bare word
|
|
247
|
-
// `delegate` for up to DEFAULT_TIMEOUT_MS —
|
|
247
|
+
// `delegate` for up to DEFAULT_TIMEOUT_MS — twenty minutes by default.
|
|
248
248
|
const progress = progressReporter(session, [params.agent ?? "delegate"], onUpdate as never);
|
|
249
249
|
const outcome = await runOneDelegation(
|
|
250
250
|
session,
|
|
@@ -52,8 +52,8 @@ export interface GrantsCommandContext {
|
|
|
52
52
|
*/
|
|
53
53
|
previewDelegation: (name: string) => Promise<GatedPlan>;
|
|
54
54
|
/**
|
|
55
|
-
* Run `/grants init`: scaffold definitions, ask about
|
|
56
|
-
* outside the workspace, and apply
|
|
55
|
+
* Run `/grants init`: scaffold definitions, ask about withheld capabilities, atomically store grant plus
|
|
56
|
+
* project-ledger consent outside the workspace, and apply both now (ADR-0030, ADR-0037).
|
|
57
57
|
*
|
|
58
58
|
* Injected rather than imported so this module stays what it is — a read-only diagnostic that cannot
|
|
59
59
|
* become a governance path by accident. The one command here that *writes* takes its ability to do so
|
|
@@ -345,7 +345,7 @@ handler: async (args: string, ctx: any) => {
|
|
|
345
345
|
// two facts about what a spawn will be sit together.
|
|
346
346
|
` executor ${executor.disclosure}`,
|
|
347
347
|
` depth ${depth} of max ${maxDepth}${maxDepth <= 0 ? " (spawning disabled)" : ""}`,
|
|
348
|
-
` ledger ${ledgerPath
|
|
348
|
+
` ledger ${ledgerPath || "(not recording — set PI_GRANTS_LEDGER)"}`,
|
|
349
349
|
` approvals ${sessionApprovals.size} this session, ${valid.size} persisted` +
|
|
350
350
|
`${inheritedApprovals.size > 0 ? `, ${inheritedApprovals.size} inherited` : ""}` +
|
|
351
351
|
` — /grants approvals`,
|
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
import { discoverSkillPackages } from "../src/skill-packages.ts";
|
|
11
11
|
import { applyInit, planInit } from "../src/init.ts";
|
|
12
12
|
import { registeredWorkspaceIds } from "../src/workspace.ts";
|
|
13
|
-
import {
|
|
13
|
+
import { grantStorePath, projectLedgerPath, saveGrant } from "../src/grant-store.ts";
|
|
14
14
|
import { expandSubsumed, SUBSUMPTION, type Capability } from "../src/resolve.ts";
|
|
15
15
|
import type { GrantsSession } from "./session.ts";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* `/grants init` — scaffold, ask about what is withheld, store
|
|
18
|
+
* `/grants init` — scaffold, ask about what is withheld, store grant + ledger consent, apply both now.
|
|
19
19
|
*
|
|
20
20
|
* **The dialog covers the withheld capabilities and nothing else** (ADR-0030). Asking about all of them
|
|
21
21
|
* would be a dozen questions for a first run, and this project has a name for what that produces: R-25,
|
|
@@ -118,7 +118,8 @@ export async function runInit(
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
const finalGrant = [...grant].sort();
|
|
121
|
-
const
|
|
121
|
+
const ledger = projectLedgerPath(ctx.cwd);
|
|
122
|
+
const saved = await saveGrant(ctx.cwd, finalGrant, { projectLedger: true });
|
|
122
123
|
if (saved !== "saved") {
|
|
123
124
|
lines.push(
|
|
124
125
|
` NOT STORED — ${saved === "busy" ? "another session holds the grant store" : "the store could not be written"}. ` +
|
|
@@ -130,12 +131,15 @@ export async function runInit(
|
|
|
130
131
|
|
|
131
132
|
// Live, without a restart — the whole point of the store. Only after a successful write, so what runs and
|
|
132
133
|
// what is recorded cannot disagree.
|
|
133
|
-
session.adoptGrant(finalGrant);
|
|
134
|
+
session.adoptGrant(finalGrant, ledger);
|
|
134
135
|
// Order matters: the grant first, then the reload, because `refreshSpawnable` filters the definitions it
|
|
135
136
|
// advertises through `maySpawnDefinition` against the grant the session now holds.
|
|
136
137
|
await refresh();
|
|
137
138
|
|
|
138
|
-
lines.push(
|
|
139
|
+
lines.push(
|
|
140
|
+
` stored at ${grantStorePath(ctx.cwd)} — outside this project, so no child can rewrite it`,
|
|
141
|
+
` ledger ${ledger} — default for future pi sessions; PI_GRANTS_LEDGER still overrides it`,
|
|
142
|
+
);
|
|
139
143
|
if (granted.length > 0) lines.push(` GRANTED: ${granted.join(", ")}`);
|
|
140
144
|
if (alreadyConferred.length > 0) {
|
|
141
145
|
lines.push(` ALREADY CONFERRED, not asked about: ${alreadyConferred.join(", ")}`);
|
package/extensions/session.ts
CHANGED
|
@@ -44,7 +44,7 @@ import type { Capability } from "../src/resolve.ts";
|
|
|
44
44
|
import { loadDefinitions } from "../src/definitions.ts";
|
|
45
45
|
import { buildCatalog } from "../src/catalog.ts";
|
|
46
46
|
import { ENV_WORKSPACE_REGISTRY } from "../src/workspace.ts";
|
|
47
|
-
import {
|
|
47
|
+
import { grantStorePath, loadStoredGrantSync, projectLedgerPath } from "../src/grant-store.ts";
|
|
48
48
|
import { republishable } from "./approvals.ts";
|
|
49
49
|
|
|
50
50
|
/**
|
|
@@ -184,7 +184,7 @@ export interface GrantsSession {
|
|
|
184
184
|
*/
|
|
185
185
|
readonly storeCwd: string;
|
|
186
186
|
/**
|
|
187
|
-
* Adopt
|
|
187
|
+
* Adopt the project choice made DURING the session — grant plus optional default ledger — without restart.
|
|
188
188
|
*
|
|
189
189
|
* Narrow by design: it sets the session's own grant and republishes, so the very next spawn is bounded by
|
|
190
190
|
* it. It does **not** reach children that already exist; those are separate processes whose environment
|
|
@@ -194,7 +194,7 @@ export interface GrantsSession {
|
|
|
194
194
|
* Only a human can reach this. Slash commands are user-invoked; no tool exposes it, so a model cannot
|
|
195
195
|
* widen its own session's ceiling by calling something.
|
|
196
196
|
*/
|
|
197
|
-
adoptGrant(grant: Capability[]): void;
|
|
197
|
+
adoptGrant(grant: Capability[], projectLedger?: string): void;
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
/**
|
|
@@ -258,9 +258,16 @@ export function createGrantsSession(extensionPath: string | undefined): GrantsSe
|
|
|
258
258
|
// against each other and says so if they differ, which is the only case this can get wrong.
|
|
259
259
|
const grantRaw = process.env[ENV_GRANT];
|
|
260
260
|
const storeCwd = process.cwd();
|
|
261
|
-
|
|
261
|
+
// One root-only store read supplies both decisions made by `/grants init`. A child always has ENV_GRANT,
|
|
262
|
+
// so it cannot activate a ledger merely because its routed cwd happens to have a v2 store (ADR-0037).
|
|
263
|
+
const stored = grantRaw === undefined ? loadStoredGrantSync(storeCwd) : null;
|
|
262
264
|
const governed = grantRaw !== undefined || stored !== null;
|
|
263
|
-
const inherited: Capability[] = grantRaw !== undefined ? parseList(grantRaw) : (stored ?? [WILDCARD]);
|
|
265
|
+
const inherited: Capability[] = grantRaw !== undefined ? parseList(grantRaw) : (stored?.grant ?? [WILDCARD]);
|
|
266
|
+
const ledgerRaw = process.env[ENV_LEDGER];
|
|
267
|
+
// Capture provenance before publishChildEnv writes this session's derived default into process.env. A later
|
|
268
|
+
// `/grants init` for ctx.cwd must not mistake our own publication for an operator override.
|
|
269
|
+
const ledgerFromEnvironment = ledgerRaw !== undefined;
|
|
270
|
+
const storedLedger = stored?.projectLedger ? projectLedgerPath(storeCwd) : undefined;
|
|
264
271
|
// G7 / A-S4 + B-I4: strict, three-way parsing that fails CLOSED. A malformed bound used to yield
|
|
265
272
|
// `NaN`, and every comparison against `NaN` is false, so depth limiting switched itself off.
|
|
266
273
|
const bounds = depthConfig(process.env[ENV_DEPTH], process.env[ENV_MAX_DEPTH]);
|
|
@@ -280,7 +287,9 @@ export function createGrantsSession(extensionPath: string | undefined): GrantsSe
|
|
|
280
287
|
// ungoverned-descendant escape hatch, and doing that silently is what changes here.
|
|
281
288
|
// `PI_GRANTS_GATED=""` turns the default off; absent and empty are deliberately distinguishable.
|
|
282
289
|
gated: governed ? gatedFromEnv(process.env[ENV_GATED]) : parseList(process.env[ENV_GATED]),
|
|
283
|
-
|
|
290
|
+
// Presence wins, including an explicitly empty value for a one-run opt-out. The store is eligible only
|
|
291
|
+
// when ENV_GRANT was absent above, preserving the environment as the child's single authority channel.
|
|
292
|
+
ledgerPath: ledgerRaw !== undefined ? ledgerRaw : storedLedger,
|
|
284
293
|
// The un-probed reading. `resolveExecutor` replaces it at session start; until then a `1` already reads as
|
|
285
294
|
// a refusal, which is the safe direction — a delegation that somehow ran before the probe would refuse
|
|
286
295
|
// rather than quietly use the wrong executor.
|
|
@@ -342,13 +351,18 @@ export function createGrantsSession(extensionPath: string | undefined): GrantsSe
|
|
|
342
351
|
|
|
343
352
|
storeCwd,
|
|
344
353
|
|
|
345
|
-
adoptGrant: (grant: Capability[]) => {
|
|
354
|
+
adoptGrant: (grant: Capability[], projectLedger?: string) => {
|
|
346
355
|
// Governed too, not just bounded. A session that starts with no grant and then runs `/grants init` is
|
|
347
356
|
// governed from that moment: every spawn is bounded by what was just stored. Leaving this false made
|
|
348
357
|
// `/grants` print "inactive" while holding thirteen capabilities — a status line contradicting the
|
|
349
358
|
// enforcer, which is the defect R-28 is named for.
|
|
350
359
|
session.governed = true;
|
|
351
360
|
session.ownGrant = grant;
|
|
361
|
+
// An environment ledger remains the explicit answer. Otherwise init's v2 choice becomes live now,
|
|
362
|
+
// before publishChildEnv gives the same absolute path to descendants.
|
|
363
|
+
if (!ledgerFromEnvironment && projectLedger !== undefined) {
|
|
364
|
+
session.ledgerPath = projectLedger;
|
|
365
|
+
}
|
|
352
366
|
session.publishChildEnv();
|
|
353
367
|
},
|
|
354
368
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-daddy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.1",
|
|
4
4
|
"description": "Capability governance for pi sub-agents: spawn Agent Skills (SKILL.md) definitions whose allowed-tools becomes a grant that can only narrow going down a delegation tree, enforced by pi's own --tools allowlist, with an append-only ledger.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
package/src/grant-env.ts
CHANGED
|
@@ -204,8 +204,9 @@ export function renderGrantEnv(input: GrantEnvInput): string {
|
|
|
204
204
|
"# tool:delegate is what registers the delegation tools at all — withhold it and this session is a leaf.",
|
|
205
205
|
`export PI_GRANTS_GRANT="${input.live.join(",")}"`,
|
|
206
206
|
"",
|
|
207
|
-
"#
|
|
208
|
-
'#
|
|
207
|
+
"# Init enables this project ledger. It is LOAD-BEARING: a spawn that cannot be recorded is refused.",
|
|
208
|
+
'# PI_GRANTS_LEDGER still overrides the stored default used by plain `pi` after `/grants init`.',
|
|
209
|
+
'export PI_GRANTS_LEDGER=".pi/grants.jsonl"',
|
|
209
210
|
"",
|
|
210
211
|
"# Optional. tool:bash is ALREADY gated by default, so this line only matters if you widen it:",
|
|
211
212
|
"# gating is closed under subsumption, so gating tool:write also gates tool:bash (bash can write).",
|
package/src/grant-store.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
2
|
+
* The init choice for a directory, stored **outside** it: its grant and, in v2, explicit project-ledger
|
|
3
|
+
* consent.
|
|
3
4
|
*
|
|
4
|
-
* `PI_GRANTS_GRANT`
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* `PI_GRANTS_GRANT` and `PI_GRANTS_LEDGER` remain the propagation channel to children — a parent writes them
|
|
6
|
+
* and every child inherits them. The store is a root-session source only, so an operator does not have to
|
|
7
|
+
* `source` a file and restart pi after making the project choice.
|
|
7
8
|
*
|
|
8
9
|
* **Outside the workspace, and that is the whole design.** A grant is a ceiling; a ceiling a governed child
|
|
9
10
|
* can rewrite is not a ceiling. `<cwd>/.pi/grants.env` is writable by any child holding `tool:write`, so
|
|
@@ -23,11 +24,11 @@ import { readFileSync } from "node:fs";
|
|
|
23
24
|
import { mkdir, readFile, rename, rm, unlink, writeFile } from "node:fs/promises";
|
|
24
25
|
import { randomUUID } from "node:crypto";
|
|
25
26
|
import { homedir } from "node:os";
|
|
26
|
-
import { basename, dirname, join } from "node:path";
|
|
27
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
27
28
|
import { withFileLock, LockTimeoutError } from "./file-lock.ts";
|
|
28
29
|
import type { Capability } from "./resolve.ts";
|
|
29
30
|
|
|
30
|
-
interface
|
|
31
|
+
interface GrantFileV1 {
|
|
31
32
|
version: 1;
|
|
32
33
|
/** The directory this grant is for. Checked on read — an entry copied elsewhere is refused (R-27). */
|
|
33
34
|
cwd: string;
|
|
@@ -36,6 +37,25 @@ interface GrantFile {
|
|
|
36
37
|
writtenAt: string;
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
interface GrantFileV2 {
|
|
41
|
+
version: 2;
|
|
42
|
+
cwd: string;
|
|
43
|
+
grant: Capability[];
|
|
44
|
+
/** Explicit consent from ADR-0037's `/grants init`; never inferred from a legacy file merely existing. */
|
|
45
|
+
projectLedger: true;
|
|
46
|
+
writtenAt: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface StoredGrant {
|
|
50
|
+
grant: Capability[];
|
|
51
|
+
/** Whether a root session defaults to `<cwd>/.pi/grants.jsonl`. False for every legacy v1 store. */
|
|
52
|
+
projectLedger: boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface SaveGrantOptions {
|
|
56
|
+
projectLedger?: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
39
59
|
/** `$PI_CODING_AGENT_DIR`, or pi's default. Same resolution as the approval store. */
|
|
40
60
|
function agentDir(): string {
|
|
41
61
|
return process.env.PI_CODING_AGENT_DIR ?? join(homedir(), ".pi", "agent");
|
|
@@ -55,28 +75,42 @@ export function grantStorePath(cwd: string): string {
|
|
|
55
75
|
}
|
|
56
76
|
|
|
57
77
|
/**
|
|
58
|
-
* Parse a store file's text into
|
|
78
|
+
* Parse a store file's text into its versioned project choice, or null.
|
|
59
79
|
*
|
|
60
80
|
* Split out from the readers so the **one** validation lives in one place: both the sync and async paths
|
|
61
81
|
* must agree, and two parsers is how they come to disagree.
|
|
62
82
|
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
83
|
+
* Rejects every doubt at this parser boundary — it never constructs a partial ceiling. The session currently
|
|
84
|
+
* treats absent and invalid stores alike (R-175), so do not call that wider behavior fail-closed. The `cwd`
|
|
85
|
+
* check is R-27's: a copied file describes a directory nobody authorised it for.
|
|
66
86
|
*/
|
|
67
|
-
export function
|
|
87
|
+
export function parseStoredGrant(text: string, cwd: string): StoredGrant | null {
|
|
68
88
|
try {
|
|
69
|
-
const parsed = JSON.parse(text) as
|
|
70
|
-
|
|
89
|
+
const parsed = JSON.parse(text) as {
|
|
90
|
+
version?: unknown;
|
|
91
|
+
cwd?: unknown;
|
|
92
|
+
grant?: unknown;
|
|
93
|
+
projectLedger?: unknown;
|
|
94
|
+
};
|
|
95
|
+
if (parsed.version !== 1 && parsed.version !== 2) return null;
|
|
71
96
|
if (parsed.cwd !== cwd) return null;
|
|
72
97
|
if (!Array.isArray(parsed.grant)) return null;
|
|
73
98
|
if (!parsed.grant.every((c) => typeof c === "string" && c.length > 0)) return null;
|
|
74
|
-
|
|
99
|
+
if (parsed.version === 2 && parsed.projectLedger !== true) return null;
|
|
100
|
+
return {
|
|
101
|
+
grant: parsed.grant as Capability[],
|
|
102
|
+
projectLedger: parsed.version === 2,
|
|
103
|
+
};
|
|
75
104
|
} catch {
|
|
76
105
|
return null;
|
|
77
106
|
}
|
|
78
107
|
}
|
|
79
108
|
|
|
109
|
+
/** Compatibility view for callers that need only the capability ceiling. */
|
|
110
|
+
export function parseGrantFile(text: string, cwd: string): Capability[] | null {
|
|
111
|
+
return parseStoredGrant(text, cwd)?.grant ?? null;
|
|
112
|
+
}
|
|
113
|
+
|
|
80
114
|
/**
|
|
81
115
|
* Read this directory's stored grant, synchronously.
|
|
82
116
|
*
|
|
@@ -86,27 +120,40 @@ export function parseGrantFile(text: string, cwd: string): Capability[] | null {
|
|
|
86
120
|
* decision it exists to inform, so the store would silently fail to grant delegation — the exact class of
|
|
87
121
|
* defect R-38 and R-39 were.
|
|
88
122
|
*/
|
|
89
|
-
export function
|
|
123
|
+
export function loadStoredGrantSync(cwd: string): StoredGrant | null {
|
|
90
124
|
try {
|
|
91
|
-
return
|
|
125
|
+
return parseStoredGrant(readFileSync(grantStorePath(cwd), "utf8"), cwd);
|
|
92
126
|
} catch {
|
|
93
127
|
return null;
|
|
94
128
|
}
|
|
95
129
|
}
|
|
96
130
|
|
|
131
|
+
export function loadGrantSync(cwd: string): Capability[] | null {
|
|
132
|
+
return loadStoredGrantSync(cwd)?.grant ?? null;
|
|
133
|
+
}
|
|
134
|
+
|
|
97
135
|
/** Async twin, for callers that already have one. Same parser, so they cannot disagree. */
|
|
98
|
-
export async function
|
|
136
|
+
export async function loadStoredGrant(cwd: string): Promise<StoredGrant | null> {
|
|
99
137
|
try {
|
|
100
|
-
return
|
|
138
|
+
return parseStoredGrant(await readFile(grantStorePath(cwd), "utf8"), cwd);
|
|
101
139
|
} catch {
|
|
102
140
|
return null;
|
|
103
141
|
}
|
|
104
142
|
}
|
|
105
143
|
|
|
144
|
+
export async function loadGrant(cwd: string): Promise<Capability[] | null> {
|
|
145
|
+
return (await loadStoredGrant(cwd))?.grant ?? null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** The one project-local default ADR-0037 binds to an explicit v2 init choice. */
|
|
149
|
+
export function projectLedgerPath(cwd: string): string {
|
|
150
|
+
return resolve(cwd, ".pi", "grants.jsonl");
|
|
151
|
+
}
|
|
152
|
+
|
|
106
153
|
export type SaveOutcome = "saved" | "failed" | "busy";
|
|
107
154
|
|
|
108
155
|
/**
|
|
109
|
-
* Write this directory's grant.
|
|
156
|
+
* Write this directory's grant and optional project-ledger consent as one atomic choice.
|
|
110
157
|
*
|
|
111
158
|
* Locked with the same lock the ledger and the approval store use, for the same reason: two sessions in one
|
|
112
159
|
* directory running `/grants init` concurrently must not interleave. A lock this cannot take yields `busy`
|
|
@@ -117,9 +164,16 @@ export type SaveOutcome = "saved" | "failed" | "busy";
|
|
|
117
164
|
* filesystem, so a reader never sees a half-written grant. Both copied from `writeFileSafely`, deliberately
|
|
118
165
|
* — a second, subtly different atomic-write is how the two come to disagree about what "safe" meant.
|
|
119
166
|
*/
|
|
120
|
-
export async function saveGrant(
|
|
167
|
+
export async function saveGrant(
|
|
168
|
+
cwd: string,
|
|
169
|
+
grant: Capability[],
|
|
170
|
+
options: SaveGrantOptions = {},
|
|
171
|
+
): Promise<SaveOutcome> {
|
|
121
172
|
const path = grantStorePath(cwd);
|
|
122
|
-
const
|
|
173
|
+
const common = { cwd, grant: [...grant].sort(), writtenAt: new Date().toISOString() };
|
|
174
|
+
const file: GrantFileV1 | GrantFileV2 = options.projectLedger
|
|
175
|
+
? { version: 2, ...common, projectLedger: true }
|
|
176
|
+
: { version: 1, ...common };
|
|
123
177
|
try {
|
|
124
178
|
await mkdir(dirname(path), { recursive: true });
|
|
125
179
|
return await withFileLock(path, "grant store", async () => {
|
package/src/herdr-poll.ts
CHANGED
|
@@ -67,7 +67,7 @@ export async function waitForSettled(
|
|
|
67
67
|
): Promise<{ status?: string; timedOut?: boolean; aborted?: boolean; spawnError?: string }> {
|
|
68
68
|
const interval = request.pollIntervalMs ?? POLL_INTERVAL_MS;
|
|
69
69
|
// ADR-0032. The pane is read on every poll so the parent can show what the child is doing, rather than the
|
|
70
|
-
// one word `delegate` for up to
|
|
70
|
+
// one word `delegate` for up to twenty minutes by default.
|
|
71
71
|
//
|
|
72
72
|
// No cross-poll state is kept, deliberately: the previous design remembered what it had reported so it could
|
|
73
73
|
// send a diff, and that is what broke — see `tailLines`. A snapshot needs no memory.
|
package/src/run-child.ts
CHANGED
|
@@ -111,8 +111,8 @@ export interface ChildRunResult {
|
|
|
111
111
|
|
|
112
112
|
/** 1 MiB. A delegation returns a summary; anything larger is a runaway, not an answer. */
|
|
113
113
|
export const DEFAULT_MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
114
|
-
/**
|
|
115
|
-
export const DEFAULT_TIMEOUT_MS =
|
|
114
|
+
/** 20 minutes. Long-running sub-agent work often exceeded ten; a hang remains bounded. */
|
|
115
|
+
export const DEFAULT_TIMEOUT_MS = 20 * 60 * 1000;
|
|
116
116
|
/** Grace between SIGTERM and SIGKILL. A child that ignores SIGTERM must not make the timeout advisory. */
|
|
117
117
|
export const DEFAULT_KILL_GRACE_MS = 5000;
|
|
118
118
|
|