pi-daddy 0.17.0 → 0.18.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/CHANGELOG.md +154 -80
- package/README.md +54 -25
- package/dist/approval-prompt.d.ts +3 -1
- package/dist/approval-prompt.d.ts.map +1 -1
- package/dist/approval-prompt.js +1 -1
- package/dist/approval-prompt.js.map +1 -1
- package/dist/approval-store.d.ts.map +1 -1
- package/dist/approval-store.js +4 -1
- package/dist/approval-store.js.map +1 -1
- package/dist/approval.d.ts +20 -2
- package/dist/approval.d.ts.map +1 -1
- package/dist/approval.js +26 -6
- package/dist/approval.js.map +1 -1
- package/dist/chain.d.ts +6 -1
- package/dist/chain.d.ts.map +1 -1
- package/dist/chain.js +1 -1
- package/dist/chain.js.map +1 -1
- package/dist/check-runner.d.ts +61 -0
- package/dist/check-runner.d.ts.map +1 -0
- package/dist/check-runner.js +237 -0
- package/dist/check-runner.js.map +1 -0
- package/dist/correlation.d.ts +90 -0
- package/dist/correlation.d.ts.map +1 -0
- package/dist/correlation.js +183 -0
- package/dist/correlation.js.map +1 -0
- package/dist/delegate-types.d.ts +140 -0
- package/dist/delegate-types.d.ts.map +1 -0
- package/dist/delegate-types.js +8 -0
- package/dist/delegate-types.js.map +1 -0
- package/dist/delegate.d.ts +4 -128
- package/dist/delegate.d.ts.map +1 -1
- package/dist/delegate.js +68 -72
- package/dist/delegate.js.map +1 -1
- package/dist/delegation-approval.d.ts +36 -0
- package/dist/delegation-approval.d.ts.map +1 -0
- package/dist/delegation-approval.js +67 -0
- package/dist/delegation-approval.js.map +1 -0
- package/dist/git-identity.d.ts +13 -0
- package/dist/git-identity.d.ts.map +1 -0
- package/dist/git-identity.js +44 -0
- package/dist/git-identity.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/lease-record.d.ts +78 -0
- package/dist/lease-record.d.ts.map +1 -0
- package/dist/lease-record.js +52 -0
- package/dist/lease-record.js.map +1 -0
- package/dist/ledger-events.d.ts +87 -0
- package/dist/ledger-events.d.ts.map +1 -0
- package/dist/ledger-events.js +45 -0
- package/dist/ledger-events.js.map +1 -0
- package/dist/ledger-report.d.ts +19 -12
- package/dist/ledger-report.d.ts.map +1 -1
- package/dist/ledger-report.js +81 -1
- package/dist/ledger-report.js.map +1 -1
- package/dist/ledger.d.ts +44 -1
- package/dist/ledger.d.ts.map +1 -1
- package/dist/ledger.js +20 -2
- package/dist/ledger.js.map +1 -1
- package/dist/refusals.d.ts +16 -0
- package/dist/refusals.d.ts.map +1 -0
- package/dist/refusals.js +51 -0
- package/dist/refusals.js.map +1 -0
- package/dist/run-child.d.ts +4 -0
- package/dist/run-child.d.ts.map +1 -1
- package/dist/run-child.js +21 -1
- package/dist/run-child.js.map +1 -1
- package/dist/run-herdr.d.ts +7 -0
- package/dist/run-herdr.d.ts.map +1 -1
- package/dist/run-herdr.js +41 -12
- package/dist/run-herdr.js.map +1 -1
- package/dist/workspace-lease.d.ts +28 -0
- package/dist/workspace-lease.d.ts.map +1 -0
- package/dist/workspace-lease.js +276 -0
- package/dist/workspace-lease.js.map +1 -0
- package/dist/workspace.d.ts +32 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +79 -0
- package/dist/workspace.js.map +1 -0
- package/extensions/approval-banking.ts +66 -0
- package/extensions/approvals.ts +95 -7
- package/extensions/chain-approval-facts.ts +51 -0
- package/extensions/chain-ledger.ts +48 -0
- package/extensions/delegate-chain.ts +115 -81
- package/extensions/delegation.ts +81 -23
- package/extensions/execute-child.ts +289 -0
- package/extensions/fanout-outcome.ts +97 -0
- package/extensions/run-delegation.ts +130 -120
- package/extensions/session.ts +4 -0
- package/extensions/workspace-runtime.ts +165 -0
- package/package.json +17 -1
- package/src/approval-prompt.ts +4 -2
- package/src/approval-store.ts +4 -1
- package/src/approval.ts +47 -14
- package/src/chain.ts +3 -1
- package/src/check-runner.ts +341 -0
- package/src/correlation.ts +260 -0
- package/src/delegate-types.ts +144 -0
- package/src/delegate.ts +80 -179
- package/src/delegation-approval.ts +99 -0
- package/src/git-identity.ts +52 -0
- package/src/index.ts +50 -0
- package/src/lease-record.ts +119 -0
- package/src/ledger-events.ts +138 -0
- package/src/ledger-report.ts +90 -2
- package/src/ledger.ts +68 -3
- package/src/refusals.ts +66 -0
- package/src/run-child.ts +23 -1
- package/src/run-herdr.ts +41 -11
- package/src/workspace-lease.ts +303 -0
- package/src/workspace.ts +135 -0
package/CHANGELOG.md
CHANGED
|
@@ -12,86 +12,79 @@ 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.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
`
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
Names are now whitelisted at discovery and a refusal is printed with its reason.
|
|
89
|
-
|
|
90
|
-
- **Fixed before release: `npx pi-daddy init` printed nothing and exited 0 for every installed copy** (R-73).
|
|
91
|
-
npm installs a bin as a symlink, so `process.argv[1]` is the link and the entry-point guard compared it
|
|
92
|
-
against the real file's URL. Caught by the smoke test, which now runs the installed bin — the same class of
|
|
93
|
-
defect as the `exports` map that worked in the tree and threw for every consumer, and the second time that
|
|
94
|
-
script has caught it.
|
|
15
|
+
## 0.18.0 — generic runtime enforcement for external controllers
|
|
16
|
+
|
|
17
|
+
- Optional correlation metadata joins capability decisions to run/task/workspace/context IDs, candidate
|
|
18
|
+
`tree_sha`, sequence floors and opaque policy metadata. Trusted task/definition/request/effective digests
|
|
19
|
+
are computed separately; supplied IDs and digests never grant authority.
|
|
20
|
+
- Correlated gated approvals bind the exact definition, task, requested/effective capabilities,
|
|
21
|
+
workspace/context and parent. They do not inherit. Legacy calls without correlation keep their existing
|
|
22
|
+
approval behavior. Persisted approvals retain the 30-day expiry; `once` remains one-use. Concurrent exact
|
|
23
|
+
scopes never share a dialog or rebind one human answer to another task.
|
|
24
|
+
- Operator-registered Git worktrees can be selected by ID. The child starts at the validated canonical root;
|
|
25
|
+
a kernel `flock` permits at most one pi-daddy-governed writer per canonical root. Caller `read` cannot
|
|
26
|
+
lower write-capable grants; parent death stops the attached process/herdr tab before recovery. This is
|
|
27
|
+
coordination, **not path confinement** and not exclusion of unrelated writers or detached bash children.
|
|
28
|
+
- Stable refusal codes accompany existing human diagnostics.
|
|
29
|
+
- `pi-daddy/check-runner` runs operator-named executable+argv definitions without shell interpolation,
|
|
30
|
+
with an environment allowlist, timeout/output bounds, privately staged exact executable bytes, and
|
|
31
|
+
pre/post-verified Git HEAD/candidate-tree receipts under an exclusive coordination lease. Arbitrary
|
|
32
|
+
executables remain arbitrary code; no filesystem/network sandbox is claimed.
|
|
33
|
+
- **BREAKING — ledger format v2:** append-only capability, workspace-lease, child-lifecycle and
|
|
34
|
+
check-receipt events. The new reader accepts legacy grant lines. Three things a consumer must know, two of
|
|
35
|
+
which are compile-or-run breaks rather than advisories:
|
|
36
|
+
- External readers that assume every line is a grant record must **switch on `event`** first.
|
|
37
|
+
- `LedgerReport` (published via `pi-daddy/ledger`) gained **required** fields — `events`,
|
|
38
|
+
`workspaceLeases`, `lifecycle`. Any TypeScript consumer that constructs one, or handles it
|
|
39
|
+
exhaustively, breaks at compile time.
|
|
40
|
+
- `report.records` **changed meaning**: it counted every parsed line and now counts capability decisions
|
|
41
|
+
only, with lease/lifecycle/receipt lines going to `events`. A consumer reading it as "ledger lines"
|
|
42
|
+
silently gets a different number.
|
|
43
|
+
- A line carrying `ledgerVersion` is now **rejected as corrupt** unless it satisfies the full v2 field
|
|
44
|
+
set, which matters to anyone who hand-writes or re-emits ledger lines.
|
|
45
|
+
- **BREAKING — `correlation` is a whitelist.** Only the pinned schema 1.0 field set is accepted; strings are
|
|
46
|
+
capped at 512 characters, `assurance_scope` at 4 KB, and an **undeclared key is refused by name** rather
|
|
47
|
+
than passed through. A caller sending extra fields must stop. This is a privacy control: `correlation` is
|
|
48
|
+
model-facing and copied verbatim onto every append-only event, so an unbounded object was a channel for
|
|
49
|
+
writing arbitrary text into a file that carries no prompts, arguments or results.
|
|
50
|
+
- **BREAKING for direct API callers — `WorkspaceLease.release()` returns
|
|
51
|
+
`"released" | "released-unrecorded" | "lost"` and no longer throws**, and `recovered` is
|
|
52
|
+
`boolean | "unknown"`. `WorkspaceLeaseOutcome` gains `uncontended`, `released-unrecorded`, `lost` and
|
|
53
|
+
`retained`. Code that relied on `release()` rejecting must read the value instead.
|
|
54
|
+
- **Fixes from a six-reviewer pass over this candidate before release.** The capability invariant held on
|
|
55
|
+
every path any reviewer could construct; these are the runtime half. `flock`'s command inherits the lock
|
|
56
|
+
file descriptor (measured — `docs/probes/g35-flock-fd-inheritance`), so teardown killing only the wrapper
|
|
57
|
+
stranded the lock and reported it to everyone else as a conflict. `recovered` could assert a crash after a
|
|
58
|
+
clean handover and hide a real one. The herdr close loop retried forever while holding the lock. A bound
|
|
59
|
+
approval could be spent outside the workspace it named, because two of its six identity components were
|
|
60
|
+
read from caller-supplied correlation. A refused delegation could leave a 30-day approval on disk. A child
|
|
61
|
+
could mint the upstream controller's `BLOCKED_CRITICAL_ASSURANCE` verdict out of a timeout. Fan-out
|
|
62
|
+
discarded every sibling error but the first. Five planner refusals and every execution-phase failure
|
|
63
|
+
carried no stable code. See `docs/03-risks.md` R-99…R-118 and the ADR-0034 amendment, which also lists
|
|
64
|
+
what the pass did **not** resolve.
|
|
65
|
+
|
|
66
|
+
New public subpaths: `pi-daddy/correlation`, `pi-daddy/refusals`, `pi-daddy/workspace`, and
|
|
67
|
+
`pi-daddy/check-runner`.
|
|
68
|
+
|
|
69
|
+
## 0.17.1 — no functional change: the release that exists because a rule got enforced
|
|
70
|
+
|
|
71
|
+
**Nothing in the shipped code changed.** This tarball differs from 0.17.0 in its version and in this file,
|
|
72
|
+
and that is stated here rather than dressed up, because a changelog that implies behaviour changed is worse
|
|
73
|
+
than a version nobody needed. `dist/`, `src/` and `extensions/` are byte-identical to 0.17.0.
|
|
74
|
+
|
|
75
|
+
What happened is in the repository, not the package: working rule 10 — **`main` is only ever advanced by
|
|
76
|
+
merging a pull request** — plus `hooks/pre-commit`, which refuses a commit on `main` and names a recovery that
|
|
77
|
+
is never a force-push, and `test/branch-guard.test.ts`, which pins it against seven mutations of the hook
|
|
78
|
+
(tests are not published, so that file is not in this tarball either).
|
|
79
|
+
|
|
80
|
+
**Why a version at all**, since nothing here changed: rule 10 says version bumps take the same path as
|
|
81
|
+
everything else, and this one did — branch, PR, review, squash-merge. The rule's first draft was reviewed by
|
|
82
|
+
six independent agents across two rounds that found sixteen defects, including that *"never commit to `main`"*
|
|
83
|
+
forbids the merge the rule requires, and that the guard written to fix that had reproduced the same defect in
|
|
84
|
+
shell. `docs/03-risks.md` R-85 and the 2026-08-18 session-log entry hold the details.
|
|
85
|
+
|
|
86
|
+
**Also fixed here:** this file claimed "Newest first" while 0.14.0 sat above 0.17.0, 0.16.0 and 0.15.0. The
|
|
87
|
+
order is now what the sentence says it is.
|
|
95
88
|
|
|
96
89
|
## 0.17.0 — `delegate_chain`
|
|
97
90
|
|
|
@@ -244,6 +237,87 @@ pi
|
|
|
244
237
|
- **`init` counted authorisations and called them declarations** — "7 skill(s), 3 declaring allowed-tools"
|
|
245
238
|
when all seven declared.
|
|
246
239
|
|
|
240
|
+
## 0.14.0 — `pi-daddy init`, and a startup line that names what it will and will not spawn
|
|
241
|
+
|
|
242
|
+
> **Reviewed before release by five independent agents, one hypothesis each. All five found something, and
|
|
243
|
+
> nine defects were fixed here** — including one that executed arbitrary code from the file this feature
|
|
244
|
+
> tells you to commit (R-78), one that overwrote an operator's file and wrote through symlinks (R-79), and
|
|
245
|
+
> one where the startup line blamed your `SKILL.md` files for a misconfigured environment variable (R-81).
|
|
246
|
+
> **ADR-0029 came out of that review**: the generated grant is read-only by default. The reasoning for each
|
|
247
|
+
> is in `docs/03-risks.md` R-78 through R-82.
|
|
248
|
+
|
|
249
|
+
The pi-daddy half of making this package and a package of skills work together out of the box
|
|
250
|
+
(`docs/HANDOFF-principal-pi-skills-integration.md`, items B1/B2/B4; **ADR-0028**). Nothing about grant
|
|
251
|
+
resolution, enforcement, approvals or the ledger changed — this is the part before and around them.
|
|
252
|
+
|
|
253
|
+
- **The generated grant is READ-ONLY by default** (ADR-0029). `init` grants what the copied skills declare
|
|
254
|
+
minus anything that can change your machine — `bash`, `write`, `edit` and the universal capabilities are
|
|
255
|
+
written **commented**, naming the definitions that need them. `init` + `source` gives a working read-only
|
|
256
|
+
setup; widening costs one deliberate uncomment. The reason: `PI_GRANTS_GRANT` is what *bounds* a declared
|
|
257
|
+
ceiling, so generating it from those ceilings would give the bound and the bounded one author, and it
|
|
258
|
+
would not be you.
|
|
259
|
+
|
|
260
|
+
- **`npx pi-daddy init` scaffolds a governed project.** It reads `<cwd>/node_modules` for packages declaring
|
|
261
|
+
skills in their own `package.json` (`"pi": {"skills": [...]}`, pi's convention), copies each declared
|
|
262
|
+
`SKILL.md` into `.pi/skills/`, and writes an annotated `.pi/grants.env`. That replaces, per skill: make a
|
|
263
|
+
directory, copy the body, hand-write frontmatter, choose a capability set with no guidance, and assemble a
|
|
264
|
+
`PI_GRANTS_GRANT` string by hand — seven times for `principal-pi-skills`.
|
|
265
|
+
|
|
266
|
+
**It chooses no ceiling, and that boundary is the whole design.** A skill that declares `allowed-tools` is
|
|
267
|
+
copied byte for byte; one that declares none is copied with a *commented* placeholder and stays
|
|
268
|
+
unspawnable until a human fills it in. The placeholder is deliberately not a working example, so
|
|
269
|
+
uncommenting it unedited fails loudly instead of granting something nobody decided. An existing file is
|
|
270
|
+
**kept**, never overwritten — that edit is the capability decision, and a second `init` run is exactly
|
|
271
|
+
when it would be destroyed. `--force` exists and says what it costs.
|
|
272
|
+
|
|
273
|
+
- **Session start says how many definitions are spawnable, and names the withheld ones.** The line reported
|
|
274
|
+
the grant and never the definitions, so *"governance is working"* and *"did the install fail?"* looked
|
|
275
|
+
identical:
|
|
276
|
+
|
|
277
|
+
```
|
|
278
|
+
grants: 1 of 7 definitions spawnable — review
|
|
279
|
+
withheld: architect, build, … — need agent:architect, …, which this session does not hold
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Classified by the same planner a real spawn comes through (no human is asked, stored approvals count), and
|
|
283
|
+
it speaks even when **nothing** is spawnable — which is the state most worth being told about. It is an
|
|
284
|
+
upper bound: it runs before the tool surface is observed, and `/grants` is the settled answer.
|
|
285
|
+
|
|
286
|
+
- **A worked `principal-pi-skills` example in the README**, replacing the invented one, with every line
|
|
287
|
+
produced by running the commands (`docs/probes/b2-init-principal-pi-skills`).
|
|
288
|
+
|
|
289
|
+
- **Fixed before release: a skill's `allowed-tools` VALUE could execute code from the generated grant file**
|
|
290
|
+
(R-78). `ceilingForDefinition` passes `ext:`/`skill:`/`agent:` entries through as written — correct for
|
|
291
|
+
enforcement, where the catalog refuses what it does not know — so a package declaring
|
|
292
|
+
`allowed-tools: Read,ext:x";touch /tmp/pwned;PI_GRANTS_GRANT="` produced a `.pi/grants.env` that ran the
|
|
293
|
+
payload when sourced: silently, exit 0, with the variable left looking plausible. It survives
|
|
294
|
+
`--ignore-scripts` and travels in the file you commit. Declared ids are whitelisted now, `tool:*`/`agent:*`
|
|
295
|
+
from a package are refused, and the assembled grant is charset-checked before the file is written at all.
|
|
296
|
+
|
|
297
|
+
- **Fixed before release: `init` overwrote an operator's file and wrote through symlinks** (R-79). The
|
|
298
|
+
presence probe was `readFile`, which treats *unreadable* as *absent* — so a permissions-restricted
|
|
299
|
+
`SKILL.md` was replaced and its ceiling **widened**, with no `--force`. And `writeFile` follows symlinks, so
|
|
300
|
+
a dangling link at a target path created the file outside the project while reporting an in-project path.
|
|
301
|
+
Both are one `open(path, "wx")`. `--force` no longer regenerates `.pi/grants.env`, and `pi-daddy init
|
|
302
|
+
--Force` is no longer accepted as a silent no-op.
|
|
303
|
+
|
|
304
|
+
- **Fixed before release: the startup line blamed your files for a session-level refusal** (R-81). A session
|
|
305
|
+
at its depth limit, or with a malformed `PI_GRANTS_MAX_DEPTH`, was told its `SKILL.md` files were written
|
|
306
|
+
wrong — two lines above `/grants` saying "delegation is disabled (maxDepth 0)". A session with no
|
|
307
|
+
`tool:delegate`, which has no delegate tool at all, was told definitions were spawnable.
|
|
308
|
+
|
|
309
|
+
- **Fixed before release: a skill's directory name could write a capability into the generated grant**
|
|
310
|
+
(R-77). A name is interpolated into a comma-separated `PI_GRANTS_GRANT`, into a file the operator sources,
|
|
311
|
+
and into a path. A package shipping a directory called `a,tool:bash` produced
|
|
312
|
+
`PI_GRANTS_GRANT="agent:a,tool:bash,…"` — `tool:bash` in an operator's grant, declared by no definition.
|
|
313
|
+
Names are now whitelisted at discovery and a refusal is printed with its reason.
|
|
314
|
+
|
|
315
|
+
- **Fixed before release: `npx pi-daddy init` printed nothing and exited 0 for every installed copy** (R-73).
|
|
316
|
+
npm installs a bin as a symlink, so `process.argv[1]` is the link and the entry-point guard compared it
|
|
317
|
+
against the real file's URL. Caught by the smoke test, which now runs the installed bin — the same class of
|
|
318
|
+
defect as the `exports` map that worked in the tree and threw for every consumer, and the second time that
|
|
319
|
+
script has caught it.
|
|
320
|
+
|
|
247
321
|
## 0.13.0 — the approvals file gets the lock the ledger already had, and two silences end
|
|
248
322
|
|
|
249
323
|
Closing the last items that were open rather than out of scope, then **red-teaming the result**: an
|
package/README.md
CHANGED
|
@@ -193,12 +193,13 @@ A chain's handoff is wrapped in a labelled, **nonce-delimited** fence, so the pr
|
|
|
193
193
|
data — and because the nonce is minted after that agent finished, it cannot forge a closing delimiter to escape its
|
|
194
194
|
own fence. The label itself is framing and this README will not pretend otherwise; the nonce is the mechanism.
|
|
195
195
|
|
|
196
|
-
A chain is **gated upfront**: every step is planned first, and every approval it needs is
|
|
197
|
-
first step starts
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
`Allow once` covers exactly
|
|
201
|
-
|
|
196
|
+
A legacy uncorrelated chain is **gated upfront**: every step is planned first, and every approval it needs is
|
|
197
|
+
asked for before the first step starts. Exact correlated steps gate only after their composed task exists;
|
|
198
|
+
binding a template and spending it on different generated instructions would be false assurance. One dialog
|
|
199
|
+
per capability and definition names the step that needs it. Decline an upfront gate and nothing runs. A step
|
|
200
|
+
that could never run refuses before anyone is asked; `Allow once` covers exactly the step it named. A failed
|
|
201
|
+
step stops the rest, and you still get everything completed—except `BLOCKED_CRITICAL_ASSURANCE`, which
|
|
202
|
+
remains a failed tool call. Each step spends one unit of the fan-out budget.
|
|
202
203
|
|
|
203
204
|
### Two executors, one plan
|
|
204
205
|
|
|
@@ -269,11 +270,10 @@ cannot make the next legitimate write destroy every other entry.
|
|
|
269
270
|
|
|
270
271
|
**Other properties worth knowing:**
|
|
271
272
|
|
|
272
|
-
- **
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
matches any subject one hop down.
|
|
273
|
+
- **Legacy session/always approvals ride down the tree with the grant**, intersected with what each child
|
|
274
|
+
actually receives, so `approved ⊆ grant` holds at every level. `once` is dropped. A correlated approval
|
|
275
|
+
instead binds the exact definition, task, requested/effective sets, workspace/context and parent, and
|
|
276
|
+
never crosses a delegation boundary — approval for one probe cannot become subtree authority.
|
|
277
277
|
- **Concurrent callers share one dialog per `capability@subject`, but only share the *answer* when it was
|
|
278
278
|
about more than one spawn.** `session`, `always`, a decline and an error answer everyone; **a `once` is
|
|
279
279
|
consumed by exactly one caller** and the rest are asked their own question. Measured before the fix: four
|
|
@@ -320,6 +320,28 @@ Seven further tests in that file cost no model tokens and cover the reload and e
|
|
|
320
320
|
transcripts in `docs/probes/approval-ux` describe an interceptor path that no longer exists — they are kept
|
|
321
321
|
as the record of that run and are not a description of this version.
|
|
322
322
|
|
|
323
|
+
## Runtime enforcement for external controllers (0.18.0)
|
|
324
|
+
|
|
325
|
+
All fields are optional; existing callers behave unchanged.
|
|
326
|
+
|
|
327
|
+
- `correlation` carries join-only run/task/workspace/context IDs, opaque policy metadata, base/head/tree SHAs
|
|
328
|
+
and sequence floors. Supplied IDs/digests never authorize; trusted digests are computed separately.
|
|
329
|
+
- `workspace: {workspace_id, access}` resolves through `PI_GRANTS_WORKSPACE_REGISTRY`, validates a canonical
|
|
330
|
+
Git worktree root, and sets initial CWD. A caller cannot label a write-capable grant read-only. Kernel
|
|
331
|
+
util-linux `flock` allows one **pi-daddy-governed** writer per canonical root; `setpriv --pdeathsig` plus
|
|
332
|
+
helper attachment stops the writer process or herdr tab on parent death before release. This does not confine paths or exclude unrelated writers; `bash` remains an escape.
|
|
333
|
+
- Refusals retain current prose and add stable codes such as `CAPABILITY_ESCALATION`,
|
|
334
|
+
`GATED_UNAPPROVED`, `APPROVAL_SCOPE_MISMATCH`, and `WORKSPACE_WRITE_CONFLICT`.
|
|
335
|
+
- Ledger v2 adds joinable capability, lease, lifecycle and check-receipt events while reading legacy lines.
|
|
336
|
+
- `pi-daddy/check-runner` selects an operator-named absolute executable+argv definition, never a shell
|
|
337
|
+
command string. It strips sensitive inherited environment, enforces timeout/output caps, executes a
|
|
338
|
+
private copy of the exact executable bytes it hashed, and pre/post-verifies Git head/candidate-tree
|
|
339
|
+
identity under an exclusive coordination lease. The executable remains arbitrary code; no filesystem or
|
|
340
|
+
network sandbox is claimed.
|
|
341
|
+
|
|
342
|
+
Public subpaths: `pi-daddy/correlation`, `pi-daddy/refusals`, `pi-daddy/workspace`,
|
|
343
|
+
`pi-daddy/check-runner`.
|
|
344
|
+
|
|
323
345
|
## Running it
|
|
324
346
|
|
|
325
347
|
```bash
|
|
@@ -485,8 +507,10 @@ everything below it.
|
|
|
485
507
|
| `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). |
|
|
486
508
|
| `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. |
|
|
487
509
|
| `PI_GRANTS_LEDGER` | unset → not recording | **Setting this makes the ledger load-bearing** — see below. |
|
|
510
|
+
| `PI_GRANTS_WORKSPACE_REGISTRY` | unset | Operator-owned `{version:1, workspaces:{id:{path}}}` file, required only for workspace-routed spawns. |
|
|
511
|
+
| `PI_GRANTS_WORKSPACE_LEASE_DIR` | under `$PI_CODING_AGENT_DIR/pi-daddy/` | Kernel writer locks and ownership metadata. |
|
|
488
512
|
| `PI_GRANTS_CHILD_TIMEOUT` | `600` (seconds) | Wall-clock limit for a child. Inherited by descendants — an operator preference, deliberately *not* attenuating state. |
|
|
489
|
-
| `PI_GRANTS_FANOUT` | `8` |
|
|
513
|
+
| `PI_GRANTS_FANOUT` | `8` | Per-call width and downward subtree budget; not a session-total counter. Malformed or `0` falls back to the default. |
|
|
490
514
|
| `PI_GRANTS_PARENT_ID` | `d0` | This session's ledger id; set by the parent. Makes sibling records joinable into a tree. |
|
|
491
515
|
| `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`. |
|
|
492
516
|
| `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. |
|
|
@@ -508,7 +532,10 @@ is broken after 10s.
|
|
|
508
532
|
|
|
509
533
|
## The ledger
|
|
510
534
|
|
|
511
|
-
Append-only JSONL.
|
|
535
|
+
Append-only JSONL. Version 2 records capability decisions plus workspace-lease, child-lifecycle and
|
|
536
|
+
check-receipt events. Every per-child capability decision is present, **including refusals**; call-level
|
|
537
|
+
schema/cardinality rejections that create no child ID are not capability events. The reader still accepts
|
|
538
|
+
legacy grant-only lines.
|
|
512
539
|
|
|
513
540
|
Ids are hierarchical and derived: a child of `d0` is `d0.1`, its own second child `d0.1.2`. Ancestry reads
|
|
514
541
|
from the id alone with no join, and it is reproducible, so two runs of the same fan-out produce a diffable
|
|
@@ -516,9 +543,10 @@ ledger. `denied` non-empty is the one designated escalation signal — **an agen
|
|
|
516
543
|
hold is an escalation attempt, and it is invisible without a record.**
|
|
517
544
|
|
|
518
545
|
**Privacy is a property of this file, and the boundary is exact: capability ids, counts and identifiers only
|
|
519
|
-
— never prompts, tool arguments or results.**
|
|
520
|
-
|
|
521
|
-
|
|
546
|
+
— never prompts, task text, tool arguments or results.** Trusted `definitionDigest` and `taskDigest` values
|
|
547
|
+
identify the exact operator body and task. A predictable task can be guessed from SHA-256, so its digest is
|
|
548
|
+
sensitive/linkable metadata, not anonymization. Caller-supplied digest-looking values remain under
|
|
549
|
+
`correlation` and never authorize.
|
|
522
550
|
|
|
523
551
|
## Propagation is race-free by construction
|
|
524
552
|
|
|
@@ -655,12 +683,12 @@ every in-repo test passed. `npm run test:smoke` packs a tarball, installs it int
|
|
|
655
683
|
## Testing
|
|
656
684
|
|
|
657
685
|
```bash
|
|
658
|
-
npm test #
|
|
686
|
+
npm test # 587 unit tests. Fast, pure, no pi, no network.
|
|
659
687
|
npm run typecheck # src + extensions + tests + integration tests
|
|
660
|
-
npm run test:integration #
|
|
688
|
+
npm run test:integration # 44 tests against a REAL pi process. ~55s, no model tokens.
|
|
661
689
|
npm run test:smoke # pack, install into a scratch project, import and use it — and run the
|
|
662
690
|
# installed `pi-daddy init` bin, which is how R-73 was found
|
|
663
|
-
PI_GRANTS_IT_MODEL=1 npm run test:integration # +
|
|
691
|
+
PI_GRANTS_IT_MODEL=1 npm run test:integration # + 10 end-to-end tests with a real model. Costs money.
|
|
664
692
|
```
|
|
665
693
|
|
|
666
694
|
The resolver is a pure function, which is deliberate: it is the only place an escalation could be
|
|
@@ -685,15 +713,16 @@ its own author the day after it was added: rather than raise the cap, `delegatio
|
|
|
685
713
|
|
|
686
714
|
## Status
|
|
687
715
|
|
|
688
|
-
**0.
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
both the tools and the instructions).
|
|
716
|
+
**0.18.0 — generic runtime enforcement, still honest about scope.** The governed spawn path now includes
|
|
717
|
+
optional correlation, exact task-bound approvals, registered-worktree CWD validation, OS-backed governed
|
|
718
|
+
writer leases, structured refusals, lifecycle/lease ledger events, and a no-shell named-check subpath. All
|
|
719
|
+
new spawn fields are optional; legacy callers retain their behavior.
|
|
693
720
|
|
|
694
721
|
Known gaps, stated because a gap nobody wrote down is the one that surprises somebody:
|
|
695
722
|
|
|
696
|
-
- **`bash` escapes governance.** Out of scope by decision (ADR-0012).
|
|
723
|
+
- **`bash` escapes governance.** Out of scope by decision (ADR-0012); workspace routing and leases do not contain it.
|
|
724
|
+
- **A workspace lease coordinates only pi-daddy-governed writers.** It is not a filesystem sandbox and cannot stop unrelated processes. The measured writer path currently requires util-linux `flock`.
|
|
725
|
+
- **A named check is arbitrary code without shell interpolation.** It may write, use the network, invoke a shell or leave descendants; no OS containment is claimed.
|
|
697
726
|
- **`subagents:rpc:spawn` bypasses the tripwire.** Unfixable from here.
|
|
698
727
|
- **The ledger is verified at session start** when one is configured: a damaged trail announces itself, an intact one stays quiet.
|
|
699
728
|
- **A pane outlives its tool call only if its child settled.** A child that answered keeps its pane so you can
|
|
@@ -26,8 +26,10 @@ export interface PromptRequest {
|
|
|
26
26
|
/** Agent type name, or `DELEGATE_SUBJECT` on the delegate path. */
|
|
27
27
|
subject: string;
|
|
28
28
|
path: ApprovalPath;
|
|
29
|
-
/** Shown to the human for context. Never part of a key. */
|
|
29
|
+
/** Shown to the human for context. Never itself part of a key. */
|
|
30
30
|
task?: string;
|
|
31
|
+
/** Trusted exact-scope identity; bound requests single-flight only with an identical binding. */
|
|
32
|
+
bindingKey?: string;
|
|
31
33
|
signal?: AbortSignal;
|
|
32
34
|
}
|
|
33
35
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-prompt.d.ts","sourceRoot":"","sources":["../src/approval-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAA8B,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAClG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,gEAAgE;AAChE,MAAM,WAAW,UAAU;IACzB,MAAM,CACJ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAChD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/B,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,IAAI,CAAC;CACpE;AAED,eAAO,MAAM,UAAU,SAAS,CAAC;AAEjC,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAItD,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,CAAC;IACvB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,YAAY,CAAC;IACnB,
|
|
1
|
+
{"version":3,"file":"approval-prompt.d.ts","sourceRoot":"","sources":["../src/approval-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAA8B,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAClG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,gEAAgE;AAChE,MAAM,WAAW,UAAU;IACzB,MAAM,CACJ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAChD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/B,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,IAAI,CAAC;CACpE;AAED,eAAO,MAAM,UAAU,SAAS,CAAC;AAEjC,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAItD,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,CAAC;IACvB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,YAAY,CAAC;IACnB,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iGAAiG;IACjG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,GAAG,OAAO,CAAC;AAEzF,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IAC5B,qEAAqE;IACrE,IAAI,EAAE,iBAAiB,CAAC;IACxB,mCAAmC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,UAAU,CAAC;IACf,0FAA0F;IAC1F,KAAK,EAAE,OAAO,CAAC;IACf,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACzD;AAID;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAK5E;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,iBAAiB,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;AAEpE;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,IAAI,CAAC,OAAO,EAAE,mBAAmB,KAAK,YAAY,CAG3F;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,GAAE,iBAA6B,GACtC,YAAY,CAwEd"}
|
package/dist/approval-prompt.js
CHANGED
|
@@ -95,7 +95,7 @@ export function createApprovalGate(options, inFlight = new Map()) {
|
|
|
95
95
|
`(mode: ${options.mode}). Pre-approve it in an interactive session, or drop it from the request.`,
|
|
96
96
|
};
|
|
97
97
|
}
|
|
98
|
-
const key = approvalKey(request.capability, request.subject)
|
|
98
|
+
const key = `${approvalKey(request.capability, request.subject)}${request.bindingKey ? `#${request.bindingKey}` : ""}`;
|
|
99
99
|
// R-29. Join an in-flight dialog, but only *keep* its answer if that answer was about more than one
|
|
100
100
|
// spawn. A `once` belongs to whichever caller the human was actually looking at — the title shows
|
|
101
101
|
// that caller's task — so anyone else who joined must ask their own question rather than ride a yes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-prompt.js","sourceRoot":"","sources":["../src/approval-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,WAAW,EAAE,aAAa,EAAyC,MAAM,eAAe,CAAC;AAalG,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC;AAEjC,MAAM,CAAC,MAAM,YAAY,GAAkC;IACzD,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,wBAAwB;IACjC,MAAM,EAAE,wCAAwC;CACjD,CAAC;
|
|
1
|
+
{"version":3,"file":"approval-prompt.js","sourceRoot":"","sources":["../src/approval-prompt.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-store.d.ts","sourceRoot":"","sources":["../src/approval-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAOH,OAAO,EAAgB,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"approval-store.d.ts","sourceRoot":"","sources":["../src/approval-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAOH,OAAO,EAAgB,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAQ1G,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,aAAa,CAAC;IACrB,OAAO,EAAE,YAAY,CAAC;CACvB;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,eAAe,GAAG,IAAI,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASjD;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEvD;AAqED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,IAAI,CAAC;IACV,UAAU,EAAE,aAAa,CAAC;CAC3B;AAED,sFAAsF;AACtF,wBAAsB,aAAa,CACjC,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC;IAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAAC,OAAO,EAAE,eAAe,EAAE,CAAA;CAAE,CAAC,CAwB5E;AA4CD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,aAAa,EACpB,UAAU,EAAE,aAAa,EACzB,GAAG,EAAE,IAAI,GACR,OAAO,CAAC,OAAO,CAAC,CASlB;AAED;;;;;;;;;;;GAWG;AACH;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAErE,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,aAAa,EACzB,GAAG,EAAE,IAAI,GACR,OAAO,CAAC,aAAa,CAAC,CAOxB;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE7D"}
|
package/dist/approval-store.js
CHANGED
|
@@ -35,6 +35,7 @@ import { withFileLock } from "./file-lock.js";
|
|
|
35
35
|
import { homedir } from "node:os";
|
|
36
36
|
import { basename, dirname, join } from "node:path";
|
|
37
37
|
import { entryVerdict } from "./approval.js";
|
|
38
|
+
import { isApprovalBinding } from "./correlation.js";
|
|
38
39
|
/**
|
|
39
40
|
* Where persisted approvals live — **outside the governed workspace** (ADR-0014).
|
|
40
41
|
*
|
|
@@ -121,7 +122,8 @@ function isValidEntryShape(entry) {
|
|
|
121
122
|
return (typeof obj.approvedAt === "string" &&
|
|
122
123
|
typeof obj.expiresAt === "string" &&
|
|
123
124
|
typeof obj.cwd === "string" &&
|
|
124
|
-
Array.isArray(obj.grantAtApproval)
|
|
125
|
+
Array.isArray(obj.grantAtApproval) &&
|
|
126
|
+
(obj.binding === undefined || isApprovalBinding(obj.binding)));
|
|
125
127
|
}
|
|
126
128
|
/**
|
|
127
129
|
* Project every entry through its DECLARED fields on the way out (ADR-0021).
|
|
@@ -143,6 +145,7 @@ function sanitise(valid) {
|
|
|
143
145
|
cwd: e.cwd,
|
|
144
146
|
grantAtApproval: e.grantAtApproval,
|
|
145
147
|
...(e.bodyAtApproval !== undefined ? { bodyAtApproval: e.bodyAtApproval } : {}),
|
|
148
|
+
...(e.binding !== undefined ? { binding: structuredClone(e.binding) } : {}),
|
|
146
149
|
},
|
|
147
150
|
]));
|
|
148
151
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-store.js","sourceRoot":"","sources":["../src/approval-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,YAAY,EAA+D,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"approval-store.js","sourceRoot":"","sources":["../src/approval-store.ts"],"names":[],"mappings":"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"}
|
package/dist/approval.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* ADR-0010 records the four decisions encoded here.
|
|
10
10
|
*/
|
|
11
11
|
import type { Capability, ResolveResult } from "./resolve.ts";
|
|
12
|
+
import { type ApprovalBinding } from "./correlation.ts";
|
|
12
13
|
/** How far a single yes reaches in time. */
|
|
13
14
|
export type ApprovalScope = "once" | "session" | "always";
|
|
14
15
|
/** Where a yes came from, for the ledger. These call for different follow-ups, so they stay distinct. */
|
|
@@ -84,6 +85,11 @@ export interface InheritableApproval {
|
|
|
84
85
|
* no file to hash — and, per ADR-0019, is never persisted or offered `always` for the same reason.
|
|
85
86
|
*/
|
|
86
87
|
bodySha256?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Exact delegation binding for controllers that supply correlation/workspace context (ADR-0034).
|
|
90
|
+
* Bound approvals are deliberately not inherited: authority for one task must not become subtree-wide.
|
|
91
|
+
*/
|
|
92
|
+
binding?: ApprovalBinding;
|
|
87
93
|
}
|
|
88
94
|
/**
|
|
89
95
|
* What a child may inherit, as `capability@subject` keys.
|
|
@@ -145,6 +151,8 @@ export interface ApprovalEntry {
|
|
|
145
151
|
* predates 0.10.0 and cannot be verified, which `entryVerdict` treats as changed: fail closed.
|
|
146
152
|
*/
|
|
147
153
|
bodyAtApproval?: string;
|
|
154
|
+
/** Exact task/grant/workspace/context/parent binding for correlated controller calls (ADR-0034). */
|
|
155
|
+
binding?: ApprovalBinding;
|
|
148
156
|
}
|
|
149
157
|
export type EntryVerdict = "valid" | "expired" | "foreign-cwd" | "type-changed" | "instructions-changed" | "type-missing";
|
|
150
158
|
/**
|
|
@@ -193,9 +201,14 @@ export interface ResolveApprovalsInput {
|
|
|
193
201
|
subject: string;
|
|
194
202
|
/** Approval KEYS approved for this session, in memory only. */
|
|
195
203
|
sessionApprovals: ReadonlySet<string>;
|
|
196
|
-
/**
|
|
204
|
+
/** Exact bindings for correlated session approvals. Kept separate so legacy keys remain compatible. */
|
|
205
|
+
sessionApprovalBindings?: ReadonlyMap<string, ApprovalBinding>;
|
|
206
|
+
/** Persisted entries by key, ALREADY definition/expiry-filtered by the store. */
|
|
197
207
|
persisted: ReadonlyMap<string, ApprovalEntry>;
|
|
198
|
-
/**
|
|
208
|
+
/** When present, only an exact binding may satisfy this gate. */
|
|
209
|
+
expectedBinding?: ApprovalBinding;
|
|
210
|
+
/** Same-key persisted entries dropped specifically because their expiry passed. */
|
|
211
|
+
expiredKeys?: ReadonlySet<string>;
|
|
199
212
|
/**
|
|
200
213
|
* `capability@subject` keys inherited from the delegator (ADR-0014).
|
|
201
214
|
*
|
|
@@ -208,7 +221,12 @@ export interface ResolveApprovalsResult {
|
|
|
208
221
|
approved: Capability[];
|
|
209
222
|
/** Gated capabilities still requiring a live human. */
|
|
210
223
|
needsPrompt: Capability[];
|
|
224
|
+
/** A same-key approval existed but named another task/workspace/context/parent. */
|
|
225
|
+
scopeMismatched: Capability[];
|
|
226
|
+
expired: Capability[];
|
|
211
227
|
sources: Record<Capability, ApprovalSource>;
|
|
228
|
+
scopes: Record<Capability, ApprovalScope>;
|
|
229
|
+
expiresAt: Record<Capability, string>;
|
|
212
230
|
}
|
|
213
231
|
/**
|
|
214
232
|
* Satisfy as much of `gated` as possible without asking anyone.
|