pi-daddy 0.14.0 → 0.16.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 +123 -0
- package/README.md +37 -14
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +10 -4
- package/dist/cli.js.map +1 -1
- package/dist/executor.d.ts +38 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +93 -0
- package/dist/executor.js.map +1 -0
- package/dist/grant-store.d.ts +68 -0
- package/dist/grant-store.d.ts.map +1 -0
- package/dist/grant-store.js +142 -0
- package/dist/grant-store.js.map +1 -0
- package/dist/herdr-cli.d.ts +78 -0
- package/dist/herdr-cli.d.ts.map +1 -0
- package/dist/herdr-cli.js +113 -0
- package/dist/herdr-cli.js.map +1 -0
- package/dist/herdr-name.d.ts +37 -0
- package/dist/herdr-name.d.ts.map +1 -0
- package/dist/herdr-name.js +59 -0
- package/dist/herdr-name.js.map +1 -0
- package/dist/herdr-poll.d.ts +104 -0
- package/dist/herdr-poll.d.ts.map +1 -0
- package/dist/herdr-poll.js +150 -0
- package/dist/herdr-poll.js.map +1 -0
- package/dist/herdr-stage.d.ts +40 -0
- package/dist/herdr-stage.d.ts.map +1 -0
- package/dist/herdr-stage.js +54 -0
- package/dist/herdr-stage.js.map +1 -0
- package/dist/ledger-report.d.ts +18 -0
- package/dist/ledger-report.d.ts.map +1 -1
- package/dist/ledger-report.js +10 -0
- package/dist/ledger-report.js.map +1 -1
- package/dist/ledger.d.ts +17 -0
- package/dist/ledger.d.ts.map +1 -1
- package/dist/ledger.js +1 -0
- package/dist/ledger.js.map +1 -1
- package/dist/pane-reaper.d.ts +66 -4
- package/dist/pane-reaper.d.ts.map +1 -1
- package/dist/pane-reaper.js +131 -9
- package/dist/pane-reaper.js.map +1 -1
- package/dist/progress.d.ts +96 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +167 -0
- package/dist/progress.js.map +1 -0
- package/dist/run-child.d.ts +27 -0
- package/dist/run-child.d.ts.map +1 -1
- package/dist/run-child.js +84 -7
- package/dist/run-child.js.map +1 -1
- package/dist/run-herdr.d.ts +41 -28
- package/dist/run-herdr.d.ts.map +1 -1
- package/dist/run-herdr.js +150 -167
- package/dist/run-herdr.js.map +1 -1
- package/dist/skill-packages.d.ts +16 -0
- package/dist/skill-packages.d.ts.map +1 -1
- package/dist/skill-packages.js +39 -10
- package/dist/skill-packages.js.map +1 -1
- package/extensions/delegation.ts +94 -2
- package/extensions/grants-command.ts +57 -1
- package/extensions/grants.ts +109 -165
- package/extensions/init-command.ts +132 -0
- package/extensions/run-delegation.ts +70 -8
- package/extensions/session-report.ts +231 -0
- package/extensions/session.ts +138 -17
- package/extensions/tripwire.ts +44 -0
- package/package.json +17 -1
- package/src/cli.ts +10 -4
- package/src/executor.ts +122 -0
- package/src/grant-store.ts +151 -0
- package/src/herdr-cli.ts +125 -0
- package/src/herdr-name.ts +61 -0
- package/src/herdr-poll.ts +185 -0
- package/src/herdr-stage.ts +55 -0
- package/src/ledger-report.ts +21 -0
- package/src/ledger.ts +18 -0
- package/src/pane-reaper.ts +147 -9
- package/src/progress.ts +206 -0
- package/src/run-child.ts +96 -7
- package/src/run-herdr.ts +170 -174
- package/src/skill-packages.ts +41 -10
package/dist/skill-packages.js
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
* `source`s; the only strings that may reach it are ones that survived a whitelist here.
|
|
26
26
|
*/
|
|
27
27
|
import { readdir, readFile, realpath } from "node:fs/promises";
|
|
28
|
+
import { homedir } from "node:os";
|
|
28
29
|
import { join, resolve, sep } from "node:path";
|
|
29
30
|
import { ceilingForDefinition, parseSkillDefinition } from "./definitions.js";
|
|
30
31
|
import { WILDCARD } from "./pi-tools.js";
|
|
@@ -179,16 +180,51 @@ export async function readSkillPackage(packageDir) {
|
|
|
179
180
|
* `node_modules`: a transitive skill package is not something an operator asked to install definitions
|
|
180
181
|
* from, and scaffolding one into their project would be a surprise wearing a helpful face.
|
|
181
182
|
*/
|
|
183
|
+
/**
|
|
184
|
+
* Every place a pi package can be installed, most specific first (R-75).
|
|
185
|
+
*
|
|
186
|
+
* **Two roots, because pi has two install paths and only one of them is `npm install`.** `pi install
|
|
187
|
+
* npm:principal-pi-skills` — the documented, pi-native way, and the only one that registers the package so
|
|
188
|
+
* pi will auto-load its extension — puts it in `$PI_CODING_AGENT_DIR/npm/node_modules`, and leaves the
|
|
189
|
+
* project without a `node_modules` at all. Searching only `<cwd>/node_modules` therefore found **nothing**
|
|
190
|
+
* for an operator who followed pi's own instructions, and said "install principal-pi-skills" to somebody
|
|
191
|
+
* who just had.
|
|
192
|
+
*
|
|
193
|
+
* Measured, in a fresh `PI_CODING_AGENT_DIR` with an empty project: `pi install` populates the agent root
|
|
194
|
+
* and creates no project root.
|
|
195
|
+
*
|
|
196
|
+
* Project first when both exist, because a package pinned in the repository is the one the team agreed on.
|
|
197
|
+
*/
|
|
198
|
+
export function skillPackageRoots(cwd) {
|
|
199
|
+
const agentDir = process.env.PI_CODING_AGENT_DIR ?? join(homedir(), ".pi", "agent");
|
|
200
|
+
return [join(cwd, "node_modules"), join(agentDir, "npm", "node_modules")];
|
|
201
|
+
}
|
|
182
202
|
export async function discoverSkillPackages(cwd) {
|
|
183
|
-
const
|
|
203
|
+
const dirs = [];
|
|
204
|
+
const seenNames = new Set();
|
|
205
|
+
for (const root of skillPackageRoots(cwd))
|
|
206
|
+
await collectFrom(root, dirs);
|
|
207
|
+
const packages = [];
|
|
208
|
+
for (const dir of dirs) {
|
|
209
|
+
const found = await readSkillPackage(dir);
|
|
210
|
+
// First root wins on a name collision: the project's pinned copy outranks the machine-wide one, and
|
|
211
|
+
// silently preferring the other would make a committed lockfile stop meaning anything.
|
|
212
|
+
if (found && !seenNames.has(found.name)) {
|
|
213
|
+
seenNames.add(found.name);
|
|
214
|
+
packages.push(found);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return packages.sort((a, b) => a.name.localeCompare(b.name));
|
|
218
|
+
}
|
|
219
|
+
/** Append every package directory under one `node_modules`, scoped packages included. */
|
|
220
|
+
async function collectFrom(root, dirs) {
|
|
184
221
|
let entries;
|
|
185
222
|
try {
|
|
186
223
|
entries = await readdir(root);
|
|
187
224
|
}
|
|
188
225
|
catch {
|
|
189
|
-
return
|
|
226
|
+
return; // a root that does not exist is a normal state, not a failure
|
|
190
227
|
}
|
|
191
|
-
const dirs = [];
|
|
192
228
|
for (const entry of entries.sort()) {
|
|
193
229
|
if (entry.startsWith("."))
|
|
194
230
|
continue; // .bin, .package-lock.json
|
|
@@ -205,12 +241,5 @@ export async function discoverSkillPackages(cwd) {
|
|
|
205
241
|
dirs.push(join(root, entry));
|
|
206
242
|
}
|
|
207
243
|
}
|
|
208
|
-
const packages = [];
|
|
209
|
-
for (const dir of dirs) {
|
|
210
|
-
const found = await readSkillPackage(dir);
|
|
211
|
-
if (found)
|
|
212
|
-
packages.push(found);
|
|
213
|
-
}
|
|
214
|
-
return packages.sort((a, b) => a.name.localeCompare(b.name));
|
|
215
244
|
}
|
|
216
245
|
//# sourceMappingURL=skill-packages.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-packages.js","sourceRoot":"","sources":["../src/skill-packages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAwB,MAAM,kBAAkB,CAAC;AACpG,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,cAAc,EAAmB,MAAM,cAAc,CAAC;AAsC/D;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,8BAA8B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAc;IAC7C,MAAM,OAAO,GAAG,4BAA4B,CAAC;IAC7C,OAAO,CACL,IAAI,MAAM,CAAC,uBAAuB,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,IAAI,MAAM,CAAC,UAAU,OAAO,MAAM,OAAO,IAAI,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAClE,CAAC;AACJ,CAAC;AAED,6GAA6G;AAC7G,SAAS,WAAW,CAAC,YAA0B;IAC7C,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,cAAc,CAAC,CAAC;AAC5E,CAAC;AAED;;;;;GAKG;AACH,SAAS,UAAU,CAAC,KAAsB;IACxC,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;IACnC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;IAEvF,MAAM,OAAO,GAAG,oBAAoB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACpD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAE1F,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IACxE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAE7F,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8GAA8G;AAC9G,KAAK,UAAU,SAAS,CAAC,UAAkB,EAAE,KAAa;IACxD,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC1C,yGAAyG;IACzG,oGAAoG;IACpG,yGAAyG;IACzG,0GAA0G;IAC1G,yGAAyG;IACzG,mDAAmD;IACnD,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC;IAC1E,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAC3F,IAAI,KAAa,CAAC;QAClB,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,cAAc,GAAG,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAE5D,oGAAoG;QACpG,yGAAyG;QACzG,8EAA8E;QAC9E,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,OAAO,UAAU,CAAC;QAEhE,MAAM,UAAU,GAAG,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACpD,OAAO,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACxD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,2GAA2G;AAC3G,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,UAAkB;IACvD,IAAI,QAAwE,CAAC;IAC7E,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAClF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACrC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnE,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC7B,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,SAAS;QACxC,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QACjD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;aAAM,IAAI,KAAK,KAAK,UAAU,EAAE,CAAC;YAChC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QACnE,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;YAClC,IAAI,OAAO;gBAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;;gBAC9B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,IAAI,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,WAAW;QACjE,OAAO,EAAE,QAAQ,CAAC,OAAO,IAAI,cAAc;QAC3C,UAAU;QACV,OAAO;QACP,MAAM;KACP,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,
|
|
1
|
+
{"version":3,"file":"skill-packages.js","sourceRoot":"","sources":["../src/skill-packages.ts"],"names":[],"mappings":"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"}
|
package/extensions/delegation.ts
CHANGED
|
@@ -13,9 +13,90 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
|
13
13
|
import { Type } from "typebox";
|
|
14
14
|
import { maySpawnDefinition } from "../src/delegate.ts";
|
|
15
15
|
import { MAX_CHILDREN_PER_CALL, childSpawnId, splitBudget } from "../src/fanout.ts";
|
|
16
|
+
import {
|
|
17
|
+
PAINT_INTERVAL_MS,
|
|
18
|
+
appendTail,
|
|
19
|
+
emptyTail,
|
|
20
|
+
renderProgress,
|
|
21
|
+
replaceTail,
|
|
22
|
+
throttle,
|
|
23
|
+
type ChildProgress,
|
|
24
|
+
} from "../src/progress.ts";
|
|
16
25
|
import { runOneDelegation } from "./run-delegation.ts";
|
|
17
26
|
import { type GrantsSession } from "./session.ts";
|
|
18
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Wire a set of children to pi's partial-result channel — ADR-0032.
|
|
30
|
+
*
|
|
31
|
+
* **One block for the whole call**, not one per child: `onUpdate` replaces the tool's rendered result, so N
|
|
32
|
+
* independent painters would each overwrite the others and the operator would see one child flickering.
|
|
33
|
+
* `delegate` is simply the one-child case of the same thing, which is why both tools come through here.
|
|
34
|
+
*
|
|
35
|
+
* Painting is throttled, and the trailing frame matters more than the throttling: without it the final paint —
|
|
36
|
+
* the one showing every child settled — is the one most likely to be dropped, so the block would freeze
|
|
37
|
+
* mid-run. `flush()` at the end is what guarantees the last state is the one left on screen.
|
|
38
|
+
*
|
|
39
|
+
* **Nothing here is the result.** The tool's content still comes from each child's returned text.
|
|
40
|
+
*/
|
|
41
|
+
function progressReporter(
|
|
42
|
+
session: GrantsSession,
|
|
43
|
+
labels: string[],
|
|
44
|
+
onUpdate: ((partial: { content: Array<{ type: "text"; text: string }> }) => void) | undefined,
|
|
45
|
+
) {
|
|
46
|
+
const started = Date.now();
|
|
47
|
+
const children: ChildProgress[] = labels.map((label) => ({
|
|
48
|
+
label,
|
|
49
|
+
state: "starting",
|
|
50
|
+
startedAt: started,
|
|
51
|
+
tail: emptyTail,
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
const paint = throttle(() => {
|
|
55
|
+
onUpdate?.({
|
|
56
|
+
content: [{ type: "text", text: renderProgress(children, session.executor.kind, Date.now()) }],
|
|
57
|
+
});
|
|
58
|
+
}, PAINT_INTERVAL_MS);
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
/** One sink per child index, shaped for `runOneDelegation`'s `onProgress`. */
|
|
62
|
+
sink: (index: number) => (update: {
|
|
63
|
+
chunk?: string;
|
|
64
|
+
snapshot?: string[];
|
|
65
|
+
paneId?: string;
|
|
66
|
+
agentName?: string;
|
|
67
|
+
state?: ChildProgress["state"];
|
|
68
|
+
}) => {
|
|
69
|
+
const child = children[index];
|
|
70
|
+
if (!child) return;
|
|
71
|
+
if (update.paneId) child.paneId = update.paneId;
|
|
72
|
+
// **Reported, not derived.** It used to be rebuilt here from the label and the child id, which was true
|
|
73
|
+
// until `runHerdrPane` began uniquifying the name to stop herdr's `agent_name_taken` — after which the
|
|
74
|
+
// block named an agent that did not exist, and an operator following it would find nothing. The name is
|
|
75
|
+
// known only where it is minted, so it travels from there.
|
|
76
|
+
if (update.agentName) child.agentName = update.agentName;
|
|
77
|
+
// Two shapes, deliberately distinct, because the two executors are: a subprocess APPENDS bytes, a pane
|
|
78
|
+
// reports a SNAPSHOT that replaces. Collapsing them into one "output" field is what caused the herdr
|
|
79
|
+
// path's amplification, so the difference is spelled out in the type rather than remembered.
|
|
80
|
+
if (update.chunk) child.tail = appendTail(child.tail, update.chunk);
|
|
81
|
+
if (update.snapshot) child.tail = replaceTail(update.snapshot);
|
|
82
|
+
if (update.state) child.state = update.state;
|
|
83
|
+
else if (child.state === "starting") child.state = "running";
|
|
84
|
+
paint.call();
|
|
85
|
+
},
|
|
86
|
+
/** Record how each child ended and leave the final frame on screen. */
|
|
87
|
+
settle: (outcomes: Array<{ ok: boolean }>) => {
|
|
88
|
+
const at = Date.now();
|
|
89
|
+
outcomes.forEach((outcome, index) => {
|
|
90
|
+
const child = children[index];
|
|
91
|
+
if (!child) return;
|
|
92
|
+
child.state = outcome.ok ? "completed" : "failed";
|
|
93
|
+
child.settledAt = at;
|
|
94
|
+
});
|
|
95
|
+
paint.flush();
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
19
100
|
export interface DelegationRegistration {
|
|
20
101
|
/**
|
|
21
102
|
* Re-derive "which definitions may this session spawn?" into the registered tool schemas.
|
|
@@ -113,7 +194,10 @@ export function registerDelegationTools(pi: ExtensionAPI, session: GrantsSession
|
|
|
113
194
|
"written by the operator. Use 'tools' only when no definition fits. Grant 'delegate' if the " +
|
|
114
195
|
"sub-agent must itself delegate further; withhold it to make the sub-agent a leaf.",
|
|
115
196
|
parameters: delegateParams,
|
|
116
|
-
async execute(_toolCallId, params, signal,
|
|
197
|
+
async execute(_toolCallId, params, signal, onUpdate, ctx) {
|
|
198
|
+
// ADR-0032: one child, same block. `_onUpdate` was discarded here, so a delegation showed the bare word
|
|
199
|
+
// `delegate` for up to DEFAULT_TIMEOUT_MS — ten minutes of nothing.
|
|
200
|
+
const progress = progressReporter(session, [params.agent ?? "delegate"], onUpdate as never);
|
|
117
201
|
const outcome = await runOneDelegation(
|
|
118
202
|
session,
|
|
119
203
|
{ task: params.task, agent: params.agent, tools: params.tools, model: params.model },
|
|
@@ -124,7 +208,9 @@ export function registerDelegationTools(pi: ExtensionAPI, session: GrantsSession
|
|
|
124
208
|
session.fanoutBudget,
|
|
125
209
|
ctx,
|
|
126
210
|
signal,
|
|
211
|
+
progress.sink(0),
|
|
127
212
|
);
|
|
213
|
+
progress.settle([outcome]);
|
|
128
214
|
|
|
129
215
|
if (!outcome.ok) {
|
|
130
216
|
// THROW, do not return. `AgentToolResult` has no `isError` field: pi sets it only when `execute`
|
|
@@ -168,7 +254,7 @@ export function registerDelegationTools(pi: ExtensionAPI, session: GrantsSession
|
|
|
168
254
|
"when independent tasks can proceed in parallel — several reviewers over one diff, say — and read " +
|
|
169
255
|
"every child's outcome, because one can be refused while the others succeed.",
|
|
170
256
|
parameters: delegateAllParams,
|
|
171
|
-
async execute(_toolCallId, params, signal,
|
|
257
|
+
async execute(_toolCallId, params, signal, onUpdate, ctx) {
|
|
172
258
|
const children = params.children ?? [];
|
|
173
259
|
const split = splitBudget(session.fanoutBudget, children.length);
|
|
174
260
|
if (!split.ok) {
|
|
@@ -177,6 +263,10 @@ export function registerDelegationTools(pi: ExtensionAPI, session: GrantsSession
|
|
|
177
263
|
throw new Error(`fan-out refused: ${split.reason}`);
|
|
178
264
|
}
|
|
179
265
|
|
|
266
|
+
// ADR-0032: ONE status block covering every child. `onUpdate` replaces the tool's rendered result, so a
|
|
267
|
+
// painter per child would have each overwriting the others.
|
|
268
|
+
const progress = progressReporter(session, children.map((c) => c.agent ?? "delegate"), onUpdate as never);
|
|
269
|
+
|
|
180
270
|
// Concurrent by construction. Each child gets its own budget share and its own ledger id, so the
|
|
181
271
|
// records form a tree and two siblings can never be confused for one another.
|
|
182
272
|
const outcomes = await Promise.all(
|
|
@@ -188,9 +278,11 @@ export function registerDelegationTools(pi: ExtensionAPI, session: GrantsSession
|
|
|
188
278
|
split.perChild,
|
|
189
279
|
ctx,
|
|
190
280
|
signal,
|
|
281
|
+
progress.sink(index),
|
|
191
282
|
),
|
|
192
283
|
),
|
|
193
284
|
);
|
|
285
|
+
progress.settle(outcomes);
|
|
194
286
|
|
|
195
287
|
const failed = outcomes.filter((o) => !o.ok);
|
|
196
288
|
// Every child is reported, including the ones that failed. R-03's rule: a missing result must never
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import type { Capability } from "../src/resolve.ts";
|
|
16
|
+
import type { ExecutorChoice } from "../src/executor.ts";
|
|
16
17
|
import type { Catalog } from "../src/catalog.ts";
|
|
17
18
|
import type { SkillDefinition } from "../src/definitions.ts";
|
|
18
19
|
import type { GatedPlan } from "./run-delegation.ts";
|
|
@@ -23,6 +24,13 @@ export interface GrantsCommandContext {
|
|
|
23
24
|
cwd: string;
|
|
24
25
|
governed: boolean;
|
|
25
26
|
ownGrant: Capability[];
|
|
27
|
+
/**
|
|
28
|
+
* Which executor this session settled on, and why — ADR-0031.
|
|
29
|
+
*
|
|
30
|
+
* The whole `ExecutorChoice` rather than a rendered string, so this command cannot compose a different
|
|
31
|
+
* sentence from the one the session banner printed. Two spellings of one fact is R-28.
|
|
32
|
+
*/
|
|
33
|
+
executor: ExecutorChoice;
|
|
26
34
|
observed: boolean;
|
|
27
35
|
depth: number;
|
|
28
36
|
maxDepth: number;
|
|
@@ -43,6 +51,15 @@ export interface GrantsCommandContext {
|
|
|
43
51
|
* R-28 discipline where it belongs: this command asks what would happen instead of working it out.
|
|
44
52
|
*/
|
|
45
53
|
previewDelegation: (name: string) => Promise<GatedPlan>;
|
|
54
|
+
/**
|
|
55
|
+
* Run `/grants init`: scaffold definitions, ask about the withheld capabilities only, store the answer
|
|
56
|
+
* outside the workspace, and apply it to this session (ADR-0030).
|
|
57
|
+
*
|
|
58
|
+
* Injected rather than imported so this module stays what it is — a read-only diagnostic that cannot
|
|
59
|
+
* become a governance path by accident. The one command here that *writes* takes its ability to do so
|
|
60
|
+
* from the caller, visibly.
|
|
61
|
+
*/
|
|
62
|
+
runInit: () => Promise<void>;
|
|
46
63
|
}
|
|
47
64
|
|
|
48
65
|
/**
|
|
@@ -51,6 +68,9 @@ export interface GrantsCommandContext {
|
|
|
51
68
|
*/
|
|
52
69
|
const PREVIEW_LIMIT = 12;
|
|
53
70
|
|
|
71
|
+
/** The verbs `/grants` answers to. Anything else is refused rather than silently treated as no verb. */
|
|
72
|
+
const KNOWN_SUBCOMMANDS: readonly string[] = ["init", "ledger", "approvals", "revoke"];
|
|
73
|
+
|
|
54
74
|
export const grantsCommand = {
|
|
55
75
|
description:
|
|
56
76
|
"Show this session's capability grant, delegation depth, and known agent-type ceilings; " +
|
|
@@ -59,12 +79,17 @@ handler: async (args: string, ctx: any) => {
|
|
|
59
79
|
// Everything this command may see, named in one place. Previously these were whatever happened to be in
|
|
60
80
|
// the enclosing closure — which is how a diagnostic came to disagree with the enforcer (R-28).
|
|
61
81
|
const {
|
|
62
|
-
cwd, governed, ownGrant, observed, depth, maxDepth, ledgerPath,
|
|
82
|
+
cwd, governed, ownGrant, executor, observed, depth, maxDepth, ledgerPath,
|
|
63
83
|
catalog, definitions, sessionApprovals, inheritedApprovals, snapshotOf, previewDelegation,
|
|
64
84
|
} = ctx.grants as GrantsCommandContext;
|
|
65
85
|
|
|
66
86
|
const [sub, target] = args.trim().split(/\s+/).filter(Boolean);
|
|
67
87
|
|
|
88
|
+
if (sub === "init") {
|
|
89
|
+
await ctx.grants.runInit();
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
68
93
|
if (sub === "ledger") {
|
|
69
94
|
// The detector, made reachable. `verifyLedger` exists because nothing in this package had ever read
|
|
70
95
|
// a ledger back, so a torn line was indistinguishable from a spawn that never happened — and a
|
|
@@ -85,6 +110,17 @@ handler: async (args: string, ctx: any) => {
|
|
|
85
110
|
` integrity ${report.ok ? "OK" : `${report.corrupt.length} UNPARSEABLE LINE(S)`}`,
|
|
86
111
|
];
|
|
87
112
|
for (const bad of report.corrupt.slice(0, 5)) lines.push(` line ${bad.line}: ${bad.text}`);
|
|
113
|
+
// ADR-0031, and R-51's lesson applied on the day the field was added rather than a release later: a field
|
|
114
|
+
// the writer sets and no diagnostic reads is one that needs `jq`, and `docs/SPEC.md` claims the executor is
|
|
115
|
+
// announced "per child in the ledger". `unknown` is shown only when present, because on a fresh ledger it
|
|
116
|
+
// is always zero and a permanent zero is noise; on an upgraded one it is the count of pre-0.16 lines, which
|
|
117
|
+
// is worth seeing.
|
|
118
|
+
lines.push(
|
|
119
|
+
` executors ${report.executors.herdr} herdr pane(s) · ${report.executors.process} subprocess(es)` +
|
|
120
|
+
(report.executors.unknown > 0
|
|
121
|
+
? ` · ${report.executors.unknown} not recorded (written before 0.16.0, which added the field)`
|
|
122
|
+
: ""),
|
|
123
|
+
);
|
|
88
124
|
// R-51. ADR-0018 advertises that the ledger answers "did these four children run the same
|
|
89
125
|
// instructions?" and "has this definition changed since?" — and nothing read `definitionDigest`, so
|
|
90
126
|
// both needed hand-written jq and the second was not reproducible with `sha256sum` (the digest covers
|
|
@@ -265,10 +301,30 @@ handler: async (args: string, ctx: any) => {
|
|
|
265
301
|
return;
|
|
266
302
|
}
|
|
267
303
|
|
|
304
|
+
// **An unrecognised subcommand is refused, not ignored (R-74).** Every `sub` that is not a known verb
|
|
305
|
+
// fell through to this status screen with the word silently dropped, so `/grants init` — a command that
|
|
306
|
+
// does not exist — printed a healthy-looking report and read as though it had run. `/grants ledgr` did
|
|
307
|
+
// the same. A diagnostic that answers a question nobody asked is worse than one that refuses: it is
|
|
308
|
+
// indistinguishable from success, which is the shape this package spends most of its risk register on.
|
|
309
|
+
if (sub !== undefined && !KNOWN_SUBCOMMANDS.includes(sub)) {
|
|
310
|
+
ctx.ui.notify(
|
|
311
|
+
`grants: unknown subcommand "${sub}" — did nothing. Known: ${KNOWN_SUBCOMMANDS.join(", ")}. ` +
|
|
312
|
+
`Plain /grants shows this session's status.`,
|
|
313
|
+
"warning",
|
|
314
|
+
);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
|
|
268
318
|
const { valid } = await loadApprovals({ cwd, now: new Date(), snapshotOf });
|
|
269
319
|
const lines = [
|
|
270
320
|
governed ? "grants: ACTIVE" : "grants: inactive (set PI_GRANTS_GRANT to govern this session)",
|
|
271
321
|
` holding ${ownGrant.join(", ") || "(nothing)"}${observed ? " (observed)" : " (inherited, not yet observed)"}`,
|
|
322
|
+
// ADR-0031/0032. This screen named the grant, the depth, the ledger, the approvals and the catalog, and
|
|
323
|
+
// never said WHERE children run — so an operator on a machine where herdr hosts their whole workspace
|
|
324
|
+
// could not discover that their children were invisible subprocesses. That gap is what produced
|
|
325
|
+
// ADR-0031, and its probe is only defensible because this line exists. Placed next to `holding` so the
|
|
326
|
+
// two facts about what a spawn will be sit together.
|
|
327
|
+
` executor ${executor.disclosure}`,
|
|
272
328
|
` depth ${depth} of max ${maxDepth}${maxDepth <= 0 ? " (spawning disabled)" : ""}`,
|
|
273
329
|
` ledger ${ledgerPath ?? "(not recording — set PI_GRANTS_LEDGER)"}`,
|
|
274
330
|
` approvals ${sessionApprovals.size} this session, ${valid.size} persisted` +
|