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.
Files changed (105) hide show
  1. package/CHANGELOG.md +187 -0
  2. package/LICENSE +21 -0
  3. package/README.md +584 -0
  4. package/dist/approval-prompt.d.ts +116 -0
  5. package/dist/approval-prompt.d.ts.map +1 -0
  6. package/dist/approval-prompt.js +124 -0
  7. package/dist/approval-prompt.js.map +1 -0
  8. package/dist/approval-store.d.ts +149 -0
  9. package/dist/approval-store.d.ts.map +1 -0
  10. package/dist/approval-store.js +311 -0
  11. package/dist/approval-store.js.map +1 -0
  12. package/dist/approval.d.ts +221 -0
  13. package/dist/approval.d.ts.map +1 -0
  14. package/dist/approval.js +244 -0
  15. package/dist/approval.js.map +1 -0
  16. package/dist/capabilities.d.ts +31 -0
  17. package/dist/capabilities.d.ts.map +1 -0
  18. package/dist/capabilities.js +45 -0
  19. package/dist/capabilities.js.map +1 -0
  20. package/dist/catalog.d.ts +81 -0
  21. package/dist/catalog.d.ts.map +1 -0
  22. package/dist/catalog.js +164 -0
  23. package/dist/catalog.js.map +1 -0
  24. package/dist/definitions.d.ts +101 -0
  25. package/dist/definitions.d.ts.map +1 -0
  26. package/dist/definitions.js +182 -0
  27. package/dist/definitions.js.map +1 -0
  28. package/dist/delegate.d.ts +133 -0
  29. package/dist/delegate.d.ts.map +1 -0
  30. package/dist/delegate.js +261 -0
  31. package/dist/delegate.js.map +1 -0
  32. package/dist/fanout.d.ts +62 -0
  33. package/dist/fanout.d.ts.map +1 -0
  34. package/dist/fanout.js +84 -0
  35. package/dist/fanout.js.map +1 -0
  36. package/dist/file-lock.d.ts +54 -0
  37. package/dist/file-lock.d.ts.map +1 -0
  38. package/dist/file-lock.js +142 -0
  39. package/dist/file-lock.js.map +1 -0
  40. package/dist/index.d.ts +7 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +7 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/ledger-report.d.ts +106 -0
  45. package/dist/ledger-report.d.ts.map +1 -0
  46. package/dist/ledger-report.js +157 -0
  47. package/dist/ledger-report.js.map +1 -0
  48. package/dist/ledger.d.ts +139 -0
  49. package/dist/ledger.d.ts.map +1 -0
  50. package/dist/ledger.js +94 -0
  51. package/dist/ledger.js.map +1 -0
  52. package/dist/pane-reaper.d.ts +49 -0
  53. package/dist/pane-reaper.d.ts.map +1 -0
  54. package/dist/pane-reaper.js +120 -0
  55. package/dist/pane-reaper.js.map +1 -0
  56. package/dist/pi-tools.d.ts +20 -0
  57. package/dist/pi-tools.d.ts.map +1 -0
  58. package/dist/pi-tools.js +21 -0
  59. package/dist/pi-tools.js.map +1 -0
  60. package/dist/propagation.d.ts +185 -0
  61. package/dist/propagation.d.ts.map +1 -0
  62. package/dist/propagation.js +255 -0
  63. package/dist/propagation.js.map +1 -0
  64. package/dist/resolve.d.ts +110 -0
  65. package/dist/resolve.d.ts.map +1 -0
  66. package/dist/resolve.js +181 -0
  67. package/dist/resolve.js.map +1 -0
  68. package/dist/run-child.d.ts +50 -0
  69. package/dist/run-child.d.ts.map +1 -0
  70. package/dist/run-child.js +109 -0
  71. package/dist/run-child.js.map +1 -0
  72. package/dist/run-herdr.d.ts +91 -0
  73. package/dist/run-herdr.d.ts.map +1 -0
  74. package/dist/run-herdr.js +306 -0
  75. package/dist/run-herdr.js.map +1 -0
  76. package/dist/spawn.d.ts +60 -0
  77. package/dist/spawn.d.ts.map +1 -0
  78. package/dist/spawn.js +116 -0
  79. package/dist/spawn.js.map +1 -0
  80. package/extensions/approvals.ts +285 -0
  81. package/extensions/delegation.ts +237 -0
  82. package/extensions/grants-command.ts +310 -0
  83. package/extensions/grants.ts +346 -0
  84. package/extensions/run-delegation.ts +270 -0
  85. package/extensions/session.ts +234 -0
  86. package/package.json +122 -0
  87. package/src/approval-prompt.ts +222 -0
  88. package/src/approval-store.ts +383 -0
  89. package/src/approval.ts +364 -0
  90. package/src/capabilities.ts +51 -0
  91. package/src/catalog.ts +186 -0
  92. package/src/definitions.ts +233 -0
  93. package/src/delegate.ts +383 -0
  94. package/src/fanout.ts +96 -0
  95. package/src/file-lock.ts +142 -0
  96. package/src/index.ts +59 -0
  97. package/src/ledger-report.ts +227 -0
  98. package/src/ledger.ts +214 -0
  99. package/src/pane-reaper.ts +132 -0
  100. package/src/pi-tools.ts +25 -0
  101. package/src/propagation.ts +308 -0
  102. package/src/resolve.ts +235 -0
  103. package/src/run-child.ts +149 -0
  104. package/src/run-herdr.ts +357 -0
  105. package/src/spawn.ts +156 -0
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Agent Skills (`SKILL.md`) as this package's definition format — ADR-0016.
3
+ *
4
+ * A subagent is a skill you spawn: the `SKILL.md` body becomes the child's system prompt
5
+ * (`--append-system-prompt`) and `allowed-tools` becomes its capability ceiling, enforced through
6
+ * `--tools`. That collapses a duplication `principal-pi-skills` already strains against, where
7
+ * `plan`/`review`/`debug` exist twice — once as a skill and once as a subagent prompt — and are
8
+ * generated from one contract precisely so the two cannot drift.
9
+ *
10
+ * **The spec's own words about `allowed-tools`:** *"a space-separated string of tools that are
11
+ * pre-approved to run"*, marked **experimental**. Pre-approved, not enforced — the field declares intent
12
+ * and blocks nothing, and implementations differ on whether they honour it at all. Turning that
13
+ * declaration into something structural is this package's entire value here.
14
+ *
15
+ * **One inversion is deliberate and load-bearing.** In pi-subagents' frontmatter an absent `tools:` key
16
+ * means *pi's full default toolset*, so an undeclared definition was the most powerful kind and any
17
+ * parse failure produced a wildcard — the direction that caused R-28 and review finding F18. Here an
18
+ * absent `allowed-tools` means **undeclared, therefore not spawnable**. A typo or an unreadable YAML
19
+ * form now costs a refusal instead of a grant.
20
+ */
21
+ import type { Capability } from "./resolve.ts";
22
+ /**
23
+ * Identifies WHICH instructions a child was given, without reproducing them (ADR-0018).
24
+ *
25
+ * The ledger's standing rule is *capability ids, counts and identifiers only — never prompts, tool
26
+ * arguments or results*. A hash is an identifier: it names a version of an operator-authored file. The
27
+ * **task** is model-assembled from the parent's context and is never recorded anywhere, by decision.
28
+ */
29
+ export interface DefinitionDigest {
30
+ name: string;
31
+ /** Where the definition was read from, so a reader can go and rehash it. */
32
+ source: string;
33
+ /** SHA-256 of the body — the exact text passed as `--append-system-prompt`. */
34
+ sha256: string;
35
+ }
36
+ /**
37
+ * Digest a definition's body.
38
+ *
39
+ * Over the **body alone**, deliberately: that is precisely the text the child receives, so a digest that
40
+ * also covered the frontmatter would change when `description` was reworded and report an instruction
41
+ * change that never happened. `allowed-tools` is already recorded in full on every record.
42
+ */
43
+ export declare function digestDefinition(definition: SkillDefinition): DefinitionDigest;
44
+ export interface SkillDefinition {
45
+ /** From the path, never the frontmatter — see `parseSkillDefinition`. */
46
+ name: string;
47
+ description: string;
48
+ /** Raw `allowed-tools` value. `undefined` means the key was absent; `""` means it declared none. */
49
+ allowedTools?: string;
50
+ /** The spec's sanctioned extension point: a map of string keys to string values. */
51
+ metadata?: Record<string, string>;
52
+ /** Everything after the frontmatter — the child's system prompt. */
53
+ body: string;
54
+ source: string;
55
+ }
56
+ export interface DefinitionCeiling {
57
+ /** The declared capabilities, as this package's ids. */
58
+ capabilities: Capability[];
59
+ /**
60
+ * Entries carrying a sub-tool pattern, e.g. `Bash(git:*)`.
61
+ *
62
+ * ADR-0016 refuses these rather than reinterpreting them, because every reinterpretation is wrong:
63
+ * granting bare `bash` **widens** a deliberately narrow declaration, dropping the tool silently
64
+ * **narrows** and yields a child that mysteriously cannot work, and matching patterns inside a wrapper
65
+ * would be a security control implemented by string-matching a shell command. Non-empty means the
66
+ * caller must refuse and say so.
67
+ */
68
+ patterns: string[];
69
+ /** The `allowed-tools` key was absent entirely: the definition is not spawnable. */
70
+ undeclared: boolean;
71
+ }
72
+ /**
73
+ * Read a `SKILL.md`.
74
+ *
75
+ * The frontmatter reader handles the subset these files use — `key: value`, block scalars (`>` / `|`),
76
+ * and a one-level `metadata:` map. Anything it cannot read leaves the key **absent**, which for
77
+ * `allowed-tools` means *undeclared* and therefore refused. That is the whole reason this parser can be
78
+ * hand-rolled without the hazard its sibling in `agent-types.ts` carries.
79
+ */
80
+ export declare function parseSkillDefinition(source: string, text: string): SkillDefinition | null;
81
+ /**
82
+ * Turn a definition's `allowed-tools` into a capability ceiling.
83
+ *
84
+ * Name mapping is **lowercasing and nothing else**, deliberately. A translation table from Claude
85
+ * Code's names to pi's would have to decide what `Glob` means, and pi has no glob tool — so the table
86
+ * would either invent a grant or quietly drop one. Lowercasing leaves `Glob` as `tool:glob`, which the
87
+ * catalog then refuses as unknown, naming the actual problem to whoever wrote the file.
88
+ */
89
+ export declare function ceilingForDefinition(definition: SkillDefinition): DefinitionCeiling;
90
+ /**
91
+ * Discover `SKILL.md` definitions under pi's skill roots.
92
+ *
93
+ * Deliberately the SAME roots and the same convention the catalog uses (`skillDirs`): a directory
94
+ * containing `SKILL.md` is one definition named after the directory, and a top-level `.md` is one named
95
+ * after the file. If discovery and the catalog disagreed, a definition could be spawnable but not
96
+ * grantable, or listed but unspawnable.
97
+ *
98
+ * Earlier directories win on a name collision, matching pi's own precedence — project before global.
99
+ */
100
+ export declare function loadDefinitions(cwd: string): Promise<Map<string, SkillDefinition>>;
101
+ //# sourceMappingURL=definitions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../src/definitions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,eAAe,GAAG,gBAAgB,CAM9E;AAED,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,oGAAoG;IACpG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,wDAAwD;IACxD,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B;;;;;;;;OAQG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,oFAAoF;IACpF,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAyDzF;AAUD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,eAAe,GAAG,iBAAiB,CAsBnF;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CA4BxF"}
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Agent Skills (`SKILL.md`) as this package's definition format — ADR-0016.
3
+ *
4
+ * A subagent is a skill you spawn: the `SKILL.md` body becomes the child's system prompt
5
+ * (`--append-system-prompt`) and `allowed-tools` becomes its capability ceiling, enforced through
6
+ * `--tools`. That collapses a duplication `principal-pi-skills` already strains against, where
7
+ * `plan`/`review`/`debug` exist twice — once as a skill and once as a subagent prompt — and are
8
+ * generated from one contract precisely so the two cannot drift.
9
+ *
10
+ * **The spec's own words about `allowed-tools`:** *"a space-separated string of tools that are
11
+ * pre-approved to run"*, marked **experimental**. Pre-approved, not enforced — the field declares intent
12
+ * and blocks nothing, and implementations differ on whether they honour it at all. Turning that
13
+ * declaration into something structural is this package's entire value here.
14
+ *
15
+ * **One inversion is deliberate and load-bearing.** In pi-subagents' frontmatter an absent `tools:` key
16
+ * means *pi's full default toolset*, so an undeclared definition was the most powerful kind and any
17
+ * parse failure produced a wildcard — the direction that caused R-28 and review finding F18. Here an
18
+ * absent `allowed-tools` means **undeclared, therefore not spawnable**. A typo or an unreadable YAML
19
+ * form now costs a refusal instead of a grant.
20
+ */
21
+ import { createHash } from "node:crypto";
22
+ import { readFile, readdir } from "node:fs/promises";
23
+ import { join } from "node:path";
24
+ import { skillDirs } from "./catalog.js";
25
+ /**
26
+ * Digest a definition's body.
27
+ *
28
+ * Over the **body alone**, deliberately: that is precisely the text the child receives, so a digest that
29
+ * also covered the frontmatter would change when `description` was reworded and report an instruction
30
+ * change that never happened. `allowed-tools` is already recorded in full on every record.
31
+ */
32
+ export function digestDefinition(definition) {
33
+ return {
34
+ name: definition.name,
35
+ source: definition.source,
36
+ sha256: createHash("sha256").update(definition.body, "utf8").digest("hex"),
37
+ };
38
+ }
39
+ /**
40
+ * Read a `SKILL.md`.
41
+ *
42
+ * The frontmatter reader handles the subset these files use — `key: value`, block scalars (`>` / `|`),
43
+ * and a one-level `metadata:` map. Anything it cannot read leaves the key **absent**, which for
44
+ * `allowed-tools` means *undeclared* and therefore refused. That is the whole reason this parser can be
45
+ * hand-rolled without the hazard its sibling in `agent-types.ts` carries.
46
+ */
47
+ export function parseSkillDefinition(source, text) {
48
+ const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text);
49
+ if (!match)
50
+ return null;
51
+ const fields = new Map();
52
+ const metadata = {};
53
+ const lines = match[1].split(/\r?\n/);
54
+ for (let i = 0; i < lines.length; i++) {
55
+ const kv = /^([A-Za-z_][A-Za-z0-9_-]*)\s*:\s*(.*)$/.exec(lines[i]);
56
+ if (!kv)
57
+ continue;
58
+ const [, key, rawValue] = kv;
59
+ const value = rawValue.trim();
60
+ // A folded/literal scalar: fold the indented continuation into one line. `principal-pi-skills`
61
+ // writes every description this way, and the sibling parser SKIPS these — which is safe there only
62
+ // because it never needs the value. Here a skipped `description` would be a missing required field.
63
+ if (value === ">" || value === "|") {
64
+ const parts = [];
65
+ for (let j = i + 1; j < lines.length; j++) {
66
+ if (!/^\s+\S/.test(lines[j]))
67
+ break;
68
+ parts.push(lines[j].trim());
69
+ i = j;
70
+ }
71
+ fields.set(key, parts.join(" "));
72
+ continue;
73
+ }
74
+ // `metadata:` introduces a one-level map of string keys to string values (the spec's shape).
75
+ if (key === "metadata" && value === "") {
76
+ for (let j = i + 1; j < lines.length; j++) {
77
+ const item = /^\s+([A-Za-z_][A-Za-z0-9_-]*)\s*:\s*(.*)$/.exec(lines[j]);
78
+ if (!item)
79
+ break;
80
+ metadata[item[1]] = item[2].trim().replace(/^["']|["']$/g, "");
81
+ i = j;
82
+ }
83
+ continue;
84
+ }
85
+ fields.set(key, value);
86
+ }
87
+ const description = fields.get("description");
88
+ if (description === undefined)
89
+ return null;
90
+ return {
91
+ // Identity comes from the PATH. ADR-0013 learned this the hard way on the other format: pi keys
92
+ // skills by their directory, so trusting a frontmatter `name` lets our view and the loader's
93
+ // disagree about which file a name refers to. The spec requires `name` to match the parent
94
+ // directory anyway, so a mismatch is the file's defect and not something to honour.
95
+ name: nameFromPath(source),
96
+ description,
97
+ allowedTools: fields.get("allowed-tools"),
98
+ metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
99
+ body: text.slice(match[0].length).trim(),
100
+ source,
101
+ };
102
+ }
103
+ /** `/skills/review/SKILL.md` -> `review`; `/skills/triage.md` -> `triage`. */
104
+ function nameFromPath(source) {
105
+ const parts = source.split("/").filter((p) => p.length > 0);
106
+ const last = parts.at(-1) ?? "";
107
+ if (last.toLowerCase() === "skill.md")
108
+ return parts.at(-2) ?? "";
109
+ return last.replace(/\.md$/i, "");
110
+ }
111
+ /**
112
+ * Turn a definition's `allowed-tools` into a capability ceiling.
113
+ *
114
+ * Name mapping is **lowercasing and nothing else**, deliberately. A translation table from Claude
115
+ * Code's names to pi's would have to decide what `Glob` means, and pi has no glob tool — so the table
116
+ * would either invent a grant or quietly drop one. Lowercasing leaves `Glob` as `tool:glob`, which the
117
+ * catalog then refuses as unknown, naming the actual problem to whoever wrote the file.
118
+ */
119
+ export function ceilingForDefinition(definition) {
120
+ const raw = definition.allowedTools;
121
+ if (raw === undefined)
122
+ return { capabilities: [], patterns: [], undeclared: true };
123
+ const capabilities = new Set();
124
+ const patterns = [];
125
+ // The spec says space-separated. Commas are tolerated because `Read, Grep` is what people type, and
126
+ // accepting them grants nothing extra — it only avoids a comma becoming part of a capability name.
127
+ for (const entry of raw.split(/[\s,]+/).filter((e) => e.length > 0)) {
128
+ if (entry.includes("(")) {
129
+ patterns.push(entry);
130
+ continue;
131
+ }
132
+ if (entry.startsWith("ext:") || entry.startsWith("skill:") || entry.startsWith("agent:")) {
133
+ capabilities.add(entry);
134
+ continue;
135
+ }
136
+ capabilities.add(`tool:${entry.toLowerCase()}`);
137
+ }
138
+ return { capabilities: [...capabilities].sort(), patterns, undeclared: false };
139
+ }
140
+ /**
141
+ * Discover `SKILL.md` definitions under pi's skill roots.
142
+ *
143
+ * Deliberately the SAME roots and the same convention the catalog uses (`skillDirs`): a directory
144
+ * containing `SKILL.md` is one definition named after the directory, and a top-level `.md` is one named
145
+ * after the file. If discovery and the catalog disagreed, a definition could be spawnable but not
146
+ * grantable, or listed but unspawnable.
147
+ *
148
+ * Earlier directories win on a name collision, matching pi's own precedence — project before global.
149
+ */
150
+ export async function loadDefinitions(cwd) {
151
+ const definitions = new Map();
152
+ for (const dir of skillDirs(cwd)) {
153
+ let names;
154
+ try {
155
+ names = await readdir(dir);
156
+ }
157
+ catch {
158
+ continue; // an absent skill root is normal
159
+ }
160
+ for (const name of [...names].sort()) {
161
+ // A directory holding SKILL.md, or a top-level .md — try the former first, exactly as the
162
+ // catalog does, so the two cannot disagree about what exists.
163
+ const candidates = [join(dir, name, "SKILL.md"), ...(name.endsWith(".md") ? [join(dir, name)] : [])];
164
+ for (const path of candidates) {
165
+ let text;
166
+ try {
167
+ text = await readFile(path, "utf8");
168
+ }
169
+ catch {
170
+ continue; // not this shape; try the next candidate
171
+ }
172
+ const parsed = parseSkillDefinition(path, text);
173
+ // First writer wins, so project definitions shadow global ones rather than the reverse.
174
+ if (parsed && !definitions.has(parsed.name))
175
+ definitions.set(parsed.name, parsed);
176
+ break;
177
+ }
178
+ }
179
+ }
180
+ return definitions;
181
+ }
182
+ //# sourceMappingURL=definitions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../src/definitions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Governed delegation — provisioning, not merely enforcement.
3
+ *
4
+ * The `tool_call` interceptor can only *permit or refuse* a `pi-subagents` spawn, because that package's
5
+ * `Agent` tool has no `tools` parameter. When we do the spawning ourselves the grant becomes an argument,
6
+ * which is what "give them some tools but not others" actually requires.
7
+ *
8
+ * Two properties fall out of owning the spawn:
9
+ *
10
+ * 1. **No propagation race at all.** Each child receives its own explicit `env` object, so nothing is
11
+ * written to the shared `process.env`. The interceptor's constraint (only parent-level facts may be
12
+ * pushed, because the channel is global) does not apply here.
13
+ * 2. **Depth control by capability.** `tool:delegate` is itself a capability. Grant it and the child can
14
+ * sub-delegate; withhold it and the child is a leaf. No separate depth mechanism is required, though
15
+ * `maxDepth` remains as a cheap backstop.
16
+ */
17
+ import { type DefinitionDigest, type SkillDefinition } from "./definitions.ts";
18
+ import { type Capability, type ResolveResult } from "./resolve.ts";
19
+ export { DELEGATE_CAPABILITY, agentCapability, maySpawnDefinition, normaliseCapability } from "./capabilities.ts";
20
+ import { type InheritableApproval } from "./approval.ts";
21
+ import { type Catalog } from "./catalog.ts";
22
+ export interface DelegationRequest {
23
+ task: string;
24
+ /**
25
+ * Capabilities the delegator wants the child to hold.
26
+ *
27
+ * Optional since ADR-0016: prefer `agent`, which names an operator-authored definition. This form
28
+ * lets the MODEL choose the capability set, which is the weaker arrangement — it is still bounded by
29
+ * the session grant (ADR-0008), so it cannot escalate, but nothing about it was reviewed by a human.
30
+ */
31
+ tools?: string[];
32
+ /**
33
+ * Name of a `SKILL.md` definition to spawn (ADR-0016).
34
+ *
35
+ * When given, the definition's `allowed-tools` is the ceiling and its body is the child's system
36
+ * prompt. The model chooses only *which* definition and *what* task; the capability set is the
37
+ * operator's, written down in a file.
38
+ */
39
+ agent?: string;
40
+ model?: string;
41
+ provider?: string;
42
+ thinking?: string;
43
+ }
44
+ export interface DelegationContext {
45
+ ownGrant: Capability[];
46
+ depth: number;
47
+ maxDepth: number;
48
+ gated: Capability[];
49
+ /**
50
+ * Approvals in force for this delegation, with subject and scope (ADR-0014).
51
+ *
52
+ * One source of truth for two different questions. The **gate check here** honours every entry,
53
+ * including `once` — that approval applies to *this* spawn, which is exactly what the human said yes
54
+ * to. What crosses to the CHILD is `inheritApprovals`, which drops `once` and keeps the subject, so
55
+ * the same list cannot silently authorise a subtree.
56
+ */
57
+ approved?: InheritableApproval[];
58
+ ledgerPath?: string;
59
+ /** Path to this extension, so a child granted `tool:delegate` can delegate in turn. */
60
+ extensionPath?: string;
61
+ /** Live capability catalog. When supplied, capabilities absent from it are refused as unknown. */
62
+ catalog?: Catalog;
63
+ /**
64
+ * Absolute path per skill NAME, from the catalog's `source` field (R-32).
65
+ *
66
+ * Without it every granted `skill:` capability is unresolvable and the delegation is refused, which
67
+ * is the correct direction: a caller that cannot say where a skill lives cannot honestly grant it.
68
+ */
69
+ skillPaths?: Record<string, string>;
70
+ /** Let the child load `AGENTS.md` / `CLAUDE.md`. Default false — see `planSpawn`. */
71
+ contextFiles?: boolean;
72
+ /** Known `SKILL.md` definitions by name, for `DelegationRequest.agent` (ADR-0016). */
73
+ definitions?: Map<string, SkillDefinition>;
74
+ /**
75
+ * Build an INTERACTIVE plan — no `--print` — for an executor that drives the child after starting it.
76
+ *
77
+ * `runHerdrPane` requires this: `--print` makes pi process the prompt and exit, so it never reaches the
78
+ * interactive readiness `herdr agent start` waits for and the agent is never detected. Default is the
79
+ * non-interactive plan, because a governed child should not sit waiting for a human by accident.
80
+ */
81
+ interactive?: boolean;
82
+ /**
83
+ * Total descendants this session may still create (`src/fanout.ts`). Split among children by the caller.
84
+ *
85
+ * Omitted means unbounded, which is the pre-fan-out behaviour and correct for a single blocking
86
+ * delegation — the accident that used to bound cardinality to one.
87
+ */
88
+ fanoutBudget?: number;
89
+ /** This session's ledger id, so a child's `parentId` names its real parent (F8). */
90
+ spawnId?: string;
91
+ /** Ledger id assigned to THIS child, distinguishing it from its siblings (F8). */
92
+ childSpawnId?: string;
93
+ }
94
+ export interface Delegation {
95
+ ok: boolean;
96
+ reason?: string;
97
+ args: string[];
98
+ /** Per-child environment — never merged into the parent's process.env. */
99
+ env: Record<string, string>;
100
+ effective: Capability[];
101
+ /**
102
+ * The result this plan was made from. **Required** (B-I3): while it was optional the extension
103
+ * guarded its ledger write with `if (ledgerPath && plan.result)`, silently dropping every refusal
104
+ * that returned before `resolve()` ran. The type is what keeps a new early exit auditable.
105
+ */
106
+ result: ResolveResult;
107
+ childDepth: number;
108
+ /**
109
+ * The capabilities this delegation asked for, whatever route named them.
110
+ *
111
+ * Carried on the plan rather than re-derived by the caller (the B-I3 lesson): with `agent`, the
112
+ * request names a DEFINITION and the capabilities come from its `allowed-tools`, so a ledger that
113
+ * read the tool parameters would record an empty request for every definition spawn.
114
+ */
115
+ requested: Capability[];
116
+ /** Ledger id for this child, if the caller assigned one (F8). */
117
+ childId?: string;
118
+ /**
119
+ * Which operator-authored instructions this spawn used (ADR-0018).
120
+ *
121
+ * Absent for a `tools:`-style delegation, which has no definition and therefore no instructions to
122
+ * identify — and absent on an ADR-0017 authorisation refusal, which is decided before the file is read.
123
+ */
124
+ definitionDigest?: DefinitionDigest;
125
+ }
126
+ /**
127
+ * Plan a governed delegation. Pure: returns argv and env, spawns nothing.
128
+ *
129
+ * Fails closed on depth, on any requested capability the delegator does not hold, on gated capabilities
130
+ * without approval, and on a grant that cannot narrow (a universal capability slipping through).
131
+ */
132
+ export declare function planDelegation(request: DelegationRequest, ctx: DelegationContext): Delegation;
133
+ //# sourceMappingURL=delegate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delegate.d.ts","sourceRoot":"","sources":["../src/delegate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAA0C,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACvH,OAAO,EAA4B,KAAK,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAO7F,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAElH,OAAO,EAAoB,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAuB,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AAEjE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uFAAuF;IACvF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kGAAkG;IAClG,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,qFAAqF;IACrF,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,sFAAsF;IACtF,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC3C;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oFAAoF;IACpF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,0EAA0E;IAC1E,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB;;;;OAIG;IACH,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,EAAE,iBAAiB,GAAG,UAAU,CA8O7F"}