@akagilnc/pi-workflow-roles 0.1.5593 → 0.1.5614
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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/acp-host/production-host.js +521 -707
- package/dist/compliance-transport.js +2 -5
- package/dist/doctor-auditor.js +1 -1
- package/dist/gatekeeper-role.js +1 -1
- package/dist/headless-host/production-host.js +505 -691
- package/dist/merger-contracts.js +6 -2
- package/dist/migrate-book-topology.js +5142 -10735
- package/dist/navigator-public-session.js +4 -4
- package/dist/navigator-work-base.js +5 -30
- package/dist/package-contracts/worker-output.js +1 -6
- package/dist/packaged-role-registry.js +9 -6
- package/dist/pi/role-turn-host.js +10 -1
- package/dist/public-cli/instruction-seat-run.js +133 -38
- package/dist/public-cli/invocation.js +38 -74
- package/dist/public-cli/main.js +18155 -18235
- package/dist/public-cli/option-definitions.js +21 -2
- package/dist/public-cli/post-admission.js +25 -24
- package/dist/public-cli/run-lifecycle.js +4 -43
- package/dist/public-cli/turn-request.js +4 -9
- package/dist/public-role-summons.js +5 -3
- package/dist/role-run-placement.js +7 -1
- package/dist/role-run-relocation.js +3 -4
- package/package.json +1 -1
- package/scripts/build-package.mjs +2 -4
- package/src/audited-run-identity.ts +30 -0
- package/src/compliance-transport.ts +1 -4
- package/src/doctor-auditor.ts +1 -1
- package/src/gatekeeper-role.ts +1 -1
- package/src/host-contracts.ts +6 -4
- package/src/merger-contracts.ts +6 -2
- package/src/merger-role.ts +11 -1
- package/src/navigator-attendance.ts +2 -2
- package/src/navigator-public-session.ts +9 -5
- package/src/navigator-work-base.ts +19 -34
- package/src/notary-role.ts +12 -21
- package/src/package-contracts/worker-output.ts +0 -8
- package/src/packaged-role-registry.ts +8 -7
- package/src/pi/role-turn-host.ts +11 -1
- package/src/public-cli/instruction-seat-run.ts +162 -42
- package/src/public-cli/invocation.ts +55 -93
- package/src/public-cli/option-definitions.ts +22 -2
- package/src/public-cli/post-admission.ts +30 -24
- package/src/public-cli/run-lifecycle.ts +4 -56
- package/src/public-cli/turn-request.ts +9 -8
- package/src/public-role-summons.ts +17 -6
- package/src/role-envelope.ts +4 -0
- package/src/role-run-placement.ts +10 -1
- package/src/role-run-relocation.ts +3 -4
- package/src/role-runtime-dependencies.ts +0 -2
- package/src/role-runtime.ts +54 -47
- package/src/worker-role.ts +11 -78
- package/dist/auditor-dossier-tool.js +0 -47
- package/dist/package-contracts/fixer-packet.js +0 -77
- package/packets/fixer-prerequisites.json +0 -6
- package/src/auditor-dossier-tool.ts +0 -63
- package/src/package-contracts/fixer-packet.ts +0 -91
|
@@ -121,6 +121,11 @@ export type PublicSummonRequest = {
|
|
|
121
121
|
* (#946 / ADR 0082).
|
|
122
122
|
*/
|
|
123
123
|
readonly stationChild?: boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Navigator nest work-context locator (#1166). Request-scoped internal path —
|
|
126
|
+
* never dialogue content; never shared parent process.env across await.
|
|
127
|
+
*/
|
|
128
|
+
readonly navigatorWorkContextPath?: string;
|
|
124
129
|
};
|
|
125
130
|
|
|
126
131
|
const execFileAsync = promisify(execFile);
|
|
@@ -421,6 +426,10 @@ export async function summonPublicRole(
|
|
|
421
426
|
? {}
|
|
422
427
|
: { correlationId: options.correlationId }),
|
|
423
428
|
...(options.createRunId === undefined ? {} : { createRunId: options.createRunId }),
|
|
429
|
+
...(options.navigatorWorkContextPath === undefined
|
|
430
|
+
|| options.navigatorWorkContextPath.trim() === ""
|
|
431
|
+
? {}
|
|
432
|
+
: { navigatorWorkContextPath: options.navigatorWorkContextPath }),
|
|
424
433
|
},
|
|
425
434
|
};
|
|
426
435
|
} catch (error) {
|
|
@@ -746,13 +755,13 @@ export async function summonGateOfficer(options: {
|
|
|
746
755
|
/**
|
|
747
756
|
* Plain-language re-ask when the prior officer reply was not three-state (#753 / #756).
|
|
748
757
|
* Officers: reviewReask → same-ticket resume summons.instruction.
|
|
749
|
-
* Never concatenated into argv (
|
|
758
|
+
* Never concatenated into argv (binding stays on --source-run / parentRunPath).
|
|
750
759
|
*/
|
|
751
760
|
readonly reask?: string;
|
|
752
761
|
/**
|
|
753
762
|
* In-flight parent 交卷 body (tool-call arguments). Relayed verbatim as officer
|
|
754
763
|
* dialogue content when reask is absent (#879). Binding pointer stays on
|
|
755
|
-
* --source-run /
|
|
764
|
+
* --source-run / parentRunPath — never a content substitute.
|
|
756
765
|
*/
|
|
757
766
|
readonly submission?: unknown;
|
|
758
767
|
/** Pi-adapter inject — forwarded to summonPublicRole (not a parent-host override). */
|
|
@@ -808,6 +817,7 @@ export async function summonGateOfficer(options: {
|
|
|
808
817
|
if (gateSummon === "subject-source") {
|
|
809
818
|
// #756: judge compliance path — same queue law as notary/inspector.
|
|
810
819
|
// Binding pointer on argv; dialogue content rides gateReviewInstruction.
|
|
820
|
+
// #1166: no code-authored 卷宗指针 instruction — identity is startup material.
|
|
811
821
|
return summonPublicRole({
|
|
812
822
|
role: options.officer,
|
|
813
823
|
argv: [
|
|
@@ -815,7 +825,8 @@ export async function summonGateOfficer(options: {
|
|
|
815
825
|
"judge",
|
|
816
826
|
"--source-run",
|
|
817
827
|
options.sourceRunDirectory,
|
|
818
|
-
|
|
828
|
+
"--project",
|
|
829
|
+
options.cwd,
|
|
819
830
|
],
|
|
820
831
|
...common,
|
|
821
832
|
});
|
|
@@ -850,11 +861,11 @@ export async function summonGateOfficer(options: {
|
|
|
850
861
|
...(courtTicket === undefined ? {} : { boundTicketNumber: courtTicket }),
|
|
851
862
|
});
|
|
852
863
|
}
|
|
853
|
-
// Inspector:
|
|
854
|
-
//
|
|
864
|
+
// Inspector: bind via --source-run (same face as notary); dialogue rides env.
|
|
865
|
+
// #1166: no code-authored 卷宗指针 instruction — identity is startup material.
|
|
855
866
|
return summonPublicRole({
|
|
856
867
|
role: options.officer,
|
|
857
|
-
argv: [
|
|
868
|
+
argv: ["--source-run", options.sourceRunDirectory, "--project", options.cwd],
|
|
858
869
|
...common,
|
|
859
870
|
});
|
|
860
871
|
}
|
package/src/role-envelope.ts
CHANGED
|
@@ -178,6 +178,10 @@ export async function prepareRoleEnvelope(options: {
|
|
|
178
178
|
...(request.courtAttemptId === undefined ? {} : { courtAttemptId: request.courtAttemptId }),
|
|
179
179
|
...(request.invocationScopeId === undefined ? {} : { invocationScopeId: request.invocationScopeId }),
|
|
180
180
|
...(request.host === undefined || request.host.trim() === "" ? {} : { host: request.host.trim() }),
|
|
181
|
+
...(request.navigatorWorkContextPath === undefined
|
|
182
|
+
|| request.navigatorWorkContextPath.trim() === ""
|
|
183
|
+
? {}
|
|
184
|
+
: { navigatorWorkContextPath: request.navigatorWorkContextPath }),
|
|
181
185
|
sessionManager: {
|
|
182
186
|
getLeafEntry: () => sessionEntries.at(-1) as ReturnType<HostContext["sessionManager"]["getLeafEntry"]>,
|
|
183
187
|
getLeafId: () => runId,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readdir } from "node:fs/promises";
|
|
2
|
-
import { basename, dirname, join } from "node:path";
|
|
2
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
activationBookDirectory,
|
|
@@ -54,6 +54,15 @@ export function runDirectoryOfSessionFile(sessionFile: string): string {
|
|
|
54
54
|
return dirname(dirname(sessionFile));
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
/** Climb session/session.jsonl → run directory when the host exposes a session file. */
|
|
58
|
+
export function auditorRunDirectory(context: {
|
|
59
|
+
readonly sessionManager?: { getSessionFile?: () => string | undefined };
|
|
60
|
+
}): string | undefined {
|
|
61
|
+
const sessionFile = context.sessionManager?.getSessionFile?.();
|
|
62
|
+
if (sessionFile === undefined) return undefined;
|
|
63
|
+
return resolve(runDirectoryOfSessionFile(sessionFile));
|
|
64
|
+
}
|
|
65
|
+
|
|
57
66
|
/** `<run>/session` → run directory. */
|
|
58
67
|
export function runDirectoryFromSessionDirectory(sessionDirectory: string): string {
|
|
59
68
|
return dirname(sessionDirectory);
|
|
@@ -23,10 +23,9 @@ const ADMITTED_PAGE_FIELDS = [
|
|
|
23
23
|
"admittedRequestPath", // pre-#1161 pages only
|
|
24
24
|
"sessionDirectory",
|
|
25
25
|
"sessionFile",
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
// #1165: requestManifestPath is a caller path — never rewrite.
|
|
26
|
+
// #1165/#1168: caller file-flag paths (requestManifestPath, prerequisitesPath)
|
|
27
|
+
// stay as given. Obsolete copy fields (taskPath/packetPath) are not rewritten —
|
|
28
|
+
// stock volumes keep their bytes; live relocate no longer maintains them.
|
|
30
29
|
"mergerInputPath",
|
|
31
30
|
"sourceRunPath",
|
|
32
31
|
] as const;
|
|
@@ -45,8 +45,6 @@ export function createRoleRuntimeDependencies(packageRoot: string): RoleRuntimeD
|
|
|
45
45
|
packageRoot,
|
|
46
46
|
loadRoleReferenceMaterials: loadPackagedRoleReferenceMaterials,
|
|
47
47
|
loadRoleSoul: loadRegisteredRoleSoul,
|
|
48
|
-
loadFixPacket: (path) => readFile(path, "utf8"),
|
|
49
|
-
loadCoderTask: (path) => readFile(path, "utf8"),
|
|
50
48
|
loadDoctorCase,
|
|
51
49
|
loadNotarySourceRun: loadNotarySourceRunLocator,
|
|
52
50
|
loadMergerInput: async (path) => JSON.parse(await readFile(path, "utf8")),
|
package/src/role-runtime.ts
CHANGED
|
@@ -106,8 +106,13 @@ import {
|
|
|
106
106
|
type AuditorRuntimeDependencies,
|
|
107
107
|
} from "./auditor-role.ts";
|
|
108
108
|
|
|
109
|
+
import {
|
|
110
|
+
auditedRunIdentityFromDirectory,
|
|
111
|
+
auditedRunIdentityMaterial,
|
|
112
|
+
} from "./audited-run-identity.ts";
|
|
109
113
|
import { formatNavigatorReport, NAVIGATOR_EVENT_TYPE, NAVIGATOR_ROUTE_PLAYBOOK_FAILURE_ENTRY, navigatorSubjectKey, navigatorUnavailableError, subjectPath, type NavigatorAttendance, type NavigatorAttendanceOptions, type NavigatorEvent, type NavigatorPhase, type NavigatorReport, type NavigatorSettlement, type NavigatorSubjectProvenance, type NavigatorWorkContext } from "./navigator-attendance.ts";
|
|
110
114
|
import { loadNavigatorWorkBaseSuffix } from "./navigator-work-base.ts";
|
|
115
|
+
import { AK_ROLE_AUDITOR_SOURCE_RUN_ENV } from "./auditor-soul.ts";
|
|
111
116
|
import {
|
|
112
117
|
buildNavigatorInfrastructureFailureFact,
|
|
113
118
|
classifyPackagedRoleTerminalResult,
|
|
@@ -346,8 +351,6 @@ export {
|
|
|
346
351
|
} from "./worker-role.ts";
|
|
347
352
|
export { fixerOutputSchema, validateFixerOutput } from "./package-contracts/fixer-output.ts";
|
|
348
353
|
export type { FixerBlocker, FixerClassResult, FixerPhase, FixerTestEvidence } from "./package-contracts/fixer-output.ts";
|
|
349
|
-
export { fixerPrerequisiteSchema, fixerPrerequisitesSchema, parseFixerPrerequisites, validateFixerPrerequisites } from "./package-contracts/fixer-packet.ts";
|
|
350
|
-
export type { FixerInvocationInput, FixerPrerequisite } from "./package-contracts/fixer-packet.ts";
|
|
351
354
|
export {
|
|
352
355
|
AUDITOR_SOUL_ROLES,
|
|
353
356
|
AK_ROLE_AUDITOR_SUBJECT_ENV,
|
|
@@ -460,8 +463,6 @@ export type RoleRuntimeDependencies = {
|
|
|
460
463
|
loadRoleReferenceMaterials?(role: PackagedRole): Promise<string>;
|
|
461
464
|
/** One soul loader. The role argument selects the registry record. */
|
|
462
465
|
loadRoleSoul(role: PackagedRole): Promise<string>;
|
|
463
|
-
loadFixPacket?(path: string): Promise<string>;
|
|
464
|
-
loadCoderTask?(path: string): Promise<string>;
|
|
465
466
|
loadNotarySourceRun?(path: string): Promise<import("./notary-contracts.ts").NotarySourceRunLocator>;
|
|
466
467
|
loadDoctorCase?(path: string): Promise<import("./doctor-contracts.ts").DoctorCase>;
|
|
467
468
|
loadMergerInput?(path: string): Promise<unknown>;
|
|
@@ -694,7 +695,7 @@ export function createNavigatorRoleRuntime(
|
|
|
694
695
|
const loadRoutePlaybook = dependencies.loadRoutePlaybook
|
|
695
696
|
?? (() => readPackageMaterial("resources/navigator-route-playbook.md"));
|
|
696
697
|
let playbookRead: Promise<string> | undefined;
|
|
697
|
-
roleHost.on("before_agent_start", async (event) => {
|
|
698
|
+
roleHost.on("before_agent_start", async (event, ctx) => {
|
|
698
699
|
const basePrompt = typeof event.systemPrompt === "string" ? event.systemPrompt : "";
|
|
699
700
|
const parts: string[] = [];
|
|
700
701
|
try {
|
|
@@ -709,8 +710,10 @@ export function createNavigatorRoleRuntime(
|
|
|
709
710
|
parts.push(message);
|
|
710
711
|
}
|
|
711
712
|
}
|
|
712
|
-
const
|
|
713
|
-
|
|
713
|
+
const work = await loadNavigatorWorkBaseSuffix(
|
|
714
|
+
ctx.sessionManager?.getSessionDir?.(),
|
|
715
|
+
ctx.navigatorWorkContextPath,
|
|
716
|
+
);
|
|
714
717
|
if (work !== undefined && work.trim() !== "") parts.push(work);
|
|
715
718
|
if (parts.length === 0) return;
|
|
716
719
|
const text = parts.join("\n\n");
|
|
@@ -727,7 +730,7 @@ export function createAuditorRoleRuntime(
|
|
|
727
730
|
roleHost: RoleHost,
|
|
728
731
|
dependencies: AuditorRuntimeDependencies,
|
|
729
732
|
) {
|
|
730
|
-
|
|
733
|
+
return createFiledOfficerRuntime(
|
|
731
734
|
roleHost,
|
|
732
735
|
{
|
|
733
736
|
role: "auditor",
|
|
@@ -736,24 +739,39 @@ export function createAuditorRoleRuntime(
|
|
|
736
739
|
},
|
|
737
740
|
dependencies,
|
|
738
741
|
);
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
function isAuditedIdentitySeat(role: string): boolean {
|
|
745
|
+
return role === "notary" || role === "inspector" || role === "auditor" || role === "countersign";
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/** Resolve audited-run directory for identity material — this-leg flags / admitted page first. */
|
|
749
|
+
function resolveAuditedSourceRunDirectory(
|
|
750
|
+
roleHost: RoleHost,
|
|
751
|
+
ctx: HostContext,
|
|
752
|
+
role: string,
|
|
753
|
+
): string | undefined {
|
|
754
|
+
const notary = roleHost.getFlag(NOTARY_SOURCE_RUN_FLAG.name);
|
|
755
|
+
if (typeof notary === "string" && notary.trim() !== "") return notary.trim();
|
|
756
|
+
const inspector = roleHost.getFlag(INSPECTOR_SOURCE_RUN_FLAG.name);
|
|
757
|
+
if (typeof inspector === "string" && inspector.trim() !== "") return inspector.trim();
|
|
758
|
+
// This-leg admitted binding wins over shared auditor env (#1166 J3).
|
|
759
|
+
const runDirectory = runDirectoryFromHostContext(ctx);
|
|
760
|
+
if (runDirectory !== undefined) {
|
|
761
|
+
const admitted = readPageSync(runDirectory, "admitted");
|
|
762
|
+
if (typeof admitted?.sourceRunPath === "string" && admitted.sourceRunPath.trim() !== "") {
|
|
763
|
+
return admitted.sourceRunPath.trim();
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
// Auditor env is request-scoped soul binding for the auditor seat only.
|
|
767
|
+
if (role === "auditor") {
|
|
768
|
+
const auditor =
|
|
769
|
+
typeof process.env[AK_ROLE_AUDITOR_SOURCE_RUN_ENV] === "string"
|
|
770
|
+
? process.env[AK_ROLE_AUDITOR_SOURCE_RUN_ENV].trim()
|
|
771
|
+
: "";
|
|
772
|
+
if (auditor !== "") return auditor;
|
|
773
|
+
}
|
|
774
|
+
return undefined;
|
|
757
775
|
}
|
|
758
776
|
|
|
759
777
|
/**
|
|
@@ -1224,15 +1242,16 @@ export function createRoleRuntimeExtension(
|
|
|
1224
1242
|
if (reading === undefined) return;
|
|
1225
1243
|
return { readingMaterial: reading };
|
|
1226
1244
|
});
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1245
|
+
// #1166 / ADR 0087: four audit seats share one audited-run identity material.
|
|
1246
|
+
// Notary also emits identity from its own before_agent_start; skip double fold.
|
|
1247
|
+
roleHost.on("before_agent_start", (_event, ctx) => {
|
|
1248
|
+
const role = selectedRole ?? roleHost.getFlag(ROLE_FLAG.name);
|
|
1249
|
+
if (typeof role !== "string" || !isAuditedIdentitySeat(role) || role === "notary") return;
|
|
1250
|
+
const sourceDirectory = resolveAuditedSourceRunDirectory(roleHost, ctx, role);
|
|
1251
|
+
if (sourceDirectory === undefined) return;
|
|
1252
|
+
const identity = auditedRunIdentityFromDirectory(sourceDirectory);
|
|
1253
|
+
if (identity === undefined) return;
|
|
1254
|
+
return { readingMaterial: auditedRunIdentityMaterial(identity) };
|
|
1236
1255
|
});
|
|
1237
1256
|
roleHost.on("tool_result", async (event, ctx) => {
|
|
1238
1257
|
const role = selectedRole;
|
|
@@ -1459,12 +1478,6 @@ export function createRoleRuntimeExtension(
|
|
|
1459
1478
|
roleHost,
|
|
1460
1479
|
{
|
|
1461
1480
|
loadSoul: () => requireRoleSoul("fixer"),
|
|
1462
|
-
async loadPacket(path) {
|
|
1463
|
-
if (dependencies.loadFixPacket === undefined) {
|
|
1464
|
-
throw new Error("Fixer packet loader is not configured");
|
|
1465
|
-
}
|
|
1466
|
-
return dependencies.loadFixPacket(path);
|
|
1467
|
-
},
|
|
1468
1481
|
},
|
|
1469
1482
|
hostActions,
|
|
1470
1483
|
{ unfinishedReasonBounceLimit: deliveryLimit },
|
|
@@ -1473,12 +1486,6 @@ export function createRoleRuntimeExtension(
|
|
|
1473
1486
|
roleHost,
|
|
1474
1487
|
{
|
|
1475
1488
|
loadSoul: () => requireRoleSoul("coder"),
|
|
1476
|
-
async loadTask(path) {
|
|
1477
|
-
if (dependencies.loadCoderTask === undefined) {
|
|
1478
|
-
throw new Error("Coder task loader is not configured");
|
|
1479
|
-
}
|
|
1480
|
-
return dependencies.loadCoderTask(path);
|
|
1481
|
-
},
|
|
1482
1489
|
},
|
|
1483
1490
|
hostActions,
|
|
1484
1491
|
{ unfinishedReasonBounceLimit: deliveryLimit },
|
package/src/worker-role.ts
CHANGED
|
@@ -10,11 +10,6 @@ import {
|
|
|
10
10
|
import { validateFixerOutput, type FixerPhase } from "./package-contracts/fixer-output.ts";
|
|
11
11
|
import { registerFiledSubmissionTool } from "./filed-submission.ts";
|
|
12
12
|
import { roleSubmissionDeclaration } from "./role-submission-declarations.ts";
|
|
13
|
-
import {
|
|
14
|
-
FixerPacketValidationError,
|
|
15
|
-
parseFixerPrerequisites,
|
|
16
|
-
type FixerInvocationInput,
|
|
17
|
-
} from "./package-contracts/fixer-packet.ts";
|
|
18
13
|
import {
|
|
19
14
|
createWorkerSubmissionGate,
|
|
20
15
|
WorkerCommitReminderError,
|
|
@@ -37,21 +32,8 @@ export {
|
|
|
37
32
|
validateAcceptedWorkerDetails,
|
|
38
33
|
} from "./package-contracts/worker-output.ts";
|
|
39
34
|
export type { WorkerOutput, FixerOutput, CoderOutput };
|
|
35
|
+
/** #1168: phase only — dispatch text is the first message, not a packet flag. */
|
|
40
36
|
export const FIXER_FLAG_DEFINITIONS = {
|
|
41
|
-
packet: {
|
|
42
|
-
name: "ak-fix-packet",
|
|
43
|
-
definition: {
|
|
44
|
-
description: "Path to opaque prose instructions for the Fixer",
|
|
45
|
-
type: "string" as const,
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
prerequisites: {
|
|
49
|
-
name: "ak-fixer-prerequisites",
|
|
50
|
-
definition: {
|
|
51
|
-
description: "Optional path to a JSON array of typed Fixer prerequisites",
|
|
52
|
-
type: "string" as const,
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
37
|
phase: {
|
|
56
38
|
name: "ak-fixer-phase",
|
|
57
39
|
definition: {
|
|
@@ -73,12 +55,10 @@ export type WorkerRoleHostActions = HostGatekeeperActions;
|
|
|
73
55
|
|
|
74
56
|
export type FixerRoleDependencies = {
|
|
75
57
|
loadSoul(): Promise<string>;
|
|
76
|
-
loadPacket(path: string): Promise<string>;
|
|
77
58
|
};
|
|
78
59
|
|
|
79
60
|
export type CoderRoleDependencies = {
|
|
80
61
|
loadSoul(): Promise<string>;
|
|
81
|
-
loadTask(path: string): Promise<string>;
|
|
82
62
|
};
|
|
83
63
|
|
|
84
64
|
export type WorkerRoleRuntime = {
|
|
@@ -178,9 +158,6 @@ export function createFixerRoleRuntime(
|
|
|
178
158
|
options?: { readonly unfinishedReasonBounceLimit?: number },
|
|
179
159
|
): WorkerRoleRuntime {
|
|
180
160
|
let soul: string | undefined;
|
|
181
|
-
let packet: FixerInvocationInput | undefined;
|
|
182
|
-
let packetPath: string | undefined;
|
|
183
|
-
let prerequisitesPath: string | undefined;
|
|
184
161
|
let phase: WorkerPhase | undefined;
|
|
185
162
|
let lifecycleRegistered = false;
|
|
186
163
|
// #1132: ADR 0050 缺理由催全次数. The in-process seam passes the value it
|
|
@@ -190,14 +167,6 @@ export function createFixerRoleRuntime(
|
|
|
190
167
|
?? deliveryLimitFromEnv(process.env),
|
|
191
168
|
});
|
|
192
169
|
|
|
193
|
-
pi.registerFlag(
|
|
194
|
-
FIXER_FLAG_DEFINITIONS.packet.name,
|
|
195
|
-
FIXER_FLAG_DEFINITIONS.packet.definition,
|
|
196
|
-
);
|
|
197
|
-
pi.registerFlag(
|
|
198
|
-
FIXER_FLAG_DEFINITIONS.prerequisites.name,
|
|
199
|
-
FIXER_FLAG_DEFINITIONS.prerequisites.definition,
|
|
200
|
-
);
|
|
201
170
|
pi.registerFlag(
|
|
202
171
|
FIXER_FLAG_DEFINITIONS.phase.name,
|
|
203
172
|
FIXER_FLAG_DEFINITIONS.phase.definition,
|
|
@@ -214,33 +183,12 @@ export function createFixerRoleRuntime(
|
|
|
214
183
|
);
|
|
215
184
|
}
|
|
216
185
|
phase = selectedPhase;
|
|
217
|
-
const resolvedPacketPath = pi.getFlag(FIXER_FLAG_DEFINITIONS.packet.name);
|
|
218
|
-
if (typeof resolvedPacketPath !== "string" || resolvedPacketPath.trim().length === 0) {
|
|
219
|
-
throw new Error("Fixer role requires --ak-fix-packet");
|
|
220
|
-
}
|
|
221
|
-
packetPath = resolvedPacketPath;
|
|
222
|
-
const instructions = await dependencies.loadPacket(packetPath);
|
|
223
|
-
if (instructions.trim().length === 0) {
|
|
224
|
-
throw new FixerPacketValidationError(
|
|
225
|
-
new Error("Fixer instructions must be nonblank"),
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
const resolvedPrerequisitesPath = pi.getFlag(FIXER_FLAG_DEFINITIONS.prerequisites.name);
|
|
229
|
-
if (resolvedPrerequisitesPath !== undefined && (typeof resolvedPrerequisitesPath !== "string" || resolvedPrerequisitesPath.trim().length === 0)) {
|
|
230
|
-
throw new Error("Fixer --ak-fixer-prerequisites path must be nonblank when supplied");
|
|
231
|
-
}
|
|
232
|
-
prerequisitesPath =
|
|
233
|
-
typeof resolvedPrerequisitesPath === "string" ? resolvedPrerequisitesPath : undefined;
|
|
234
|
-
const prerequisites = prerequisitesPath !== undefined
|
|
235
|
-
? parseFixerPrerequisites(await dependencies.loadPacket(prerequisitesPath))
|
|
236
|
-
: Object.freeze([]);
|
|
237
|
-
packet = Object.freeze({ instructions, prerequisites });
|
|
238
186
|
|
|
239
187
|
if (!lifecycleRegistered) {
|
|
240
188
|
lifecycleRegistered = true;
|
|
241
189
|
registerWorkerSubmission(pi, "fixer", {
|
|
242
|
-
notReady: "
|
|
243
|
-
ready: () =>
|
|
190
|
+
notReady: "修内司阶段未装载",
|
|
191
|
+
ready: () => phase !== undefined,
|
|
244
192
|
phase: () => phase,
|
|
245
193
|
project: (parameters, current) => deepFreeze(validateFixerOutput(parameters, current)),
|
|
246
194
|
submissionGate,
|
|
@@ -257,17 +205,12 @@ export function createFixerRoleRuntime(
|
|
|
257
205
|
reason: fixerBashSeatbeltDenyReason(matched),
|
|
258
206
|
};
|
|
259
207
|
});
|
|
208
|
+
// #1168: soul + phase only; dispatch text is the first message.
|
|
260
209
|
pi.on("before_agent_start", (event) => {
|
|
261
210
|
if (soul === undefined) throw new Error("修内司职分未装载");
|
|
262
|
-
if (packetPath === undefined) throw new Error("修内司修理包路径未装载");
|
|
263
|
-
// Path delivery only — body is self-fetched; no inline duplicate of flag bytes (#632).
|
|
264
|
-
const prerequisitesBlock =
|
|
265
|
-
prerequisitesPath === undefined
|
|
266
|
-
? ""
|
|
267
|
-
: `\n\n<fixer_prerequisites_path>\n${prerequisitesPath}\n</fixer_prerequisites_path>`;
|
|
268
211
|
return {
|
|
269
212
|
systemPrompt:
|
|
270
|
-
`${event.systemPrompt}\n\n<fixer_soul>\n${soul}\n</fixer_soul>\n\n<fixer_phase>\n${phase ?? ""}\n</fixer_phase
|
|
213
|
+
`${event.systemPrompt}\n\n<fixer_soul>\n${soul}\n</fixer_soul>\n\n<fixer_phase>\n${phase ?? ""}\n</fixer_phase>`,
|
|
271
214
|
};
|
|
272
215
|
});
|
|
273
216
|
}
|
|
@@ -285,7 +228,6 @@ export function createCoderRoleRuntime(
|
|
|
285
228
|
options?: { readonly unfinishedReasonBounceLimit?: number },
|
|
286
229
|
): WorkerRoleRuntime {
|
|
287
230
|
let soul: string | undefined;
|
|
288
|
-
let task: string | undefined;
|
|
289
231
|
let phase: WorkerPhase | undefined;
|
|
290
232
|
let lifecycleRegistered = false;
|
|
291
233
|
// #1132: same resolved ceiling as the fixer gate. Absent = Pi child env.
|
|
@@ -294,10 +236,6 @@ export function createCoderRoleRuntime(
|
|
|
294
236
|
?? deliveryLimitFromEnv(process.env),
|
|
295
237
|
});
|
|
296
238
|
|
|
297
|
-
pi.registerFlag("ak-coder-task", {
|
|
298
|
-
description: "Markdown task assigned to the coder role",
|
|
299
|
-
type: "string",
|
|
300
|
-
});
|
|
301
239
|
pi.registerFlag("ak-coder-phase", {
|
|
302
240
|
description:
|
|
303
241
|
"Coder phase: plan (inspect and propose an implementation plan; no edits or commits) or apply (execute the approved plan and verify the first implementation)",
|
|
@@ -305,7 +243,7 @@ export function createCoderRoleRuntime(
|
|
|
305
243
|
});
|
|
306
244
|
|
|
307
245
|
return {
|
|
308
|
-
async activate(
|
|
246
|
+
async activate() {
|
|
309
247
|
soul = (await dependencies.loadSoul()).trim();
|
|
310
248
|
if (soul.length === 0) throw new Error("Coder soul is empty");
|
|
311
249
|
const selectedPhase = pi.getFlag("ak-coder-phase");
|
|
@@ -315,28 +253,23 @@ export function createCoderRoleRuntime(
|
|
|
315
253
|
);
|
|
316
254
|
}
|
|
317
255
|
phase = selectedPhase;
|
|
318
|
-
const taskPath = pi.getFlag("ak-coder-task");
|
|
319
|
-
if (typeof taskPath !== "string" || taskPath.trim().length === 0) {
|
|
320
|
-
throw new Error("Coder role requires --ak-coder-task");
|
|
321
|
-
}
|
|
322
|
-
task = (await dependencies.loadTask(taskPath)).trim();
|
|
323
|
-
if (task.length === 0) throw new Error("Coder task is empty");
|
|
324
256
|
|
|
325
257
|
if (!lifecycleRegistered) {
|
|
326
258
|
lifecycleRegistered = true;
|
|
327
259
|
registerWorkerSubmission(pi, "coder", {
|
|
328
|
-
notReady: "
|
|
329
|
-
ready: () =>
|
|
260
|
+
notReady: "将作监阶段未装载",
|
|
261
|
+
ready: () => phase !== undefined,
|
|
330
262
|
phase: () => phase,
|
|
331
263
|
project: (parameters, current) => validateWorkerOutput(parameters, current, "Coder"),
|
|
332
264
|
submissionGate,
|
|
333
265
|
hostActions,
|
|
334
266
|
});
|
|
335
|
-
|
|
267
|
+
// #1168: soul + phase only; dispatch text is the first message.
|
|
268
|
+
pi.on("before_agent_start", (event) => {
|
|
336
269
|
if (soul === undefined) throw new Error("将作监职分未装载");
|
|
337
270
|
return {
|
|
338
271
|
systemPrompt:
|
|
339
|
-
`${event.systemPrompt}\n\n<coder_soul>\n${soul}\n</coder_soul>\n\n<coder_phase>\n${phase ?? ""}\n</coder_phase
|
|
272
|
+
`${event.systemPrompt}\n\n<coder_soul>\n${soul}\n</coder_soul>\n\n<coder_phase>\n${phase ?? ""}\n</coder_phase>`,
|
|
340
273
|
};
|
|
341
274
|
});
|
|
342
275
|
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { join, resolve } from "node:path";
|
|
2
|
-
import { RUN_HISTORY_FILE, RUN_LOG_FILE, runCurrentPath } from "./run-dossier.js";
|
|
3
|
-
import {
|
|
4
|
-
runDirectoryOfSessionFile,
|
|
5
|
-
sessionFileOf
|
|
6
|
-
} from "./role-run-placement.js";
|
|
7
|
-
import { Type } from "typebox";
|
|
8
|
-
const AUDITOR_DOSSIER_TOOL_NAME = "ak_get_run_dossier";
|
|
9
|
-
function auditorRunDirectory(context) {
|
|
10
|
-
const sessionFile = context.sessionManager?.getSessionFile?.();
|
|
11
|
-
if (sessionFile === void 0) return void 0;
|
|
12
|
-
return resolve(runDirectoryOfSessionFile(sessionFile));
|
|
13
|
-
}
|
|
14
|
-
function createAuditorDossierTool(runDirectory) {
|
|
15
|
-
return {
|
|
16
|
-
name: AUDITOR_DOSSIER_TOOL_NAME,
|
|
17
|
-
description: "\u5B9A\u4F4D\u672C\u5BA1\u8BA1\u5E2D\u7ED1\u5B9A\u7684 run \u5377\u5B97\u53CA\u5176\u8BC1\u636E\u5165\u53E3\u3002",
|
|
18
|
-
// #836 r16 class 3: execute() ignores `_params` entirely — a closed root
|
|
19
|
-
// only rejects the role for saying more.
|
|
20
|
-
parameters: Type.Object({}, { additionalProperties: true }),
|
|
21
|
-
async execute(_id, _params) {
|
|
22
|
-
if (runDirectory === void 0) {
|
|
23
|
-
return {
|
|
24
|
-
content: [{ type: "text", text: "\u672C\u5BA1\u8BA1\u5E2D\u65E0\u7ED1\u5B9A run \u5377\u5B97\u8BB0\u5F55\u3002" }],
|
|
25
|
-
details: void 0
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
const details = {
|
|
29
|
-
runDirectory,
|
|
30
|
-
current: runCurrentPath(runDirectory),
|
|
31
|
-
parentSessionCandidate: sessionFileOf(runDirectory),
|
|
32
|
-
attachments: join(runDirectory, "attachments"),
|
|
33
|
-
log: join(runDirectory, RUN_LOG_FILE),
|
|
34
|
-
history: join(runDirectory, RUN_HISTORY_FILE)
|
|
35
|
-
};
|
|
36
|
-
return {
|
|
37
|
-
content: [{ type: "text", text: JSON.stringify(details) }],
|
|
38
|
-
details
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
export {
|
|
44
|
-
AUDITOR_DOSSIER_TOOL_NAME,
|
|
45
|
-
auditorRunDirectory,
|
|
46
|
-
createAuditorDossierTool
|
|
47
|
-
};
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { Type } from "typebox";
|
|
2
|
-
import { Value } from "typebox/value";
|
|
3
|
-
import { isRecord } from "../unknown-value.js";
|
|
4
|
-
const FIXER_PREREQUISITE_ID_PATTERN = "^[A-Za-z0-9][A-Za-z0-9._-]*$";
|
|
5
|
-
const fixerPrerequisiteSchema = Type.Object({
|
|
6
|
-
id: Type.String({ pattern: FIXER_PREREQUISITE_ID_PATTERN }),
|
|
7
|
-
requirement: Type.String({ pattern: "\\S" })
|
|
8
|
-
});
|
|
9
|
-
const fixerPrerequisitesSchema = Type.Array(fixerPrerequisiteSchema);
|
|
10
|
-
function causeMessage(cause) {
|
|
11
|
-
if (cause instanceof Error) return cause.message;
|
|
12
|
-
if (typeof cause === "string") return cause;
|
|
13
|
-
try {
|
|
14
|
-
return JSON.stringify(cause) ?? String(cause);
|
|
15
|
-
} catch {
|
|
16
|
-
return String(cause);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
class FixerPacketValidationError extends Error {
|
|
20
|
-
code = "AK_INVALID_FIX_PACKET";
|
|
21
|
-
constructor(cause) {
|
|
22
|
-
const prefix = "Fixer prerequisites or instructions violate the invocation contract";
|
|
23
|
-
super(
|
|
24
|
-
cause === void 0 ? prefix : `${prefix}: ${causeMessage(cause)}`,
|
|
25
|
-
cause === void 0 ? void 0 : { cause }
|
|
26
|
-
);
|
|
27
|
-
this.name = "FixerPacketValidationError";
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
function fail(cause) {
|
|
31
|
-
throw new FixerPacketValidationError(cause);
|
|
32
|
-
}
|
|
33
|
-
function parseFailure(value) {
|
|
34
|
-
if (!Array.isArray(value)) fail(new Error("Fixer prerequisites must be a JSON array"));
|
|
35
|
-
for (const entry of value) {
|
|
36
|
-
if (!isRecord(entry)) {
|
|
37
|
-
fail(new Error("Fixer prerequisite entry must be an object with id and requirement fields"));
|
|
38
|
-
}
|
|
39
|
-
if (typeof entry.id !== "string" || !new RegExp(FIXER_PREREQUISITE_ID_PATTERN).test(entry.id)) {
|
|
40
|
-
fail(new Error(`Fixer prerequisite id violates pattern ${FIXER_PREREQUISITE_ID_PATTERN}`));
|
|
41
|
-
}
|
|
42
|
-
if (typeof entry.requirement !== "string" || !/\S/.test(entry.requirement)) {
|
|
43
|
-
fail(new Error("Fixer prerequisite requirement must be nonblank"));
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
fail(new Error("Fixer prerequisites violate the attachment schema"));
|
|
47
|
-
}
|
|
48
|
-
function validateFixerPrerequisites(value) {
|
|
49
|
-
if (!Value.Check(fixerPrerequisitesSchema, value)) parseFailure(value);
|
|
50
|
-
const entries = value;
|
|
51
|
-
const ids = /* @__PURE__ */ new Set();
|
|
52
|
-
const prerequisites = entries.map((entry) => {
|
|
53
|
-
if (ids.has(entry.id)) {
|
|
54
|
-
fail(new Error(`Fixer prerequisites contain duplicate id: ${entry.id}`));
|
|
55
|
-
}
|
|
56
|
-
ids.add(entry.id);
|
|
57
|
-
return Object.freeze({ id: entry.id, requirement: entry.requirement });
|
|
58
|
-
});
|
|
59
|
-
return Object.freeze(prerequisites);
|
|
60
|
-
}
|
|
61
|
-
function parseFixerPrerequisites(source) {
|
|
62
|
-
let decoded;
|
|
63
|
-
try {
|
|
64
|
-
decoded = JSON.parse(source);
|
|
65
|
-
} catch (error) {
|
|
66
|
-
fail(error);
|
|
67
|
-
}
|
|
68
|
-
return validateFixerPrerequisites(decoded);
|
|
69
|
-
}
|
|
70
|
-
export {
|
|
71
|
-
FIXER_PREREQUISITE_ID_PATTERN,
|
|
72
|
-
FixerPacketValidationError,
|
|
73
|
-
fixerPrerequisiteSchema,
|
|
74
|
-
fixerPrerequisitesSchema,
|
|
75
|
-
parseFixerPrerequisites,
|
|
76
|
-
validateFixerPrerequisites
|
|
77
|
-
};
|