@akagilnc/pi-workflow-roles 0.1.2521 → 0.1.2653-next.71811ca

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 (109) hide show
  1. package/README.md +129 -39
  2. package/README.zh-CN.md +128 -39
  3. package/dist/activation-ledger-topology.js +1 -1
  4. package/dist/archivist-record-entry.js +47 -26
  5. package/dist/auditor-dossier-tool.js +3 -1
  6. package/dist/compliance-transport.js +17 -26
  7. package/dist/doctor-contracts.js +1 -2
  8. package/dist/dossier-resolution.js +4 -8
  9. package/dist/engine-detour-tool.js +33 -8
  10. package/dist/engine-detour.js +1 -0
  11. package/dist/evidence-child-executor.js +277 -424
  12. package/dist/host-contracts.js +22 -0
  13. package/dist/institutional-resolution.js +88 -0
  14. package/dist/merger-contracts.js +1 -2
  15. package/dist/navigator-attendance.js +16 -0
  16. package/dist/notary-contracts.js +2 -3
  17. package/dist/package-contracts/fixer-output.js +1 -2
  18. package/dist/packaged-role-registry.js +102 -9
  19. package/dist/pi/in-process-session.js +671 -0
  20. package/dist/public-cli/config.js +7 -5
  21. package/dist/public-cli/main.js +3767 -4113
  22. package/dist/reviewer-child-executor.js +6 -1
  23. package/dist/session-opening-materials.js +10 -38
  24. package/dist/sitian-appender.js +146 -0
  25. package/dist/sitian-contracts.js +21 -0
  26. package/dist/sitian-facade.js +15 -0
  27. package/dist/sitian-reader.js +52 -0
  28. package/extensions/role-runtime.ts +9 -7
  29. package/package.json +5 -5
  30. package/resources/engines/cursor.md +12 -26
  31. package/resources/engines/hermes.md +2 -23
  32. package/resources/engines/opus.md +1 -16
  33. package/resources/navigator-route-playbook.md +2 -2
  34. package/scripts/build-package.mjs +0 -1
  35. package/souls/quality-law.md +1 -1
  36. package/src/activation-ledger-topology.ts +1 -1
  37. package/src/archivist-record-entry.ts +57 -45
  38. package/src/auditor-dossier-tool.ts +4 -2
  39. package/src/canonical-skill-binding.ts +37 -27
  40. package/src/collector-role.ts +11 -20
  41. package/src/collector-tool-schemas.ts +1 -4
  42. package/src/compliance-transport.ts +19 -44
  43. package/src/doctor-auditor.ts +1 -5
  44. package/src/doctor-contracts.ts +1 -4
  45. package/src/doctor-role.ts +31 -8
  46. package/src/dossier-resolution.ts +8 -8
  47. package/src/engine-detour-tool.ts +48 -19
  48. package/src/engine-detour.ts +3 -0
  49. package/src/evidence-child-executor.ts +277 -485
  50. package/src/factory-board.ts +3 -3
  51. package/src/gatekeeper-role.ts +21 -10
  52. package/src/host-contracts.ts +386 -0
  53. package/src/in-process-session.ts +1 -115
  54. package/src/institutional-resolution.ts +135 -0
  55. package/src/judge-auditor.ts +1 -5
  56. package/src/judge-role.ts +37 -51
  57. package/src/merger-contracts.ts +1 -4
  58. package/src/merger-role.ts +7 -11
  59. package/src/navigator-attendance.ts +20 -1
  60. package/src/notary-contracts.ts +8 -11
  61. package/src/notary-role.ts +7 -23
  62. package/src/notary-source-run.ts +4 -3
  63. package/src/package-contracts/fixer-output.ts +1 -4
  64. package/src/package-resources/method-skill-binding.ts +10 -34
  65. package/src/packaged-role-registry.ts +122 -12
  66. package/src/pi/adapter.ts +192 -0
  67. package/src/pi/durable-principal.ts +98 -0
  68. package/src/pi/in-process-session.ts +819 -0
  69. package/src/pi/known-failure.ts +77 -0
  70. package/src/pi/pi-normalization.ts +284 -0
  71. package/src/pi/role-turn-host.ts +459 -0
  72. package/src/public-cli/auto-resume.ts +42 -44
  73. package/src/public-cli/cli.ts +171 -257
  74. package/src/public-cli/coder-run.ts +115 -433
  75. package/src/public-cli/collector-run.ts +62 -314
  76. package/src/public-cli/config.ts +7 -5
  77. package/src/public-cli/doctor-run.ts +41 -52
  78. package/src/public-cli/fixer-run.ts +122 -427
  79. package/src/public-cli/invocation.ts +287 -96
  80. package/src/public-cli/judge-run.ts +92 -422
  81. package/src/public-cli/merger-run.ts +167 -429
  82. package/src/public-cli/notary-run.ts +41 -47
  83. package/src/public-cli/option-definitions.ts +136 -3
  84. package/src/public-cli/post-admission.ts +497 -0
  85. package/src/public-cli/public-run-credentials.ts +4 -4
  86. package/src/public-cli/reviewer-dispatch-rejection.ts +106 -0
  87. package/src/public-cli/reviewer-run.ts +132 -449
  88. package/src/public-cli/run-lifecycle.ts +339 -327
  89. package/src/public-cli/settlement.ts +251 -134
  90. package/src/public-cli/terminal.ts +3 -9
  91. package/src/public-cli/turn-request.ts +87 -0
  92. package/src/reviewer-child-executor.ts +9 -1
  93. package/src/reviewer-role.ts +11 -20
  94. package/src/role-runtime.ts +129 -78
  95. package/src/session-opening-materials.ts +25 -39
  96. package/src/sitian-appender.ts +171 -0
  97. package/src/sitian-contracts.ts +106 -0
  98. package/src/sitian-facade.ts +18 -0
  99. package/src/sitian-reader.ts +62 -0
  100. package/src/worker-role.ts +42 -40
  101. package/src/worker-submission-gates.ts +33 -0
  102. package/dist/archivist-role-run-coordinates.js +0 -28
  103. package/dist/package-contracts/terminating-infrastructure.js +0 -90
  104. package/resources/engines/sonnet.md +0 -27
  105. package/resources/engines/zcode.md +0 -63
  106. package/src/archivist-role-run-coordinates.ts +0 -45
  107. package/src/package-contracts/terminating-infrastructure.ts +0 -132
  108. package/src/public-cli/explicit-internal.ts +0 -427
  109. package/src/public-cli/one-shot-dispatch.ts +0 -300
