@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
|
@@ -370,8 +370,8 @@ const FIXER_OPTIONS = [
|
|
|
370
370
|
repeatable: false,
|
|
371
371
|
form: "option",
|
|
372
372
|
description: {
|
|
373
|
-
en: "
|
|
374
|
-
zh: "
|
|
373
|
+
en: "Caller prerequisites path passed as-is to the role. Package does not read, copy, or validate; use an absolute path when cwd differs from --project.",
|
|
374
|
+
zh: "调用方前置条件文件路径原样递给衙门。包不读、不复制、不校验;调用方当前目录与 --project 不同时请给绝对路径。",
|
|
375
375
|
},
|
|
376
376
|
},
|
|
377
377
|
];
|
|
@@ -514,6 +514,24 @@ const NOTARY_OPTIONS = [
|
|
|
514
514
|
},
|
|
515
515
|
},
|
|
516
516
|
];
|
|
517
|
+
/** 台院: optional --source-run binds the audited leg; gate summons always pass it (#1166). */
|
|
518
|
+
const INSPECTOR_OPTIONS = [
|
|
519
|
+
...projectAndAttach("inspector"),
|
|
520
|
+
{
|
|
521
|
+
id: "source-run",
|
|
522
|
+
owner: "inspector",
|
|
523
|
+
canonical: "--source-run",
|
|
524
|
+
aliases: [],
|
|
525
|
+
valueMetavar: "runId@role|path",
|
|
526
|
+
required: false,
|
|
527
|
+
repeatable: false,
|
|
528
|
+
form: "option",
|
|
529
|
+
description: {
|
|
530
|
+
en: "Optional audited source-run locator (runId@role or path). Gate summons always supply it; identity rides startup materials.",
|
|
531
|
+
zh: "可选被审腿定位符(runId@role 或路径)。闸传召必带;身份在启动材料里。",
|
|
532
|
+
},
|
|
533
|
+
},
|
|
534
|
+
];
|
|
517
535
|
const MERGER_OPTIONS = [
|
|
518
536
|
// Merger project face: worktree whose Git materials are handed to the role.
|
|
519
537
|
{
|
|
@@ -677,6 +695,7 @@ const SEAT_OPTION_ROWS = {
|
|
|
677
695
|
merger: MERGER_OPTIONS,
|
|
678
696
|
notary: NOTARY_OPTIONS,
|
|
679
697
|
auditor: AUDITOR_OPTIONS,
|
|
698
|
+
inspector: INSPECTOR_OPTIONS,
|
|
680
699
|
};
|
|
681
700
|
function seatOptionRows(role) {
|
|
682
701
|
return SEAT_OPTION_ROWS[role] ?? projectAndAttach(role);
|
|
@@ -10,7 +10,7 @@ import { writeFile } from "node:fs/promises";
|
|
|
10
10
|
import { buildAutoResumeContinuationPrompt, findRunDirectoryById, readRoleRunState, RESUME_TRANSPORT_ENVELOPE, } from "./run-lifecycle.js";
|
|
11
11
|
import { CliUsageError } from "./cli-errors.js";
|
|
12
12
|
import { projectPublicTurnAxes } from "./turn-request.js";
|
|
13
|
-
import {
|
|
13
|
+
import { appendCallerFileFlagPaths, bindAdmittedTicketNumber, relocateAdmittedRunToTicket, } from "./invocation.js";
|
|
14
14
|
import { readRecordedSubmissionRows } from "../submission-ledger.js";
|
|
15
15
|
import { parseTicketNumber, readDeclaredTicketNumber } from "../run-ticket-number.js";
|
|
16
16
|
import { readStoredHostSessionId } from "../session-identity.js";
|
|
@@ -49,12 +49,12 @@ function projectRelocatedTurnIdentity(request, result, admitted, relocation) {
|
|
|
49
49
|
mutableRequest.principal = admitted.principal;
|
|
50
50
|
const activation = mutableRequest.activation;
|
|
51
51
|
if (isRecord(activation)) {
|
|
52
|
-
for (const field of ["
|
|
52
|
+
for (const field of ["inputPath"]) {
|
|
53
53
|
const record = activation;
|
|
54
54
|
if (field in record)
|
|
55
55
|
record[field] = rewrite(record[field]);
|
|
56
56
|
}
|
|
57
|
-
// #1165:
|
|
57
|
+
// #1165/#1168: caller file-flag paths are not activation fields to rewrite.
|
|
58
58
|
}
|
|
59
59
|
if (result.terminal !== undefined) {
|
|
60
60
|
for (const artifact of result.terminal.artifacts) {
|
|
@@ -906,8 +906,8 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
906
906
|
* Shared resume continuation projection (#471 / #600 / #633 / #637 / #755 / #879):
|
|
907
907
|
* seat-table model/engine/timeout axes, restored correlation, and either
|
|
908
908
|
* - manual resume (no same-ticket summons): caller message bytes, or
|
|
909
|
-
* - same-ticket summons (审核循环续话): caller/peer words + optional
|
|
910
|
-
*
|
|
909
|
+
* - same-ticket summons (审核循环续话): caller/peer words + optional caller file-flag
|
|
910
|
+
* paths only — no「请重读」、no code-authored content substitute,
|
|
911
911
|
* no engine handbook packaging (#750/#755/#879).
|
|
912
912
|
* Caller message wins as prompt base when supplied (bytes unchanged, including
|
|
913
913
|
* blank/whitespace); else summons instruction (parent payload or reask).
|
|
@@ -916,22 +916,17 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
916
916
|
* first when request.summons carries instruction or attachment paths.
|
|
917
917
|
*/
|
|
918
918
|
export function resumeTurnRequestProjectionOptions(admitted, request, env, summonsPrepared) {
|
|
919
|
-
// #879: officer dialogue
|
|
920
|
-
//
|
|
921
|
-
// Binding pointer stays on summons sourceRunPath / activation / attachments.
|
|
919
|
+
// #879: officer dialogue is caller/peer words; #1166 J11 merges caller file-flag
|
|
920
|
+
// paths when present. Gate with no file flags stays body-only (ADR 0085).
|
|
922
921
|
const officerDialogue = isStationChildOfficerDialogue(admitted.role, env);
|
|
922
|
+
const fileFlags = summonsPrepared?.attachments ?? [];
|
|
923
923
|
let prompt;
|
|
924
924
|
if (request.message !== undefined) {
|
|
925
925
|
if (summonsPrepared !== undefined) {
|
|
926
|
-
// #755: same-ticket review / open-court — caller words.
|
|
927
|
-
|
|
928
|
-
prompt = officerDialogue
|
|
926
|
+
// #755: same-ticket review / open-court — caller words + caller file flags.
|
|
927
|
+
prompt = officerDialogue && fileFlags.length === 0
|
|
929
928
|
? request.message
|
|
930
|
-
:
|
|
931
|
-
instruction: request.message,
|
|
932
|
-
instructionEmpty: false,
|
|
933
|
-
attachments: summonsPrepared.attachments,
|
|
934
|
-
});
|
|
929
|
+
: appendCallerFileFlagPaths(request.message, fileFlags);
|
|
935
930
|
}
|
|
936
931
|
else if (request.summons !== undefined) {
|
|
937
932
|
// #755: same-ticket summons without prepared materials — caller words only.
|
|
@@ -942,13 +937,11 @@ export function resumeTurnRequestProjectionOptions(admitted, request, env, summo
|
|
|
942
937
|
}
|
|
943
938
|
}
|
|
944
939
|
else if (summonsPrepared !== undefined) {
|
|
945
|
-
|
|
946
|
-
//
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
? summonsPrepared.instruction
|
|
951
|
-
: buildInstructionTransportPrompt(summonsPrepared);
|
|
940
|
+
const body = summonsPrepared.instruction;
|
|
941
|
+
// No file flags: body alone (gate peer words). With flags: merge delivery.
|
|
942
|
+
prompt = officerDialogue && fileFlags.length === 0
|
|
943
|
+
? body
|
|
944
|
+
: appendCallerFileFlagPaths(body, fileFlags);
|
|
952
945
|
}
|
|
953
946
|
else if (request.summons !== undefined) {
|
|
954
947
|
// #879: same-ticket summons with no instruction (e.g. notary source-run binding
|
|
@@ -971,6 +964,10 @@ export function resumeTurnRequestProjectionOptions(admitted, request, env, summo
|
|
|
971
964
|
...(env.stationChild === undefined ? {} : { stationChild: env.stationChild }),
|
|
972
965
|
// #1132: one configured ceiling, already resolved by the caller (#422).
|
|
973
966
|
deliveryRequestLimit: deliveryLimitFromConfig(env.autoResumeLimit),
|
|
967
|
+
...(env.navigatorWorkContextPath === undefined
|
|
968
|
+
|| env.navigatorWorkContextPath.trim() === ""
|
|
969
|
+
? {}
|
|
970
|
+
: { navigatorWorkContextPath: env.navigatorWorkContextPath }),
|
|
974
971
|
};
|
|
975
972
|
}
|
|
976
973
|
/** Shared new-turn and in-call auto-resume projection. Seat code supplies prompt and activation. */
|
|
@@ -986,6 +983,10 @@ export function roleTurnOptions(env, admitted, continuation) {
|
|
|
986
983
|
...(env.stationChild === undefined ? {} : { stationChild: env.stationChild }),
|
|
987
984
|
// #1132: one configured ceiling, already resolved by the caller (#422).
|
|
988
985
|
deliveryRequestLimit: deliveryLimitFromConfig(env.autoResumeLimit),
|
|
986
|
+
...(env.navigatorWorkContextPath === undefined
|
|
987
|
+
|| env.navigatorWorkContextPath.trim() === ""
|
|
988
|
+
? {}
|
|
989
|
+
: { navigatorWorkContextPath: env.navigatorWorkContextPath }),
|
|
989
990
|
};
|
|
990
991
|
}
|
|
991
992
|
/**
|
|
@@ -1070,7 +1071,7 @@ export async function prepareSummonsResumeMaterials(_runDirectory, summons) {
|
|
|
1070
1071
|
* validation, turn builder, and adapters stay on the seat.
|
|
1071
1072
|
*
|
|
1072
1073
|
* Court handling (#637): public manual resume reads only the open court's
|
|
1073
|
-
* settlement identity; internal re-summons
|
|
1074
|
+
* settlement identity; internal re-summons passes caller file-flag paths as-is.
|
|
1074
1075
|
*/
|
|
1075
1076
|
export async function runPostAdmissionSeatResume(input) {
|
|
1076
1077
|
let request = input.request;
|
|
@@ -631,18 +631,9 @@ export async function findRunDirectoryById(home, runId, onlyBookKey, onlyRole) {
|
|
|
631
631
|
.filter((bookKey) => onlyBookKey === undefined || bookKey === onlyBookKey)
|
|
632
632
|
.map((bookKey) => activationBookDirectory(ledgerHome, bookKey)), runId, onlyRole);
|
|
633
633
|
}
|
|
634
|
-
/** Code-owned gate inspector summons prefix (public-role-summons / #747). */
|
|
635
|
-
export const GATE_DOSSIER_POINTER_PREFIX = "卷宗指针:";
|
|
636
|
-
/** Parent path from a code-owned inspector 卷宗指针 instruction; else undefined. */
|
|
637
|
-
export function parentRunPathFromGatePointerInstruction(instruction) {
|
|
638
|
-
if (!instruction.startsWith(GATE_DOSSIER_POINTER_PREFIX))
|
|
639
|
-
return undefined;
|
|
640
|
-
const path = instruction.slice(GATE_DOSSIER_POINTER_PREFIX.length).trim();
|
|
641
|
-
return path === "" ? undefined : path;
|
|
642
|
-
}
|
|
643
634
|
/**
|
|
644
|
-
* Parent-run binding on a retained officer run (#747).
|
|
645
|
-
*
|
|
635
|
+
* Parent-run binding on a retained officer run (#747 / #1166).
|
|
636
|
+
* Typed sourceRunPath only — instruction bytes are never a path protocol.
|
|
646
637
|
* Missing page → undefined; damage / non-ENOENT IO propagates.
|
|
647
638
|
*/
|
|
648
639
|
export async function readRunParentPath(runDirectory) {
|
|
@@ -652,9 +643,6 @@ export async function readRunParentPath(runDirectory) {
|
|
|
652
643
|
if (typeof record.sourceRunPath === "string" && record.sourceRunPath.trim() !== "") {
|
|
653
644
|
return record.sourceRunPath;
|
|
654
645
|
}
|
|
655
|
-
if (typeof record.instruction === "string") {
|
|
656
|
-
return parentRunPathFromGatePointerInstruction(record.instruction);
|
|
657
|
-
}
|
|
658
646
|
return undefined;
|
|
659
647
|
}
|
|
660
648
|
/**
|
|
@@ -766,10 +754,7 @@ async function loadResumableRunRecord(home, runId, authority) {
|
|
|
766
754
|
let instructionEmpty = true;
|
|
767
755
|
let attachments = [];
|
|
768
756
|
let phase;
|
|
769
|
-
let taskPath;
|
|
770
|
-
let packetPath;
|
|
771
757
|
let prerequisitesPath;
|
|
772
|
-
let prerequisites;
|
|
773
758
|
let baseRevision;
|
|
774
759
|
let lens;
|
|
775
760
|
let authorityRefs;
|
|
@@ -813,19 +798,10 @@ async function loadResumableRunRecord(home, runId, authority) {
|
|
|
813
798
|
if (record.phase === "plan" || record.phase === "apply") {
|
|
814
799
|
phase = record.phase;
|
|
815
800
|
}
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
}
|
|
819
|
-
if (typeof record.packetPath === "string" && record.packetPath.trim() !== "") {
|
|
820
|
-
packetPath = record.packetPath;
|
|
821
|
-
}
|
|
822
|
-
if (typeof record.prerequisitesPath === "string" &&
|
|
823
|
-
record.prerequisitesPath.trim() !== "") {
|
|
801
|
+
// #1168: opaque caller path on resume — do not trim-filter provided values.
|
|
802
|
+
if (typeof record.prerequisitesPath === "string") {
|
|
824
803
|
prerequisitesPath = record.prerequisitesPath;
|
|
825
804
|
}
|
|
826
|
-
if (Array.isArray(record.prerequisites)) {
|
|
827
|
-
prerequisites = record.prerequisites;
|
|
828
|
-
}
|
|
829
805
|
if (typeof record.baseRevision === "string" &&
|
|
830
806
|
record.baseRevision.trim() !== "") {
|
|
831
807
|
baseRevision = record.baseRevision;
|
|
@@ -974,10 +950,7 @@ async function loadResumableRunRecord(home, runId, authority) {
|
|
|
974
950
|
instructionEmpty,
|
|
975
951
|
attachments,
|
|
976
952
|
...(phase === undefined ? {} : { phase }),
|
|
977
|
-
...(taskPath === undefined ? {} : { taskPath }),
|
|
978
|
-
...(packetPath === undefined ? {} : { packetPath }),
|
|
979
953
|
...(prerequisitesPath === undefined ? {} : { prerequisitesPath }),
|
|
980
|
-
...(prerequisites === undefined ? {} : { prerequisites }),
|
|
981
954
|
...(baseRevision === undefined ? {} : { baseRevision }),
|
|
982
955
|
...(lens === undefined ? {} : { lens }),
|
|
983
956
|
...(authorityRefs === undefined ? {} : { authorityRefs }),
|
|
@@ -1079,10 +1052,6 @@ function admitResumedRole(loaded) {
|
|
|
1079
1052
|
}
|
|
1080
1053
|
case "worker-task": {
|
|
1081
1054
|
const phase = resumedWorkerPhase(fields.phase ?? loaded.run.phase, record.phases, role, runId);
|
|
1082
|
-
const taskPath = fields.taskPath;
|
|
1083
|
-
if (taskPath === undefined) {
|
|
1084
|
-
throw new CliUsageError(`role run admitted coder task path is missing: ${runId}`);
|
|
1085
|
-
}
|
|
1086
1055
|
if (fields.instruction.trim() === "") {
|
|
1087
1056
|
throw new CliUsageError(`role run admitted coder task is blank: ${runId}`);
|
|
1088
1057
|
}
|
|
@@ -1091,30 +1060,22 @@ function admitResumedRole(loaded) {
|
|
|
1091
1060
|
phase,
|
|
1092
1061
|
...base,
|
|
1093
1062
|
instructionEmpty: false,
|
|
1094
|
-
taskPath,
|
|
1095
1063
|
};
|
|
1096
1064
|
return admitted;
|
|
1097
1065
|
}
|
|
1098
1066
|
case "worker-packet": {
|
|
1099
1067
|
const phase = resumedWorkerPhase(fields.phase ?? loaded.run.phase, record.phases, role, runId);
|
|
1100
|
-
const packetPath = fields.packetPath;
|
|
1101
|
-
if (packetPath === undefined) {
|
|
1102
|
-
throw new CliUsageError(`role run admitted fixer packet path is missing: ${runId}`);
|
|
1103
|
-
}
|
|
1104
1068
|
if (fields.instruction.trim() === "") {
|
|
1105
1069
|
throw new CliUsageError(`role run admitted fixer instruction is blank: ${runId}`);
|
|
1106
1070
|
}
|
|
1107
|
-
const prerequisites = fields.prerequisites ?? Object.freeze([]);
|
|
1108
1071
|
const admitted = {
|
|
1109
1072
|
role: "fixer",
|
|
1110
1073
|
phase,
|
|
1111
1074
|
...base,
|
|
1112
1075
|
instructionEmpty: false,
|
|
1113
|
-
packetPath,
|
|
1114
1076
|
...(fields.prerequisitesPath === undefined
|
|
1115
1077
|
? {}
|
|
1116
1078
|
: { prerequisitesPath: fields.prerequisitesPath }),
|
|
1117
|
-
prerequisites,
|
|
1118
1079
|
};
|
|
1119
1080
|
return admitted;
|
|
1120
1081
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { pickEngineAxis } from "../package-resources/engine-material.js";
|
|
2
2
|
import { packagedRoleActivationFlags, packagedRoleMetadata, } from "../packaged-role-registry.js";
|
|
3
3
|
import { installedMethodSkillPath } from "./machine-method-skills.js";
|
|
4
|
-
import { parentRunPathFromGatePointerInstruction } from "./run-lifecycle.js";
|
|
5
4
|
/**
|
|
6
5
|
* Env axes shared by every public turn projection.
|
|
7
6
|
* Callers add correlation, continuation, host, and station-only fields.
|
|
@@ -49,6 +48,10 @@ export function projectRoleTurnRequest(admitted, roleDetails, options) {
|
|
|
49
48
|
...(options.deliveryRequestLimit === undefined
|
|
50
49
|
? {}
|
|
51
50
|
: { deliveryRequestLimit: options.deliveryRequestLimit }),
|
|
51
|
+
...(options.navigatorWorkContextPath === undefined
|
|
52
|
+
|| options.navigatorWorkContextPath.trim() === ""
|
|
53
|
+
? {}
|
|
54
|
+
: { navigatorWorkContextPath: options.navigatorWorkContextPath }),
|
|
52
55
|
};
|
|
53
56
|
}
|
|
54
57
|
/**
|
|
@@ -83,14 +86,6 @@ function activationForAdmitted(admitted) {
|
|
|
83
86
|
const activation = { role: admitted.role };
|
|
84
87
|
for (const spec of packagedRoleActivationFlags(admitted.role)) {
|
|
85
88
|
let value = readAdmittedPath(admitted, spec.from ?? spec.field);
|
|
86
|
-
if (spec.fallback === "gate-pointer") {
|
|
87
|
-
const trimmed = typeof value === "string" ? value.trim() : "";
|
|
88
|
-
value = trimmed !== ""
|
|
89
|
-
? trimmed
|
|
90
|
-
: parentRunPathFromGatePointerInstruction(admitted.instruction);
|
|
91
|
-
if (typeof value !== "string" || value === "")
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
89
|
if (value === undefined)
|
|
95
90
|
continue;
|
|
96
91
|
if (spec.text === true) {
|
|
@@ -197,7 +197,8 @@ async function summonPublicRole(options) {
|
|
|
197
197
|
...options.boundTicketNumber === void 0 ? {} : { boundTicketNumber: options.boundTicketNumber },
|
|
198
198
|
...options.parentRunPath === void 0 || options.parentRunPath.trim() === "" ? {} : { parentRunPath: options.parentRunPath },
|
|
199
199
|
...options.correlationId === void 0 || options.correlationId.trim() === "" ? {} : { correlationId: options.correlationId },
|
|
200
|
-
...options.createRunId === void 0 ? {} : { createRunId: options.createRunId }
|
|
200
|
+
...options.createRunId === void 0 ? {} : { createRunId: options.createRunId },
|
|
201
|
+
...options.navigatorWorkContextPath === void 0 || options.navigatorWorkContextPath.trim() === "" ? {} : { navigatorWorkContextPath: options.navigatorWorkContextPath }
|
|
201
202
|
}
|
|
202
203
|
};
|
|
203
204
|
} catch (error) {
|
|
@@ -454,7 +455,8 @@ async function summonGateOfficer(options) {
|
|
|
454
455
|
"judge",
|
|
455
456
|
"--source-run",
|
|
456
457
|
options.sourceRunDirectory,
|
|
457
|
-
|
|
458
|
+
"--project",
|
|
459
|
+
options.cwd
|
|
458
460
|
],
|
|
459
461
|
...common
|
|
460
462
|
});
|
|
@@ -482,7 +484,7 @@ async function summonGateOfficer(options) {
|
|
|
482
484
|
}
|
|
483
485
|
return summonPublicRole({
|
|
484
486
|
role: options.officer,
|
|
485
|
-
argv: [
|
|
487
|
+
argv: ["--source-run", options.sourceRunDirectory, "--project", options.cwd],
|
|
486
488
|
...common
|
|
487
489
|
});
|
|
488
490
|
}
|
|
@@ -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
|
import {
|
|
4
4
|
activationBookDirectory,
|
|
5
5
|
ensureRealDirectoryTree
|
|
@@ -27,6 +27,11 @@ function sessionFileOf(runDirectory) {
|
|
|
27
27
|
function runDirectoryOfSessionFile(sessionFile) {
|
|
28
28
|
return dirname(dirname(sessionFile));
|
|
29
29
|
}
|
|
30
|
+
function auditorRunDirectory(context) {
|
|
31
|
+
const sessionFile = context.sessionManager?.getSessionFile?.();
|
|
32
|
+
if (sessionFile === void 0) return void 0;
|
|
33
|
+
return resolve(runDirectoryOfSessionFile(sessionFile));
|
|
34
|
+
}
|
|
30
35
|
function runDirectoryFromSessionDirectory(sessionDirectory) {
|
|
31
36
|
return dirname(sessionDirectory);
|
|
32
37
|
}
|
|
@@ -107,6 +112,7 @@ function ensureRoleRunPlacement(ledgerHome, placement) {
|
|
|
107
112
|
}
|
|
108
113
|
export {
|
|
109
114
|
ROLE_RUN_SESSION_FILENAME,
|
|
115
|
+
auditorRunDirectory,
|
|
110
116
|
ensureRoleRunDirectory,
|
|
111
117
|
ensureRoleRunPlacement,
|
|
112
118
|
findRoleRunDirectory,
|
|
@@ -19,10 +19,9 @@ const ADMITTED_PAGE_FIELDS = [
|
|
|
19
19
|
"admittedRequestPath", // pre-#1161 pages only
|
|
20
20
|
"sessionDirectory",
|
|
21
21
|
"sessionFile",
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// #1165: requestManifestPath is a caller path — never rewrite.
|
|
22
|
+
// #1165/#1168: caller file-flag paths (requestManifestPath, prerequisitesPath)
|
|
23
|
+
// stay as given. Obsolete copy fields (taskPath/packetPath) are not rewritten —
|
|
24
|
+
// stock volumes keep their bytes; live relocate no longer maintains them.
|
|
26
25
|
"mergerInputPath",
|
|
27
26
|
"sourceRunPath",
|
|
28
27
|
];
|
package/package.json
CHANGED
|
@@ -32,9 +32,8 @@ const entries = [
|
|
|
32
32
|
"archivist-record-topology",
|
|
33
33
|
// Session material loaders used by published non-bundle roots.
|
|
34
34
|
"session-opening-materials",
|
|
35
|
-
// Value-import closure of published non-bundle roots (build-package-only loadable)
|
|
36
|
-
|
|
37
|
-
// Static import of auditor-dossier-tool / placement path authority (#859).
|
|
35
|
+
// Value-import closure of published non-bundle roots (build-package-only loadable);
|
|
36
|
+
// placement path authority (#859).
|
|
38
37
|
"role-run-placement",
|
|
39
38
|
// Static import of role-run-placement (safe-positive ticket invariant).
|
|
40
39
|
"run-ticket-number",
|
|
@@ -55,7 +54,6 @@ const entries = [
|
|
|
55
54
|
"open-tool-schema",
|
|
56
55
|
"package-contracts/collector-output",
|
|
57
56
|
"package-contracts/fixer-output",
|
|
58
|
-
"package-contracts/fixer-packet",
|
|
59
57
|
"package-contracts/gatekeeper-output",
|
|
60
58
|
"package-contracts/judge-output",
|
|
61
59
|
"package-contracts/navigator-output",
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared audited-run identity for review-officer startup materials (#1166 / ADR 0087).
|
|
3
|
+
* Value form is `<runId>@<席>` only — no directory path.
|
|
4
|
+
*/
|
|
5
|
+
import { basename } from "node:path";
|
|
6
|
+
|
|
7
|
+
import { formatRunLeaf, parseRunLeaf } from "./role-run-placement.ts";
|
|
8
|
+
|
|
9
|
+
export const AUDITED_RUN_IDENTITY_KIND = "audited-run-identity" as const;
|
|
10
|
+
|
|
11
|
+
export type AuditedRunIdentityMaterial = {
|
|
12
|
+
readonly kind: typeof AUDITED_RUN_IDENTITY_KIND;
|
|
13
|
+
readonly identity: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/** Identity leaf from a run directory basename; undefined when the leaf is not `runId@role`. */
|
|
17
|
+
export function auditedRunIdentityFromDirectory(runDirectory: string): string | undefined {
|
|
18
|
+
const parsed = parseRunLeaf(basename(runDirectory));
|
|
19
|
+
if (parsed === undefined) return undefined;
|
|
20
|
+
return formatRunLeaf(parsed.runId, parsed.role);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function auditedRunIdentityMaterial(identity: string): AuditedRunIdentityMaterial {
|
|
24
|
+
return { kind: AUDITED_RUN_IDENTITY_KIND, identity };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Identity from locator fields already in hand (notary source-run). */
|
|
28
|
+
export function auditedRunIdentityFromParts(runId: string, role: string): string {
|
|
29
|
+
return formatRunLeaf(runId, role);
|
|
30
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Usage } from "@earendil-works/pi-ai";
|
|
2
2
|
import type { AuditorSoulRole } from "./auditor-soul.ts";
|
|
3
|
-
import { auditorRunDirectory } from "./
|
|
3
|
+
import { auditorRunDirectory } from "./role-run-placement.ts";
|
|
4
4
|
import type { HostContext } from "./host-contracts.ts";
|
|
5
5
|
import type { NoReceiptLifecycleFacts } from "./receipt-delivery-policy.ts";
|
|
6
6
|
import type { PublicSummonResult } from "./public-role-summons.ts";
|
|
@@ -40,8 +40,6 @@ export type ComplianceDecision =
|
|
|
40
40
|
| ComplianceReceived
|
|
41
41
|
| ComplianceTransportFailure;
|
|
42
42
|
/** Source-run pointer remains the binding locator; parent body rides the separate instruction. */
|
|
43
|
-
export const AUDITOR_DOSSIER_PROMPT = "卷宗指针:" as const;
|
|
44
|
-
|
|
45
43
|
export const COMPLIANCE_RESPONSE_ENTRY_TYPE = "ak_compliance_response" as const;
|
|
46
44
|
export const AUDITOR_PARENT_ATTEMPT_BINDING_ENTRY_TYPE = "ak_auditor_parent_attempt_binding" as const;
|
|
47
45
|
export const AUDITOR_COMPLIANCE_FAILURE_ENTRY_TYPE = "ak_auditor_compliance_failure" as const;
|
|
@@ -215,7 +213,6 @@ export async function runComplianceAudit(options: RunComplianceAuditOptions): Pr
|
|
|
215
213
|
auditSubject,
|
|
216
214
|
"--source-run",
|
|
217
215
|
sourceRunDirectory,
|
|
218
|
-
`${AUDITOR_DOSSIER_PROMPT}${sourceRunDirectory}`,
|
|
219
216
|
],
|
|
220
217
|
cwd: options.context.cwd ?? process.cwd(),
|
|
221
218
|
home,
|
package/src/doctor-auditor.ts
CHANGED
package/src/gatekeeper-role.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { HostContext } from "./host-contracts.ts";
|
|
3
3
|
|
|
4
|
-
import { auditorRunDirectory } from "./
|
|
4
|
+
import { auditorRunDirectory } from "./role-run-placement.ts";
|
|
5
5
|
import { packagedGateStageLabel } from "./packaged-role-registry.ts";
|
|
6
6
|
import type { NoReceiptLifecycleFacts } from "./receipt-delivery-policy.ts";
|
|
7
7
|
import { GatekeeperDecisionError, receivedDiscriminator, unreadableDiscriminatorNotice } from "./submission-errors.ts";
|
package/src/host-contracts.ts
CHANGED
|
@@ -87,13 +87,10 @@ export type RoleTurnActivation =
|
|
|
87
87
|
| {
|
|
88
88
|
readonly role: "coder";
|
|
89
89
|
readonly phase: string;
|
|
90
|
-
readonly taskPath: string;
|
|
91
90
|
}
|
|
92
91
|
| {
|
|
93
92
|
readonly role: "fixer";
|
|
94
93
|
readonly phase: string;
|
|
95
|
-
readonly packetPath: string;
|
|
96
|
-
readonly prerequisitesPath?: string;
|
|
97
94
|
}
|
|
98
95
|
| {
|
|
99
96
|
readonly role: "reviewer";
|
|
@@ -203,6 +200,11 @@ export type RoleTurnRequest = {
|
|
|
203
200
|
* number. Absent = package default. Never re-read from disk downstream.
|
|
204
201
|
*/
|
|
205
202
|
readonly deliveryRequestLimit?: number;
|
|
203
|
+
/**
|
|
204
|
+
* Navigator nest work-context locator for startup materials (#1166).
|
|
205
|
+
* Request-scoped — never parent process.env across await.
|
|
206
|
+
*/
|
|
207
|
+
readonly navigatorWorkContextPath?: string;
|
|
206
208
|
};
|
|
207
209
|
|
|
208
210
|
/** Turn result — only fields upper layers currently consume. */
|
|
@@ -261,7 +263,7 @@ export interface DurablePrincipalAuthority {
|
|
|
261
263
|
type HostSessionManager = { getLeafEntry(): HostSessionEntry | undefined; getLeafId(): string | null | undefined; getEntries(): Iterable<HostSessionEntry>; getSessionDir(): string; getSessionFile(): string | undefined; getHeader?(): { readonly type: string; readonly id?: string } | null; setSessionFile?(path: string): void; appendCustomEntry?(customType: string, data?: unknown): unknown; };
|
|
262
264
|
|
|
263
265
|
/** Context supplied by a host for one activation and its interceptable events. */
|
|
264
|
-
export type HostContext = { cwd: string; mode: string; model: { readonly provider: string } | undefined; sessionManager: HostSessionManager; /** Per-turn admitted run directory (#879); never process-global env. */ runDirectory?: string; /** Per-turn court attempt (#879); never process-global env. */ courtAttemptId?: string; /** Public-invocation scope (#537); never process-global env. */ invocationScopeId?: string; /** Selected host axis (#537 / ADR 0082); never process-global env invent. */ host?: string; signal?: AbortSignal | undefined; ui?: { notify?(message: string, type?: "info" | "warning" | "error"): void }; transcript?(): string; abort(): void; };
|
|
266
|
+
export type HostContext = { cwd: string; mode: string; model: { readonly provider: string } | undefined; sessionManager: HostSessionManager; /** Per-turn admitted run directory (#879); never process-global env. */ runDirectory?: string; /** Per-turn court attempt (#879); never process-global env. */ courtAttemptId?: string; /** Public-invocation scope (#537); never process-global env. */ invocationScopeId?: string; /** Selected host axis (#537 / ADR 0082); never process-global env invent. */ host?: string; /** Navigator nest work-context locator (#1166); never process-global env. */ navigatorWorkContextPath?: string; signal?: AbortSignal | undefined; ui?: { notify?(message: string, type?: "info" | "warning" | "error"): void }; transcript?(): string; abort(): void; };
|
|
265
267
|
|
|
266
268
|
/** Per-turn run directory; adapters must project any child-process identity. */
|
|
267
269
|
export function runDirectoryFromHostContext(context: HostContext): string | undefined {
|
package/src/merger-contracts.ts
CHANGED
|
@@ -11,7 +11,8 @@ export const mergerInputSchema = Type.Object({
|
|
|
11
11
|
attemptId: Type.String({ minLength: 1, description: "对账 attempt 身份(transport)" }),
|
|
12
12
|
targetObjectId: Type.String({ description: "材料:target parent OID;可空" }),
|
|
13
13
|
sourceObjectId: Type.String({ description: "材料:source parent OID;可空" }),
|
|
14
|
-
|
|
14
|
+
// #1168: task/authority dispatch copies removed; git-fact intents remain.
|
|
15
|
+
materials: Type.Object({ targetIntent: materialSchema, sourceIntent: materialSchema }),
|
|
15
16
|
expectedConflictPaths: Type.Array(Type.String(), { description: "材料:当前未合并路径;可空" }),
|
|
16
17
|
resolutionScope: Type.Array(Type.String(), { description: "材料:解析范围提示;可空" }),
|
|
17
18
|
authorizedChecks: Type.Array(checkSchema),
|
|
@@ -62,7 +63,10 @@ function readMaterial(value: unknown, label: string): MergerMaterial {
|
|
|
62
63
|
export function validateMergerInput(value: unknown): MergerInput {
|
|
63
64
|
if (!isRecord(value) || blank(value.attemptId)) fail("Merger input requires a non-empty attemptId for accounting");
|
|
64
65
|
if (!isRecord(value.materials)) fail("Merger materials are missing");
|
|
65
|
-
const materials = {
|
|
66
|
+
const materials = {
|
|
67
|
+
targetIntent: readMaterial(value.materials.targetIntent, "targetIntent"),
|
|
68
|
+
sourceIntent: readMaterial(value.materials.sourceIntent, "sourceIntent"),
|
|
69
|
+
};
|
|
66
70
|
const authorizedChecks = Array.isArray(value.authorizedChecks) ? value.authorizedChecks.filter((check): check is Record<string, unknown> => isRecord(check)).map(c => ({ name: asString(c.name), argv: asStringArray(c.argv).filter(a => a.trim().length > 0) })).filter(c => c.name.trim().length > 0 && c.argv.length > 0) : [];
|
|
67
71
|
return deepFreeze(structuredClone({ attemptId: (value.attemptId as string).trim(), targetObjectId: asString(value.targetObjectId), sourceObjectId: asString(value.sourceObjectId), materials, expectedConflictPaths: asStringArray(value.expectedConflictPaths), resolutionScope: asStringArray(value.resolutionScope), authorizedChecks }) as MergerInput);
|
|
68
72
|
}
|
package/src/merger-role.ts
CHANGED
|
@@ -21,6 +21,7 @@ function materialText(input: MergerInput, key: keyof MergerInput["materials"]):
|
|
|
21
21
|
* Merger (校书郎) role runtime.
|
|
22
22
|
* Submission tool records every call (#836); host end is the final.
|
|
23
23
|
* Git state / completion verification are not attendance or rejection gates (#827).
|
|
24
|
+
* #1168: dispatch text is the first message; assignment carries git facts only.
|
|
24
25
|
*/
|
|
25
26
|
export function createMergerRoleRuntime(pi: RoleHost, dependencies: MergerRoleDependencies) {
|
|
26
27
|
let activation: { soul: string; input: Readonly<MergerInput> } | undefined;
|
|
@@ -41,7 +42,16 @@ export function createMergerRoleRuntime(pi: RoleHost, dependencies: MergerRoleDe
|
|
|
41
42
|
});
|
|
42
43
|
pi.on("before_agent_start", (event) => {
|
|
43
44
|
if (!activation) throw new Error("校书郎未激活");
|
|
44
|
-
const admitted = {
|
|
45
|
+
const admitted = {
|
|
46
|
+
attemptId: activation.input.attemptId,
|
|
47
|
+
targetObjectId: activation.input.targetObjectId,
|
|
48
|
+
sourceObjectId: activation.input.sourceObjectId,
|
|
49
|
+
targetIntent: materialText(activation.input, "targetIntent"),
|
|
50
|
+
sourceIntent: materialText(activation.input, "sourceIntent"),
|
|
51
|
+
expectedConflictPaths: activation.input.expectedConflictPaths,
|
|
52
|
+
resolutionScope: activation.input.resolutionScope,
|
|
53
|
+
authorizedChecks: activation.input.authorizedChecks,
|
|
54
|
+
};
|
|
45
55
|
return { systemPrompt: `${event.systemPrompt}\n\n<merger_soul>\n${activation.soul}\n</merger_soul>\n\n<merger_assignment>\n${JSON.stringify(admitted)}\n</merger_assignment>` };
|
|
46
56
|
});
|
|
47
57
|
}
|
|
@@ -229,14 +229,14 @@ export function navigatorSubjectKey(
|
|
|
229
229
|
/**
|
|
230
230
|
* Role inputs for one ad-hoc work item live below role-specific run folders.
|
|
231
231
|
* The folder and filename are transport, not identity: the shared work root
|
|
232
|
-
* keeps
|
|
232
|
+
* keeps natural inputs on one subject.
|
|
233
233
|
*/
|
|
234
234
|
export function navigatorSubjectKeyForInput(subjectRoot: string, reference: string, cwd = process.cwd()): string {
|
|
235
235
|
if (issueRoot(subjectRoot) !== undefined || !subjectRoot.includes("/.ak/work/")) return subjectRoot;
|
|
236
236
|
const resolvedReference = resolve(cwd, reference);
|
|
237
237
|
const marker = "/runs/";
|
|
238
238
|
if (resolvedReference.includes(marker)) {
|
|
239
|
-
// The work root, not
|
|
239
|
+
// The work root, not a role-input filename, is the stable subject.
|
|
240
240
|
// Different roots remain isolated without inventing a filename convention.
|
|
241
241
|
return subjectRoot;
|
|
242
242
|
}
|
|
@@ -26,7 +26,6 @@ import type { PublicSummonResult } from "./public-role-summons.ts";
|
|
|
26
26
|
import { CliUsageError } from "./public-cli/cli-errors.ts";
|
|
27
27
|
import { isNavigatorSeat } from "./packaged-role-registry.ts";
|
|
28
28
|
import {
|
|
29
|
-
attachWorkContextPointer,
|
|
30
29
|
navigatorWorkContextFile,
|
|
31
30
|
} from "./navigator-work-base.ts";
|
|
32
31
|
|
|
@@ -157,19 +156,24 @@ export function createNativeNavigatorSessionFactory(deps?: {
|
|
|
157
156
|
// (ADR 0018 / #959 — legal HostContext may omit signal).
|
|
158
157
|
if (disposed) return;
|
|
159
158
|
const resumeRunId = hostRunId;
|
|
159
|
+
// Prompt stays caller/summoner bytes (#1166). Nest work-context path is an
|
|
160
|
+
// internal locator for startup materials only — never folded into argv,
|
|
161
|
+
// never written onto shared parent process.env across await.
|
|
160
162
|
const workContextPath = navigatorWorkContextFile(sessionManager.getSessionDir());
|
|
161
|
-
const
|
|
162
|
-
?
|
|
163
|
-
: text;
|
|
163
|
+
const workContextLocator =
|
|
164
|
+
existsSync(workContextPath) ? workContextPath : undefined;
|
|
164
165
|
|
|
165
166
|
// Call contract only: forward shared-lifecycle signal; do not own AbortController here
|
|
166
167
|
// (ADR 0018 / #959 — cancel ownership stays on the attendance/envelope seam).
|
|
167
168
|
const baseSummon = {
|
|
168
169
|
role: "navigator" as const,
|
|
169
|
-
argv: [
|
|
170
|
+
argv: [text] as const,
|
|
170
171
|
cwd: context.cwd,
|
|
171
172
|
...(summonHome === undefined ? {} : { home: summonHome }),
|
|
172
173
|
...(context.signal === undefined ? {} : { signal: context.signal }),
|
|
174
|
+
...(workContextLocator === undefined
|
|
175
|
+
? {}
|
|
176
|
+
: { navigatorWorkContextPath: workContextLocator }),
|
|
173
177
|
};
|
|
174
178
|
|
|
175
179
|
// Prefer host CLI resume so prior advice stays on the host session.
|