@akagilnc/pi-workflow-roles 0.1.5583 → 0.1.5598
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 +2 -0
- package/README.zh-CN.md +2 -0
- package/dist/acp-host/production-host.js +393 -854
- package/dist/collector-config.js +0 -44
- package/dist/headless-host/production-host.js +361 -822
- package/dist/merger-contracts.js +6 -2
- package/dist/migrate-book-topology.js +4855 -10472
- package/dist/package-contracts/worker-output.js +1 -6
- package/dist/packaged-role-registry.js +5 -4
- package/dist/public-cli/instruction-seat-run.js +8 -8
- package/dist/public-cli/invocation.js +93 -236
- package/dist/public-cli/main.js +18409 -18786
- package/dist/public-cli/option-definitions.js +7 -7
- package/dist/public-cli/post-admission.js +11 -40
- package/dist/public-cli/run-lifecycle.js +11 -43
- package/dist/public-role-summons.js +1 -1
- package/dist/role-run-relocation.js +14 -23
- package/package.json +1 -1
- package/scripts/build-package.mjs +0 -1
- package/src/collector-config.ts +0 -42
- package/src/collector-role.ts +10 -20
- package/src/host-contracts.ts +0 -3
- package/src/merger-contracts.ts +6 -2
- package/src/merger-role.ts +11 -1
- package/src/navigator-attendance.ts +2 -2
- package/src/package-contracts/worker-output.ts +0 -8
- package/src/packaged-role-registry.ts +4 -3
- package/src/public-cli/instruction-seat-run.ts +7 -8
- package/src/public-cli/invocation.ts +113 -351
- package/src/public-cli/option-definitions.ts +7 -7
- package/src/public-cli/post-admission.ts +12 -56
- package/src/public-cli/run-lifecycle.ts +11 -55
- package/src/public-role-summons.ts +1 -1
- package/src/role-run-placement.ts +0 -1
- package/src/role-run-relocation.ts +14 -25
- package/src/role-runtime-dependencies.ts +0 -2
- package/src/role-runtime.ts +0 -16
- package/src/worker-role.ts +11 -78
- package/dist/package-contracts/fixer-packet.js +0 -77
- package/packets/fixer-prerequisites.json +0 -6
- package/src/package-contracts/fixer-packet.ts +0 -91
|
@@ -261,7 +261,7 @@ const SHARED_PROJECT_SEMANTICS = {
|
|
|
261
261
|
},
|
|
262
262
|
};
|
|
263
263
|
/**
|
|
264
|
-
* Immutable shared semantics for the common
|
|
264
|
+
* Immutable shared semantics for the common `--attach` face (#1165).
|
|
265
265
|
* Role rows bind owner only. Reviewer has no attach face; analyst sweep attach
|
|
266
266
|
* keeps its own modes/selectsMode/description and must not use this binding.
|
|
267
267
|
*/
|
|
@@ -274,8 +274,8 @@ const SHARED_ATTACH_SEMANTICS = {
|
|
|
274
274
|
repeatable: true,
|
|
275
275
|
form: "option",
|
|
276
276
|
description: {
|
|
277
|
-
en: "
|
|
278
|
-
zh: "
|
|
277
|
+
en: "Caller file path passed as-is to the role (repeatable). Package does not read, copy, or validate; use an absolute path when cwd differs from --project.",
|
|
278
|
+
zh: "调用方文件路径原样递给衙门(可重复)。包不读、不复制、不校验;调用方当前目录与 --project 不同时请给绝对路径。",
|
|
279
279
|
},
|
|
280
280
|
};
|
|
281
281
|
/** Minimal owner-binding: one immutable semantic row → one role table entry. */
|
|
@@ -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
|
];
|
|
@@ -461,8 +461,8 @@ const COLLECTOR_OPTIONS = [
|
|
|
461
461
|
repeatable: false,
|
|
462
462
|
form: "option",
|
|
463
463
|
description: {
|
|
464
|
-
en: "
|
|
465
|
-
zh: "
|
|
464
|
+
en: "Caller path to a request manifest JSON file, passed as-is. Package does not read, copy, or validate; use an absolute path when cwd differs from --project.",
|
|
465
|
+
zh: "调用方 request manifest JSON 路径,原样传递。包不读、不复制、不校验;调用方当前目录与 --project 不同时请给绝对路径。",
|
|
466
466
|
},
|
|
467
467
|
},
|
|
468
468
|
];
|
|
@@ -7,14 +7,12 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
9
|
import { writeFile } from "node:fs/promises";
|
|
10
|
-
import { isAbsolute, join, resolve } from "node:path";
|
|
11
10
|
import { buildAutoResumeContinuationPrompt, findRunDirectoryById, readRoleRunState, RESUME_TRANSPORT_ENVELOPE, } from "./run-lifecycle.js";
|
|
12
11
|
import { CliUsageError } from "./cli-errors.js";
|
|
13
12
|
import { projectPublicTurnAxes } from "./turn-request.js";
|
|
14
|
-
import { bindAdmittedTicketNumber, buildInstructionTransportPrompt,
|
|
13
|
+
import { bindAdmittedTicketNumber, buildInstructionTransportPrompt, relocateAdmittedRunToTicket, } from "./invocation.js";
|
|
15
14
|
import { readRecordedSubmissionRows } from "../submission-ledger.js";
|
|
16
15
|
import { parseTicketNumber, readDeclaredTicketNumber } from "../run-ticket-number.js";
|
|
17
|
-
import { pathContainedIn } from "../activation-ledger-topology.js";
|
|
18
16
|
import { readStoredHostSessionId } from "../session-identity.js";
|
|
19
17
|
import { reportRunRecord } from "../sitian-facade.js";
|
|
20
18
|
import { createReceiptDeliveryPolicy, deliveryLimitFromConfig, } from "../receipt-delivery-policy.js";
|
|
@@ -51,11 +49,12 @@ function projectRelocatedTurnIdentity(request, result, admitted, relocation) {
|
|
|
51
49
|
mutableRequest.principal = admitted.principal;
|
|
52
50
|
const activation = mutableRequest.activation;
|
|
53
51
|
if (isRecord(activation)) {
|
|
54
|
-
for (const field of ["
|
|
52
|
+
for (const field of ["inputPath"]) {
|
|
55
53
|
const record = activation;
|
|
56
54
|
if (field in record)
|
|
57
55
|
record[field] = rewrite(record[field]);
|
|
58
56
|
}
|
|
57
|
+
// #1165/#1168: caller file-flag paths are not activation fields to rewrite.
|
|
59
58
|
}
|
|
60
59
|
if (result.terminal !== undefined) {
|
|
61
60
|
for (const artifact of result.terminal.artifacts) {
|
|
@@ -925,7 +924,7 @@ export function resumeTurnRequestProjectionOptions(admitted, request, env, summo
|
|
|
925
924
|
if (request.message !== undefined) {
|
|
926
925
|
if (summonsPrepared !== undefined) {
|
|
927
926
|
// #755: same-ticket review / open-court — caller words.
|
|
928
|
-
// #879 station-child officer: words only (
|
|
927
|
+
// #879 station-child officer: words only (paths remain on summons materials).
|
|
929
928
|
prompt = officerDialogue
|
|
930
929
|
? request.message
|
|
931
930
|
: buildInstructionTransportPrompt({
|
|
@@ -945,8 +944,10 @@ export function resumeTurnRequestProjectionOptions(admitted, request, env, summo
|
|
|
945
944
|
else if (summonsPrepared !== undefined) {
|
|
946
945
|
// #879 station-child officer: instruction bytes === peer body/reask (no wrap).
|
|
947
946
|
// Other seats keep #755 instruction + optional attachment path listing.
|
|
947
|
+
// #1165 J3: officer dialogue is raw instruction bytes; do not gate on
|
|
948
|
+
// instructionEmpty metadata (resume of older admitted pages).
|
|
948
949
|
prompt = officerDialogue
|
|
949
|
-
?
|
|
950
|
+
? summonsPrepared.instruction
|
|
950
951
|
: buildInstructionTransportPrompt(summonsPrepared);
|
|
951
952
|
}
|
|
952
953
|
else if (request.summons !== undefined) {
|
|
@@ -1046,34 +1047,18 @@ async function runSettledAutoResumeLoop(input) {
|
|
|
1046
1047
|
}),
|
|
1047
1048
|
});
|
|
1048
1049
|
}
|
|
1049
|
-
function isAlreadyFrozenSummonsAttachment(runDirectory, attachmentPath) {
|
|
1050
|
-
const absolute = isAbsolute(attachmentPath)
|
|
1051
|
-
? attachmentPath
|
|
1052
|
-
: resolve(attachmentPath);
|
|
1053
|
-
return pathContainedIn(join(runDirectory, "attachments"), absolute);
|
|
1054
|
-
}
|
|
1055
1050
|
/**
|
|
1056
|
-
*
|
|
1057
|
-
* No-op materials (no paths / instruction-only) skip the freeze.
|
|
1058
|
-
* Paths already under this run's attachments/ are the accepted freeze identity —
|
|
1059
|
-
* reuse them for the same internal re-summons flow.
|
|
1060
|
-
* Manual resume never calls this — old attachment semantics stay intact.
|
|
1051
|
+
* Same-ticket summons materials: caller paths as-is (#1165). No copy or freeze.
|
|
1061
1052
|
*/
|
|
1062
|
-
export async function prepareSummonsResumeMaterials(
|
|
1053
|
+
export async function prepareSummonsResumeMaterials(_runDirectory, summons) {
|
|
1063
1054
|
if (summons === undefined)
|
|
1064
1055
|
return undefined;
|
|
1065
1056
|
if (summons.instruction === undefined && (summons.attachmentPaths?.length ?? 0) === 0) {
|
|
1066
1057
|
return undefined;
|
|
1067
1058
|
}
|
|
1068
1059
|
const instruction = summons.instruction ?? "";
|
|
1069
|
-
const instructionEmpty = summons.instructionEmpty ?? instruction.
|
|
1070
|
-
|
|
1071
|
-
if (summons.attachmentPaths !== undefined && summons.attachmentPaths.length > 0) {
|
|
1072
|
-
const alreadyFrozen = summons.attachmentPaths.every((path) => isAlreadyFrozenSummonsAttachment(runDirectory, path));
|
|
1073
|
-
attachments = alreadyFrozen
|
|
1074
|
-
? summons.attachmentPaths.map((frozenPath) => ({ frozenPath }))
|
|
1075
|
-
: await freezeAttachmentsIntoRun(summons.attachmentPaths, runDirectory);
|
|
1076
|
-
}
|
|
1060
|
+
const instructionEmpty = summons.instructionEmpty ?? instruction.length === 0;
|
|
1061
|
+
const attachments = (summons.attachmentPaths ?? []).map((path) => ({ path }));
|
|
1077
1062
|
return { instruction, instructionEmpty, attachments };
|
|
1078
1063
|
}
|
|
1079
1064
|
/**
|
|
@@ -1137,20 +1122,6 @@ export async function runPostAdmissionSeatResume(input) {
|
|
|
1137
1122
|
openCourtAttemptId = openCourt.courtAttemptId;
|
|
1138
1123
|
}
|
|
1139
1124
|
}
|
|
1140
|
-
// Internal re-summons freezes external paths once and records that identity.
|
|
1141
|
-
if (request.summons !== undefined) {
|
|
1142
|
-
const prepared = await prepareSummonsResumeMaterials(admittedForBuild.runDirectory, request.summons);
|
|
1143
|
-
if (prepared !== undefined &&
|
|
1144
|
-
(request.summons.attachmentPaths?.length ?? 0) > 0) {
|
|
1145
|
-
request = {
|
|
1146
|
-
...request,
|
|
1147
|
-
summons: {
|
|
1148
|
-
...request.summons,
|
|
1149
|
-
attachmentPaths: prepared.attachments.map((attachment) => attachment.frozenPath),
|
|
1150
|
-
},
|
|
1151
|
-
};
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
1125
|
// Public explicit resume: attach the stored native id when the caller
|
|
1155
1126
|
// left it unset (399c3c8c). In-call auto-resume / 催交 / gate retry omit
|
|
1156
1127
|
// the field; those load inside the host adapter (host-contracts).
|
|
@@ -14,7 +14,7 @@ import { CliUsageError } from "./cli-errors.js";
|
|
|
14
14
|
import { parseCollectorRepository } from "../collector-config.js";
|
|
15
15
|
import { retainedRunPathsMatch, rewriteAdmittedRoleRunPage, rewriteRunDirectoryPathValue, } from "../role-run-relocation.js";
|
|
16
16
|
import { packagedResumeSourcePath, packagedRoleMetadata, } from "../packaged-role-registry.js";
|
|
17
|
-
import { admittedReviewerBaseFault, recordEffectiveInvocationModel, requireAuthorityRef, isReviewerLens, } from "./invocation.js";
|
|
17
|
+
import { admittedReviewerBaseFault, recordEffectiveInvocationModel, requireAuthorityRef, isReviewerLens, normalizeAdmittedAttachment, } from "./invocation.js";
|
|
18
18
|
import { readPageSync, writeSectionSync } from "../run-dossier.js";
|
|
19
19
|
import { isRecord, errorText, isEnoent } from "../unknown-value.js";
|
|
20
20
|
/** Default for the #422 configurable single-call auto-resume ceiling
|
|
@@ -51,7 +51,7 @@ function parseSameTicketSummonsMaterials(raw) {
|
|
|
51
51
|
const instruction = typeof record.instruction === "string" ? record.instruction : undefined;
|
|
52
52
|
const instructionEmpty = typeof record.instructionEmpty === "boolean" ? record.instructionEmpty : undefined;
|
|
53
53
|
const attachmentPaths = Array.isArray(record.attachmentPaths)
|
|
54
|
-
? record.attachmentPaths.filter((p) => typeof p === "string"
|
|
54
|
+
? record.attachmentPaths.filter((p) => typeof p === "string")
|
|
55
55
|
: undefined;
|
|
56
56
|
const sourceRunPath = typeof record.sourceRunPath === "string" && record.sourceRunPath.trim() !== ""
|
|
57
57
|
? record.sourceRunPath
|
|
@@ -766,10 +766,7 @@ async function loadResumableRunRecord(home, runId, authority) {
|
|
|
766
766
|
let instructionEmpty = true;
|
|
767
767
|
let attachments = [];
|
|
768
768
|
let phase;
|
|
769
|
-
let taskPath;
|
|
770
|
-
let packetPath;
|
|
771
769
|
let prerequisitesPath;
|
|
772
|
-
let prerequisites;
|
|
773
770
|
let baseRevision;
|
|
774
771
|
let lens;
|
|
775
772
|
let authorityRefs;
|
|
@@ -781,7 +778,6 @@ async function loadResumableRunRecord(home, runId, authority) {
|
|
|
781
778
|
let repository;
|
|
782
779
|
let repositoryDisplay;
|
|
783
780
|
let requestManifestPath;
|
|
784
|
-
let manifestDigest;
|
|
785
781
|
let waitWindowMs;
|
|
786
782
|
let issueNumber;
|
|
787
783
|
let caseRunsPath;
|
|
@@ -807,24 +803,17 @@ async function loadResumableRunRecord(home, runId, authority) {
|
|
|
807
803
|
instructionEmpty = record.instructionEmpty;
|
|
808
804
|
}
|
|
809
805
|
if (Array.isArray(record.attachments)) {
|
|
810
|
-
attachments = record.attachments
|
|
806
|
+
attachments = record.attachments
|
|
807
|
+
.map((item) => normalizeAdmittedAttachment(item))
|
|
808
|
+
.filter((item) => item !== undefined);
|
|
811
809
|
}
|
|
812
810
|
if (record.phase === "plan" || record.phase === "apply") {
|
|
813
811
|
phase = record.phase;
|
|
814
812
|
}
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
}
|
|
818
|
-
if (typeof record.packetPath === "string" && record.packetPath.trim() !== "") {
|
|
819
|
-
packetPath = record.packetPath;
|
|
820
|
-
}
|
|
821
|
-
if (typeof record.prerequisitesPath === "string" &&
|
|
822
|
-
record.prerequisitesPath.trim() !== "") {
|
|
813
|
+
// #1168: opaque caller path on resume — do not trim-filter provided values.
|
|
814
|
+
if (typeof record.prerequisitesPath === "string") {
|
|
823
815
|
prerequisitesPath = record.prerequisitesPath;
|
|
824
816
|
}
|
|
825
|
-
if (Array.isArray(record.prerequisites)) {
|
|
826
|
-
prerequisites = record.prerequisites;
|
|
827
|
-
}
|
|
828
817
|
if (typeof record.baseRevision === "string" &&
|
|
829
818
|
record.baseRevision.trim() !== "") {
|
|
830
819
|
baseRevision = record.baseRevision;
|
|
@@ -842,12 +831,10 @@ async function loadResumableRunRecord(home, runId, authority) {
|
|
|
842
831
|
if (typeof record.repositoryDisplay === "string" && record.repositoryDisplay.trim() !== "") {
|
|
843
832
|
repositoryDisplay = record.repositoryDisplay;
|
|
844
833
|
}
|
|
845
|
-
|
|
834
|
+
// #1165: opaque caller path on resume — do not trim-filter provided values.
|
|
835
|
+
if (typeof record.requestManifestPath === "string") {
|
|
846
836
|
requestManifestPath = record.requestManifestPath;
|
|
847
837
|
}
|
|
848
|
-
if (typeof record.manifestDigest === "string" && record.manifestDigest.trim() !== "") {
|
|
849
|
-
manifestDigest = record.manifestDigest;
|
|
850
|
-
}
|
|
851
838
|
if (typeof record.waitWindowMs === "number" && Number.isSafeInteger(record.waitWindowMs) && record.waitWindowMs >= 1) {
|
|
852
839
|
waitWindowMs = record.waitWindowMs;
|
|
853
840
|
}
|
|
@@ -975,10 +962,7 @@ async function loadResumableRunRecord(home, runId, authority) {
|
|
|
975
962
|
instructionEmpty,
|
|
976
963
|
attachments,
|
|
977
964
|
...(phase === undefined ? {} : { phase }),
|
|
978
|
-
...(taskPath === undefined ? {} : { taskPath }),
|
|
979
|
-
...(packetPath === undefined ? {} : { packetPath }),
|
|
980
965
|
...(prerequisitesPath === undefined ? {} : { prerequisitesPath }),
|
|
981
|
-
...(prerequisites === undefined ? {} : { prerequisites }),
|
|
982
966
|
...(baseRevision === undefined ? {} : { baseRevision }),
|
|
983
967
|
...(lens === undefined ? {} : { lens }),
|
|
984
968
|
...(authorityRefs === undefined ? {} : { authorityRefs }),
|
|
@@ -990,7 +974,6 @@ async function loadResumableRunRecord(home, runId, authority) {
|
|
|
990
974
|
...(repository === undefined ? {} : { repository }),
|
|
991
975
|
...(repositoryDisplay === undefined ? {} : { repositoryDisplay }),
|
|
992
976
|
...(requestManifestPath === undefined ? {} : { requestManifestPath }),
|
|
993
|
-
...(manifestDigest === undefined ? {} : { manifestDigest }),
|
|
994
977
|
...(waitWindowMs === undefined ? {} : { waitWindowMs }),
|
|
995
978
|
...(issueNumber === undefined ? {} : { issueNumber }),
|
|
996
979
|
...(caseRunsPath === undefined ? {} : { caseRunsPath }),
|
|
@@ -1081,10 +1064,6 @@ function admitResumedRole(loaded) {
|
|
|
1081
1064
|
}
|
|
1082
1065
|
case "worker-task": {
|
|
1083
1066
|
const phase = resumedWorkerPhase(fields.phase ?? loaded.run.phase, record.phases, role, runId);
|
|
1084
|
-
const taskPath = fields.taskPath;
|
|
1085
|
-
if (taskPath === undefined) {
|
|
1086
|
-
throw new CliUsageError(`role run admitted coder task path is missing: ${runId}`);
|
|
1087
|
-
}
|
|
1088
1067
|
if (fields.instruction.trim() === "") {
|
|
1089
1068
|
throw new CliUsageError(`role run admitted coder task is blank: ${runId}`);
|
|
1090
1069
|
}
|
|
@@ -1093,30 +1072,22 @@ function admitResumedRole(loaded) {
|
|
|
1093
1072
|
phase,
|
|
1094
1073
|
...base,
|
|
1095
1074
|
instructionEmpty: false,
|
|
1096
|
-
taskPath,
|
|
1097
1075
|
};
|
|
1098
1076
|
return admitted;
|
|
1099
1077
|
}
|
|
1100
1078
|
case "worker-packet": {
|
|
1101
1079
|
const phase = resumedWorkerPhase(fields.phase ?? loaded.run.phase, record.phases, role, runId);
|
|
1102
|
-
const packetPath = fields.packetPath;
|
|
1103
|
-
if (packetPath === undefined) {
|
|
1104
|
-
throw new CliUsageError(`role run admitted fixer packet path is missing: ${runId}`);
|
|
1105
|
-
}
|
|
1106
1080
|
if (fields.instruction.trim() === "") {
|
|
1107
1081
|
throw new CliUsageError(`role run admitted fixer instruction is blank: ${runId}`);
|
|
1108
1082
|
}
|
|
1109
|
-
const prerequisites = fields.prerequisites ?? Object.freeze([]);
|
|
1110
1083
|
const admitted = {
|
|
1111
1084
|
role: "fixer",
|
|
1112
1085
|
phase,
|
|
1113
1086
|
...base,
|
|
1114
1087
|
instructionEmpty: false,
|
|
1115
|
-
packetPath,
|
|
1116
1088
|
...(fields.prerequisitesPath === undefined
|
|
1117
1089
|
? {}
|
|
1118
1090
|
: { prerequisitesPath: fields.prerequisitesPath }),
|
|
1119
|
-
prerequisites,
|
|
1120
1091
|
};
|
|
1121
1092
|
return admitted;
|
|
1122
1093
|
}
|
|
@@ -1179,10 +1150,8 @@ function admitResumedRole(loaded) {
|
|
|
1179
1150
|
return admitted;
|
|
1180
1151
|
}
|
|
1181
1152
|
case "collect-target": {
|
|
1182
|
-
const { prNumber, repository, repositoryDisplay
|
|
1183
|
-
if (repository === undefined ||
|
|
1184
|
-
repositoryDisplay === undefined ||
|
|
1185
|
-
manifestDigest === undefined) {
|
|
1153
|
+
const { prNumber, repository, repositoryDisplay } = fields;
|
|
1154
|
+
if (repository === undefined || repositoryDisplay === undefined) {
|
|
1186
1155
|
throw new CliUsageError(`role run admitted collector repository identity is missing: ${runId}`);
|
|
1187
1156
|
}
|
|
1188
1157
|
let parsedRepository;
|
|
@@ -1205,7 +1174,6 @@ function admitResumedRole(loaded) {
|
|
|
1205
1174
|
? {}
|
|
1206
1175
|
: { requestManifestPath: fields.requestManifestPath }),
|
|
1207
1176
|
...(fields.waitWindowMs === undefined ? {} : { waitWindowMs: fields.waitWindowMs }),
|
|
1208
|
-
manifestDigest,
|
|
1209
1177
|
};
|
|
1210
1178
|
return admitted;
|
|
1211
1179
|
}
|
|
@@ -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
|
-
"requestManifestPath",
|
|
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
|
];
|
|
@@ -150,28 +149,19 @@ function rewriteSourceRunLocator(value, rewrites) {
|
|
|
150
149
|
return;
|
|
151
150
|
rewriteRunDirectoryPathFieldsAgainstRewrites(value, SOURCE_RUN_LOCATOR_FIELDS, rewrites);
|
|
152
151
|
}
|
|
153
|
-
/** Same-ticket summons materials: typed source-run
|
|
152
|
+
/** Same-ticket summons materials: typed source-run; caller attach paths stay as-is (#1165). */
|
|
154
153
|
function rewriteSummonsMaterials(value, rewrites) {
|
|
155
154
|
if (!isRecord(value))
|
|
156
155
|
return;
|
|
157
156
|
rewriteRunDirectoryPathFieldsAgainstRewrites(value, SUMMONS_PATH_FIELDS, rewrites);
|
|
158
157
|
rewriteSourceRunLocator(value.sourceRun, rewrites);
|
|
159
|
-
//
|
|
160
|
-
if (Array.isArray(value.attachmentPaths)) {
|
|
161
|
-
value.attachmentPaths = value.attachmentPaths.map((path) => rewriteRunDirectoryPathValueAgainstRewrites(path, rewrites));
|
|
162
|
-
}
|
|
158
|
+
// #1165: summons.attachmentPaths are caller paths — do not rewrite.
|
|
163
159
|
}
|
|
164
160
|
/** Project one admitted page in memory after its containing run moved. */
|
|
165
161
|
export function rewriteAdmittedRoleRunPage(page, rewrites) {
|
|
166
162
|
rewriteRunDirectoryPathFieldsAgainstRewrites(page, ADMITTED_PAGE_FIELDS, rewrites);
|
|
167
163
|
rewriteSourceRunLocator(page.sourceRun, rewrites);
|
|
168
|
-
|
|
169
|
-
for (const attachment of page.attachments) {
|
|
170
|
-
if (isRecord(attachment)) {
|
|
171
|
-
rewriteRunDirectoryPathFieldsAgainstRewrites(attachment, ["frozenPath"], rewrites);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
164
|
+
// #1165: admitted attachments are caller paths outside the run directory — do not rewrite.
|
|
175
165
|
if (isRecord(page.principal)) {
|
|
176
166
|
rewriteRunDirectoryPathFieldsAgainstRewrites(page.principal, ["sessionDirectory", "sessionFile"], rewrites);
|
|
177
167
|
}
|
|
@@ -347,12 +337,13 @@ async function rewriteNestedMachinePathPages(pagesDirectory, rewrites) {
|
|
|
347
337
|
await walk(sessionRoot);
|
|
348
338
|
}
|
|
349
339
|
/**
|
|
350
|
-
* Rewrite the admitted / invocation / runState fact rows (
|
|
351
|
-
*
|
|
352
|
-
* session seams. Callers may rewrite before or after
|
|
353
|
-
* `pagesDirectory` is where the pages currently live
|
|
354
|
-
* still name `oldRunDirectory` become
|
|
355
|
-
* covers officer/parent pointers that
|
|
340
|
+
* Rewrite the admitted / invocation / runState fact rows (typed run placement
|
|
341
|
+
* paths only; caller --attach / --request-manifest paths stay as-is, #1165),
|
|
342
|
+
* then nested package-owned session seams. Callers may rewrite before or after
|
|
343
|
+
* the filesystem move/copy: `pagesDirectory` is where the pages currently live
|
|
344
|
+
* on disk; path strings that still name `oldRunDirectory` become
|
|
345
|
+
* `newRunDirectory`. `crossRunRewrites` covers officer/parent pointers that
|
|
346
|
+
* landed under a different final placement.
|
|
356
347
|
*/
|
|
357
348
|
export async function rewriteRoleRunDurablePages(input) {
|
|
358
349
|
const { pagesDirectory } = input;
|
|
@@ -366,7 +357,7 @@ export async function rewriteRoleRunDurablePages(input) {
|
|
|
366
357
|
if (isRecord(page.principal)) {
|
|
367
358
|
rewriteRunDirectoryPathFieldsAgainstRewrites(page.principal, ["sessionDirectory", "sessionFile"], rewrites);
|
|
368
359
|
}
|
|
369
|
-
// Open court summons: source-run locators
|
|
360
|
+
// Open court summons: source-run locators only; caller attach paths stay (#1165).
|
|
370
361
|
if (isRecord(page.currentCourt)) {
|
|
371
362
|
rewriteSummonsMaterials(page.currentCourt.summons, rewrites);
|
|
372
363
|
}
|
package/package.json
CHANGED
|
@@ -55,7 +55,6 @@ const entries = [
|
|
|
55
55
|
"open-tool-schema",
|
|
56
56
|
"package-contracts/collector-output",
|
|
57
57
|
"package-contracts/fixer-output",
|
|
58
|
-
"package-contracts/fixer-packet",
|
|
59
58
|
"package-contracts/gatekeeper-output",
|
|
60
59
|
"package-contracts/judge-output",
|
|
61
60
|
"package-contracts/navigator-output",
|
package/src/collector-config.ts
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
|
|
3
|
-
import { sha256Hex } from "./sha256.ts";
|
|
4
|
-
import { isRecord } from "./unknown-value.ts";
|
|
5
1
|
import { isTicketNumberString, parseTicketNumber } from "./run-ticket-number.ts";
|
|
6
2
|
|
|
7
3
|
export const COLLECTOR_OWNER_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/;
|
|
@@ -14,14 +10,6 @@ export type CollectorRepository = {
|
|
|
14
10
|
repo: string;
|
|
15
11
|
};
|
|
16
12
|
|
|
17
|
-
export type CollectorRequestConfig = { id: string; requestBody: string };
|
|
18
|
-
export type CollectorManifest = {
|
|
19
|
-
requests: readonly CollectorRequestConfig[];
|
|
20
|
-
canonicalJson: string;
|
|
21
|
-
digest: string;
|
|
22
|
-
sourcePath?: string;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
13
|
function fail(message: string, cause?: unknown): never {
|
|
26
14
|
throw new Error(message, cause === undefined ? undefined : { cause });
|
|
27
15
|
}
|
|
@@ -54,33 +42,3 @@ export function parseCollectorPrNumber(raw: unknown): number {
|
|
|
54
42
|
: "Collector pull request number must be a positive safe integer");
|
|
55
43
|
return value;
|
|
56
44
|
}
|
|
57
|
-
|
|
58
|
-
function canonicalManifest(requests: readonly CollectorRequestConfig[]): string {
|
|
59
|
-
return `${JSON.stringify({ requests: requests.map((request) => ({ id: request.id, body: request.requestBody })) })}\n`;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function emptyCollectorManifest(): CollectorManifest {
|
|
63
|
-
const canonicalJson = canonicalManifest([]);
|
|
64
|
-
return { requests: [], canonicalJson, digest: sha256Hex(canonicalJson) };
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** Optional request configuration. It names requests, never expected observers. */
|
|
68
|
-
export async function loadCollectorManifest(path: string): Promise<CollectorManifest> {
|
|
69
|
-
let bytes: Buffer;
|
|
70
|
-
try { bytes = await readFile(path); } catch (error) { fail(`Collector request manifest is unreadable at ${path}`, error); }
|
|
71
|
-
let parsed: unknown;
|
|
72
|
-
try { parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes)); } catch (error) { fail("Collector request manifest must be UTF-8 JSON", error); }
|
|
73
|
-
if (!isRecord(parsed)) fail("Collector request manifest must be an object");
|
|
74
|
-
const rawRequests = parsed.requests ?? [];
|
|
75
|
-
if (!Array.isArray(rawRequests)) fail("Collector request manifest requests must be an array");
|
|
76
|
-
const requests: CollectorRequestConfig[] = [];
|
|
77
|
-
const ids = new Set<string>();
|
|
78
|
-
for (const [index, item] of rawRequests.entries()) {
|
|
79
|
-
if (!isRecord(item) || typeof item.id !== "string" || item.id.length === 0 || typeof item.body !== "string" || item.body.trim() === "") fail(`Collector request manifest requests[${index}] is invalid`);
|
|
80
|
-
if (ids.has(item.id)) fail(`Collector request manifest has duplicate request id "${item.id}"`);
|
|
81
|
-
ids.add(item.id);
|
|
82
|
-
requests.push({ id: item.id, requestBody: item.body });
|
|
83
|
-
}
|
|
84
|
-
const canonicalJson = canonicalManifest(requests);
|
|
85
|
-
return { requests, canonicalJson, digest: sha256Hex(canonicalJson), sourcePath: path };
|
|
86
|
-
}
|
package/src/collector-role.ts
CHANGED
|
@@ -2,17 +2,15 @@
|
|
|
2
2
|
* Collector business: soul/material assembly and sole submission tool.
|
|
3
3
|
* #1088: code no longer observes/requests/merges GitHub findings — the LLM
|
|
4
4
|
* uses host CLI tools. Envelope owns host-surface + construction seatbelt.
|
|
5
|
+
* #1165: --request-manifest is a caller path only; package does not load it.
|
|
5
6
|
*/
|
|
6
7
|
import type { RoleHost, HostContext } from "./host-contracts.ts";
|
|
7
8
|
import { registerFiledSubmissionTool } from "./filed-submission.ts";
|
|
8
9
|
import { roleSubmissionDeclaration } from "./role-submission-declarations.ts";
|
|
9
10
|
|
|
10
11
|
import {
|
|
11
|
-
emptyCollectorManifest,
|
|
12
|
-
loadCollectorManifest,
|
|
13
12
|
parseCollectorPrNumber,
|
|
14
13
|
parseCollectorRepository,
|
|
15
|
-
type CollectorManifest,
|
|
16
14
|
type CollectorRepository,
|
|
17
15
|
} from "./collector-config.ts";
|
|
18
16
|
import {
|
|
@@ -47,7 +45,7 @@ export const COLLECTOR_TRANSPORT_FLAGS = Object.freeze([
|
|
|
47
45
|
name: "ak-collector-request-manifest",
|
|
48
46
|
definition: Object.freeze({
|
|
49
47
|
description:
|
|
50
|
-
"
|
|
48
|
+
"Caller path to a request manifest JSON file (passed as-is; package does not read or validate).",
|
|
51
49
|
type: "string" as const,
|
|
52
50
|
}),
|
|
53
51
|
}),
|
|
@@ -62,7 +60,7 @@ export type CollectorActivation = {
|
|
|
62
60
|
soul: string;
|
|
63
61
|
repository: CollectorRepository;
|
|
64
62
|
prNumber: number | undefined;
|
|
65
|
-
|
|
63
|
+
requestManifestPath?: string;
|
|
66
64
|
};
|
|
67
65
|
|
|
68
66
|
function buildMethodContext(activation: CollectorActivation): string {
|
|
@@ -71,19 +69,11 @@ function buildMethodContext(activation: CollectorActivation): string {
|
|
|
71
69
|
`host: github.com`,
|
|
72
70
|
`repository: ${activation.repository.canonical}`,
|
|
73
71
|
`prNumber: ${activation.prNumber === undefined ? "未绑定" : String(activation.prNumber)}`,
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
...(activation.requestManifestPath === undefined
|
|
73
|
+
? []
|
|
74
|
+
: [`requestManifestPath: ${activation.requestManifestPath}`]),
|
|
76
75
|
"</collector_method>",
|
|
77
76
|
];
|
|
78
|
-
if (activation.manifest.requests.length > 0) {
|
|
79
|
-
const payload = JSON.stringify({
|
|
80
|
-
requests: activation.manifest.requests.map((request) => ({
|
|
81
|
-
id: request.id,
|
|
82
|
-
body: request.requestBody,
|
|
83
|
-
})),
|
|
84
|
-
}).replaceAll("<", "\\u003c");
|
|
85
|
-
lines.push("", "<collector_request_manifest>", payload, "</collector_request_manifest>");
|
|
86
|
-
}
|
|
87
77
|
return lines.join("\n");
|
|
88
78
|
}
|
|
89
79
|
|
|
@@ -123,15 +113,15 @@ export function createCollectorRoleRuntime(
|
|
|
123
113
|
} else if (typeof prFlag === "number") {
|
|
124
114
|
prNumber = parseCollectorPrNumber(prFlag);
|
|
125
115
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
:
|
|
116
|
+
// #1165: opaque caller path — keep spaces/"" when the flag was provided.
|
|
117
|
+
const requestManifestPath =
|
|
118
|
+
typeof requestManifestFlag === "string" ? requestManifestFlag : undefined;
|
|
129
119
|
|
|
130
120
|
return {
|
|
131
121
|
soul,
|
|
132
122
|
repository,
|
|
133
123
|
prNumber,
|
|
134
|
-
|
|
124
|
+
...(requestManifestPath === undefined ? {} : { requestManifestPath }),
|
|
135
125
|
};
|
|
136
126
|
},
|
|
137
127
|
|
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";
|
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
|
}
|