@@ -1,427 +0,0 @@
1
- /**
2
- * ak-role-owned one-invocation explicit Internal activation (ADR 0052 / #105).
3
- * Ordinary Pi package auto-registration does not load the role runtime; only
4
- * this adapter (or an intentional developer `pi -e`) crosses that boundary.
5
- */
6
- import { execFile, spawn } from "node:child_process";
7
- import { constants, writeFileSync } from "node:fs";
8
- import { access, readFile, realpath, unlink } 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
-
13
- import {
14
- observeLaunchedRolePackageIdentity,
15
- recordLaunchedPiIdentity,
16
- recordLaunchedRolePackageIdentity,
17
- } from "./invocation.ts";
18
- import { INTERNAL_ROLE_ENTRYPOINT_RELATIVE } from "./registry.ts";
19
- import {
20
- REVIEWER_PREFLIGHT_VIOLATIONS,
21
- type ReviewerPreflightViolation,
22
- } from "../reviewer-dispatch.ts";
23
- import type { ControlledFailureCause } from "./terminal.ts";
24
- import {
25
- hasUpstreamErrorTestimony,
26
- projectConfirmedRemotePayload,
27
- } from "../upstream-error-testimony.ts";
28
-
29
- export { hasUpstreamErrorTestimony } from "../upstream-error-testimony.ts";
30
-
31
- /** Durable Reviewer-rejection child→parent page under AK_ROLE_RUN_DIR. */
32
- const REVIEWER_DISPATCH_REJECTION_FILE = "typed-known-failure.json";
33
-
34
- function isReviewerPreflightViolation(value: unknown): value is ReviewerPreflightViolation {
35
- return (
36
- typeof value === "string" &&
37
- (REVIEWER_PREFLIGHT_VIOLATIONS as readonly string[]).includes(value)
38
- );
39
- }
40
-
41
- function reviewerDispatchRejectionPath(runDirectory: string): string {
42
- return join(runDirectory, REVIEWER_DISPATCH_REJECTION_FILE);
43
- }
44
-
45
- /**
46
- * Clear any prior attempt's Reviewer rejection page so resume/retry cannot
47
- * inherit a stale knownFailure.details.
48
- */
49
- export async function clearReviewerDispatchRejection(runDirectory: string): Promise<void> {
50
- try {
51
- await unlink(reviewerDispatchRejectionPath(runDirectory));
52
- } catch (error) {
53
- if (
54
- error instanceof Error &&
55
- "code" in error &&
56
- (error as { code?: unknown }).code === "ENOENT"
57
- ) {
58
- return;
59
- }
60
- throw error;
61
- }
62
- }
63
-
64
- /**
65
- * Synchronous durable write for Reviewer dispatch rejection (child process exit is sync).
66
- * Parent public CLI recovers via readReviewerDispatchRejection into knownFailure.
67
- */
68
- export function recordReviewerDispatchRejectionSync(
69
- runDirectory: string,
70
- rejection: Readonly<{
71
- diagnostic: string;
72
- violations: readonly ReviewerPreflightViolation[];
73
- }>,
74
- ): void {
75
- writeFileSync(
76
- reviewerDispatchRejectionPath(runDirectory),
77
- `${JSON.stringify(rejection)}\n`,
78
- "utf8",
79
- );
80
- }
81
-
82
- /** Recover a child-written Reviewer dispatch rejection through a fixed mapping. */
83
- export async function readReviewerDispatchRejection(
84
- runDirectory: string,
85
- ): Promise<ExplicitInternalKnownFailure | undefined> {
86
- let raw: string;
87
- try {
88
- raw = await readFile(reviewerDispatchRejectionPath(runDirectory), "utf8");
89
- } catch (error) {
90
- if (
91
- error instanceof Error &&
92
- "code" in error &&
93
- (error as { code?: unknown }).code === "ENOENT"
94
- ) {
95
- return undefined;
96
- }
97
- throw error;
98
- }
99
- const parsed: unknown = JSON.parse(raw);
100
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
101
- const error = new Error("Reviewer dispatch rejection page must be a JSON object");
102
- error.name = "ReviewerDispatchRejectionContractError";
103
- throw error;
104
- }
105
- const record = parsed as Record<string, unknown>;
106
- if (
107
- typeof record.diagnostic !== "string" ||
108
- record.diagnostic.trim() === "" ||
109
- !Array.isArray(record.violations) ||
110
- record.violations.length === 0 ||
111
- record.violations.some((value) => !isReviewerPreflightViolation(value))
112
- ) {
113
- const error = new Error("Reviewer dispatch rejection page has unusable required fields");
114
- error.name = "ReviewerDispatchRejectionContractError";
115
- throw error;
116
- }
117
- return {
118
- cause: "activation",
119
- diagnostic: record.diagnostic,
120
- identity: { name: "ReviewerDispatchRejectionError" },
121
- details: { violations: Object.freeze([...record.violations]) },
122
- };
123
- }
124
-
125
- export function resolveInternalRoleEntrypoint(packageRoot: string): string {
126
- return join(packageRoot, INTERNAL_ROLE_ENTRYPOINT_RELATIVE);
127
- }
128
-
129
- /**
130
- * Explicit one-invocation Internal activation args for the installed package copy.
131
- * Ordinary Pi package auto-registration does not include this entrypoint (ADR 0052).
132
- */
133
- export function buildExplicitInternalActivationArgs(
134
- selectedRoleEntry: string,
135
- extraArgs: readonly string[] = [],
136
- ): string[] {
137
- return ["--no-extensions", "-e", selectedRoleEntry, ...extraArgs];
138
- }
139
-
140
- /** Production-owned typed failure carried on a resolved runner result. */
141
- export type ExplicitInternalKnownFailure = {
142
- readonly cause: ControlledFailureCause;
143
- readonly identity?: {
144
- readonly name?: string;
145
- readonly code?: string | number;
146
- };
147
- /**
148
- * Optional diagnostic already owned by a typed production field (e.g. session
149
- * assistant errorMessage). Settlement prefers this over child stderr selection.
150
- */
151
- readonly diagnostic?: string;
152
- /** Secondary evidence attached to the same typed failure record. */
153
- readonly details?: Readonly<Record<string, unknown>>;
154
- };
155
-
156
- function nonEmptyString(value: unknown): string | undefined {
157
- return typeof value === "string" && value.trim() !== "" ? value : undefined;
158
- }
159
-
160
- function sessionStopDetails(input: {
161
- readonly errorMessage?: string | null;
162
- readonly provider?: string;
163
- readonly model?: string;
164
- readonly api?: string;
165
- readonly rawStopReason?: string;
166
- readonly httpStatus?: number;
167
- readonly diagnostics?: unknown;
168
- readonly body?: unknown;
169
- readonly code?: unknown;
170
- readonly errno?: unknown;
171
- }): Record<string, unknown> {
172
- const details: Record<string, unknown> = {};
173
- const errorMessage = nonEmptyString(input.errorMessage);
174
- if (errorMessage !== undefined) details.errorMessage = errorMessage;
175
- const api = nonEmptyString(input.api);
176
- if (api !== undefined) details.api = api;
177
- const rawStopReason = nonEmptyString(input.rawStopReason);
178
- if (rawStopReason !== undefined) details.rawStopReason = rawStopReason;
179
- const testimony = hasUpstreamErrorTestimony(input);
180
- if (testimony) {
181
- const provider = nonEmptyString(input.provider);
182
- if (provider !== undefined) details.provider = provider;
183
- const model = nonEmptyString(input.model);
184
- if (model !== undefined) details.model = model;
185
- }
186
- if (typeof input.httpStatus === "number") details.httpStatus = input.httpStatus;
187
- if (input.diagnostics !== undefined) details.diagnostics = input.diagnostics;
188
- // SDK structured payload fields: project only when held on a confirmed-remote node.
189
- if (testimony) Object.assign(details, projectConfirmedRemotePayload(input));
190
- return details;
191
- }
192
-
193
- /**
194
- * Project a native session assistant stop onto the existing knownFailure chain.
195
- * Classification follows two-way testimony: typed HTTP status or SDK structure
196
- * keeps provider; stopReason, configured provider/model, or errorMessage prose
197
- * alone is the existing unrecognized value. Present upstream payload is preserved
198
- * in details without rewriting; missing fields are omitted.
199
- */
200
- export function knownFailureFromProviderStop(input: {
201
- readonly stopReason?: string;
202
- readonly errorMessage?: string | null;
203
- readonly provider?: string;
204
- readonly model?: string;
205
- readonly api?: string;
206
- readonly rawStopReason?: string;
207
- readonly httpStatus?: number;
208
- readonly diagnostics?: unknown;
209
- readonly body?: unknown;
210
- readonly code?: unknown;
211
- readonly errno?: unknown;
212
- }): ExplicitInternalKnownFailure | undefined {
213
- if (input.stopReason !== "error" && input.stopReason !== "aborted") return undefined;
214
- const diagnostic = nonEmptyString(input.errorMessage);
215
- const details = sessionStopDetails(input);
216
- return {
217
- cause: hasUpstreamErrorTestimony(input) ? "provider" : "unrecognized",
218
- ...(diagnostic === undefined ? {} : { diagnostic }),
219
- ...(Object.keys(details).length === 0 ? {} : { details }),
220
- };
221
- }
222
-
223
- export type ExplicitInternalPiResult = {
224
- code: number | null;
225
- stderr: string;
226
- timedOut: boolean;
227
- /** Full argv passed to the Pi process (includes explicit -e load). */
228
- args: string[];
229
- /** Canonical identity of the executable selected and launched by this runner. */
230
- piIdentity?: { executable: string; version: string };
231
- /**
232
- * Production-owned typed failure channel. Set only when the runner already
233
- * knows the cause without stderr-prose inference. Settlement trusts this over
234
- * the nonzero→activation default.
235
- */
236
- knownFailure?: ExplicitInternalKnownFailure;
237
- };
238
-
239
- /**
240
- * Thrown activation failure with a production-owned typed cause.
241
- * Prefer this over ad-hoc Error property tags so settlement retains typed identity.
242
- */
243
- export class ExplicitInternalActivationError extends Error {
244
- readonly knownCause: ControlledFailureCause;
245
- readonly failureCode?: string | number;
246
-
247
- constructor(
248
- message: string,
249
- options: {
250
- knownCause: ControlledFailureCause;
251
- code?: string | number;
252
- name?: string;
253
- cause?: unknown;
254
- },
255
- ) {
256
- super(
257
- message,
258
- options.cause === undefined ? undefined : { cause: options.cause },
259
- );
260
- this.name = options.name ?? "ExplicitInternalActivationError";
261
- this.knownCause = options.knownCause;
262
- if (options.code !== undefined) {
263
- this.failureCode = options.code;
264
- }
265
- }
266
- }
267
-
268
- export type ExplicitInternalPiRunner = (
269
- args: readonly string[],
270
- options: {
271
- cwd: string;
272
- env: NodeJS.ProcessEnv;
273
- timeoutMs?: number;
274
- },
275
- ) => Promise<ExplicitInternalPiResult>;
276
-
277
- const execFileAsync = promisify(execFile);
278
-
279
- async function resolveSelectedPi(command: string, cwd: string, env: NodeJS.ProcessEnv): Promise<string> {
280
- // Match child_process.spawn lookup: path-like commands and every relative or
281
- // empty PATH entry are interpreted from the child's cwd. When PATH is absent,
282
- // Node uses the platform search default rather than an empty search list.
283
- const searchPath = env.PATH ?? (platform === "win32" ? (process.env.PATH ?? "") : "/usr/bin:/bin");
284
- const candidates = isAbsolute(command) || command.includes("/")
285
- ? [resolve(cwd, command)]
286
- : searchPath.split(delimiter).map((dir) => resolve(cwd, dir, command));
287
- for (const candidate of candidates) {
288
- try {
289
- await access(candidate, constants.X_OK);
290
- } catch (error) {
291
- const code = (error as NodeJS.ErrnoException).code;
292
- if (code === "ENOENT" || code === "ENOTDIR" || code === "EACCES") continue;
293
- throw error;
294
- }
295
- // Once a candidate qualifies, canonicalization failures are real filesystem
296
- // failures, not evidence that PATH contained no executable.
297
- return await realpath(candidate);
298
- }
299
- throw new Error(`Pi executable not found: ${command}`);
300
- }
301
-
302
- async function selectedPiIdentity(command: string, cwd: string, env: NodeJS.ProcessEnv): Promise<{ executable: string; version: string }> {
303
- const executable = await resolveSelectedPi(command, cwd, env);
304
- const { stdout } = await execFileAsync(executable, ["--version"], {
305
- cwd,
306
- env,
307
- encoding: "utf8",
308
- });
309
- const version = stdout.trim();
310
- if (version === "") throw new Error(`Pi executable returned an empty version: ${executable}`);
311
- return { executable, version };
312
- }
313
-
314
- /** Default runner: canonically select `pi` on PATH (or PI_BINARY) and launch that exact file. */
315
- export const defaultExplicitInternalPiRunner: ExplicitInternalPiRunner = async (
316
- args,
317
- options,
318
- ) => {
319
- const command = options.env.PI_BINARY ?? "pi";
320
- const piIdentity = await selectedPiIdentity(command, options.cwd, options.env);
321
- return await new Promise((resolveResult, reject) => {
322
- // Child stdout is discarded at the stdio seam (CLAUDE.md Role invocation
323
- // evidence). Do not pipe or accumulate it. stderr stays piped for diagnostics.
324
- const child = spawn(piIdentity.executable, [...args], {
325
- cwd: options.cwd,
326
- env: options.env,
327
- stdio: ["ignore", "ignore", "pipe"],
328
- });
329
- let stderr = "";
330
- let timedOut = false;
331
- // No default wall clock. Only an explicit caller budget arms a timer (ADR 0010).
332
- // SIGKILL is unconditionally forbidden (host constitution art. 9) — graceful SIGTERM only.
333
- let timer: ReturnType<typeof setTimeout> | undefined;
334
- const armTimeoutAfterChildReady = (): void => {
335
- if (options.timeoutMs === undefined) return;
336
- timer = setTimeout(() => {
337
- timedOut = true;
338
- child.kill("SIGTERM");
339
- }, options.timeoutMs);
340
- };
341
- // The spawn event is the child-process readiness seam. Start the caller's
342
- // budget only after the child is actually created, not while spawn is pending.
343
- let identityRecorded: Promise<void> = Promise.resolve();
344
- child.once("spawn", () => {
345
- armTimeoutAfterChildReady();
346
- const runDirectory = options.env.AK_ROLE_RUN_DIR;
347
- if (typeof runDirectory === "string" && runDirectory !== "") {
348
- identityRecorded = recordLaunchedPiIdentity(runDirectory, piIdentity);
349
- }
350
- });
351
- child.stderr.setEncoding("utf8").on("data", (chunk) => {
352
- stderr += chunk;
353
- });
354
- child.on("error", (error) => {
355
- if (timer !== undefined) clearTimeout(timer);
356
- reject(error);
357
- });
358
- child.on("close", (code) => {
359
- if (timer !== undefined) clearTimeout(timer);
360
- void identityRecorded.then(
361
- () => resolveResult({
362
- code,
363
- stderr,
364
- timedOut,
365
- args: [...args],
366
- piIdentity,
367
- }),
368
- reject,
369
- );
370
- });
371
- });
372
- };
373
-
374
- /**
375
- * Spawn Pi once with `--no-extensions -e <packageRoot>/extensions/role-runtime.ts`
376
- * plus caller args. Used by ak-role so the public CLI owns the load boundary.
377
- */
378
- export async function runExplicitInternalActivation(options: {
379
- packageRoot: string;
380
- extraArgs?: readonly string[];
381
- cwd: string;
382
- home: string;
383
- agentDir: string;
384
- env?: NodeJS.ProcessEnv;
385
- timeoutMs?: number | undefined;
386
- runner?: ExplicitInternalPiRunner;
387
- }): Promise<ExplicitInternalPiResult> {
388
- const roleEntry = await realpath(
389
- resolveInternalRoleEntrypoint(options.packageRoot),
390
- );
391
- const args = buildExplicitInternalActivationArgs(
392
- roleEntry,
393
- options.extraArgs ?? [],
394
- );
395
- const runner = options.runner ?? defaultExplicitInternalPiRunner;
396
- const env: NodeJS.ProcessEnv = {
397
- ...process.env,
398
- ...options.env,
399
- HOME: options.home,
400
- PI_CODING_AGENT_DIR: options.agentDir,
401
- };
402
- // Package provenance is known at the public CLI seam before Pi starts — write it
403
- // onto the existing invocation page so runs remain attributable even when the
404
- // child runner is injected or Pi identity recording never fires.
405
- const runDirectory = env.AK_ROLE_RUN_DIR;
406
- if (typeof runDirectory === "string" && runDirectory !== "") {
407
- await recordLaunchedRolePackageIdentity(
408
- runDirectory,
409
- await observeLaunchedRolePackageIdentity(options.packageRoot, roleEntry),
410
- );
411
- }
412
- return await runner(args, {
413
- cwd: options.cwd,
414
- ...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
415
- env,
416
- });
417
- }
418
-
419
- /** Non-dispatch args: load Internal once and exit via Pi help (no model turn). */
420
- export const EXPLICIT_INTERNAL_LOAD_PROBE_ARGS = [
421
- "--no-skills",
422
- "--no-prompt-templates",
423
- "--no-themes",
424
- "--no-context-files",
425
- "--no-session",
426
- "--help",
427
- ] as const;