pi-daddy 0.13.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 +187 -0
- package/LICENSE +21 -0
- package/README.md +584 -0
- package/dist/approval-prompt.d.ts +116 -0
- package/dist/approval-prompt.d.ts.map +1 -0
- package/dist/approval-prompt.js +124 -0
- package/dist/approval-prompt.js.map +1 -0
- package/dist/approval-store.d.ts +149 -0
- package/dist/approval-store.d.ts.map +1 -0
- package/dist/approval-store.js +311 -0
- package/dist/approval-store.js.map +1 -0
- package/dist/approval.d.ts +221 -0
- package/dist/approval.d.ts.map +1 -0
- package/dist/approval.js +244 -0
- package/dist/approval.js.map +1 -0
- package/dist/capabilities.d.ts +31 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +45 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/catalog.d.ts +81 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +164 -0
- package/dist/catalog.js.map +1 -0
- package/dist/definitions.d.ts +101 -0
- package/dist/definitions.d.ts.map +1 -0
- package/dist/definitions.js +182 -0
- package/dist/definitions.js.map +1 -0
- package/dist/delegate.d.ts +133 -0
- package/dist/delegate.d.ts.map +1 -0
- package/dist/delegate.js +261 -0
- package/dist/delegate.js.map +1 -0
- package/dist/fanout.d.ts +62 -0
- package/dist/fanout.d.ts.map +1 -0
- package/dist/fanout.js +84 -0
- package/dist/fanout.js.map +1 -0
- package/dist/file-lock.d.ts +54 -0
- package/dist/file-lock.d.ts.map +1 -0
- package/dist/file-lock.js +142 -0
- package/dist/file-lock.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/ledger-report.d.ts +106 -0
- package/dist/ledger-report.d.ts.map +1 -0
- package/dist/ledger-report.js +157 -0
- package/dist/ledger-report.js.map +1 -0
- package/dist/ledger.d.ts +139 -0
- package/dist/ledger.d.ts.map +1 -0
- package/dist/ledger.js +94 -0
- package/dist/ledger.js.map +1 -0
- package/dist/pane-reaper.d.ts +49 -0
- package/dist/pane-reaper.d.ts.map +1 -0
- package/dist/pane-reaper.js +120 -0
- package/dist/pane-reaper.js.map +1 -0
- package/dist/pi-tools.d.ts +20 -0
- package/dist/pi-tools.d.ts.map +1 -0
- package/dist/pi-tools.js +21 -0
- package/dist/pi-tools.js.map +1 -0
- package/dist/propagation.d.ts +185 -0
- package/dist/propagation.d.ts.map +1 -0
- package/dist/propagation.js +255 -0
- package/dist/propagation.js.map +1 -0
- package/dist/resolve.d.ts +110 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +181 -0
- package/dist/resolve.js.map +1 -0
- package/dist/run-child.d.ts +50 -0
- package/dist/run-child.d.ts.map +1 -0
- package/dist/run-child.js +109 -0
- package/dist/run-child.js.map +1 -0
- package/dist/run-herdr.d.ts +91 -0
- package/dist/run-herdr.d.ts.map +1 -0
- package/dist/run-herdr.js +306 -0
- package/dist/run-herdr.js.map +1 -0
- package/dist/spawn.d.ts +60 -0
- package/dist/spawn.d.ts.map +1 -0
- package/dist/spawn.js +116 -0
- package/dist/spawn.js.map +1 -0
- package/extensions/approvals.ts +285 -0
- package/extensions/delegation.ts +237 -0
- package/extensions/grants-command.ts +310 -0
- package/extensions/grants.ts +346 -0
- package/extensions/run-delegation.ts +270 -0
- package/extensions/session.ts +234 -0
- package/package.json +122 -0
- package/src/approval-prompt.ts +222 -0
- package/src/approval-store.ts +383 -0
- package/src/approval.ts +364 -0
- package/src/capabilities.ts +51 -0
- package/src/catalog.ts +186 -0
- package/src/definitions.ts +233 -0
- package/src/delegate.ts +383 -0
- package/src/fanout.ts +96 -0
- package/src/file-lock.ts +142 -0
- package/src/index.ts +59 -0
- package/src/ledger-report.ts +227 -0
- package/src/ledger.ts +214 -0
- package/src/pane-reaper.ts +132 -0
- package/src/pi-tools.ts +25 -0
- package/src/propagation.ts +308 -0
- package/src/resolve.ts +235 -0
- package/src/run-child.ts +149 -0
- package/src/run-herdr.ts +357 -0
- package/src/spawn.ts +156 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Changelog — pi-daddy
|
|
2
|
+
|
|
3
|
+
Newest first. **Breaking changes are marked and say what to do about them.**
|
|
4
|
+
|
|
5
|
+
This file exists because the README had grown ninety lines of stacked version banners before a reader
|
|
6
|
+
reached what the package *does* — churn documentation in front of product documentation. The banners are
|
|
7
|
+
the record of how the package got here and are worth keeping; they are not worth reading first.
|
|
8
|
+
|
|
9
|
+
> **0.13.0 is the first PUBLISHED release.** Every version below it was developed in this repository and
|
|
10
|
+
> never shipped to npm, so if you are reading this as a new user, **none of the breaking changes described
|
|
11
|
+
> below can have affected you** — there was no earlier version to install. They are kept because they are
|
|
12
|
+
> the record of how the package arrived at what it does, and because the reasoning behind each one is
|
|
13
|
+
> usually the clearest statement of why the current behaviour is what it is.
|
|
14
|
+
|
|
15
|
+
## 0.13.0 — the approvals file gets the lock the ledger already had, and two silences end
|
|
16
|
+
|
|
17
|
+
Closing the last items that were open rather than out of scope, then **red-teaming the result**: an
|
|
18
|
+
operator review and four independent agents, each given one hypothesis to attack. Between them they found
|
|
19
|
+
eight further defects **in that work**, all repaired here before release. The two worth knowing about
|
|
20
|
+
as a user of this package:
|
|
21
|
+
|
|
22
|
+
- **The file lock admitted two writers into the critical section.** `rm(lockPath)` deletes whatever is at
|
|
23
|
+
the path, not the lock this process created, so a broken stale lock cascaded: the old holder freed the new
|
|
24
|
+
owner's lock on the way out, and the next arrival — which raced nothing — walked in beside it. Reproduced
|
|
25
|
+
across real OS processes. Every lock now carries a token and proves ownership before deleting.
|
|
26
|
+
- **The ledger over-claimed human approval under concurrency.** One *Allow for this session* answered under
|
|
27
|
+
a fan-out of eight wrote eight lines each recording `approvalSource: "prompt"`. Riders now record
|
|
28
|
+
`session`, which is what actually happened.
|
|
29
|
+
|
|
30
|
+
One breaking change, and it is a type.
|
|
31
|
+
|
|
32
|
+
- **BREAKING: `revokeApproval` returns `"revoked" | "absent" | "failed" | "busy"`**, not a boolean. It had
|
|
33
|
+
two outcomes for four facts, and `/grants revoke` printed *"no persisted approval named X"* whenever the
|
|
34
|
+
write failed — telling an operator that the approval they are revoking does not exist **while it is still
|
|
35
|
+
in effect**. The most alarming outcome wore the most reassuring message. `busy` is separate because a lock
|
|
36
|
+
timeout happens *before* the load, so nothing was looked at and nothing may be claimed about the entry.
|
|
37
|
+
Callers switching on the boolean must switch on the string; `"revoked"` is the only success.
|
|
38
|
+
- **Approval writes hold a lock (R-49).** Every write is load → modify → write and none of them was
|
|
39
|
+
serialised, so session 1 could load, session 2 could revoke, and session 1's next save would restore the
|
|
40
|
+
revoked entry for the rest of its 30 days. The lock is the ledger's, moved to `src/file-lock.ts` and used
|
|
41
|
+
by both — one implementation, two callers, opposite failure policies: the ledger fails a delegation closed
|
|
42
|
+
when it cannot take the lock, the approvals store never fails your work, because it is a convenience cache.
|
|
43
|
+
- **`/grants ledger` counts where each approval came from.** ADR-0020 keeps the persistence layer on an
|
|
44
|
+
asserted fatigue argument and named the evidence that would settle it — `persisted` against `prompt` over
|
|
45
|
+
real use. The data was already recorded and nothing read it. **Two numbers, both labelled**: raw records
|
|
46
|
+
are an *upper bound* on prompts avoided, because within one session only the first would have been a
|
|
47
|
+
prompt and the rest come from the in-memory session cache; distinct `capability@subject` pairs are the
|
|
48
|
+
closer estimate. Reporting records alone overstated the layer twentyfold in the obvious case (R-63).
|
|
49
|
+
Records written before per-capability sources existed are reported as *not counted* rather than folded in,
|
|
50
|
+
because that older scalar over-claimed `prompt`.
|
|
51
|
+
- **A revoke is documented as taking effect at the next gate check**, not "immediately". A spawn whose gate
|
|
52
|
+
check already passed is not retracted by a revoke arriving microseconds later — inherent to revoking
|
|
53
|
+
anything, and no lock closes it.
|
|
54
|
+
- **An unreadable ledger no longer silences session start (R-60).** `verifyLedger` rethrows on anything but
|
|
55
|
+
a missing file, and that call sat inside an empty catch — so a `PI_GRANTS_LEDGER` pointing at a directory
|
|
56
|
+
produced no alarm, no warning, and not even the line saying governance was on.
|
|
57
|
+
- **Herdr panes opened by a killed process are closed at exit.** Coverage is exact and documented in
|
|
58
|
+
`src/pane-reaper.ts`: normal exit and `process.exit()` are covered; SIGKILL is not, and neither is a
|
|
59
|
+
SIGTERM nothing else in the process is listening for. **No signal handler is installed**, deliberately —
|
|
60
|
+
one here would suppress Node's default termination and turn pi's "interrupt this turn" into "exit pi".
|
|
61
|
+
|
|
62
|
+
## 0.11.0 is a breaking change: per-project approvals, and an inherited yes names its instructions
|
|
63
|
+
|
|
64
|
+
Four decisions taken together after the first independent review of this package's approval layer
|
|
65
|
+
(ADR-0020…ADR-0023). Two of them break compatibility.
|
|
66
|
+
|
|
67
|
+
- **Approvals are stored one file per project**, under `$PI_CODING_AGENT_DIR/grants-approvals/`. The
|
|
68
|
+
single shared file could not express two checkouts holding an approval for a same-named definition —
|
|
69
|
+
`review`, `deploy`, i.e. what happens the moment you reuse your own conventions — and every write
|
|
70
|
+
touched every project's data, which is where four defects came from. **The old file is ignored, not
|
|
71
|
+
migrated**, and reported once; re-approve when next asked.
|
|
72
|
+
- **`PI_GRANTS_APPROVED` carries a body digest**: `capability@subject#sha256`. A child verifies it against
|
|
73
|
+
the definition **it** loaded, because a child is a fresh process that re-reads from disk — so a
|
|
74
|
+
`git pull` mid-tree could otherwise let a descendant run rewritten instructions under a yes given about
|
|
75
|
+
the old ones. A 0.10 parent and a 0.11 child do not understand each other's format.
|
|
76
|
+
- **The task is never stored.** `taskAtApproval` is gone: it put model-authored text in an always-on file
|
|
77
|
+
outside your repository for 30 days, which this package's own rule forbids — and it displayed as though
|
|
78
|
+
it scoped the approval, which it never did.
|
|
79
|
+
- **`agent:*` exists.** "May spawn any of our definitions, but never hand over `write`" was previously
|
|
80
|
+
unexpressible; the only wildcard was `tool:*`, which is authority to grant every tool. `agent:*` confers
|
|
81
|
+
no tool authority. Do not pair it with `tool:bash`.
|
|
82
|
+
|
|
83
|
+
## 0.9.0 / 0.10.0: an approval is pinned to the *instructions* as well as the tools
|
|
84
|
+
|
|
85
|
+
**ADR-0018 and ADR-0019.** Two changes, and the second was a repair.
|
|
86
|
+
|
|
87
|
+
**Every spawn naming a definition now records a `definitionDigest`** — `{name, source, sha256}` over the
|
|
88
|
+
body, which is the exact text passed to the child as `--append-system-prompt`. So the ledger answers *"did
|
|
89
|
+
these four children run the same instructions?"* and *"has this definition changed since?"*. It does not
|
|
90
|
+
answer *what the instructions said*: the digest identifies text without reproducing it. **The task string
|
|
91
|
+
is never recorded, in any field, by decision** — it is assembled by the model from the parent's context and
|
|
92
|
+
could carry anything the parent could see.
|
|
93
|
+
|
|
94
|
+
**`always` approvals were unreachable and are not any more.** `offeredScopes` gated that scope on the
|
|
95
|
+
interceptor path, which 0.7.0 deleted — so **no version from 0.7.0 to 0.9.0 could create a persisted
|
|
96
|
+
approval at all**, and the whole store was guarding a file nothing could write. `delegate({agent: X})` now
|
|
97
|
+
approves against **`X`** and offers `always`; `delegate({tools: […]})` keeps the fixed `<delegate>` subject
|
|
98
|
+
and is still never offered it. A persisted entry pins the definition's `allowed-tools` **and** its body
|
|
99
|
+
digest, so rewriting what a child is told to do voids the approval (`instructions-changed`) — strictly
|
|
100
|
+
stronger than ADR-0010 designed, since the ceiling check alone could never have seen a body change. An
|
|
101
|
+
entry carrying no body pin fails closed: unverifiable is not unchanged.
|
|
102
|
+
|
|
103
|
+
## 0.8.0 is a breaking change: spawning a definition requires `agent:<name>`
|
|
104
|
+
|
|
105
|
+
**ADR-0017.** The catalog has always emitted `agent:<name>` for every definition and the parser has always
|
|
106
|
+
accepted it, but **nothing ever checked it** (R-35). The only gate on `delegate({agent: "deploy"})` was
|
|
107
|
+
whether that definition's `allowed-tools` fitted inside the session's grant — so governance covered what a
|
|
108
|
+
child *can do* and never *which operator-authored instructions it was given*, and an operator could not
|
|
109
|
+
say "this session may spawn `review` but not `deploy`".
|
|
110
|
+
|
|
111
|
+
**What you must change:** an enumerated `PI_GRANTS_GRANT` now needs an `agent:` id per definition it may
|
|
112
|
+
spawn. `PI_GRANTS_GRANT="tool:read,tool:delegate"` can spawn nothing by name; add `agent:review` to allow
|
|
113
|
+
that one. `tool:*` satisfies any of them, so an **ungoverned session is unaffected** and `delegate({tools:
|
|
114
|
+
[…]})` is untouched. The refusal names the missing capability and lists what the session *may* spawn.
|
|
115
|
+
|
|
116
|
+
It attenuates like every other capability: a definition's own `allowed-tools` may list `agent:other`,
|
|
117
|
+
which is how a delegator is told which definitions **it** may spawn — and a parent can never hand down one
|
|
118
|
+
it does not hold. The id authorises; it is never passed to `--tools`.
|
|
119
|
+
|
|
120
|
+
**Also fixed, and required for the above (R-36):** `deriveOwnGrant` filtered the inherited grant against
|
|
121
|
+
the session's *observed tools*, which silently dropped `skill:` and `agent:` capabilities at the first
|
|
122
|
+
provider request. A child holding `skill:review` therefore could not re-grant it, and `/grants` stopped
|
|
123
|
+
listing it. Only `tool:` and `ext:` are filtered now — an observation says nothing about a namespace that
|
|
124
|
+
is not tools.
|
|
125
|
+
|
|
126
|
+
## 0.7.0 is a breaking change: this package is now the spawner, not a fence
|
|
127
|
+
|
|
128
|
+
**ADR-0016.** Earlier versions were a governance layer wrapped around `@tintinweb/pi-subagents`: the
|
|
129
|
+
product was a `tool_call` interceptor that decided whether *someone else's* spawn was permissible. It
|
|
130
|
+
could refuse or allow, never narrow, because that package's `Agent` tool has no `tools` parameter — a
|
|
131
|
+
ceiling no amount of local work could lift.
|
|
132
|
+
|
|
133
|
+
This version spawns children itself, so **the grant is an argument rather than a veto**. What changed:
|
|
134
|
+
|
|
135
|
+
- **`delegate({agent, task})` spawns a definition by name.** Definitions are **Agent Skills
|
|
136
|
+
(`SKILL.md`)** files — the open standard, already read by 16+ tools — and their `allowed-tools` field
|
|
137
|
+
becomes the grant. The spec calls that field *"pre-approved"* and **experimental**; it declares intent
|
|
138
|
+
and blocks nothing. Passed through `--tools` it becomes structural. **The standard declares intent;
|
|
139
|
+
this package makes it enforced.**
|
|
140
|
+
- **`delegate_all` runs several children concurrently**, each with its own grant, its own instructions,
|
|
141
|
+
and no knowledge of the others.
|
|
142
|
+
- **Two executors, one plan**: a captured child process (default) or a visible, attachable **herdr** pane
|
|
143
|
+
(`PI_GRANTS_HERDR=1`).
|
|
144
|
+
- **Skills and context files are no longer inherited.** Previously a child spawned with `--tools read`
|
|
145
|
+
still loaded every skill the operator had, plus `CLAUDE.md` — measured, `docs/probes/g16-herdr`. So the
|
|
146
|
+
`skill:` capability namespace enforced nothing. It does now.
|
|
147
|
+
- **A cardinality bound.** A subtree *budget* caps how many descendants may exist at all, because the old
|
|
148
|
+
`delegate` bounded that to one only by accident of being blocking.
|
|
149
|
+
- **Removed:** the pi-subagents ceiling port (`agent-types.ts`, `interceptor.ts`). The `tool_call` hook
|
|
150
|
+
remains as a **tripwire** that refuses third-party spawn tools — installing one is a single command,
|
|
151
|
+
and a silently ungoverned descendant is the thing this package exists to prevent.
|
|
152
|
+
|
|
153
|
+
Built because that guarantee does not exist elsewhere. `@tintinweb/pi-subagents` provisions statically per
|
|
154
|
+
agent type and cannot be narrowed per spawn; `pi-fabric` provisions dynamically but **cannot constrain a
|
|
155
|
+
recursive child at all** (measured: `docs/probes/pi-fabric-eval`).
|
|
156
|
+
|
|
157
|
+
## Earlier
|
|
158
|
+
|
|
159
|
+
### 0.6.0
|
|
160
|
+
|
|
161
|
+
- **The approvals store moved out of the workspace** and a legacy in-workspace file is ignored with a
|
|
162
|
+
warning (see *Approving a gated capability*).
|
|
163
|
+
- **`PI_GRANTS_APPROVED` carries `capability@subject` pairs** and `once` no longer crosses a boundary
|
|
164
|
+
(**ADR-0014**). A 0.5.x parent and a 0.6.x child do not understand each other's format.
|
|
165
|
+
- **`bash` is gated by default** in a governed session, and gating is closed under subsumption, so
|
|
166
|
+
`PI_GRANTS_GATED=tool:write` also gates `bash` (**ADR-0012**). Set `PI_GRANTS_GATED=""` for the old
|
|
167
|
+
behaviour.
|
|
168
|
+
- **`delegate` is registered only when the session may delegate**, which is what the docs always claimed.
|
|
169
|
+
- Library entry points are compiled to `dist/`, so consumer imports work at all.
|
|
170
|
+
|
|
171
|
+
### 0.5.0 — hardening from two independent reviews
|
|
172
|
+
|
|
173
|
+
- **G1 · the argv channel.** Closed; see *Propagation is race-free by construction*.
|
|
174
|
+
- **G6 · the ledger.** It reported allowed wildcard spawns as escalation attempts, and dropped every
|
|
175
|
+
refusal decided before resolution. Both fixed at the type level, so a new early exit cannot reintroduce
|
|
176
|
+
them.
|
|
177
|
+
- **G7 · configuration.** Malformed bounds fail closed and say so; ungoverned sessions publish nothing; the
|
|
178
|
+
catalog is awaited rather than raced.
|
|
179
|
+
- **G8 · child processes.** Caps, timeout, abort-before-spawn, real errors for failed children.
|
|
180
|
+
- **ADR-0011 · universal capabilities** are refused on every path, and a wildcard-holding delegator no
|
|
181
|
+
longer bypasses a configured gate. Spawns that succeeded in 0.4.0 therefore fail — and **that reliance was
|
|
182
|
+
never sound**, since each of them handed a child either the entire catalog or a capability an operator had
|
|
183
|
+
explicitly gated. There is deliberately no override flag; the ledger names the capability and the reason.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
Requires pi ≥ 0.83.0, Node ≥ 22.19. MIT.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mojomanyana
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|