@akagilnc/pi-workflow-roles 0.1.5583 → 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 +231 -466
- package/dist/collector-config.js +0 -44
- package/dist/headless-host/production-host.js +199 -434
- package/dist/migrate-book-topology.js +16 -30
- package/dist/public-cli/instruction-seat-run.js +8 -8
- package/dist/public-cli/invocation.js +77 -187
- package/dist/public-cli/main.js +137 -363
- package/dist/public-cli/option-definitions.js +5 -5
- package/dist/public-cli/post-admission.js +11 -40
- package/dist/public-cli/run-lifecycle.js +9 -14
- 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/public-cli/instruction-seat-run.ts +7 -8
- package/src/public-cli/invocation.ts +92 -283
- package/src/public-cli/option-definitions.ts +5 -5
- package/src/public-cli/post-admission.ts +12 -56
- package/src/public-cli/run-lifecycle.ts +9 -16
- package/src/public-role-summons.ts +1 -1
- package/src/role-run-placement.ts +0 -1
- package/src/role-run-relocation.ts +12 -22
|
@@ -1392,23 +1392,10 @@ var init_cli_errors = __esm({
|
|
|
1392
1392
|
}
|
|
1393
1393
|
});
|
|
1394
1394
|
|
|
1395
|
-
// src/sha256.ts
|
|
1396
|
-
import { createHash } from "node:crypto";
|
|
1397
|
-
function sha256Hex(bytes) {
|
|
1398
|
-
return createHash("sha256").update(bytes).digest("hex");
|
|
1399
|
-
}
|
|
1400
|
-
var init_sha256 = __esm({
|
|
1401
|
-
"src/sha256.ts"() {
|
|
1402
|
-
"use strict";
|
|
1403
|
-
}
|
|
1404
|
-
});
|
|
1405
|
-
|
|
1406
1395
|
// src/collector-config.ts
|
|
1407
1396
|
var init_collector_config = __esm({
|
|
1408
1397
|
"src/collector-config.ts"() {
|
|
1409
1398
|
"use strict";
|
|
1410
|
-
init_sha256();
|
|
1411
|
-
init_unknown_value();
|
|
1412
1399
|
init_run_ticket_number();
|
|
1413
1400
|
}
|
|
1414
1401
|
});
|
|
@@ -15608,22 +15595,10 @@ function rewriteSummonsMaterials(value2, rewrites) {
|
|
|
15608
15595
|
rewrites
|
|
15609
15596
|
);
|
|
15610
15597
|
rewriteSourceRunLocator(value2.sourceRun, rewrites);
|
|
15611
|
-
if (Array.isArray(value2.attachmentPaths)) {
|
|
15612
|
-
value2.attachmentPaths = value2.attachmentPaths.map(
|
|
15613
|
-
(path8) => rewriteRunDirectoryPathValueAgainstRewrites(path8, rewrites)
|
|
15614
|
-
);
|
|
15615
|
-
}
|
|
15616
15598
|
}
|
|
15617
15599
|
function rewriteAdmittedRoleRunPage(page, rewrites) {
|
|
15618
15600
|
rewriteRunDirectoryPathFieldsAgainstRewrites(page, ADMITTED_PAGE_FIELDS, rewrites);
|
|
15619
15601
|
rewriteSourceRunLocator(page.sourceRun, rewrites);
|
|
15620
|
-
if (Array.isArray(page.attachments)) {
|
|
15621
|
-
for (const attachment of page.attachments) {
|
|
15622
|
-
if (isRecord(attachment)) {
|
|
15623
|
-
rewriteRunDirectoryPathFieldsAgainstRewrites(attachment, ["frozenPath"], rewrites);
|
|
15624
|
-
}
|
|
15625
|
-
}
|
|
15626
|
-
}
|
|
15627
15602
|
if (isRecord(page.principal)) {
|
|
15628
15603
|
rewriteRunDirectoryPathFieldsAgainstRewrites(
|
|
15629
15604
|
page.principal,
|
|
@@ -15859,7 +15834,7 @@ var init_role_run_relocation = __esm({
|
|
|
15859
15834
|
"taskPath",
|
|
15860
15835
|
"packetPath",
|
|
15861
15836
|
"prerequisitesPath",
|
|
15862
|
-
|
|
15837
|
+
// #1165: requestManifestPath is a caller path — never rewrite.
|
|
15863
15838
|
"mergerInputPath",
|
|
15864
15839
|
"sourceRunPath"
|
|
15865
15840
|
];
|
|
@@ -15884,6 +15859,17 @@ var init_role_run_relocation = __esm({
|
|
|
15884
15859
|
}
|
|
15885
15860
|
});
|
|
15886
15861
|
|
|
15862
|
+
// src/sha256.ts
|
|
15863
|
+
import { createHash } from "node:crypto";
|
|
15864
|
+
function sha256Hex(bytes) {
|
|
15865
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
15866
|
+
}
|
|
15867
|
+
var init_sha256 = __esm({
|
|
15868
|
+
"src/sha256.ts"() {
|
|
15869
|
+
"use strict";
|
|
15870
|
+
}
|
|
15871
|
+
});
|
|
15872
|
+
|
|
15887
15873
|
// src/submission-correctable-error.ts
|
|
15888
15874
|
var correctableSubmissionErrorBrand, CorrectableSubmissionError;
|
|
15889
15875
|
var init_submission_correctable_error = __esm({
|
|
@@ -16149,8 +16135,8 @@ var init_option_definitions = __esm({
|
|
|
16149
16135
|
repeatable: true,
|
|
16150
16136
|
form: "option",
|
|
16151
16137
|
description: {
|
|
16152
|
-
en: "
|
|
16153
|
-
zh: "\
|
|
16138
|
+
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.",
|
|
16139
|
+
zh: "\u8C03\u7528\u65B9\u6587\u4EF6\u8DEF\u5F84\u539F\u6837\u9012\u7ED9\u8859\u95E8\uFF08\u53EF\u91CD\u590D\uFF09\u3002\u5305\u4E0D\u8BFB\u3001\u4E0D\u590D\u5236\u3001\u4E0D\u6821\u9A8C\uFF1B\u8C03\u7528\u65B9\u5F53\u524D\u76EE\u5F55\u4E0E --project \u4E0D\u540C\u65F6\u8BF7\u7ED9\u7EDD\u5BF9\u8DEF\u5F84\u3002"
|
|
16154
16140
|
}
|
|
16155
16141
|
};
|
|
16156
16142
|
SHARED_PHASE_SEMANTICS = {
|
|
@@ -16325,8 +16311,8 @@ var init_option_definitions = __esm({
|
|
|
16325
16311
|
repeatable: false,
|
|
16326
16312
|
form: "option",
|
|
16327
16313
|
description: {
|
|
16328
|
-
en: "
|
|
16329
|
-
zh: "\
|
|
16314
|
+
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.",
|
|
16315
|
+
zh: "\u8C03\u7528\u65B9 request manifest JSON \u8DEF\u5F84\uFF0C\u539F\u6837\u4F20\u9012\u3002\u5305\u4E0D\u8BFB\u3001\u4E0D\u590D\u5236\u3001\u4E0D\u6821\u9A8C\uFF1B\u8C03\u7528\u65B9\u5F53\u524D\u76EE\u5F55\u4E0E --project \u4E0D\u540C\u65F6\u8BF7\u7ED9\u7EDD\u5BF9\u8DEF\u5F84\u3002"
|
|
16330
16316
|
}
|
|
16331
16317
|
}
|
|
16332
16318
|
];
|
|
@@ -27,7 +27,7 @@ import { NotarySourceRunError, resolveNotarySourceRunLocator } from "../notary-s
|
|
|
27
27
|
import { packagedAdmitsCountersign, packagedBindsBoardTicket, packagedRebindSourceOnResume, packagedRoleMetadata, } from "../packaged-role-registry.js";
|
|
28
28
|
import { readAuditorResumeBinding } from "../auditor-soul.js";
|
|
29
29
|
import { CliUsageError } from "./cli-errors.js";
|
|
30
|
-
import { admitPublicRole, bindAdmittedTicketNumber, buildInstructionTransportPrompt, materializeCountersignInvocation, persistAdmittedSourceRunPath, recordAdmittedCorrelation, recordChildDiaristRun, relocateAdmittedRunToTicket,
|
|
30
|
+
import { admitPublicRole, bindAdmittedTicketNumber, buildInstructionTransportPrompt, materializeCountersignInvocation, persistAdmittedSourceRunPath, recordAdmittedCorrelation, recordChildDiaristRun, relocateAdmittedRunToTicket, } from "./invocation.js";
|
|
31
31
|
import { bindDiaristAssertedTicketNumber, presentControlledFailure, packageFaultNoteFor, prepareSummonsResumeMaterials, roleTurnOptions, runPostAdmissionOneShot, runPostAdmissionResumable, runPostAdmissionSeatResume, showResumeErrorPointer, resumeTurnRequestProjectionOptions, } from "./post-admission.js";
|
|
32
32
|
import { presentTerminal } from "./auto-resume.js";
|
|
33
33
|
import { buildAutoResumeContinuationPrompt, loadResumablePublicRole, markRunAdmitted, parentRunPathFromGatePointerInstruction, readCurrentCourt, } from "./run-lifecycle.js";
|
|
@@ -429,7 +429,7 @@ async function runCountersignBody(parsed, env, io) {
|
|
|
429
429
|
summons: {
|
|
430
430
|
sourceRunPath: gateParentRunPath,
|
|
431
431
|
instruction: resumeInstruction,
|
|
432
|
-
instructionEmpty: resumeInstruction.
|
|
432
|
+
instructionEmpty: resumeInstruction.length === 0,
|
|
433
433
|
},
|
|
434
434
|
});
|
|
435
435
|
if (resumed != null)
|
|
@@ -446,12 +446,12 @@ async function runCountersignBody(parsed, env, io) {
|
|
|
446
446
|
throw error;
|
|
447
447
|
}
|
|
448
448
|
try {
|
|
449
|
-
|
|
449
|
+
{
|
|
450
450
|
const materializeAdmission = async (ticketNumber) => {
|
|
451
451
|
await materializeCountersignInvocation(admitted, {
|
|
452
452
|
home: env.home,
|
|
453
453
|
principalAuthority: env.principalAuthority,
|
|
454
|
-
|
|
454
|
+
attachmentPaths: parsed.attachmentPaths ?? [],
|
|
455
455
|
...(env.model === undefined ? {} : { model: env.model }),
|
|
456
456
|
...(ticketNumber === undefined ? {} : { ticketNumber }),
|
|
457
457
|
});
|
|
@@ -486,7 +486,7 @@ async function runCountersignBody(parsed, env, io) {
|
|
|
486
486
|
});
|
|
487
487
|
await relocateAdmittedRunToTicket(admitted, env.principalAuthority);
|
|
488
488
|
return result;
|
|
489
|
-
}
|
|
489
|
+
}
|
|
490
490
|
}
|
|
491
491
|
catch (error) {
|
|
492
492
|
const rejected = usageExit(error, io);
|
|
@@ -557,7 +557,7 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
|
|
|
557
557
|
const summons = {
|
|
558
558
|
...sameParentInstruction(env, {
|
|
559
559
|
instruction: parsed.instruction ?? "",
|
|
560
|
-
instructionEmpty: (parsed.instruction ?? "").
|
|
560
|
+
instructionEmpty: (parsed.instruction ?? "").length === 0,
|
|
561
561
|
}),
|
|
562
562
|
attachmentPaths: parsed.attachmentPaths ?? [],
|
|
563
563
|
};
|
|
@@ -583,7 +583,7 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
|
|
|
583
583
|
sourceRunPath: parentRunPath,
|
|
584
584
|
...sameParentInstruction(env, {
|
|
585
585
|
instruction: parsed.instruction ?? "",
|
|
586
|
-
instructionEmpty: (parsed.instruction ?? "").
|
|
586
|
+
instructionEmpty: (parsed.instruction ?? "").length === 0,
|
|
587
587
|
}),
|
|
588
588
|
attachmentPaths: parsed.attachmentPaths ?? [],
|
|
589
589
|
};
|
|
@@ -669,7 +669,7 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
|
|
|
669
669
|
instruction: parsed.instruction ?? "",
|
|
670
670
|
projectRoot: admitted.projectRoot,
|
|
671
671
|
failureLabel: "secretariat unbound summons",
|
|
672
|
-
attachmentPaths: admitted.attachments.map((attachment) => attachment.
|
|
672
|
+
attachmentPaths: admitted.attachments.map((attachment) => attachment.path),
|
|
673
673
|
correlationId: admitted.runId,
|
|
674
674
|
}, env, io);
|
|
675
675
|
}
|
|
@@ -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";
|
|
@@ -28,6 +27,20 @@ import { NotarySourceRunError, resolveNotarySourceRunLocator, } from "../notary-
|
|
|
28
27
|
import { CliUsageError } from "./cli-errors.js";
|
|
29
28
|
import { REJECTED_PUBLIC_SPELLINGS, createTypedOptionConsumer, evaluateAnalystModeOptionContract, optionsForOwner, resolveAnalystMode, } from "./option-definitions.js";
|
|
30
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
|
+
}
|
|
31
44
|
/** Issue a principal from the single authoritative role-run placement. */
|
|
32
45
|
export function issueAdmissionPlacement(authority, request) {
|
|
33
46
|
const ledgerHome = resolveActivationLedgerHome(request.home);
|
|
@@ -261,12 +274,9 @@ export async function relocateAdmittedRunToTicket(admitted, authority, heldLease
|
|
|
261
274
|
"taskPath",
|
|
262
275
|
"packetPath",
|
|
263
276
|
"prerequisitesPath",
|
|
264
|
-
"requestManifestPath",
|
|
265
277
|
"mergerInputPath",
|
|
266
278
|
], oldRunDirectory, target.runDirectory);
|
|
267
|
-
|
|
268
|
-
attachment.frozenPath = rewriteRunDirectoryPathValue(attachment.frozenPath, oldRunDirectory, target.runDirectory);
|
|
269
|
-
}
|
|
279
|
+
// #1165: caller --attach / --request-manifest paths stay as given; do not rewrite.
|
|
270
280
|
admitted.principal = principal;
|
|
271
281
|
// current.json projects host.original from this run directory. Ownership is
|
|
272
282
|
// already transferred; a refuse still carries the true cause to the caller
|
|
@@ -382,7 +392,8 @@ function assignPublicSeatOption(owner, taken, fields) {
|
|
|
382
392
|
const value = taken.value;
|
|
383
393
|
switch (taken.def.id) {
|
|
384
394
|
case "attach":
|
|
385
|
-
|
|
395
|
+
// #1165: file-flag values are opaque; only a missing argument is a usage error.
|
|
396
|
+
fields.attachmentPaths.push(requireProvidedOptionValue(taken.def.canonical, value));
|
|
386
397
|
return;
|
|
387
398
|
case "project":
|
|
388
399
|
fields.project = requireOptionPath(taken.def.canonical, value);
|
|
@@ -426,7 +437,8 @@ function assignPublicSeatOption(owner, taken, fields) {
|
|
|
426
437
|
fields.repo = parseRepoOption(value);
|
|
427
438
|
return;
|
|
428
439
|
case "request-manifest":
|
|
429
|
-
|
|
440
|
+
// #1165: file-flag values are opaque; only a missing argument is a usage error.
|
|
441
|
+
fields.requestManifestPath = requireProvidedOptionValue(taken.def.canonical, value);
|
|
430
442
|
return;
|
|
431
443
|
case "issue": {
|
|
432
444
|
if (value === undefined || value.trim() === "") {
|
|
@@ -539,6 +551,16 @@ function requireOptionPath(flag, value) {
|
|
|
539
551
|
}
|
|
540
552
|
return value;
|
|
541
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
|
+
}
|
|
542
564
|
/**
|
|
543
565
|
* Shared Skill-arg token rule for caller-controlled values projected into the
|
|
544
566
|
* space-joined Skill invocation line. Rejects blank, whitespace (smuggles the
|
|
@@ -624,123 +646,6 @@ export function requireAuthorityRef(value) {
|
|
|
624
646
|
optionLike: "--authority-ref requires a durable reference, not inline Spec prose",
|
|
625
647
|
});
|
|
626
648
|
}
|
|
627
|
-
async function readRegularFileAttachment(sourcePath) {
|
|
628
|
-
const absolute = isAbsolute(sourcePath) ? sourcePath : resolve(sourcePath);
|
|
629
|
-
let st;
|
|
630
|
-
try {
|
|
631
|
-
st = await lstat(absolute);
|
|
632
|
-
}
|
|
633
|
-
catch (error) {
|
|
634
|
-
throw new CliUsageError(`attachment is not a readable regular file: ${sourcePath}`, { cause: error });
|
|
635
|
-
}
|
|
636
|
-
if (!st.isFile() || st.isSymbolicLink()) {
|
|
637
|
-
throw new CliUsageError(`attachment must be a regular file (not a directory or symlink): ${sourcePath}`);
|
|
638
|
-
}
|
|
639
|
-
try {
|
|
640
|
-
return { absolute, bytes: await readFile(absolute) };
|
|
641
|
-
}
|
|
642
|
-
catch (error) {
|
|
643
|
-
throw new CliUsageError(`attachment is not a readable regular file: ${sourcePath}`, { cause: error });
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
/**
|
|
647
|
-
* Snapshot deferred inputs sequentially before identity side effects. The staging
|
|
648
|
-
* files keep aggregate attachment bytes off heap until their final run is known.
|
|
649
|
-
*/
|
|
650
|
-
async function removePreparedAttachmentDirectory(stagingDirectory) {
|
|
651
|
-
await rm(stagingDirectory, { recursive: true, force: true });
|
|
652
|
-
}
|
|
653
|
-
/** Own the complete deferred-snapshot lifetime without masking either failure. */
|
|
654
|
-
export async function withPreparedAttachments(attachmentPaths, use) {
|
|
655
|
-
if (attachmentPaths.length === 0)
|
|
656
|
-
return await use([]);
|
|
657
|
-
const stagingDirectory = await mkdtemp(join(tmpdir(), "ak-role-attachments-"));
|
|
658
|
-
const prepared = [];
|
|
659
|
-
let result;
|
|
660
|
-
try {
|
|
661
|
-
for (let index = 0; index < attachmentPaths.length; index += 1) {
|
|
662
|
-
const { absolute, bytes } = await readRegularFileAttachment(attachmentPaths[index]);
|
|
663
|
-
const snapshotPath = join(stagingDirectory, String(index).padStart(6, "0"));
|
|
664
|
-
await writeFile(snapshotPath, bytes);
|
|
665
|
-
prepared.push({ absolute, snapshotPath });
|
|
666
|
-
}
|
|
667
|
-
result = await use(prepared);
|
|
668
|
-
}
|
|
669
|
-
catch (primary) {
|
|
670
|
-
try {
|
|
671
|
-
await removePreparedAttachmentDirectory(stagingDirectory);
|
|
672
|
-
}
|
|
673
|
-
catch (cleanup) {
|
|
674
|
-
throw new AggregateError([primary, cleanup], "attachment snapshot operation failed and cleanup also failed", { cause: primary });
|
|
675
|
-
}
|
|
676
|
-
throw primary;
|
|
677
|
-
}
|
|
678
|
-
await removePreparedAttachmentDirectory(stagingDirectory);
|
|
679
|
-
return result;
|
|
680
|
-
}
|
|
681
|
-
async function freezeAttachmentBytes(provenancePath, bytes, destinationDir, index) {
|
|
682
|
-
const frozenPath = join(destinationDir, `${String(index).padStart(2, "0")}-${basename(provenancePath)}`);
|
|
683
|
-
await writeFile(frozenPath, bytes);
|
|
684
|
-
return {
|
|
685
|
-
provenancePath,
|
|
686
|
-
frozenPath,
|
|
687
|
-
byteLength: bytes.byteLength,
|
|
688
|
-
sha256: sha256Hex(bytes),
|
|
689
|
-
mediaKind: "regular-file",
|
|
690
|
-
};
|
|
691
|
-
}
|
|
692
|
-
async function freezePreparedAttachment(prepared, destinationDir, index) {
|
|
693
|
-
return freezeAttachmentBytes(prepared.absolute, await readFile(prepared.snapshotPath), destinationDir, index);
|
|
694
|
-
}
|
|
695
|
-
async function freezeRegularFileAttachment(sourcePath, destinationDir, index) {
|
|
696
|
-
const { absolute, bytes } = await readRegularFileAttachment(sourcePath);
|
|
697
|
-
return {
|
|
698
|
-
attachment: await freezeAttachmentBytes(absolute, bytes, destinationDir, index),
|
|
699
|
-
body: bytes,
|
|
700
|
-
};
|
|
701
|
-
}
|
|
702
|
-
/** Freeze attachments only — ticket binding is the shared LLM seat path (#635). */
|
|
703
|
-
async function freezeAttachments(ledgerHome, attachmentPaths, attachmentsDirectory) {
|
|
704
|
-
const attachments = [];
|
|
705
|
-
// attachments/ appears only when something is frozen; created through the
|
|
706
|
-
// ledger's symlink-rejecting tree walk, never a plain mkdir.
|
|
707
|
-
if (attachmentPaths.length > 0) {
|
|
708
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
709
|
-
}
|
|
710
|
-
for (let i = 0; i < attachmentPaths.length; i += 1) {
|
|
711
|
-
const frozen = await freezeRegularFileAttachment(attachmentPaths[i], attachmentsDirectory, i);
|
|
712
|
-
attachments.push(frozen.attachment);
|
|
713
|
-
}
|
|
714
|
-
return attachments;
|
|
715
|
-
}
|
|
716
|
-
/**
|
|
717
|
-
* Freeze summons attachments into an already-retained run (#637 same-ticket resume).
|
|
718
|
-
* Writes under attachments/summons-<key>/ so prior freeze names stay intact.
|
|
719
|
-
* Manual resume never calls this — birth attachments keep their original semantics.
|
|
720
|
-
*/
|
|
721
|
-
export async function freezeAttachmentsIntoRun(attachmentPaths, runDirectory, summonsKey = `s-${Date.now().toString(36)}`) {
|
|
722
|
-
if (attachmentPaths.length === 0)
|
|
723
|
-
return [];
|
|
724
|
-
const ledgerHome = resolveActivationLedgerHome(homeFromRunDirectory(runDirectory));
|
|
725
|
-
const attachmentsDirectory = join(runDirectory, "attachments", summonsKey);
|
|
726
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
727
|
-
return freezeAttachments(ledgerHome, attachmentPaths, attachmentsDirectory);
|
|
728
|
-
}
|
|
729
|
-
/** Freeze prepared bytes and metadata through one path for birth or retained runs. */
|
|
730
|
-
export async function freezePreparedAttachmentsIntoRun(prepared, runDirectory, summonsKey) {
|
|
731
|
-
if (prepared.length === 0)
|
|
732
|
-
return [];
|
|
733
|
-
const ledgerHome = resolveActivationLedgerHome(homeFromRunDirectory(runDirectory));
|
|
734
|
-
const attachmentsDirectory = summonsKey === undefined
|
|
735
|
-
? join(runDirectory, "attachments")
|
|
736
|
-
: join(runDirectory, "attachments", summonsKey);
|
|
737
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
738
|
-
const attachments = [];
|
|
739
|
-
for (let index = 0; index < prepared.length; index += 1) {
|
|
740
|
-
attachments.push(await freezePreparedAttachment(prepared[index], attachmentsDirectory, index));
|
|
741
|
-
}
|
|
742
|
-
return attachments;
|
|
743
|
-
}
|
|
744
649
|
function ticketAdmissionFields(ticketNumber) {
|
|
745
650
|
if (ticketNumber === undefined)
|
|
746
651
|
return {};
|
|
@@ -891,36 +796,21 @@ export async function admitPublicRole(role, parsed, env, override) {
|
|
|
891
796
|
else {
|
|
892
797
|
repository = resolveGitHubRemoteRepository(projectRoot);
|
|
893
798
|
}
|
|
894
|
-
|
|
895
|
-
let manifestCanonicalJson;
|
|
896
|
-
if (parsed.requestManifestPath !== undefined) {
|
|
897
|
-
try {
|
|
898
|
-
manifest = await loadCollectorManifest(parsed.requestManifestPath);
|
|
899
|
-
manifestCanonicalJson = manifest.canonicalJson;
|
|
900
|
-
}
|
|
901
|
-
catch (error) {
|
|
902
|
-
throw new CliUsageError(errorText(error), { cause: error });
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
const manifestDigest = manifest.digest;
|
|
799
|
+
// #1165: pass caller path as-is; package does not read, validate, or rewrite.
|
|
906
800
|
const admittedCollector = await admitStandardMaterialInvocation("collector", {
|
|
907
801
|
...shared,
|
|
908
802
|
instruction,
|
|
909
803
|
attachmentPaths,
|
|
910
804
|
...project,
|
|
911
|
-
placedFields: async (
|
|
805
|
+
placedFields: async () => {
|
|
912
806
|
// #1088: explicit --pr only. Unbound PR is located by the LLM via host CLI.
|
|
913
|
-
let requestManifestPath;
|
|
914
|
-
if (manifestCanonicalJson !== undefined) {
|
|
915
|
-
requestManifestPath = join(placed.runDirectory, "request-manifest.json");
|
|
916
|
-
await writeFile(requestManifestPath, manifestCanonicalJson, "utf8");
|
|
917
|
-
}
|
|
918
807
|
return {
|
|
919
808
|
...(explicitPrNumber === undefined ? {} : { prNumber: explicitPrNumber }),
|
|
920
809
|
repository: repository.canonical,
|
|
921
810
|
repositoryDisplay: repository.display,
|
|
922
|
-
...(requestManifestPath === undefined
|
|
923
|
-
|
|
811
|
+
...(parsed.requestManifestPath === undefined
|
|
812
|
+
? {}
|
|
813
|
+
: { requestManifestPath: parsed.requestManifestPath }),
|
|
924
814
|
};
|
|
925
815
|
},
|
|
926
816
|
});
|
|
@@ -931,12 +821,10 @@ export async function admitPublicRole(role, parsed, env, override) {
|
|
|
931
821
|
throw new CliUsageError(`doctor --issue must be a positive integer, got ${Number.NaN}`);
|
|
932
822
|
}
|
|
933
823
|
const issueNumber = parsed.issueNumber;
|
|
934
|
-
|
|
935
|
-
const admittedDoctor = await admitStandardMaterialInvocation("doctor", {
|
|
824
|
+
return admitStandardMaterialInvocation("doctor", {
|
|
936
825
|
...shared,
|
|
937
826
|
instruction,
|
|
938
|
-
attachmentPaths
|
|
939
|
-
freezeAttachments: false,
|
|
827
|
+
attachmentPaths,
|
|
940
828
|
...project,
|
|
941
829
|
placedFields: async (placed) => {
|
|
942
830
|
let caseRunsPath;
|
|
@@ -973,16 +861,13 @@ export async function admitPublicRole(role, parsed, env, override) {
|
|
|
973
861
|
const detail = errorText(error);
|
|
974
862
|
throw new CliUsageError(`doctor case could not be constructed from retained evidence: ${detail}`, { cause: error });
|
|
975
863
|
}
|
|
976
|
-
frozenAttachments = await freezeAttachments(placed.ledgerHome, attachmentPaths, placed.attachmentsDirectory);
|
|
977
864
|
return {
|
|
978
865
|
issueNumber,
|
|
979
866
|
caseRunsPath,
|
|
980
867
|
caseIdentity,
|
|
981
|
-
attachments: persistedAttachmentRefs(frozenAttachments),
|
|
982
868
|
};
|
|
983
869
|
},
|
|
984
870
|
});
|
|
985
|
-
return { ...admittedDoctor, attachments: frozenAttachments };
|
|
986
871
|
}
|
|
987
872
|
case "source-locator": {
|
|
988
873
|
const projectRoot = resolve(parsed.project ?? shared.cwd);
|
|
@@ -1013,7 +898,7 @@ export async function admitPublicRole(role, parsed, env, override) {
|
|
|
1013
898
|
instruction: "",
|
|
1014
899
|
attachmentPaths: [],
|
|
1015
900
|
...project,
|
|
1016
|
-
|
|
901
|
+
recordAttachments: false,
|
|
1017
902
|
admittedFields: {
|
|
1018
903
|
sourceRunPath: sourceRun.runDirectory,
|
|
1019
904
|
sourceRun,
|
|
@@ -1030,7 +915,7 @@ export async function admitPublicRole(role, parsed, env, override) {
|
|
|
1030
915
|
instruction,
|
|
1031
916
|
attachmentPaths: [],
|
|
1032
917
|
...project,
|
|
1033
|
-
|
|
918
|
+
recordAttachments: false,
|
|
1034
919
|
admittedFields: { baseRevision },
|
|
1035
920
|
});
|
|
1036
921
|
}
|
|
@@ -1128,9 +1013,9 @@ async function placeRoleAdmission(options) {
|
|
|
1128
1013
|
home: options.home,
|
|
1129
1014
|
...(options.materialize === undefined ? {} : { materialize: options.materialize }),
|
|
1130
1015
|
});
|
|
1131
|
-
const attachments = options.
|
|
1016
|
+
const attachments = options.recordAttachments === false
|
|
1132
1017
|
? []
|
|
1133
|
-
:
|
|
1018
|
+
: admitCallerAttachments(options.attachmentPaths);
|
|
1134
1019
|
return {
|
|
1135
1020
|
runId,
|
|
1136
1021
|
bookKey,
|
|
@@ -1146,13 +1031,7 @@ async function placeRoleAdmission(options) {
|
|
|
1146
1031
|
};
|
|
1147
1032
|
}
|
|
1148
1033
|
function persistedAttachmentRefs(attachments) {
|
|
1149
|
-
return attachments.map((attachment) => ({
|
|
1150
|
-
provenancePath: attachment.provenancePath,
|
|
1151
|
-
frozenPath: attachment.frozenPath,
|
|
1152
|
-
byteLength: attachment.byteLength,
|
|
1153
|
-
sha256: attachment.sha256,
|
|
1154
|
-
mediaKind: attachment.mediaKind,
|
|
1155
|
-
}));
|
|
1034
|
+
return attachments.map((attachment) => ({ path: attachment.path }));
|
|
1156
1035
|
}
|
|
1157
1036
|
async function persistPlacedAdmission(admitted, placed, model) {
|
|
1158
1037
|
writeAdmittedRequestPersistence(placed.runDirectory, admitted, {
|
|
@@ -1172,19 +1051,18 @@ async function persistPlacedAdmission(admitted, placed, model) {
|
|
|
1172
1051
|
* before materializeCountersignInvocation writes the page.
|
|
1173
1052
|
* Seats whose extra facts are known before placement pass them as admittedFields.
|
|
1174
1053
|
* Seats whose extra facts depend on the placed run pass placedFields
|
|
1175
|
-
* (coder writes task.md; fixer writes fix-packet.md;
|
|
1176
|
-
* 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).
|
|
1177
1055
|
*/
|
|
1178
1056
|
async function admitStandardMaterialInvocation(role, options) {
|
|
1179
1057
|
const defer = options.deferPersistence === true;
|
|
1180
|
-
const
|
|
1058
|
+
const skipAttachments = defer || options.recordAttachments === false;
|
|
1181
1059
|
const placed = await placeRoleAdmission({
|
|
1182
1060
|
role,
|
|
1183
1061
|
home: options.home,
|
|
1184
1062
|
principalAuthority: options.principalAuthority,
|
|
1185
1063
|
cwd: options.cwd,
|
|
1186
1064
|
attachmentPaths: options.attachmentPaths,
|
|
1187
|
-
...(
|
|
1065
|
+
...(skipAttachments ? { recordAttachments: false } : {}),
|
|
1188
1066
|
...(defer ? { materialize: false } : {}),
|
|
1189
1067
|
...(options.project === undefined ? {} : { project: options.project }),
|
|
1190
1068
|
...(options.createRunId === undefined ? {} : { createRunId: options.createRunId }),
|
|
@@ -1196,7 +1074,8 @@ async function admitStandardMaterialInvocation(role, options) {
|
|
|
1196
1074
|
? {}
|
|
1197
1075
|
: { correlationId: options.correlationId };
|
|
1198
1076
|
const instruction = options.instruction;
|
|
1199
|
-
|
|
1077
|
+
// Admitted emptiness is literal absence, not whitespace-only (#1165 J3).
|
|
1078
|
+
const instructionEmpty = instruction.length === 0;
|
|
1200
1079
|
const placedExtra = options.placedFields === undefined ? undefined : await options.placedFields(placed);
|
|
1201
1080
|
const admittedFields = {
|
|
1202
1081
|
...(options.admittedFields ?? {}),
|
|
@@ -1244,7 +1123,7 @@ function admittedTransportPromptKind(admitted) {
|
|
|
1244
1123
|
/**
|
|
1245
1124
|
* One initial prompt transport. The registry `transportPrompt` leaf selects
|
|
1246
1125
|
* a fixed kickoff, a bound baseline, or frozen skill args. Absent means the
|
|
1247
|
-
* caller instruction plus
|
|
1126
|
+
* caller instruction plus caller attachment paths as-is (#1165).
|
|
1248
1127
|
* Engine / outsourcing material rides startup readingMaterial (#1167), not here.
|
|
1249
1128
|
*/
|
|
1250
1129
|
export function buildInstructionTransportPrompt(admitted) {
|
|
@@ -1260,7 +1139,9 @@ export function buildInstructionTransportPrompt(admitted) {
|
|
|
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
1147
|
return lines.join("\n");
|
|
@@ -1276,17 +1157,25 @@ export function buildInstructionTransportPrompt(admitted) {
|
|
|
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
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
1181
|
return lines.join("\n");
|
|
@@ -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") {
|