@akagilnc/pi-workflow-roles 0.1.3572 → 0.1.3621
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/dist/acp-host/production-host.js +20239 -10556
- package/dist/analyst-gate-cycles-read.js +387 -0
- package/dist/archivist-record-entry.js +22 -1
- package/dist/audit-escalation.js +6 -0
- package/dist/auditor-soul.js +74 -0
- package/dist/collector-config.js +86 -0
- package/dist/collector-evidence.js +316 -0
- package/dist/collector-github.js +527 -0
- package/dist/collector-ledger.js +853 -0
- package/dist/collector-tool-schemas.js +33 -0
- package/dist/compliance-transport.js +104 -52
- package/dist/diarist-mechanical.js +411 -0
- package/dist/diarist-ticket-resolution.js +177 -0
- package/dist/diarist.js +311 -0
- package/dist/doctor-auditor.js +25 -0
- package/dist/doctor-contracts.js +2 -0
- package/dist/doctor-evidence.js +142 -0
- package/dist/gatekeeper-role.js +104 -81
- package/dist/host-transition-prior-native.js +78 -0
- package/dist/institutional-resolution.js +1 -95
- package/dist/judge-auditor.js +26 -0
- package/dist/ledger-session-read.js +227 -0
- package/dist/merger-git-state.js +78 -0
- package/dist/navigator-attendance.js +15 -7
- package/dist/navigator-public-session.js +170 -0
- package/dist/navigator-session-contracts.js +36 -40
- package/dist/notary-source-run.js +122 -0
- package/dist/package-contracts/auditor-output.js +66 -0
- package/dist/package-contracts/evidence-child-output.js +34 -0
- package/dist/package-contracts/judge-output.js +2 -0
- package/dist/package-contracts/terminating-tools.js +25 -2
- package/dist/package-resources/method-skill.js +254 -0
- package/dist/packaged-role-registry.js +36 -0
- package/dist/pi/durable-principal.js +61 -0
- package/dist/pi/in-process-session.js +25 -6
- package/dist/pi/known-failure.js +52 -0
- package/dist/pi/role-turn-host.js +430 -0
- package/dist/public-cli/auto-resume.js +414 -0
- package/dist/public-cli/cli-errors.js +8 -0
- package/dist/public-cli/cli-io.js +1 -0
- package/dist/public-cli/command-renderer.js +5 -0
- package/dist/public-cli/doctor-run.js +84 -0
- package/dist/public-cli/inspector-run.js +136 -0
- package/dist/public-cli/instruction-seat-run.js +256 -0
- package/dist/public-cli/invocation.js +2225 -0
- package/dist/public-cli/judge-run.js +118 -0
- package/dist/public-cli/load-production-acp-host.js +40 -0
- package/dist/public-cli/main.js +1140 -652
- package/dist/public-cli/notary-run.js +161 -0
- package/dist/public-cli/option-definitions.js +1192 -0
- package/dist/public-cli/post-admission.js +667 -0
- package/dist/public-cli/public-run-credentials.js +49 -0
- package/dist/public-cli/registry.js +4 -1
- package/dist/public-cli/reviewer-dispatch-rejection.js +77 -0
- package/dist/public-cli/run-lifecycle.js +1344 -0
- package/dist/public-cli/seat-ticket-binding.js +113 -0
- package/dist/public-cli/settlement.js +3441 -0
- package/dist/public-cli/terminal.js +135 -0
- package/dist/public-cli/turn-request.js +25 -0
- package/dist/public-role-summons.js +301 -0
- package/dist/receipt-delivery-policy.js +10 -0
- package/dist/reviewer-child-executor.js +80 -8
- package/dist/reviewer-execution-ledger.js +2 -1
- package/dist/run-terminal-artifacts.js +195 -0
- package/dist/run-ticket-number.js +40 -0
- package/dist/session-assistant-usage.js +107 -0
- package/dist/shape-unreadable-failure.js +34 -0
- package/dist/submission-errors.js +3 -0
- package/dist/submission-ledger.js +388 -0
- package/dist/ticket-provenance-contracts.js +115 -0
- package/dist/ticket-provenance.js +340 -0
- package/extensions/role-runtime.ts +7 -0
- package/package.json +1 -1
- package/scripts/build-package.mjs +2 -1
- package/souls/doctor-auditor.md +1 -0
- package/souls/evidence-child.md +1 -0
- package/src/acp-host/production-host.ts +3 -0
- package/src/acp-host/role-envelope.ts +2 -2
- package/src/acp-host/role-turn-host.ts +9 -1
- package/src/analyst-gate-cycles-read.ts +37 -2
- package/src/archivist-record-entry.ts +45 -1
- package/src/audit-escalation.ts +17 -0
- package/src/auditor-role.ts +22 -0
- package/src/auditor-soul.ts +42 -0
- package/src/compliance-transport.ts +177 -66
- package/src/doctor-auditor.ts +10 -14
- package/src/doctor-contracts.ts +1 -0
- package/src/doctor-role.ts +2 -2
- package/src/evidence-child-role.ts +22 -0
- package/src/gatekeeper-pass-envelope.ts +109 -0
- package/src/gatekeeper-role.ts +145 -104
- package/src/host-contracts.ts +9 -1
- package/src/institutional-resolution.ts +8 -163
- package/src/judge-auditor.ts +10 -15
- package/src/judge-role.ts +8 -0
- package/src/navigator-attendance.ts +25 -9
- package/src/navigator-public-session.ts +217 -0
- package/src/navigator-session-contracts.ts +61 -54
- package/src/notary-source-run.ts +3 -1
- package/src/package-contracts/auditor-output.ts +82 -0
- package/src/package-contracts/evidence-child-output.ts +51 -0
- package/src/package-contracts/judge-output.ts +1 -0
- package/src/package-contracts/reviewer-output.ts +2 -2
- package/src/package-contracts/terminating-tools.ts +31 -1
- package/src/packaged-role-registry.ts +43 -0
- package/src/pi/adapter.ts +2 -1
- package/src/pi/in-process-session.ts +38 -12
- package/src/pi/role-turn-host.ts +34 -0
- package/src/public-cli/cli.ts +14 -6
- package/src/public-cli/instruction-seat-run.ts +289 -50
- package/src/public-cli/invocation.ts +66 -25
- package/src/public-cli/option-definitions.ts +61 -0
- package/src/public-cli/post-admission.ts +7 -1
- package/src/public-cli/registry.ts +4 -1
- package/src/public-cli/run-lifecycle.ts +22 -3
- package/src/public-cli/settlement.ts +120 -5
- package/src/public-cli/terminal.ts +2 -0
- package/src/public-role-summons.ts +431 -0
- package/src/receipt-delivery-policy.ts +10 -0
- package/src/reviewer-agent.ts +1 -1
- package/src/reviewer-child-executor.ts +114 -12
- package/src/reviewer-execution-ledger.ts +3 -2
- package/src/role-runtime.ts +158 -17
- package/src/session-assistant-usage.ts +119 -0
- package/src/session-opening-materials.ts +1 -1
- package/src/shape-unreadable-failure.ts +49 -0
- package/src/submission-errors.ts +3 -0
- package/dist/evidence-child-executor.js +0 -829
- package/src/evidence-child-executor.ts +0 -1140
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pi adapter for the host-neutral main-session execution seam (#526 / S1b-2).
|
|
3
|
+
* Owns argv construction, spawn/SIGTERM/close, and session codec helpers.
|
|
4
|
+
* public-cli runners project RoleTurnRequest; this module is the sole argv owner.
|
|
5
|
+
*/
|
|
6
|
+
import { execFile, spawn } from "node:child_process";
|
|
7
|
+
import { constants } from "node:fs";
|
|
8
|
+
import { access, appendFile, readFile, realpath } from "node:fs/promises";
|
|
9
|
+
import { delimiter, isAbsolute, join, resolve } from "node:path";
|
|
10
|
+
import { platform } from "node:process";
|
|
11
|
+
import { promisify } from "node:util";
|
|
12
|
+
import { randomUUID } from "node:crypto";
|
|
13
|
+
import { ExplicitInternalActivationError } from "../host-contracts.js";
|
|
14
|
+
import { applyEngineChildEnv } from "../engine-detour.js";
|
|
15
|
+
/** Package-relative Internal role entrypoint (ADR 0052; same path as public-cli registry). */
|
|
16
|
+
const INTERNAL_ROLE_ENTRYPOINT_RELATIVE = "extensions/role-runtime.ts";
|
|
17
|
+
export function resolveInternalRoleEntrypoint(packageRoot) {
|
|
18
|
+
return join(packageRoot, INTERNAL_ROLE_ENTRYPOINT_RELATIVE);
|
|
19
|
+
}
|
|
20
|
+
/** Non-dispatch args: load Internal once and exit via Pi help (no model turn). */
|
|
21
|
+
export const EXPLICIT_INTERNAL_LOAD_PROBE_ARGS = [
|
|
22
|
+
"--no-skills",
|
|
23
|
+
"--no-prompt-templates",
|
|
24
|
+
"--no-themes",
|
|
25
|
+
"--no-context-files",
|
|
26
|
+
"--no-session",
|
|
27
|
+
"--help",
|
|
28
|
+
];
|
|
29
|
+
export function buildExplicitInternalActivationArgs(selectedRoleEntry, extraArgs = []) {
|
|
30
|
+
return ["--no-extensions", "-e", selectedRoleEntry, ...extraArgs];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Pi argv for seat model. Host only passes through resolved values — no local
|
|
34
|
+
* thinking whitelist and no package default fill. Bare provider/model omits
|
|
35
|
+
* --thinking so Pi owns its own default (#346/#384). Explicit thinking only.
|
|
36
|
+
*/
|
|
37
|
+
function buildSeatModelCliArgs(model) {
|
|
38
|
+
if (model === undefined)
|
|
39
|
+
return [];
|
|
40
|
+
return [
|
|
41
|
+
"--provider",
|
|
42
|
+
model.provider,
|
|
43
|
+
"--model",
|
|
44
|
+
model.model,
|
|
45
|
+
...(model.thinking === undefined ? [] : ["--thinking", model.thinking]),
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
function buildActivationFlagArgs(activation) {
|
|
49
|
+
switch (activation.role) {
|
|
50
|
+
case "judge":
|
|
51
|
+
return ["--ak-role", "judge"];
|
|
52
|
+
case "coder":
|
|
53
|
+
return [
|
|
54
|
+
"--ak-role",
|
|
55
|
+
"coder",
|
|
56
|
+
"--ak-coder-phase",
|
|
57
|
+
activation.phase,
|
|
58
|
+
"--ak-coder-task",
|
|
59
|
+
activation.taskPath,
|
|
60
|
+
];
|
|
61
|
+
case "fixer":
|
|
62
|
+
return [
|
|
63
|
+
"--ak-role",
|
|
64
|
+
"fixer",
|
|
65
|
+
"--ak-fixer-phase",
|
|
66
|
+
activation.phase,
|
|
67
|
+
"--ak-fix-packet",
|
|
68
|
+
activation.packetPath,
|
|
69
|
+
...(activation.prerequisitesPath === undefined
|
|
70
|
+
? []
|
|
71
|
+
: ["--ak-fixer-prerequisites", activation.prerequisitesPath]),
|
|
72
|
+
];
|
|
73
|
+
case "reviewer":
|
|
74
|
+
return [
|
|
75
|
+
"--ak-role",
|
|
76
|
+
"reviewer",
|
|
77
|
+
"--ak-review-base",
|
|
78
|
+
activation.baseRevision,
|
|
79
|
+
...(activation.authorityRefs.length === 0
|
|
80
|
+
? []
|
|
81
|
+
: ["--ak-review-authority-refs", JSON.stringify([...activation.authorityRefs])]),
|
|
82
|
+
...(activation.ticketNumber === undefined
|
|
83
|
+
? []
|
|
84
|
+
: ["--ak-review-ticket-number", String(activation.ticketNumber)]),
|
|
85
|
+
];
|
|
86
|
+
case "merger":
|
|
87
|
+
return ["--ak-role", "merger", "--ak-merger-input", activation.inputPath];
|
|
88
|
+
case "collector":
|
|
89
|
+
return [
|
|
90
|
+
"--ak-role",
|
|
91
|
+
"collector",
|
|
92
|
+
"--ak-collector-repo",
|
|
93
|
+
activation.repo,
|
|
94
|
+
"--ak-collector-pr",
|
|
95
|
+
activation.pr,
|
|
96
|
+
...(activation.requestManifestPath === undefined
|
|
97
|
+
? []
|
|
98
|
+
: ["--ak-collector-request-manifest", activation.requestManifestPath]),
|
|
99
|
+
];
|
|
100
|
+
case "doctor":
|
|
101
|
+
return ["--ak-role", "doctor", "--ak-doctor-case", activation.casePath];
|
|
102
|
+
case "notary":
|
|
103
|
+
return [
|
|
104
|
+
"--ak-role",
|
|
105
|
+
"notary",
|
|
106
|
+
"--ak-notary-source-run",
|
|
107
|
+
activation.sourceRun,
|
|
108
|
+
...(activation.ticketNumber === undefined
|
|
109
|
+
? []
|
|
110
|
+
: ["--ak-notary-ticket-number", String(activation.ticketNumber)]),
|
|
111
|
+
];
|
|
112
|
+
case "countersign":
|
|
113
|
+
// ticketNumber rides activation/admission/invocation only (#632: no private flag).
|
|
114
|
+
return ["--ak-role", "countersign"];
|
|
115
|
+
case "gleaner-left":
|
|
116
|
+
return [
|
|
117
|
+
"--ak-role",
|
|
118
|
+
"gleaner-left",
|
|
119
|
+
"--ak-gleaner-left-base",
|
|
120
|
+
activation.baseRevision,
|
|
121
|
+
];
|
|
122
|
+
case "inspector":
|
|
123
|
+
return ["--ak-role", "inspector"];
|
|
124
|
+
case "gatekeeper":
|
|
125
|
+
return ["--ak-role", "gatekeeper"];
|
|
126
|
+
case "navigator":
|
|
127
|
+
return ["--ak-role", "navigator"];
|
|
128
|
+
case "auditor":
|
|
129
|
+
return ["--ak-role", "auditor"];
|
|
130
|
+
case "evidence-child":
|
|
131
|
+
return ["--ak-role", "evidence-child"];
|
|
132
|
+
case "diarist":
|
|
133
|
+
return [
|
|
134
|
+
"--ak-role",
|
|
135
|
+
"diarist",
|
|
136
|
+
...(activation.sourcesPath === undefined
|
|
137
|
+
? []
|
|
138
|
+
: ["--ak-diarist-sources", activation.sourcesPath]),
|
|
139
|
+
];
|
|
140
|
+
default: {
|
|
141
|
+
const _exhaustive = activation;
|
|
142
|
+
return _exhaustive;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function buildMethodArgs(methods) {
|
|
147
|
+
const skillArgs = [];
|
|
148
|
+
for (const method of methods) {
|
|
149
|
+
if (method.kind === "skill") {
|
|
150
|
+
skillArgs.push("--skill", method.path);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return skillArgs;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Translate a closed RoleTurnRequest into Pi argv after `--no-extensions -e entry`.
|
|
157
|
+
* Controlled session constants and session coordinates are adapter-internal.
|
|
158
|
+
*/
|
|
159
|
+
export function buildPiTurnExtraArgs(request, authority, extraPiArgs = []) {
|
|
160
|
+
const { sessionFile, sessionDirectory } = authority.decode(request.principal);
|
|
161
|
+
const prompt = request.continuation.kind === "initial" || request.continuation.kind === "resume"
|
|
162
|
+
? request.continuation.prompt
|
|
163
|
+
: (() => {
|
|
164
|
+
const _exhaustive = request.continuation;
|
|
165
|
+
return _exhaustive;
|
|
166
|
+
})();
|
|
167
|
+
return [
|
|
168
|
+
"--no-skills",
|
|
169
|
+
...buildMethodArgs(request.methods),
|
|
170
|
+
"--no-prompt-templates",
|
|
171
|
+
"--no-themes",
|
|
172
|
+
"--no-context-files",
|
|
173
|
+
"--session",
|
|
174
|
+
sessionFile,
|
|
175
|
+
"--session-dir",
|
|
176
|
+
sessionDirectory,
|
|
177
|
+
...extraPiArgs,
|
|
178
|
+
...buildActivationFlagArgs(request.activation),
|
|
179
|
+
"--mode",
|
|
180
|
+
"json",
|
|
181
|
+
...buildSeatModelCliArgs(request.model),
|
|
182
|
+
prompt,
|
|
183
|
+
];
|
|
184
|
+
}
|
|
185
|
+
const execFileAsync = promisify(execFile);
|
|
186
|
+
async function resolveSelectedPi(command, cwd, env) {
|
|
187
|
+
const searchPath = env.PATH ?? (platform === "win32" ? (process.env.PATH ?? "") : "/usr/bin:/bin");
|
|
188
|
+
const candidates = isAbsolute(command) || command.includes("/")
|
|
189
|
+
? [resolve(cwd, command)]
|
|
190
|
+
: searchPath.split(delimiter).map((dir) => resolve(cwd, dir, command));
|
|
191
|
+
for (const candidate of candidates) {
|
|
192
|
+
try {
|
|
193
|
+
await access(candidate, constants.X_OK);
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
const code = error.code;
|
|
197
|
+
if (code === "ENOENT" || code === "ENOTDIR" || code === "EACCES")
|
|
198
|
+
continue;
|
|
199
|
+
throw new ExplicitInternalActivationError(`Pi executable resolution failed: ${String(error.message)}`, { knownCause: "activation", cause: error });
|
|
200
|
+
}
|
|
201
|
+
return await realpath(candidate);
|
|
202
|
+
}
|
|
203
|
+
throw new ExplicitInternalActivationError(`Pi executable not found: ${command}`, {
|
|
204
|
+
knownCause: "activation",
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
async function selectedPiIdentity(command, cwd, env) {
|
|
208
|
+
const executable = await resolveSelectedPi(command, cwd, env);
|
|
209
|
+
const { stdout } = await execFileAsync(executable, ["--version"], {
|
|
210
|
+
cwd,
|
|
211
|
+
env,
|
|
212
|
+
encoding: "utf8",
|
|
213
|
+
});
|
|
214
|
+
const version = stdout.trim();
|
|
215
|
+
if (version === "")
|
|
216
|
+
throw new Error(`Pi executable returned an empty version: ${executable}`);
|
|
217
|
+
return { executable, version };
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Default child runner: canonically select `pi` on PATH (or PI_BINARY) and launch
|
|
221
|
+
* that exact file. Close settles exactly once for natural return / error / SIGTERM.
|
|
222
|
+
*/
|
|
223
|
+
export function createDefaultPiSpawnRunner(options) {
|
|
224
|
+
return async (args, spawnOptions) => {
|
|
225
|
+
const command = spawnOptions.env.PI_BINARY ?? "pi";
|
|
226
|
+
const piIdentity = await selectedPiIdentity(command, spawnOptions.cwd, spawnOptions.env);
|
|
227
|
+
return await new Promise((resolveResult, reject) => {
|
|
228
|
+
// Child stdout is discarded at the stdio seam (CLAUDE.md Role invocation
|
|
229
|
+
// evidence). Do not pipe or accumulate it. stderr stays piped for diagnostics.
|
|
230
|
+
const child = spawn(piIdentity.executable, [...args], {
|
|
231
|
+
cwd: spawnOptions.cwd,
|
|
232
|
+
env: spawnOptions.env,
|
|
233
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
234
|
+
});
|
|
235
|
+
if (child.stderr === null) {
|
|
236
|
+
throw new Error("Pi child stderr pipe was not created");
|
|
237
|
+
}
|
|
238
|
+
let stderr = "";
|
|
239
|
+
let timedOut = false;
|
|
240
|
+
// No default wall clock. Only an explicit caller budget arms a timer (ADR 0010).
|
|
241
|
+
// SIGKILL is unconditionally forbidden — graceful SIGTERM only.
|
|
242
|
+
let timer;
|
|
243
|
+
let settled = false;
|
|
244
|
+
// `error` fires for pre-spawn failures (ENOENT after identity check is a
|
|
245
|
+
// true activation failure) or kill/dispatch errors. Retain it so `close`
|
|
246
|
+
// remains the SOLE settlement point (spec-B: child close once). Only
|
|
247
|
+
// fall back to rejecting on `error` if `close` never fires (e.g. spawn
|
|
248
|
+
// never succeeded so no `close` event will arrive).
|
|
249
|
+
let hasSpawned = false;
|
|
250
|
+
let executionError;
|
|
251
|
+
const armTimeoutAfterChildReady = () => {
|
|
252
|
+
if (spawnOptions.timeoutMs === undefined)
|
|
253
|
+
return;
|
|
254
|
+
timer = setTimeout(() => {
|
|
255
|
+
timedOut = true;
|
|
256
|
+
child.kill("SIGTERM");
|
|
257
|
+
}, spawnOptions.timeoutMs);
|
|
258
|
+
};
|
|
259
|
+
// Parent cancellation reaches the nested activation: same graceful SIGTERM,
|
|
260
|
+
// same single close settlement. SIGKILL stays forbidden (#675 / ADR 0010).
|
|
261
|
+
const parentSignal = spawnOptions.signal;
|
|
262
|
+
const terminateForParentAbort = () => {
|
|
263
|
+
child.kill("SIGTERM");
|
|
264
|
+
};
|
|
265
|
+
parentSignal?.addEventListener("abort", terminateForParentAbort, { once: true });
|
|
266
|
+
let identityRecorded = Promise.resolve();
|
|
267
|
+
child.once("spawn", () => {
|
|
268
|
+
hasSpawned = true;
|
|
269
|
+
if (parentSignal?.aborted === true)
|
|
270
|
+
terminateForParentAbort();
|
|
271
|
+
armTimeoutAfterChildReady();
|
|
272
|
+
const runDirectory = spawnOptions.env.AK_ROLE_RUN_DIR;
|
|
273
|
+
if (typeof runDirectory === "string" &&
|
|
274
|
+
runDirectory !== "" &&
|
|
275
|
+
options.recordLaunchedPiIdentity !== undefined) {
|
|
276
|
+
identityRecorded = options.recordLaunchedPiIdentity(runDirectory, piIdentity);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
child.stderr.setEncoding("utf8").on("data", (chunk) => {
|
|
280
|
+
stderr += chunk;
|
|
281
|
+
});
|
|
282
|
+
child.on("error", (error) => {
|
|
283
|
+
// A pre-spawn error has no child lifecycle to close. After spawn,
|
|
284
|
+
// retain the execution error and let the mandatory close event own
|
|
285
|
+
// cleanup and the single settlement.
|
|
286
|
+
if (settled || hasSpawned) {
|
|
287
|
+
executionError = error;
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (timer !== undefined)
|
|
291
|
+
clearTimeout(timer);
|
|
292
|
+
parentSignal?.removeEventListener("abort", terminateForParentAbort);
|
|
293
|
+
settled = true;
|
|
294
|
+
reject(error);
|
|
295
|
+
});
|
|
296
|
+
child.on("close", (code) => {
|
|
297
|
+
if (timer !== undefined)
|
|
298
|
+
clearTimeout(timer);
|
|
299
|
+
parentSignal?.removeEventListener("abort", terminateForParentAbort);
|
|
300
|
+
void identityRecorded.then(() => {
|
|
301
|
+
if (settled)
|
|
302
|
+
return;
|
|
303
|
+
settled = true;
|
|
304
|
+
if (executionError !== undefined) {
|
|
305
|
+
reject(executionError);
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
resolveResult({
|
|
309
|
+
code,
|
|
310
|
+
stderr,
|
|
311
|
+
timedOut,
|
|
312
|
+
});
|
|
313
|
+
}, (error) => {
|
|
314
|
+
if (settled)
|
|
315
|
+
return;
|
|
316
|
+
settled = true;
|
|
317
|
+
reject(error);
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
/** Create the production Pi RoleTurnHost (composition-root assembly). */
|
|
324
|
+
export function createPiRoleTurnHost(config) {
|
|
325
|
+
const spawnRunner = config.spawnRunner ??
|
|
326
|
+
createDefaultPiSpawnRunner({
|
|
327
|
+
...(config.recordLaunchedPiIdentity === undefined
|
|
328
|
+
? {}
|
|
329
|
+
: { recordLaunchedPiIdentity: config.recordLaunchedPiIdentity }),
|
|
330
|
+
});
|
|
331
|
+
return {
|
|
332
|
+
async executeTurn(request) {
|
|
333
|
+
// #617 DK-7: Pi argv gets projected native paths once; never record bytes.
|
|
334
|
+
// Pi already owns its own session file, so only sitian prior volume rides in.
|
|
335
|
+
let turnRequest = request;
|
|
336
|
+
const paths = request.hostTransition?.priorNativeKind === "sitian"
|
|
337
|
+
? request.hostTransition.priorNativePaths
|
|
338
|
+
: undefined;
|
|
339
|
+
if (request.continuation.kind === "resume"
|
|
340
|
+
&& paths !== undefined
|
|
341
|
+
&& paths.length > 0) {
|
|
342
|
+
turnRequest = {
|
|
343
|
+
...request,
|
|
344
|
+
continuation: {
|
|
345
|
+
...request.continuation,
|
|
346
|
+
prompt: `${request.continuation.prompt}\n${paths.join("\n")}`,
|
|
347
|
+
},
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
const roleEntry = await realpath(resolveInternalRoleEntrypoint(config.packageRoot));
|
|
351
|
+
const extraArgs = buildPiTurnExtraArgs(turnRequest, config.principalAuthority, config.extraPiArgs ?? []);
|
|
352
|
+
const args = buildExplicitInternalActivationArgs(roleEntry, extraArgs);
|
|
353
|
+
// Shared envelope isolates this call's court identity: omitting courtAttemptId
|
|
354
|
+
// must not inherit a parent process.env.AK_ROLE_COURT_ATTEMPT (#637).
|
|
355
|
+
const env = {
|
|
356
|
+
...process.env,
|
|
357
|
+
HOME: request.home,
|
|
358
|
+
PI_CODING_AGENT_DIR: request.agentDir,
|
|
359
|
+
AK_ROLE_RUN_DIR: request.runDirectory,
|
|
360
|
+
// Nested public summons resolve package root without import.meta under jiti (#675).
|
|
361
|
+
// Child-process scoped only — not written back onto the parent process.env.
|
|
362
|
+
AK_ROLE_PACKAGE_ROOT: config.packageRoot,
|
|
363
|
+
};
|
|
364
|
+
if (request.courtAttemptId === undefined)
|
|
365
|
+
delete env.AK_ROLE_COURT_ATTEMPT;
|
|
366
|
+
else
|
|
367
|
+
env.AK_ROLE_COURT_ATTEMPT = request.courtAttemptId;
|
|
368
|
+
applyEngineChildEnv(env, request.engine);
|
|
369
|
+
// Nested auditor dossier tool binds the parent run pointer when published.
|
|
370
|
+
if (typeof process.env.AK_ROLE_AUDITOR_SOURCE_RUN === "string"
|
|
371
|
+
&& process.env.AK_ROLE_AUDITOR_SOURCE_RUN.trim() !== "") {
|
|
372
|
+
env.AK_ROLE_AUDITOR_SOURCE_RUN = process.env.AK_ROLE_AUDITOR_SOURCE_RUN;
|
|
373
|
+
}
|
|
374
|
+
// Audited-subject input selects soul materials (same for nested and direct).
|
|
375
|
+
if (typeof process.env.AK_ROLE_AUDITOR_SUBJECT === "string"
|
|
376
|
+
&& process.env.AK_ROLE_AUDITOR_SUBJECT.trim() !== "") {
|
|
377
|
+
env.AK_ROLE_AUDITOR_SUBJECT = process.env.AK_ROLE_AUDITOR_SUBJECT;
|
|
378
|
+
}
|
|
379
|
+
if (request.correlationId !== undefined && request.correlationId.trim() !== "") {
|
|
380
|
+
env.AK_CORRELATION_ID = request.correlationId;
|
|
381
|
+
}
|
|
382
|
+
if (config.recordLaunchedRolePackageIdentity !== undefined &&
|
|
383
|
+
config.observeLaunchedRolePackageIdentity !== undefined) {
|
|
384
|
+
await config.recordLaunchedRolePackageIdentity(request.runDirectory, await config.observeLaunchedRolePackageIdentity(config.packageRoot, roleEntry));
|
|
385
|
+
}
|
|
386
|
+
const timeoutMs = request.timeoutMs ?? config.timeoutMs;
|
|
387
|
+
return await spawnRunner(args, {
|
|
388
|
+
cwd: request.cwd,
|
|
389
|
+
env,
|
|
390
|
+
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
391
|
+
...(request.signal === undefined ? {} : { signal: request.signal }),
|
|
392
|
+
});
|
|
393
|
+
},
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
import { sitianReport } from "../sitian-facade.js";
|
|
397
|
+
/**
|
|
398
|
+
* Append one custom JSONL entry to the durable principal's session file.
|
|
399
|
+
* Pi session codec only — AK artifact O_EXCL retention stays in public-cli.
|
|
400
|
+
*/
|
|
401
|
+
export async function appendPiSessionCustomEntry(authority, principal, customType, data) {
|
|
402
|
+
const { sessionFile } = authority.decode(principal);
|
|
403
|
+
const text = await readFile(sessionFile, "utf8");
|
|
404
|
+
let parentId = null;
|
|
405
|
+
for (const line of text.trim().split("\n").filter(Boolean)) {
|
|
406
|
+
const entry = JSON.parse(line);
|
|
407
|
+
if (typeof entry.id === "string" && entry.type !== "session")
|
|
408
|
+
parentId = entry.id;
|
|
409
|
+
}
|
|
410
|
+
const timestamp = new Date().toISOString();
|
|
411
|
+
const pointerLine = `${JSON.stringify({
|
|
412
|
+
type: "custom",
|
|
413
|
+
customType,
|
|
414
|
+
data,
|
|
415
|
+
id: randomUUID(),
|
|
416
|
+
parentId,
|
|
417
|
+
timestamp,
|
|
418
|
+
})}\n`;
|
|
419
|
+
await appendFile(sessionFile, pointerLine, "utf8");
|
|
420
|
+
try {
|
|
421
|
+
sitianReport({
|
|
422
|
+
level: "event",
|
|
423
|
+
kind: "dispatch-error",
|
|
424
|
+
sessionParent: sessionFile,
|
|
425
|
+
payload: { customType, data },
|
|
426
|
+
source: "pi-role-turn-host",
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
catch { }
|
|
430
|
+
}
|