pi-daddy 0.44.4 → 0.46.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 +10 -0
- package/README.md +383 -25
- package/dist/executors/captured-execution.d.ts +2 -2
- package/dist/executors/captured-execution.d.ts.map +1 -1
- package/dist/executors/captured-execution.js +2 -2
- package/dist/executors/captured-execution.js.map +1 -1
- package/dist/executors/executor.d.ts.map +1 -1
- package/dist/executors/executor.js +4 -2
- package/dist/executors/executor.js.map +1 -1
- package/dist/executors/herdr-cli.d.ts +2 -0
- package/dist/executors/herdr-cli.d.ts.map +1 -1
- package/dist/executors/herdr-cli.js +2 -2
- package/dist/executors/herdr-cli.js.map +1 -1
- package/dist/executors/herdr-launcher.d.ts +2 -0
- package/dist/executors/herdr-launcher.d.ts.map +1 -0
- package/dist/executors/herdr-launcher.js +123 -0
- package/dist/executors/herdr-launcher.js.map +1 -0
- package/dist/executors/herdr-owned.d.ts +13 -0
- package/dist/executors/herdr-owned.d.ts.map +1 -0
- package/dist/executors/herdr-owned.js +229 -0
- package/dist/executors/herdr-owned.js.map +1 -0
- package/dist/executors/herdr-qualification.d.ts +6 -0
- package/dist/executors/herdr-qualification.d.ts.map +1 -0
- package/dist/executors/herdr-qualification.js +33 -0
- package/dist/executors/herdr-qualification.js.map +1 -0
- package/dist/executors/herdr-wire.d.ts +5 -0
- package/dist/executors/herdr-wire.d.ts.map +1 -0
- package/dist/executors/herdr-wire.js +47 -0
- package/dist/executors/herdr-wire.js.map +1 -0
- package/dist/governance/runtime-settlement-lock.d.ts +5 -0
- package/dist/governance/runtime-settlement-lock.d.ts.map +1 -0
- package/dist/governance/runtime-settlement-lock.js +72 -0
- package/dist/governance/runtime-settlement-lock.js.map +1 -0
- package/dist/governance/runtime-settlement.d.ts +22 -0
- package/dist/governance/runtime-settlement.d.ts.map +1 -0
- package/dist/governance/runtime-settlement.js +236 -0
- package/dist/governance/runtime-settlement.js.map +1 -0
- package/dist/kernel/definition-sources.d.ts +13 -0
- package/dist/kernel/definition-sources.d.ts.map +1 -0
- package/dist/kernel/definition-sources.js +2 -0
- package/dist/kernel/definition-sources.js.map +1 -0
- package/dist/kernel/definitions.d.ts +2 -0
- package/dist/kernel/definitions.d.ts.map +1 -1
- package/dist/kernel/definitions.js.map +1 -1
- package/dist/kernel/env-names.d.ts +2 -0
- package/dist/kernel/env-names.d.ts.map +1 -1
- package/dist/kernel/env-names.js +3 -0
- package/dist/kernel/env-names.js.map +1 -1
- package/dist/kernel/propagation.d.ts +1 -1
- package/dist/kernel/propagation.d.ts.map +1 -1
- package/dist/kernel/propagation.js +2 -0
- package/dist/kernel/propagation.js.map +1 -1
- package/dist/kernel/selected-definitions.d.ts +1 -1
- package/dist/kernel/selected-definitions.d.ts.map +1 -1
- package/dist/kernel/selected-definitions.js +19 -10
- package/dist/kernel/selected-definitions.js.map +1 -1
- package/dist/products/public-evidence.d.ts +62 -0
- package/dist/products/public-evidence.d.ts.map +1 -0
- package/dist/products/public-evidence.js +116 -0
- package/dist/products/public-evidence.js.map +1 -0
- package/extensions/definition-describe.ts +4 -1
- package/extensions/delegate-chain.ts +21 -15
- package/extensions/delegation.ts +57 -27
- package/extensions/execute-child.ts +98 -74
- package/extensions/execution-evidence.ts +10 -1
- package/extensions/executor-session.ts +2 -1
- package/extensions/grants.ts +3 -0
- package/extensions/public-evidence.ts +90 -0
- package/extensions/reload-environment.ts +8 -0
- package/extensions/run-delegation.ts +20 -4
- package/extensions/runtime-snapshot.ts +123 -0
- package/extensions/session.ts +11 -2
- package/package.json +1 -1
- package/src/executors/captured-execution.ts +2 -1
- package/src/executors/executor.ts +4 -2
- package/src/executors/herdr-cli.ts +19 -12
- package/src/executors/herdr-launcher.ts +124 -0
- package/src/executors/herdr-owned.ts +260 -0
- package/src/executors/herdr-qualification.ts +33 -0
- package/src/executors/herdr-wire.ts +43 -0
- package/src/governance/runtime-settlement-lock.ts +76 -0
- package/src/governance/runtime-settlement.ts +271 -0
- package/src/kernel/definition-sources.ts +12 -0
- package/src/kernel/definitions.ts +2 -0
- package/src/kernel/env-names.ts +3 -0
- package/src/kernel/propagation.ts +2 -0
- package/src/kernel/selected-definitions.ts +31 -10
- package/src/products/public-evidence.ts +181 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { DefinitionSourceSnapshot } from "../kernel/definition-sources.ts";
|
|
2
|
+
export declare const PUBLIC_EVIDENCE_SCHEMA = "pi-daddy-public-evidence-v1";
|
|
3
|
+
export declare const MAX_PUBLIC_EVIDENCE_BYTES: number;
|
|
4
|
+
export declare const MAX_PUBLIC_EVIDENCE_FILES = 64;
|
|
5
|
+
export interface PublicEvidenceRef {
|
|
6
|
+
path: string;
|
|
7
|
+
sha256: string;
|
|
8
|
+
bytes: number;
|
|
9
|
+
}
|
|
10
|
+
export interface PublicEvidenceOwner {
|
|
11
|
+
readonly directory: string;
|
|
12
|
+
readonly ownerId: string;
|
|
13
|
+
}
|
|
14
|
+
export interface PublicDefinitionEvidence {
|
|
15
|
+
agent: string;
|
|
16
|
+
definitionId: string;
|
|
17
|
+
sourceHash: string | null;
|
|
18
|
+
bodySha256: string;
|
|
19
|
+
binding: Readonly<{
|
|
20
|
+
package: string;
|
|
21
|
+
phase: string;
|
|
22
|
+
}> | null;
|
|
23
|
+
snapshot?: DefinitionSourceSnapshot;
|
|
24
|
+
}
|
|
25
|
+
export interface PublicEvidenceRequest {
|
|
26
|
+
ordinal: number;
|
|
27
|
+
agent: string | null;
|
|
28
|
+
requestedDefinitionId: string | null;
|
|
29
|
+
definitionId: string | null;
|
|
30
|
+
executionId: string | null;
|
|
31
|
+
}
|
|
32
|
+
export interface PublicFinalEvidence {
|
|
33
|
+
ordinal: number;
|
|
34
|
+
executionId: string | null;
|
|
35
|
+
final: {
|
|
36
|
+
state: "complete";
|
|
37
|
+
text: string;
|
|
38
|
+
sessionId: string;
|
|
39
|
+
messageId: string;
|
|
40
|
+
leafId: string;
|
|
41
|
+
sha256: string;
|
|
42
|
+
} | null;
|
|
43
|
+
}
|
|
44
|
+
export interface PublicEvidenceInput {
|
|
45
|
+
toolCallId: string;
|
|
46
|
+
tool: "delegate_describe" | "delegate" | "delegate_all" | "delegate_chain";
|
|
47
|
+
response: {
|
|
48
|
+
isError: boolean;
|
|
49
|
+
content: readonly {
|
|
50
|
+
type: "text";
|
|
51
|
+
text: string;
|
|
52
|
+
}[];
|
|
53
|
+
};
|
|
54
|
+
requested: readonly PublicEvidenceRequest[];
|
|
55
|
+
runtimeEvidence: unknown;
|
|
56
|
+
definitions: readonly PublicDefinitionEvidence[];
|
|
57
|
+
finals: readonly PublicFinalEvidence[];
|
|
58
|
+
}
|
|
59
|
+
export declare function createPublicEvidenceOwner(directory: string | undefined): PublicEvidenceOwner | undefined;
|
|
60
|
+
/** No schema accepts arbitrary filenames, output paths, raw arguments, environment, or native details. */
|
|
61
|
+
export declare function capturePublicEvidence(owner: PublicEvidenceOwner, input: PublicEvidenceInput): PublicEvidenceRef;
|
|
62
|
+
//# sourceMappingURL=public-evidence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-evidence.d.ts","sourceRoot":"","sources":["../../src/products/public-evidence.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAChF,eAAO,MAAM,sBAAsB,gCAAgC,CAAC;AACpE,eAAO,MAAM,yBAAyB,QAAmB,CAAC;AAC1D,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAC5C,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AACD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AACD,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,QAAQ,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;IAC7D,QAAQ,CAAC,EAAE,wBAAwB,CAAC;CACrC;AACD,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AACD,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE;QACL,KAAK,EAAE,UAAU,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;KAChB,GAAG,IAAI,CAAC;CACV;AACD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,mBAAmB,GAAG,UAAU,GAAG,cAAc,GAAG,gBAAgB,CAAC;IAC3E,QAAQ,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,SAAS;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAAE,CAAC;IACnF,SAAS,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC5C,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,SAAS,wBAAwB,EAAE,CAAC;IACjD,MAAM,EAAE,SAAS,mBAAmB,EAAE,CAAC;CACxC;AACD,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,mBAAmB,GAAG,SAAS,CAIxG;AAGD,0GAA0G;AAC1G,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,mBAAmB,GAAG,iBAAiB,CAyG/G"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/** Exact public extension-return capture. Opt-in local observation, never an authority/acceptance source.
|
|
2
|
+
* Existing operator-created root must be canonical, private and owned by this uid. Held directory
|
|
3
|
+
* descriptors anchor every exclusive write; successful refs are returned only after fsync and close.
|
|
4
|
+
* Hashes detect accidental edits; this does not authenticate against a hostile process with the same uid.
|
|
5
|
+
*/
|
|
6
|
+
import { randomUUID, createHash } from "node:crypto";
|
|
7
|
+
import { constants, openSync, closeSync, fstatSync, fsyncSync, writeFileSync, mkdirSync, realpathSync, statSync, } from "node:fs";
|
|
8
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
9
|
+
export const PUBLIC_EVIDENCE_SCHEMA = "pi-daddy-public-evidence-v1";
|
|
10
|
+
export const MAX_PUBLIC_EVIDENCE_BYTES = 64 * 1024 * 1024;
|
|
11
|
+
export const MAX_PUBLIC_EVIDENCE_FILES = 64;
|
|
12
|
+
export function createPublicEvidenceOwner(directory) {
|
|
13
|
+
return directory === undefined || directory === "off"
|
|
14
|
+
? undefined
|
|
15
|
+
: Object.freeze({ directory, ownerId: randomUUID() });
|
|
16
|
+
}
|
|
17
|
+
const sha256 = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
18
|
+
const json = (value) => Buffer.from(JSON.stringify(value) + "\n", "utf8");
|
|
19
|
+
/** No schema accepts arbitrary filenames, output paths, raw arguments, environment, or native details. */
|
|
20
|
+
export function capturePublicEvidence(owner, input) {
|
|
21
|
+
const directory = owner.directory;
|
|
22
|
+
if (process.platform !== "linux" ||
|
|
23
|
+
!isAbsolute(directory) ||
|
|
24
|
+
resolve(directory) !== directory ||
|
|
25
|
+
realpathSync(directory) !== directory)
|
|
26
|
+
throw Error("public evidence root must be an existing canonical absolute Linux directory");
|
|
27
|
+
const rootFd = openSync(directory, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
28
|
+
try {
|
|
29
|
+
const root = fstatSync(rootFd);
|
|
30
|
+
if (!root.isDirectory() || root.uid !== process.getuid?.() || (root.mode & 0o077) !== 0)
|
|
31
|
+
throw Error("public evidence root must be owned by this user and private (mode 0700)");
|
|
32
|
+
const captureId = randomUUID(), target = join(directory, captureId);
|
|
33
|
+
const rootPath = `/proc/self/fd/${rootFd}`;
|
|
34
|
+
mkdirSync(join(rootPath, captureId), { mode: 0o700 });
|
|
35
|
+
const captureFd = openSync(join(rootPath, captureId), constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
|
|
36
|
+
let manifest;
|
|
37
|
+
try {
|
|
38
|
+
let bytes = 0, files = 0;
|
|
39
|
+
const put = (name, content) => {
|
|
40
|
+
bytes += content.byteLength;
|
|
41
|
+
files += 1;
|
|
42
|
+
if (bytes > MAX_PUBLIC_EVIDENCE_BYTES || files > MAX_PUBLIC_EVIDENCE_FILES)
|
|
43
|
+
throw Error("public evidence capture exceeds its byte/file limit; no complete manifest published");
|
|
44
|
+
const fd = openSync(join(`/proc/self/fd/${captureFd}`, name), constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW | constants.O_NONBLOCK, 0o600);
|
|
45
|
+
try {
|
|
46
|
+
if (!fstatSync(fd).isFile())
|
|
47
|
+
throw Error("public evidence target is not an ordinary file");
|
|
48
|
+
writeFileSync(fd, content);
|
|
49
|
+
fsyncSync(fd);
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
closeSync(fd);
|
|
53
|
+
}
|
|
54
|
+
return { path: join(target, name), sha256: sha256(content), bytes: content.byteLength };
|
|
55
|
+
};
|
|
56
|
+
const response = put("response.json", json(input.response));
|
|
57
|
+
const finals = input.finals.map((outcome) => {
|
|
58
|
+
if (!outcome.final)
|
|
59
|
+
return { ordinal: outcome.ordinal, executionId: outcome.executionId, final: null };
|
|
60
|
+
const { text, ...identity } = outcome.final;
|
|
61
|
+
const bytes = Buffer.from(text, "utf8");
|
|
62
|
+
if (sha256(bytes) !== identity.sha256)
|
|
63
|
+
throw Error("attributed final bytes do not match the native final hash");
|
|
64
|
+
if (!text || !input.response.content.some((block) => block.text.includes(text)))
|
|
65
|
+
throw Error("attributed final is not present in the public returned content");
|
|
66
|
+
return {
|
|
67
|
+
ordinal: outcome.ordinal,
|
|
68
|
+
executionId: outcome.executionId,
|
|
69
|
+
final: { ...identity, content: put(`outcome-${outcome.ordinal}-final.txt`, bytes) },
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
const definitions = input.definitions.map((definition, index) => {
|
|
73
|
+
if (!definition.snapshot)
|
|
74
|
+
throw Error(`selected source snapshot unavailable for ${definition.agent}`);
|
|
75
|
+
const resources = definition.snapshot.resources.map((source, resource) => ({
|
|
76
|
+
kind: source.kind,
|
|
77
|
+
path: source.path,
|
|
78
|
+
copy: put(`definition-${index}-source-${resource}.bin`, Buffer.from(source.base64, "base64")),
|
|
79
|
+
}));
|
|
80
|
+
const { snapshot: _snapshot, ...identity } = definition;
|
|
81
|
+
return {
|
|
82
|
+
...identity,
|
|
83
|
+
resources,
|
|
84
|
+
body: put(`definition-${index}-body.txt`, Buffer.from(definition.snapshot.body, "utf8")),
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
manifest = put("manifest.json", json({
|
|
88
|
+
schema: PUBLIC_EVIDENCE_SCHEMA,
|
|
89
|
+
version: 1,
|
|
90
|
+
captureId,
|
|
91
|
+
ownerId: owner.ownerId,
|
|
92
|
+
toolCallId: input.toolCallId,
|
|
93
|
+
tool: input.tool,
|
|
94
|
+
state: "returned",
|
|
95
|
+
response,
|
|
96
|
+
requested: input.requested,
|
|
97
|
+
runtimeEvidence: input.runtimeEvidence,
|
|
98
|
+
finals,
|
|
99
|
+
definitions,
|
|
100
|
+
}));
|
|
101
|
+
fsyncSync(captureFd);
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
closeSync(captureFd);
|
|
105
|
+
}
|
|
106
|
+
fsyncSync(rootFd);
|
|
107
|
+
const current = statSync(directory);
|
|
108
|
+
if (realpathSync(directory) !== directory || current.dev !== root.dev || current.ino !== root.ino)
|
|
109
|
+
throw Error("public evidence root changed before reference publication");
|
|
110
|
+
return manifest;
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
closeSync(rootFd);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=public-evidence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-evidence.js","sourceRoot":"","sources":["../../src/products/public-evidence.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EACL,SAAS,EACT,QAAQ,EACR,SAAS,EACT,SAAS,EACT,SAAS,EACT,aAAa,EACb,SAAS,EACT,YAAY,EACZ,QAAQ,GACT,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEtD,MAAM,CAAC,MAAM,sBAAsB,GAAG,6BAA6B,CAAC;AACpE,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAC1D,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,CAAC;AA8C5C,MAAM,UAAU,yBAAyB,CAAC,SAA6B;IACrE,OAAO,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,KAAK;QACnD,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;AAC1D,CAAC;AACD,MAAM,MAAM,GAAG,CAAC,KAAiB,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACvF,MAAM,IAAI,GAAG,CAAC,KAAc,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;AACnF,0GAA0G;AAC1G,MAAM,UAAU,qBAAqB,CAAC,KAA0B,EAAE,KAA0B;IAC1F,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IAClC,IACE,OAAO,CAAC,QAAQ,KAAK,OAAO;QAC5B,CAAC,UAAU,CAAC,SAAS,CAAC;QACtB,OAAO,CAAC,SAAS,CAAC,KAAK,SAAS;QAChC,YAAY,CAAC,SAAS,CAAC,KAAK,SAAS;QAErC,MAAM,KAAK,CAAC,6EAA6E,CAAC,CAAC;IAC7F,MAAM,MAAM,GAAG,QAAQ,CACrB,SAAS,EACT,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,WAAW,GAAG,SAAS,CAAC,UAAU,GAAG,SAAS,CAAC,UAAU,CACzF,CAAC;IACF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,GAAG,KAAK,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC;YACrF,MAAM,KAAK,CAAC,yEAAyE,CAAC,CAAC;QACzF,MAAM,SAAS,GAAG,UAAU,EAAE,EAC5B,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,iBAAiB,MAAM,EAAE,CAAC;QAC3C,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACtD,MAAM,SAAS,GAAG,QAAQ,CACxB,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,EACzB,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,WAAW,GAAG,SAAS,CAAC,UAAU,CAClE,CAAC;QACF,IAAI,QAA2B,CAAC;QAChC,IAAI,CAAC;YACH,IAAI,KAAK,GAAG,CAAC,EACX,KAAK,GAAG,CAAC,CAAC;YACZ,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,OAAe,EAAqB,EAAE;gBAC/D,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC;gBAC5B,KAAK,IAAI,CAAC,CAAC;gBACX,IAAI,KAAK,GAAG,yBAAyB,IAAI,KAAK,GAAG,yBAAyB;oBACxE,MAAM,KAAK,CAAC,qFAAqF,CAAC,CAAC;gBACrG,MAAM,EAAE,GAAG,QAAQ,CACjB,IAAI,CAAC,iBAAiB,SAAS,EAAE,EAAE,IAAI,CAAC,EACxC,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,OAAO,GAAG,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,UAAU,GAAG,SAAS,CAAC,UAAU,EACvG,KAAK,CACN,CAAC;gBACF,IAAI,CAAC;oBACH,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE;wBAAE,MAAM,KAAK,CAAC,gDAAgD,CAAC,CAAC;oBAC3F,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;oBAC3B,SAAS,CAAC,EAAE,CAAC,CAAC;gBAChB,CAAC;wBAAS,CAAC;oBACT,SAAS,CAAC,EAAE,CAAC,CAAC;gBAChB,CAAC;gBACD,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC;YAC1F,CAAC,CAAC;YACF,MAAM,QAAQ,GAAG,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC5D,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;gBAC1C,IAAI,CAAC,OAAO,CAAC,KAAK;oBAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;gBACvG,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;gBAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBACxC,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,QAAQ,CAAC,MAAM;oBAAE,MAAM,KAAK,CAAC,2DAA2D,CAAC,CAAC;gBAChH,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;oBAC7E,MAAM,KAAK,CAAC,gEAAgE,CAAC,CAAC;gBAChF,OAAO;oBACL,OAAO,EAAE,OAAO,CAAC,OAAO;oBACxB,WAAW,EAAE,OAAO,CAAC,WAAW;oBAChC,KAAK,EAAE,EAAE,GAAG,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,WAAW,OAAO,CAAC,OAAO,YAAY,EAAE,KAAK,CAAC,EAAE;iBACpF,CAAC;YACJ,CAAC,CAAC,CAAC;YACH,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE;gBAC9D,IAAI,CAAC,UAAU,CAAC,QAAQ;oBAAE,MAAM,KAAK,CAAC,4CAA4C,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;gBACtG,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;oBACzE,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,IAAI,EAAE,GAAG,CAAC,cAAc,KAAK,WAAW,QAAQ,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;iBAC9F,CAAC,CAAC,CAAC;gBACJ,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,QAAQ,EAAE,GAAG,UAAU,CAAC;gBACxD,OAAO;oBACL,GAAG,QAAQ;oBACX,SAAS;oBACT,IAAI,EAAE,GAAG,CAAC,cAAc,KAAK,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;iBACzF,CAAC;YACJ,CAAC,CAAC,CAAC;YACH,QAAQ,GAAG,GAAG,CACZ,eAAe,EACf,IAAI,CAAC;gBACH,MAAM,EAAE,sBAAsB;gBAC9B,OAAO,EAAE,CAAC;gBACV,SAAS;gBACT,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,KAAK,EAAE,UAAU;gBACjB,QAAQ;gBACR,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,eAAe,EAAE,KAAK,CAAC,eAAe;gBACtC,MAAM;gBACN,WAAW;aACZ,CAAC,CACH,CAAC;YACF,SAAS,CAAC,SAAS,CAAC,CAAC;QACvB,CAAC;gBAAS,CAAC;YACT,SAAS,CAAC,SAAS,CAAC,CAAC;QACvB,CAAC;QACD,SAAS,CAAC,MAAM,CAAC,CAAC;QAClB,MAAM,OAAO,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;QACpC,IAAI,YAAY,CAAC,SAAS,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG;YAC/F,MAAM,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC3E,OAAO,QAAQ,CAAC;IAClB,CAAC;YAAS,CAAC;QACT,SAAS,CAAC,MAAM,CAAC,CAAC;IACpB,CAAC;AACH,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** Read-only handshake with the exact immutable definition dispatched by this extension instance. */
|
|
2
|
+
import { publicEvidenceCall } from "./public-evidence.ts";
|
|
2
3
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
4
|
import { Type } from "typebox";
|
|
4
5
|
import { digestDefinition } from "../src/kernel/definitions.ts";
|
|
@@ -38,7 +39,9 @@ export function registerDefinitionDescribe(pi: ExtensionAPI, session: GrantsSess
|
|
|
38
39
|
binding: definition.binding ?? null,
|
|
39
40
|
definitionId: definition.definitionId,
|
|
40
41
|
};
|
|
41
|
-
|
|
42
|
+
const capture = publicEvidenceCall(session.publicEvidence, _id, "delegate_describe", [{ agent: params.agent }]);
|
|
43
|
+
capture.selected(0, definition);
|
|
44
|
+
return capture.finish({ content: [{ type: "text" as const, text: JSON.stringify(details) }], details });
|
|
42
45
|
},
|
|
43
46
|
});
|
|
44
47
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { publicEvidenceCall } from "./public-evidence.ts";
|
|
1
2
|
import { executionEvidenceContent } from "./execution-evidence.ts";
|
|
2
3
|
import { assertDefinitionIdentity } from "./definition-describe.ts";
|
|
3
4
|
/**
|
|
@@ -142,6 +143,7 @@ export function registerChainTool(pi: ExtensionAPI, session: GrantsSession): voi
|
|
|
142
143
|
// Plan every step first. A step that can never run refuses the chain HERE, before anyone is asked — see
|
|
143
144
|
// `planChain`.
|
|
144
145
|
const executionIds = steps.map(() => newExecutionId());
|
|
146
|
+
const capture = publicEvidenceCall(session.publicEvidence, _toolCallId, "delegate_chain", steps, executionIds);
|
|
145
147
|
await reconcileDelegationCapacity(session);
|
|
146
148
|
const firstReservation = reserveDelegationCapacity(session, executionIds[0]);
|
|
147
149
|
try {
|
|
@@ -326,6 +328,7 @@ export function registerChainTool(pi: ExtensionAPI, session: GrantsSession): voi
|
|
|
326
328
|
{
|
|
327
329
|
...(index === 0 ? { capacityReservation: firstReservation } : {}),
|
|
328
330
|
resolvedRuntime: runtimeChoices.get(step),
|
|
331
|
+
onDefinition: (definition) => capture.selected(index, definition),
|
|
329
332
|
preApproved: availableForStep,
|
|
330
333
|
toolCallId: _toolCallId,
|
|
331
334
|
// Only approvals actually offered to this step are attributed or consumed here.
|
|
@@ -407,22 +410,25 @@ export function registerChainTool(pi: ExtensionAPI, session: GrantsSession): voi
|
|
|
407
410
|
if (outcomes[0].refusal) throw new GovernanceRefusal({ ...outcomes[0].refusal, message });
|
|
408
411
|
throw new Error(message);
|
|
409
412
|
}
|
|
410
|
-
return
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
413
|
+
return capture.finish(
|
|
414
|
+
{
|
|
415
|
+
isError: aborted || outcomes.some((o) => o.control === "failed"),
|
|
416
|
+
content: [
|
|
417
|
+
{ type: "text", text: `${report}${tail}` },
|
|
418
|
+
executionEvidenceContent("delegate_chain", outcomes, steps.length),
|
|
419
|
+
],
|
|
420
|
+
details: {
|
|
421
|
+
outcomes,
|
|
422
|
+
steps: steps.length,
|
|
423
|
+
completed: outcomes.filter((o) => o.ok).length,
|
|
424
|
+
aborted,
|
|
425
|
+
budgetPerStep: firstReservation.childAllowance,
|
|
426
|
+
...(blockedReason ? { blockedReason } : {}),
|
|
427
|
+
refusals: outcomes.map((outcome) => outcome.refusal ?? null),
|
|
428
|
+
},
|
|
424
429
|
},
|
|
425
|
-
|
|
430
|
+
outcomes,
|
|
431
|
+
);
|
|
426
432
|
} finally {
|
|
427
433
|
firstReservation.finalize({ state: "not-started", reason: "chain ended before its first execution" });
|
|
428
434
|
}
|
package/extensions/delegation.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { publicEvidenceCall } from "./public-evidence.ts";
|
|
1
2
|
import { executionEvidenceContent } from "./execution-evidence.ts";
|
|
2
3
|
import { reconcileDelegationCapacity, reserveDelegationCapacity } from "./session-capacity.ts";
|
|
3
4
|
import { registerDefinitionDescribe } from "./definition-describe.ts";
|
|
@@ -253,6 +254,14 @@ export function registerDelegationTools(pi: ExtensionAPI, session: GrantsSession
|
|
|
253
254
|
// ADR-0032: one child, same block. `_onUpdate` was discarded here, so a delegation showed the bare word
|
|
254
255
|
// `delegate` for up to DEFAULT_TIMEOUT_MS — sixty minutes by default.
|
|
255
256
|
const progress = progressReporter(session, [params.agent ?? "delegate"], onUpdate as never);
|
|
257
|
+
const occurrence = newDelegationOccurrence(session, 0);
|
|
258
|
+
const capture = publicEvidenceCall(
|
|
259
|
+
session.publicEvidence,
|
|
260
|
+
_toolCallId,
|
|
261
|
+
"delegate",
|
|
262
|
+
[params],
|
|
263
|
+
[occurrence.executionId],
|
|
264
|
+
);
|
|
256
265
|
const outcome = await runOneDelegation(
|
|
257
266
|
session,
|
|
258
267
|
{
|
|
@@ -266,12 +275,16 @@ export function registerDelegationTools(pi: ExtensionAPI, session: GrantsSession
|
|
|
266
275
|
correlation: params.correlation,
|
|
267
276
|
workspace: params.workspace,
|
|
268
277
|
},
|
|
269
|
-
|
|
278
|
+
occurrence,
|
|
270
279
|
// Reserve one actual child plus the currently available disjoint subtree allowance.
|
|
271
280
|
undefined,
|
|
272
281
|
ctx,
|
|
273
282
|
signal,
|
|
274
|
-
{
|
|
283
|
+
{
|
|
284
|
+
onProgress: progress.sink(0),
|
|
285
|
+
toolCallId: _toolCallId,
|
|
286
|
+
onDefinition: (definition) => capture.selected(0, definition),
|
|
287
|
+
},
|
|
275
288
|
);
|
|
276
289
|
progress.settle([outcome]);
|
|
277
290
|
|
|
@@ -284,19 +297,22 @@ export function registerDelegationTools(pi: ExtensionAPI, session: GrantsSession
|
|
|
284
297
|
}
|
|
285
298
|
// Pi 1.0.4 preserves returned isError. Keep every outcome dimension and useful output together.
|
|
286
299
|
const failed = !outcome.ok || outcome.control === "failed";
|
|
287
|
-
return
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
+
return capture.finish(
|
|
301
|
+
{
|
|
302
|
+
isError: failed,
|
|
303
|
+
content: [
|
|
304
|
+
{
|
|
305
|
+
type: "text",
|
|
306
|
+
text: failed
|
|
307
|
+
? `delegation failed: ${outcome.reason ?? "required control failed"}${outcome.text ? `\n\n${outcome.text}` : ""}`
|
|
308
|
+
: outcome.text || "(no output)",
|
|
309
|
+
},
|
|
310
|
+
executionEvidenceContent("delegate", [outcome], 1),
|
|
311
|
+
],
|
|
312
|
+
details: outcome,
|
|
313
|
+
},
|
|
314
|
+
[outcome],
|
|
315
|
+
);
|
|
300
316
|
},
|
|
301
317
|
});
|
|
302
318
|
|
|
@@ -356,11 +372,19 @@ export function registerDelegationTools(pi: ExtensionAPI, session: GrantsSession
|
|
|
356
372
|
// (R-116).
|
|
357
373
|
const infrastructureErrors: unknown[] = [],
|
|
358
374
|
occurrences = children.map((_, index) => newDelegationOccurrence(session, index));
|
|
375
|
+
const capture = publicEvidenceCall(
|
|
376
|
+
session.publicEvidence,
|
|
377
|
+
_toolCallId,
|
|
378
|
+
"delegate_all",
|
|
379
|
+
children,
|
|
380
|
+
occurrences.map((row) => row.executionId),
|
|
381
|
+
);
|
|
359
382
|
const pending = children.map(async (child, index): Promise<DelegationOutcome> => {
|
|
360
383
|
try {
|
|
361
384
|
return await runOneDelegation(session, child, occurrences[index], split.perChild, ctx, signal, {
|
|
362
385
|
// Reserve each batch share synchronously here, before another dispatch can interleave.
|
|
363
386
|
capacityReservation: reserveDelegationCapacity(session, occurrences[index].executionId, split.perChild),
|
|
387
|
+
onDefinition: (definition) => capture.selected(index, definition),
|
|
364
388
|
onProgress: progress.sink(index),
|
|
365
389
|
toolCallId: _toolCallId,
|
|
366
390
|
});
|
|
@@ -385,19 +409,25 @@ export function registerDelegationTools(pi: ExtensionAPI, session: GrantsSession
|
|
|
385
409
|
if (failed.length === children.length && outcomes.every((o) => !o.work && !o.final && !o.cleanup))
|
|
386
410
|
throw totalFanoutFailure(failed, `fan-out failed: every child was refused or failed.\n\n${report}`);
|
|
387
411
|
|
|
388
|
-
return
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
412
|
+
return capture.finish(
|
|
413
|
+
{
|
|
414
|
+
isError: outcomes.some((o) => !o.ok || o.control === "failed"),
|
|
415
|
+
content: [
|
|
416
|
+
{ type: "text", text: report },
|
|
417
|
+
executionEvidenceContent("delegate_all", outcomes, children.length),
|
|
418
|
+
],
|
|
419
|
+
details: {
|
|
420
|
+
outcomes,
|
|
421
|
+
children: outcomes.length,
|
|
422
|
+
failed: failed.length,
|
|
423
|
+
budgetPerChild: split.perChild,
|
|
424
|
+
granted: outcomes.map((o) => o.granted),
|
|
425
|
+
refusals: outcomes.map((o) => o.refusal ?? null),
|
|
426
|
+
retention: outcomes.map((o) => o.retention ?? null),
|
|
427
|
+
},
|
|
399
428
|
},
|
|
400
|
-
|
|
429
|
+
outcomes,
|
|
430
|
+
);
|
|
401
431
|
},
|
|
402
432
|
});
|
|
403
433
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BoundedReadCleanupError } from "../src/kernel/bounded-read.ts";
|
|
2
2
|
import { retainDiscoveryCleanupFailure } from "./session.ts";
|
|
3
3
|
import type { CapacityReservation } from "../src/kernel/capacity.ts";
|
|
4
|
-
import {
|
|
4
|
+
import { runHerdrOwned } from "../src/executors/herdr-owned.ts";
|
|
5
5
|
import { runCapturedExecution } from "../src/executors/captured-execution.ts";
|
|
6
6
|
import type { ChildFinal } from "../src/executors/child-final.ts";
|
|
7
7
|
import type { CapturedWorkerCleanup } from "../src/kernel/captured-worker-contract.ts";
|
|
@@ -20,13 +20,12 @@ import {
|
|
|
20
20
|
ENV_CHILD_IDLE_TIMEOUT,
|
|
21
21
|
ENV_CHILD_TIMEOUT,
|
|
22
22
|
idleTimeoutFromEnv,
|
|
23
|
-
runChild,
|
|
24
23
|
timeoutFromEnv,
|
|
25
24
|
} from "../src/kernel/run-child.ts";
|
|
26
25
|
import { activitySessionFor } from "../src/executors/activity-session.ts";
|
|
27
26
|
import { processTreeActivity } from "../src/executors/process-activity.ts";
|
|
28
27
|
import { resolveWorkspace } from "../src/executors/herdr-cli.ts";
|
|
29
|
-
import { HerdrWriterCloseError
|
|
28
|
+
import { HerdrWriterCloseError } from "../src/executors/run-herdr.ts";
|
|
30
29
|
import { GovernanceRefusal, refusal, type StructuredRefusal } from "../src/kernel/refusals.ts";
|
|
31
30
|
import { ENV_HERDR_KEEP_PANE, type GrantsSession } from "./session.ts";
|
|
32
31
|
import { CHILD_ATTRIBUTION_ENV_KEYS, ENV_EPISODE_ID } from "../src/kernel/env-names.ts";
|
|
@@ -138,15 +137,49 @@ export interface ChildExecutionInput {
|
|
|
138
137
|
}
|
|
139
138
|
export async function executePlannedChild(input: ChildExecutionInput): Promise<DelegationOutcome> {
|
|
140
139
|
let executorEntered = false;
|
|
140
|
+
const runtime = input.session.reloadLifecycle?.runtimeSettlement;
|
|
141
|
+
let registered = false;
|
|
141
142
|
try {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
runtime?.begin(input.executionId);
|
|
144
|
+
registered = Boolean(runtime);
|
|
145
|
+
const result = await executePreparedChild(
|
|
146
|
+
input,
|
|
147
|
+
() => {
|
|
148
|
+
executorEntered = true;
|
|
149
|
+
},
|
|
150
|
+
runtime,
|
|
151
|
+
);
|
|
152
|
+
try {
|
|
153
|
+
await runtime?.finish(
|
|
154
|
+
input.executionId,
|
|
155
|
+
result.cleanup ?? { state: "unknown", reason: "executor omitted cleanup" },
|
|
156
|
+
result.control === "failed" ? (result.reason ?? "runtime control failed") : undefined,
|
|
157
|
+
);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
return {
|
|
160
|
+
...result,
|
|
161
|
+
control: "failed",
|
|
162
|
+
reason: [result.reason, `runtime settlement record failed: ${String(error)}`].filter(Boolean).join("; "),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
return result;
|
|
145
166
|
} catch (error) {
|
|
146
|
-
if (executorEntered) throw error;
|
|
147
|
-
// Every operation above the executor-entry marker is local setup: no helper or worker exists yet.
|
|
148
|
-
input.capacityReservation?.finalize({ state: "not-started", reason: "child setup failed before executor entry" });
|
|
149
167
|
const failures: unknown[] = [error];
|
|
168
|
+
if (registered)
|
|
169
|
+
try {
|
|
170
|
+
await runtime?.finish(input.executionId, {
|
|
171
|
+
state: executorEntered ? "unknown" : "not-started",
|
|
172
|
+
reason: String(error),
|
|
173
|
+
});
|
|
174
|
+
} catch (recordError) {
|
|
175
|
+
failures.push(recordError);
|
|
176
|
+
}
|
|
177
|
+
if (executorEntered) {
|
|
178
|
+
if (failures.length > 1) throw new AggregateError(failures, failures.map(String).join("; "));
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
// Setup failures prove no worker started, even if recording that fact also failed.
|
|
182
|
+
input.capacityReservation?.finalize({ state: "not-started", reason: "child setup failed before executor entry" });
|
|
150
183
|
try {
|
|
151
184
|
const released = await releaseDelegationWorkspace({
|
|
152
185
|
prepared: input.preparedWorkspace,
|
|
@@ -174,6 +207,7 @@ export async function executePlannedChild(input: ChildExecutionInput): Promise<D
|
|
|
174
207
|
async function executePreparedChild(
|
|
175
208
|
input: ChildExecutionInput,
|
|
176
209
|
onExecutorEntry: () => void,
|
|
210
|
+
runtime?: import("../src/governance/runtime-settlement.ts").RuntimeSettlement,
|
|
177
211
|
): Promise<DelegationOutcome> {
|
|
178
212
|
const { session, plan, childId, executionId, parentExecutionId, preparedWorkspace, signal, onProgress } = input;
|
|
179
213
|
const ledgerPath = session.ledgerPath;
|
|
@@ -229,7 +263,7 @@ async function executePreparedChild(
|
|
|
229
263
|
const activitySession = await activitySessionFor(plan.args, executionId);
|
|
230
264
|
// Disposed on every path (review finding: it leaked on every throw), except when the operator keeps a Herdr pane,
|
|
231
265
|
// where the interactive pi in that pane is still alive and still appending to this file.
|
|
232
|
-
const keepPaneRequested =
|
|
266
|
+
const keepPaneRequested = false; // The qualified pane launcher exits; retained panes contain no live Pi writer.
|
|
233
267
|
try {
|
|
234
268
|
return await executeWithActivitySession();
|
|
235
269
|
} finally {
|
|
@@ -368,73 +402,63 @@ async function executePreparedChild(
|
|
|
368
402
|
}
|
|
369
403
|
};
|
|
370
404
|
try {
|
|
371
|
-
if (
|
|
372
|
-
throw new GovernanceRefusal(refusal("EXECUTOR_UNAVAILABLE",
|
|
405
|
+
if (session.executor.refusal)
|
|
406
|
+
throw new GovernanceRefusal(refusal("EXECUTOR_UNAVAILABLE", session.executor.refusal));
|
|
373
407
|
executorEntered = true;
|
|
374
408
|
onExecutorEntry();
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
executionId,
|
|
408
|
-
sessionPath: activitySession.path,
|
|
409
|
-
onReadCleanup,
|
|
410
|
-
onOwnership: async (identity) => {
|
|
411
|
-
input.capacityReservation?.bindOwnership(identity);
|
|
412
|
-
await preparedWorkspace?.lease.attachCapturedWorker(identity);
|
|
413
|
-
},
|
|
414
|
-
command: "pi",
|
|
415
|
-
args,
|
|
416
|
-
env: mergeChildEnv(process.env, plan.env),
|
|
417
|
-
cwd,
|
|
418
|
-
signal: executionSignal,
|
|
419
|
-
// SIGTERM gets only grace that fits INSIDE the recorded deadline. The independent hard timer
|
|
420
|
-
// prevents a delayed soft-timeout callback from starting a fresh grace period beyond that bound.
|
|
421
|
-
timeoutMs: Math.max(1, remainingTimeoutMs - terminationGraceMs),
|
|
422
|
-
hardDeadlineAt: Date.parse(deadlineAt),
|
|
423
|
-
idleTimeoutMs: configuredIdleMs,
|
|
424
|
-
activityProbe: probe,
|
|
425
|
-
onOutput: onProgress ? (chunk) => onProgress({ chunk }) : undefined,
|
|
426
|
-
onObservation: (stream, bytes) => retention.capture(stream, bytes),
|
|
427
|
-
onSpawn: (pid) => {
|
|
428
|
-
childPid = pid;
|
|
429
|
-
// Lease attachment is a security hook and may fail the spawn. The shared reporters isolate
|
|
430
|
-
// display exceptions before they reach this callback; runChild deliberately kills on any error
|
|
431
|
-
// here, so presentation must never be added directly without that reporter boundary.
|
|
409
|
+
let displayHerdr: ((text: string) => void) | undefined;
|
|
410
|
+
const output = await runCapturedExecution(
|
|
411
|
+
{
|
|
412
|
+
executionId,
|
|
413
|
+
sessionPath: activitySession.path,
|
|
414
|
+
onReadCleanup,
|
|
415
|
+
onOwnership: async (identity) => {
|
|
416
|
+
runtime?.bind(identity);
|
|
417
|
+
input.capacityReservation?.bindOwnership(identity);
|
|
418
|
+
await preparedWorkspace?.lease.attachCapturedWorker(identity);
|
|
419
|
+
},
|
|
420
|
+
command: "pi",
|
|
421
|
+
args,
|
|
422
|
+
env: mergeChildEnv(process.env, plan.env),
|
|
423
|
+
cwd,
|
|
424
|
+
signal: executionSignal,
|
|
425
|
+
// SIGTERM gets only grace that fits INSIDE the recorded deadline. The independent hard timer
|
|
426
|
+
// prevents a delayed soft-timeout callback from starting a fresh grace period beyond that bound.
|
|
427
|
+
timeoutMs: Math.max(1, remainingTimeoutMs - terminationGraceMs),
|
|
428
|
+
hardDeadlineAt: Date.parse(deadlineAt),
|
|
429
|
+
idleTimeoutMs: configuredIdleMs,
|
|
430
|
+
activityProbe: probe,
|
|
431
|
+
onOutput: (chunk) => {
|
|
432
|
+
displayHerdr?.(chunk);
|
|
433
|
+
onProgress?.({ chunk });
|
|
434
|
+
},
|
|
435
|
+
onObservation: (stream, bytes) => retention.capture(stream, bytes),
|
|
436
|
+
onSpawn: (pid) => {
|
|
437
|
+
childPid = pid;
|
|
438
|
+
// Lease attachment is a security hook and may fail the spawn. The shared reporters isolate
|
|
439
|
+
// display exceptions before they reach this callback; runChild deliberately kills on any error
|
|
440
|
+
// here, so presentation must never be added directly without that reporter boundary.
|
|
432
441
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
442
|
+
retention.native({ pid });
|
|
443
|
+
recordRunning(session.executor.kind);
|
|
444
|
+
onProgress?.({ state: "running" });
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
session.executor.kind === "herdr"
|
|
448
|
+
? (request) =>
|
|
449
|
+
runHerdrOwned(request, {
|
|
450
|
+
onDisplay: (display) => {
|
|
451
|
+
displayHerdr = display;
|
|
452
|
+
},
|
|
453
|
+
workspace: resolveWorkspace(process.env),
|
|
454
|
+
keepPane: process.env[ENV_HERDR_KEEP_PANE] === "1",
|
|
455
|
+
onPane: (paneId, tabId) => {
|
|
456
|
+
retention.native({ paneId, tabId });
|
|
457
|
+
onProgress?.({ paneId, state: "starting" });
|
|
458
|
+
},
|
|
459
|
+
})
|
|
460
|
+
: undefined,
|
|
461
|
+
);
|
|
438
462
|
|
|
439
463
|
if (sessionFlag >= 0) retention.observeSession({ source: "pi-session-file", value: plan.args[sessionFlag + 1] });
|
|
440
464
|
retention.capture("result", Buffer.from(output.text), true);
|