@akagilnc/pi-workflow-roles 0.1.5577 → 0.1.5593
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 +338 -617
- package/dist/collector-config.js +0 -44
- package/dist/headless-host/production-host.js +241 -520
- package/dist/migrate-book-topology.js +16 -32
- package/dist/package-resources/engine-material.js +22 -25
- package/dist/public-cli/instruction-seat-run.js +11 -21
- package/dist/public-cli/invocation.js +83 -193
- package/dist/public-cli/main.js +225 -528
- package/dist/public-cli/option-definitions.js +5 -5
- package/dist/public-cli/post-admission.js +12 -48
- package/dist/public-cli/run-lifecycle.js +13 -21
- package/dist/public-role-summons.js +1 -1
- package/dist/role-run-relocation.js +12 -20
- package/package.json +1 -1
- package/src/collector-config.ts +0 -42
- package/src/collector-role.ts +10 -20
- package/src/package-resources/engine-material.ts +42 -35
- package/src/public-cli/instruction-seat-run.ts +10 -27
- package/src/public-cli/invocation.ts +97 -292
- package/src/public-cli/option-definitions.ts +5 -5
- package/src/public-cli/post-admission.ts +13 -64
- package/src/public-cli/run-lifecycle.ts +13 -34
- package/src/public-role-summons.ts +1 -1
- package/src/role-run-placement.ts +0 -1
- package/src/role-run-relocation.ts +12 -22
- package/src/role-runtime.ts +18 -16
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Public Invocation request admission: optional opaque instruction,
|
|
3
|
-
*
|
|
2
|
+
* Public Invocation request admission: optional opaque instruction, caller
|
|
3
|
+
* attachment paths as-is, project default/override (ADR 0052 / #106 / #1165).
|
|
4
4
|
*/
|
|
5
5
|
import { execFileSync } from "node:child_process";
|
|
6
6
|
import { existsSync } from "node:fs";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { basename, dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
7
|
+
import { readFile, realpath, rename, writeFile, } from "node:fs/promises";
|
|
8
|
+
import { dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
10
9
|
import { activationBookDirectory, ensureRealDirectoryTree, homeFromRunDirectory, pathContainedIn, resolveActivationLedgerHome, } from "../activation-ledger-topology.js";
|
|
11
10
|
import { resolveBookKeyFromGit } from "../activation-ledger-git.js";
|
|
12
11
|
import { ensureRoleRunDirectory, ensureRoleRunPlacement, formatRunLeaf, isUnboundRunDirectory, listBookRunDirectories, roleRunPlacement, } from "../role-run-placement.js";
|
|
13
12
|
import { packagedAdmittedSubject, packagedArgvResult, packagedBareToken, packagedBaseIsRevision, packagedEmitsAuthorityRefs, packagedPublicInstructionSubject, packagedRoleMetadata, packagedStoresSourceRunRaw, packagedSubjectChoices, } from "../packaged-role-registry.js";
|
|
14
13
|
import { isSafePositiveTicketNumber, parseTicketNumber, readBoardTicketNumber, requireSafePositiveTicketNumber, } from "../run-ticket-number.js";
|
|
15
|
-
import { rewriteRunDirectoryPathFields,
|
|
14
|
+
import { rewriteRunDirectoryPathFields, } from "../role-run-relocation.js";
|
|
16
15
|
import { readPageSync, renderCurrentSync, updateSectionSync, writeSectionSync } from "../run-dossier.js";
|
|
17
16
|
import { loadDoctorCase, } from "../doctor-evidence.js";
|
|
18
|
-
import {
|
|
17
|
+
import { parseCollectorPrNumber, parseCollectorRepository, } from "../collector-config.js";
|
|
19
18
|
import { ownerRepoFromGitHubRemoteUrl } from "./github-remote.js";
|
|
20
19
|
import { FixerPacketValidationError, parseFixerPrerequisites, } from "../package-contracts/fixer-packet.js";
|
|
21
20
|
import { createProductionMergerGitState } from "../merger-git-state.js";
|
|
@@ -25,10 +24,23 @@ import { rehomeUnboundTicketProvenance } from "../ticket-provenance.js";
|
|
|
25
24
|
import { uuidv7 } from "../uuidv7.js";
|
|
26
25
|
import {} from "../notary-contracts.js";
|
|
27
26
|
import { NotarySourceRunError, resolveNotarySourceRunLocator, } from "../notary-source-run.js";
|
|
28
|
-
import { appendEngineSessionMaterial, } from "../package-resources/engine-material.js";
|
|
29
27
|
import { CliUsageError } from "./cli-errors.js";
|
|
30
28
|
import { REJECTED_PUBLIC_SPELLINGS, createTypedOptionConsumer, evaluateAnalystModeOptionContract, optionsForOwner, resolveAnalystMode, } from "./option-definitions.js";
|
|
31
29
|
import { errorText, isRecord } from "../unknown-value.js";
|
|
30
|
+
/** Normalize admitted attachment records (caller path only; #1165). */
|
|
31
|
+
export function normalizeAdmittedAttachment(raw) {
|
|
32
|
+
if (typeof raw !== "object" || raw === null)
|
|
33
|
+
return undefined;
|
|
34
|
+
const record = raw;
|
|
35
|
+
const path = record.path;
|
|
36
|
+
// Opaque caller path — keep "" / whitespace; only a non-string is absent.
|
|
37
|
+
if (typeof path === "string")
|
|
38
|
+
return { path };
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
function admitCallerAttachments(attachmentPaths) {
|
|
42
|
+
return attachmentPaths.map((path) => ({ path }));
|
|
43
|
+
}
|
|
32
44
|
/** Issue a principal from the single authoritative role-run placement. */
|
|
33
45
|
export function issueAdmissionPlacement(authority, request) {
|
|
34
46
|
const ledgerHome = resolveActivationLedgerHome(request.home);
|
|
@@ -262,12 +274,9 @@ export async function relocateAdmittedRunToTicket(admitted, authority, heldLease
|
|
|
262
274
|
"taskPath",
|
|
263
275
|
"packetPath",
|
|
264
276
|
"prerequisitesPath",
|
|
265
|
-
"requestManifestPath",
|
|
266
277
|
"mergerInputPath",
|
|
267
278
|
], oldRunDirectory, target.runDirectory);
|
|
268
|
-
|
|
269
|
-
attachment.frozenPath = rewriteRunDirectoryPathValue(attachment.frozenPath, oldRunDirectory, target.runDirectory);
|
|
270
|
-
}
|
|
279
|
+
// #1165: caller --attach / --request-manifest paths stay as given; do not rewrite.
|
|
271
280
|
admitted.principal = principal;
|
|
272
281
|
// current.json projects host.original from this run directory. Ownership is
|
|
273
282
|
// already transferred; a refuse still carries the true cause to the caller
|
|
@@ -383,7 +392,8 @@ function assignPublicSeatOption(owner, taken, fields) {
|
|
|
383
392
|
const value = taken.value;
|
|
384
393
|
switch (taken.def.id) {
|
|
385
394
|
case "attach":
|
|
386
|
-
|
|
395
|
+
// #1165: file-flag values are opaque; only a missing argument is a usage error.
|
|
396
|
+
fields.attachmentPaths.push(requireProvidedOptionValue(taken.def.canonical, value));
|
|
387
397
|
return;
|
|
388
398
|
case "project":
|
|
389
399
|
fields.project = requireOptionPath(taken.def.canonical, value);
|
|
@@ -427,7 +437,8 @@ function assignPublicSeatOption(owner, taken, fields) {
|
|
|
427
437
|
fields.repo = parseRepoOption(value);
|
|
428
438
|
return;
|
|
429
439
|
case "request-manifest":
|
|
430
|
-
|
|
440
|
+
// #1165: file-flag values are opaque; only a missing argument is a usage error.
|
|
441
|
+
fields.requestManifestPath = requireProvidedOptionValue(taken.def.canonical, value);
|
|
431
442
|
return;
|
|
432
443
|
case "issue": {
|
|
433
444
|
if (value === undefined || value.trim() === "") {
|
|
@@ -540,6 +551,16 @@ function requireOptionPath(flag, value) {
|
|
|
540
551
|
}
|
|
541
552
|
return value;
|
|
542
553
|
}
|
|
554
|
+
/**
|
|
555
|
+
* #1165 file flags (--attach / --request-manifest): keep the provided string
|
|
556
|
+
* opaque (including spaces and ""). Only a missing argument is a usage error.
|
|
557
|
+
*/
|
|
558
|
+
function requireProvidedOptionValue(flag, value) {
|
|
559
|
+
if (value === undefined) {
|
|
560
|
+
throw new CliUsageError(`${flag} requires a path`);
|
|
561
|
+
}
|
|
562
|
+
return value;
|
|
563
|
+
}
|
|
543
564
|
/**
|
|
544
565
|
* Shared Skill-arg token rule for caller-controlled values projected into the
|
|
545
566
|
* space-joined Skill invocation line. Rejects blank, whitespace (smuggles the
|
|
@@ -625,123 +646,6 @@ export function requireAuthorityRef(value) {
|
|
|
625
646
|
optionLike: "--authority-ref requires a durable reference, not inline Spec prose",
|
|
626
647
|
});
|
|
627
648
|
}
|
|
628
|
-
async function readRegularFileAttachment(sourcePath) {
|
|
629
|
-
const absolute = isAbsolute(sourcePath) ? sourcePath : resolve(sourcePath);
|
|
630
|
-
let st;
|
|
631
|
-
try {
|
|
632
|
-
st = await lstat(absolute);
|
|
633
|
-
}
|
|
634
|
-
catch (error) {
|
|
635
|
-
throw new CliUsageError(`attachment is not a readable regular file: ${sourcePath}`, { cause: error });
|
|
636
|
-
}
|
|
637
|
-
if (!st.isFile() || st.isSymbolicLink()) {
|
|
638
|
-
throw new CliUsageError(`attachment must be a regular file (not a directory or symlink): ${sourcePath}`);
|
|
639
|
-
}
|
|
640
|
-
try {
|
|
641
|
-
return { absolute, bytes: await readFile(absolute) };
|
|
642
|
-
}
|
|
643
|
-
catch (error) {
|
|
644
|
-
throw new CliUsageError(`attachment is not a readable regular file: ${sourcePath}`, { cause: error });
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
/**
|
|
648
|
-
* Snapshot deferred inputs sequentially before identity side effects. The staging
|
|
649
|
-
* files keep aggregate attachment bytes off heap until their final run is known.
|
|
650
|
-
*/
|
|
651
|
-
async function removePreparedAttachmentDirectory(stagingDirectory) {
|
|
652
|
-
await rm(stagingDirectory, { recursive: true, force: true });
|
|
653
|
-
}
|
|
654
|
-
/** Own the complete deferred-snapshot lifetime without masking either failure. */
|
|
655
|
-
export async function withPreparedAttachments(attachmentPaths, use) {
|
|
656
|
-
if (attachmentPaths.length === 0)
|
|
657
|
-
return await use([]);
|
|
658
|
-
const stagingDirectory = await mkdtemp(join(tmpdir(), "ak-role-attachments-"));
|
|
659
|
-
const prepared = [];
|
|
660
|
-
let result;
|
|
661
|
-
try {
|
|
662
|
-
for (let index = 0; index < attachmentPaths.length; index += 1) {
|
|
663
|
-
const { absolute, bytes } = await readRegularFileAttachment(attachmentPaths[index]);
|
|
664
|
-
const snapshotPath = join(stagingDirectory, String(index).padStart(6, "0"));
|
|
665
|
-
await writeFile(snapshotPath, bytes);
|
|
666
|
-
prepared.push({ absolute, snapshotPath });
|
|
667
|
-
}
|
|
668
|
-
result = await use(prepared);
|
|
669
|
-
}
|
|
670
|
-
catch (primary) {
|
|
671
|
-
try {
|
|
672
|
-
await removePreparedAttachmentDirectory(stagingDirectory);
|
|
673
|
-
}
|
|
674
|
-
catch (cleanup) {
|
|
675
|
-
throw new AggregateError([primary, cleanup], "attachment snapshot operation failed and cleanup also failed", { cause: primary });
|
|
676
|
-
}
|
|
677
|
-
throw primary;
|
|
678
|
-
}
|
|
679
|
-
await removePreparedAttachmentDirectory(stagingDirectory);
|
|
680
|
-
return result;
|
|
681
|
-
}
|
|
682
|
-
async function freezeAttachmentBytes(provenancePath, bytes, destinationDir, index) {
|
|
683
|
-
const frozenPath = join(destinationDir, `${String(index).padStart(2, "0")}-${basename(provenancePath)}`);
|
|
684
|
-
await writeFile(frozenPath, bytes);
|
|
685
|
-
return {
|
|
686
|
-
provenancePath,
|
|
687
|
-
frozenPath,
|
|
688
|
-
byteLength: bytes.byteLength,
|
|
689
|
-
sha256: sha256Hex(bytes),
|
|
690
|
-
mediaKind: "regular-file",
|
|
691
|
-
};
|
|
692
|
-
}
|
|
693
|
-
async function freezePreparedAttachment(prepared, destinationDir, index) {
|
|
694
|
-
return freezeAttachmentBytes(prepared.absolute, await readFile(prepared.snapshotPath), destinationDir, index);
|
|
695
|
-
}
|
|
696
|
-
async function freezeRegularFileAttachment(sourcePath, destinationDir, index) {
|
|
697
|
-
const { absolute, bytes } = await readRegularFileAttachment(sourcePath);
|
|
698
|
-
return {
|
|
699
|
-
attachment: await freezeAttachmentBytes(absolute, bytes, destinationDir, index),
|
|
700
|
-
body: bytes,
|
|
701
|
-
};
|
|
702
|
-
}
|
|
703
|
-
/** Freeze attachments only — ticket binding is the shared LLM seat path (#635). */
|
|
704
|
-
async function freezeAttachments(ledgerHome, attachmentPaths, attachmentsDirectory) {
|
|
705
|
-
const attachments = [];
|
|
706
|
-
// attachments/ appears only when something is frozen; created through the
|
|
707
|
-
// ledger's symlink-rejecting tree walk, never a plain mkdir.
|
|
708
|
-
if (attachmentPaths.length > 0) {
|
|
709
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
710
|
-
}
|
|
711
|
-
for (let i = 0; i < attachmentPaths.length; i += 1) {
|
|
712
|
-
const frozen = await freezeRegularFileAttachment(attachmentPaths[i], attachmentsDirectory, i);
|
|
713
|
-
attachments.push(frozen.attachment);
|
|
714
|
-
}
|
|
715
|
-
return attachments;
|
|
716
|
-
}
|
|
717
|
-
/**
|
|
718
|
-
* Freeze summons attachments into an already-retained run (#637 same-ticket resume).
|
|
719
|
-
* Writes under attachments/summons-<key>/ so prior freeze names stay intact.
|
|
720
|
-
* Manual resume never calls this — birth attachments keep their original semantics.
|
|
721
|
-
*/
|
|
722
|
-
export async function freezeAttachmentsIntoRun(attachmentPaths, runDirectory, summonsKey = `s-${Date.now().toString(36)}`) {
|
|
723
|
-
if (attachmentPaths.length === 0)
|
|
724
|
-
return [];
|
|
725
|
-
const ledgerHome = resolveActivationLedgerHome(homeFromRunDirectory(runDirectory));
|
|
726
|
-
const attachmentsDirectory = join(runDirectory, "attachments", summonsKey);
|
|
727
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
728
|
-
return freezeAttachments(ledgerHome, attachmentPaths, attachmentsDirectory);
|
|
729
|
-
}
|
|
730
|
-
/** Freeze prepared bytes and metadata through one path for birth or retained runs. */
|
|
731
|
-
export async function freezePreparedAttachmentsIntoRun(prepared, runDirectory, summonsKey) {
|
|
732
|
-
if (prepared.length === 0)
|
|
733
|
-
return [];
|
|
734
|
-
const ledgerHome = resolveActivationLedgerHome(homeFromRunDirectory(runDirectory));
|
|
735
|
-
const attachmentsDirectory = summonsKey === undefined
|
|
736
|
-
? join(runDirectory, "attachments")
|
|
737
|
-
: join(runDirectory, "attachments", summonsKey);
|
|
738
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
739
|
-
const attachments = [];
|
|
740
|
-
for (let index = 0; index < prepared.length; index += 1) {
|
|
741
|
-
attachments.push(await freezePreparedAttachment(prepared[index], attachmentsDirectory, index));
|
|
742
|
-
}
|
|
743
|
-
return attachments;
|
|
744
|
-
}
|
|
745
649
|
function ticketAdmissionFields(ticketNumber) {
|
|
746
650
|
if (ticketNumber === undefined)
|
|
747
651
|
return {};
|
|
@@ -892,36 +796,21 @@ export async function admitPublicRole(role, parsed, env, override) {
|
|
|
892
796
|
else {
|
|
893
797
|
repository = resolveGitHubRemoteRepository(projectRoot);
|
|
894
798
|
}
|
|
895
|
-
|
|
896
|
-
let manifestCanonicalJson;
|
|
897
|
-
if (parsed.requestManifestPath !== undefined) {
|
|
898
|
-
try {
|
|
899
|
-
manifest = await loadCollectorManifest(parsed.requestManifestPath);
|
|
900
|
-
manifestCanonicalJson = manifest.canonicalJson;
|
|
901
|
-
}
|
|
902
|
-
catch (error) {
|
|
903
|
-
throw new CliUsageError(errorText(error), { cause: error });
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
const manifestDigest = manifest.digest;
|
|
799
|
+
// #1165: pass caller path as-is; package does not read, validate, or rewrite.
|
|
907
800
|
const admittedCollector = await admitStandardMaterialInvocation("collector", {
|
|
908
801
|
...shared,
|
|
909
802
|
instruction,
|
|
910
803
|
attachmentPaths,
|
|
911
804
|
...project,
|
|
912
|
-
placedFields: async (
|
|
805
|
+
placedFields: async () => {
|
|
913
806
|
// #1088: explicit --pr only. Unbound PR is located by the LLM via host CLI.
|
|
914
|
-
let requestManifestPath;
|
|
915
|
-
if (manifestCanonicalJson !== undefined) {
|
|
916
|
-
requestManifestPath = join(placed.runDirectory, "request-manifest.json");
|
|
917
|
-
await writeFile(requestManifestPath, manifestCanonicalJson, "utf8");
|
|
918
|
-
}
|
|
919
807
|
return {
|
|
920
808
|
...(explicitPrNumber === undefined ? {} : { prNumber: explicitPrNumber }),
|
|
921
809
|
repository: repository.canonical,
|
|
922
810
|
repositoryDisplay: repository.display,
|
|
923
|
-
...(requestManifestPath === undefined
|
|
924
|
-
|
|
811
|
+
...(parsed.requestManifestPath === undefined
|
|
812
|
+
? {}
|
|
813
|
+
: { requestManifestPath: parsed.requestManifestPath }),
|
|
925
814
|
};
|
|
926
815
|
},
|
|
927
816
|
});
|
|
@@ -932,12 +821,10 @@ export async function admitPublicRole(role, parsed, env, override) {
|
|
|
932
821
|
throw new CliUsageError(`doctor --issue must be a positive integer, got ${Number.NaN}`);
|
|
933
822
|
}
|
|
934
823
|
const issueNumber = parsed.issueNumber;
|
|
935
|
-
|
|
936
|
-
const admittedDoctor = await admitStandardMaterialInvocation("doctor", {
|
|
824
|
+
return admitStandardMaterialInvocation("doctor", {
|
|
937
825
|
...shared,
|
|
938
826
|
instruction,
|
|
939
|
-
attachmentPaths
|
|
940
|
-
freezeAttachments: false,
|
|
827
|
+
attachmentPaths,
|
|
941
828
|
...project,
|
|
942
829
|
placedFields: async (placed) => {
|
|
943
830
|
let caseRunsPath;
|
|
@@ -974,16 +861,13 @@ export async function admitPublicRole(role, parsed, env, override) {
|
|
|
974
861
|
const detail = errorText(error);
|
|
975
862
|
throw new CliUsageError(`doctor case could not be constructed from retained evidence: ${detail}`, { cause: error });
|
|
976
863
|
}
|
|
977
|
-
frozenAttachments = await freezeAttachments(placed.ledgerHome, attachmentPaths, placed.attachmentsDirectory);
|
|
978
864
|
return {
|
|
979
865
|
issueNumber,
|
|
980
866
|
caseRunsPath,
|
|
981
867
|
caseIdentity,
|
|
982
|
-
attachments: persistedAttachmentRefs(frozenAttachments),
|
|
983
868
|
};
|
|
984
869
|
},
|
|
985
870
|
});
|
|
986
|
-
return { ...admittedDoctor, attachments: frozenAttachments };
|
|
987
871
|
}
|
|
988
872
|
case "source-locator": {
|
|
989
873
|
const projectRoot = resolve(parsed.project ?? shared.cwd);
|
|
@@ -1014,7 +898,7 @@ export async function admitPublicRole(role, parsed, env, override) {
|
|
|
1014
898
|
instruction: "",
|
|
1015
899
|
attachmentPaths: [],
|
|
1016
900
|
...project,
|
|
1017
|
-
|
|
901
|
+
recordAttachments: false,
|
|
1018
902
|
admittedFields: {
|
|
1019
903
|
sourceRunPath: sourceRun.runDirectory,
|
|
1020
904
|
sourceRun,
|
|
@@ -1031,7 +915,7 @@ export async function admitPublicRole(role, parsed, env, override) {
|
|
|
1031
915
|
instruction,
|
|
1032
916
|
attachmentPaths: [],
|
|
1033
917
|
...project,
|
|
1034
|
-
|
|
918
|
+
recordAttachments: false,
|
|
1035
919
|
admittedFields: { baseRevision },
|
|
1036
920
|
});
|
|
1037
921
|
}
|
|
@@ -1129,9 +1013,9 @@ async function placeRoleAdmission(options) {
|
|
|
1129
1013
|
home: options.home,
|
|
1130
1014
|
...(options.materialize === undefined ? {} : { materialize: options.materialize }),
|
|
1131
1015
|
});
|
|
1132
|
-
const attachments = options.
|
|
1016
|
+
const attachments = options.recordAttachments === false
|
|
1133
1017
|
? []
|
|
1134
|
-
:
|
|
1018
|
+
: admitCallerAttachments(options.attachmentPaths);
|
|
1135
1019
|
return {
|
|
1136
1020
|
runId,
|
|
1137
1021
|
bookKey,
|
|
@@ -1147,13 +1031,7 @@ async function placeRoleAdmission(options) {
|
|
|
1147
1031
|
};
|
|
1148
1032
|
}
|
|
1149
1033
|
function persistedAttachmentRefs(attachments) {
|
|
1150
|
-
return attachments.map((attachment) => ({
|
|
1151
|
-
provenancePath: attachment.provenancePath,
|
|
1152
|
-
frozenPath: attachment.frozenPath,
|
|
1153
|
-
byteLength: attachment.byteLength,
|
|
1154
|
-
sha256: attachment.sha256,
|
|
1155
|
-
mediaKind: attachment.mediaKind,
|
|
1156
|
-
}));
|
|
1034
|
+
return attachments.map((attachment) => ({ path: attachment.path }));
|
|
1157
1035
|
}
|
|
1158
1036
|
async function persistPlacedAdmission(admitted, placed, model) {
|
|
1159
1037
|
writeAdmittedRequestPersistence(placed.runDirectory, admitted, {
|
|
@@ -1173,19 +1051,18 @@ async function persistPlacedAdmission(admitted, placed, model) {
|
|
|
1173
1051
|
* before materializeCountersignInvocation writes the page.
|
|
1174
1052
|
* Seats whose extra facts are known before placement pass them as admittedFields.
|
|
1175
1053
|
* Seats whose extra facts depend on the placed run pass placedFields
|
|
1176
|
-
* (coder writes task.md; fixer writes fix-packet.md;
|
|
1177
|
-
* doctor resolves the case, then freezes attachments; merger writes merger-input.json).
|
|
1054
|
+
* (coder writes task.md; fixer writes fix-packet.md; merger writes merger-input.json).
|
|
1178
1055
|
*/
|
|
1179
1056
|
async function admitStandardMaterialInvocation(role, options) {
|
|
1180
1057
|
const defer = options.deferPersistence === true;
|
|
1181
|
-
const
|
|
1058
|
+
const skipAttachments = defer || options.recordAttachments === false;
|
|
1182
1059
|
const placed = await placeRoleAdmission({
|
|
1183
1060
|
role,
|
|
1184
1061
|
home: options.home,
|
|
1185
1062
|
principalAuthority: options.principalAuthority,
|
|
1186
1063
|
cwd: options.cwd,
|
|
1187
1064
|
attachmentPaths: options.attachmentPaths,
|
|
1188
|
-
...(
|
|
1065
|
+
...(skipAttachments ? { recordAttachments: false } : {}),
|
|
1189
1066
|
...(defer ? { materialize: false } : {}),
|
|
1190
1067
|
...(options.project === undefined ? {} : { project: options.project }),
|
|
1191
1068
|
...(options.createRunId === undefined ? {} : { createRunId: options.createRunId }),
|
|
@@ -1197,7 +1074,8 @@ async function admitStandardMaterialInvocation(role, options) {
|
|
|
1197
1074
|
? {}
|
|
1198
1075
|
: { correlationId: options.correlationId };
|
|
1199
1076
|
const instruction = options.instruction;
|
|
1200
|
-
|
|
1077
|
+
// Admitted emptiness is literal absence, not whitespace-only (#1165 J3).
|
|
1078
|
+
const instructionEmpty = instruction.length === 0;
|
|
1201
1079
|
const placedExtra = options.placedFields === undefined ? undefined : await options.placedFields(placed);
|
|
1202
1080
|
const admittedFields = {
|
|
1203
1081
|
...(options.admittedFields ?? {}),
|
|
@@ -1245,25 +1123,28 @@ function admittedTransportPromptKind(admitted) {
|
|
|
1245
1123
|
/**
|
|
1246
1124
|
* One initial prompt transport. The registry `transportPrompt` leaf selects
|
|
1247
1125
|
* a fixed kickoff, a bound baseline, or frozen skill args. Absent means the
|
|
1248
|
-
* caller instruction plus
|
|
1126
|
+
* caller instruction plus caller attachment paths as-is (#1165).
|
|
1127
|
+
* Engine / outsourcing material rides startup readingMaterial (#1167), not here.
|
|
1249
1128
|
*/
|
|
1250
|
-
export function buildInstructionTransportPrompt(admitted
|
|
1129
|
+
export function buildInstructionTransportPrompt(admitted) {
|
|
1251
1130
|
const kind = admittedTransportPromptKind(admitted);
|
|
1252
1131
|
if (kind === "fixed-kickoff") {
|
|
1253
1132
|
if (admitted.sourceRunPath === undefined || admitted.sourceRunPath.trim() === "") {
|
|
1254
1133
|
throw new Error("fixed-kickoff transport prompt is missing the source run pointer");
|
|
1255
1134
|
}
|
|
1256
|
-
return
|
|
1135
|
+
return admitted.sourceRunPath;
|
|
1257
1136
|
}
|
|
1258
1137
|
if (kind === "baseline") {
|
|
1259
1138
|
if (admitted.baseRevision === undefined) {
|
|
1260
1139
|
throw new Error("baseline transport prompt is missing the bound revision");
|
|
1261
1140
|
}
|
|
1262
1141
|
const lines = [admitted.baseRevision];
|
|
1263
|
-
|
|
1142
|
+
// Use raw admitted.instruction — do not gate on instructionEmpty metadata
|
|
1143
|
+
// (old pages may set that flag wrong while still holding whitespace text).
|
|
1144
|
+
if (admitted.instruction.length > 0) {
|
|
1264
1145
|
lines.push("", admitted.instruction);
|
|
1265
1146
|
}
|
|
1266
|
-
return
|
|
1147
|
+
return lines.join("\n");
|
|
1267
1148
|
}
|
|
1268
1149
|
if (kind === "skill-args") {
|
|
1269
1150
|
if (admitted.baseRevision === undefined
|
|
@@ -1276,20 +1157,28 @@ export function buildInstructionTransportPrompt(admitted, engineMaterial) {
|
|
|
1276
1157
|
lens: admitted.lens,
|
|
1277
1158
|
authorityRefs: admitted.authorityRefs,
|
|
1278
1159
|
})];
|
|
1279
|
-
if (
|
|
1160
|
+
if (admitted.instruction.length > 0) {
|
|
1280
1161
|
lines.push("", admitted.instruction);
|
|
1281
1162
|
}
|
|
1282
|
-
return
|
|
1163
|
+
return lines.join("\n");
|
|
1283
1164
|
}
|
|
1284
|
-
|
|
1285
|
-
|
|
1165
|
+
// #1165 J3: assemble from the admitted instruction bytes themselves.
|
|
1166
|
+
const lines = [admitted.instruction];
|
|
1167
|
+
// #1164/#1165: each caller path keeps its file-flag provenance.
|
|
1168
|
+
const flaggedPaths = [
|
|
1169
|
+
...admitted.attachments.map((attachment) => `--attach ${attachment.path}`),
|
|
1170
|
+
...(admitted.requestManifestPath === undefined
|
|
1171
|
+
? []
|
|
1172
|
+
: [`--request-manifest ${admitted.requestManifestPath}`]),
|
|
1173
|
+
];
|
|
1174
|
+
if (flaggedPaths.length > 0) {
|
|
1286
1175
|
lines.push("");
|
|
1287
|
-
lines.push("
|
|
1288
|
-
for (const
|
|
1289
|
-
lines.push(`- ${
|
|
1176
|
+
lines.push("已受理附件:");
|
|
1177
|
+
for (const entry of flaggedPaths) {
|
|
1178
|
+
lines.push(`- ${entry}`);
|
|
1290
1179
|
}
|
|
1291
1180
|
}
|
|
1292
|
-
return
|
|
1181
|
+
return lines.join("\n");
|
|
1293
1182
|
}
|
|
1294
1183
|
/** Persist a deferred Countersign admission after same-ticket lookup found no retained run. */
|
|
1295
1184
|
export async function materializeCountersignInvocation(admitted, options) {
|
|
@@ -1298,8 +1187,7 @@ export async function materializeCountersignInvocation(admitted, options) {
|
|
|
1298
1187
|
home: options.home,
|
|
1299
1188
|
principalAuthority: options.principalAuthority,
|
|
1300
1189
|
cwd: admitted.projectRoot,
|
|
1301
|
-
attachmentPaths:
|
|
1302
|
-
freezeAttachments: false,
|
|
1190
|
+
attachmentPaths: options.attachmentPaths,
|
|
1303
1191
|
runId: admitted.runId,
|
|
1304
1192
|
...(options.ticketNumber === undefined ? {} : { assertedTicketNumber: options.ticketNumber }),
|
|
1305
1193
|
});
|
|
@@ -1310,8 +1198,7 @@ export async function materializeCountersignInvocation(admitted, options) {
|
|
|
1310
1198
|
if (ticketFields.ticketNumber !== undefined) {
|
|
1311
1199
|
admitted.ticketNumber = ticketFields.ticketNumber;
|
|
1312
1200
|
}
|
|
1313
|
-
|
|
1314
|
-
admitted.attachments = attachments;
|
|
1201
|
+
admitted.attachments = placement.attachments;
|
|
1315
1202
|
writeAdmittedRequestPersistence(admitted.runDirectory, admitted, {
|
|
1316
1203
|
sessionDirectory: placement.sessionDirectory,
|
|
1317
1204
|
sessionFile: placement.sessionFile,
|
|
@@ -1332,10 +1219,13 @@ export async function loadAdmittedJudgeRequest(runDirectory) {
|
|
|
1332
1219
|
return undefined;
|
|
1333
1220
|
if (!Array.isArray(record.attachments))
|
|
1334
1221
|
return undefined;
|
|
1222
|
+
const attachments = record.attachments
|
|
1223
|
+
.map((item) => normalizeAdmittedAttachment(item))
|
|
1224
|
+
.filter((item) => item !== undefined);
|
|
1335
1225
|
return {
|
|
1336
1226
|
instruction: record.instruction,
|
|
1337
1227
|
instructionEmpty: record.instructionEmpty,
|
|
1338
|
-
attachments
|
|
1228
|
+
attachments,
|
|
1339
1229
|
};
|
|
1340
1230
|
}
|
|
1341
1231
|
catch {
|
|
@@ -1597,7 +1487,7 @@ export function parseAnalystArgv(args) {
|
|
|
1597
1487
|
return;
|
|
1598
1488
|
}
|
|
1599
1489
|
if (taken.def.id === "attach") {
|
|
1600
|
-
pushValue("attach",
|
|
1490
|
+
pushValue("attach", requireProvidedOptionValue(taken.def.canonical, taken.value));
|
|
1601
1491
|
return;
|
|
1602
1492
|
}
|
|
1603
1493
|
if (taken.def.id === "group-a-label" || taken.def.id === "group-b-label") {
|