@akagilnc/pi-workflow-roles 0.1.3758 → 0.1.3783

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.
Files changed (63) hide show
  1. package/README.md +3 -2
  2. package/README.zh-CN.md +3 -2
  3. package/dist/acp-host/production-host.js +1735 -948
  4. package/dist/collector-config.js +0 -1
  5. package/dist/collector-github.js +199 -2
  6. package/dist/collector-identity.js +128 -41
  7. package/dist/collector-ledger.js +38 -9
  8. package/dist/collector-receipt.js +19 -7
  9. package/dist/collector-role.js +330 -369
  10. package/dist/collector-target.js +169 -0
  11. package/dist/collector-tool-schemas.js +51 -14
  12. package/dist/headless-host/description.js +77 -0
  13. package/dist/headless-host/mcp-relay.mjs +119 -0
  14. package/dist/headless-host/production-host.js +26590 -0
  15. package/dist/host-descriptions.js +44 -3
  16. package/dist/package-contracts/collector-output.js +32 -0
  17. package/dist/package-contracts/terminating-infrastructure.js +13 -12
  18. package/dist/pi/role-turn-host.js +1 -2
  19. package/dist/public-cli/github-remote.js +45 -0
  20. package/dist/public-cli/invocation.js +53 -54
  21. package/dist/public-cli/load-production-external-host.js +19 -0
  22. package/dist/public-cli/load-production-headless-host.js +36 -0
  23. package/dist/public-cli/main.js +857 -310
  24. package/dist/public-cli/option-definitions.js +6 -4
  25. package/dist/public-cli/run-lifecycle.js +3 -3
  26. package/dist/public-cli/settlement.js +83 -6
  27. package/dist/public-role-summons.js +40 -5
  28. package/dist/role-runtime.js +137 -7
  29. package/dist/submission-correctable-error.js +24 -0
  30. package/extensions/role-runtime.ts +0 -1
  31. package/package.json +1 -1
  32. package/scripts/build-package.mjs +28 -0
  33. package/src/acp-host/role-envelope.ts +146 -103
  34. package/src/acp-host/role-turn-host.ts +12 -0
  35. package/src/collector-config.ts +0 -1
  36. package/src/collector-github.ts +236 -2
  37. package/src/collector-identity.ts +148 -40
  38. package/src/collector-ledger.ts +48 -10
  39. package/src/collector-receipt.ts +33 -14
  40. package/src/collector-role.ts +376 -450
  41. package/src/collector-target.ts +207 -0
  42. package/src/collector-tool-schemas.ts +62 -15
  43. package/src/headless-host/description.ts +123 -0
  44. package/src/headless-host/production-host.ts +75 -0
  45. package/src/headless-host/role-turn-host.ts +424 -0
  46. package/src/host-contracts.ts +2 -1
  47. package/src/host-descriptions.ts +53 -6
  48. package/src/package-contracts/collector-output.ts +72 -0
  49. package/src/package-contracts/terminating-infrastructure.ts +24 -13
  50. package/src/pi/role-turn-host.ts +1 -2
  51. package/src/public-cli/cli.ts +12 -3
  52. package/src/public-cli/collector-run.ts +3 -2
  53. package/src/public-cli/github-remote.ts +45 -0
  54. package/src/public-cli/invocation.ts +60 -59
  55. package/src/public-cli/load-production-external-host.ts +29 -0
  56. package/src/public-cli/load-production-headless-host.ts +48 -0
  57. package/src/public-cli/main.ts +5 -0
  58. package/src/public-cli/option-definitions.ts +6 -4
  59. package/src/public-cli/run-lifecycle.ts +2 -2
  60. package/src/public-cli/settlement.ts +82 -6
  61. package/src/public-role-summons.ts +62 -9
  62. package/src/role-runtime.ts +166 -13
  63. package/src/submission-correctable-error.ts +38 -0
@@ -508,10 +508,16 @@ function validateAcceptedCollectorReceipt(value) {
508
508
  materials: records(safeGet(group, "materials")),
509
509
  findings: records(safeGet(group, "findings"))
510
510
  }));
511
+ const unfinishedRaw = safeGet(value, "unfinishedReasons");
512
+ const unfinishedReasons = strings(unfinishedRaw);
513
+ const submissionProjection = projectSubmissionProjection(safeGet(value, "submissionProjection"));
514
+ const prStateRaw = safeGet(value, "prState");
515
+ const prState = typeof prStateRaw === "string" ? prStateRaw : void 0;
511
516
  return {
512
517
  host: safeGet(value, "host"),
513
518
  repository: safeGet(value, "repository"),
514
519
  prNumber: safeGet(value, "prNumber"),
520
+ ...prState === void 0 ? {} : { prState },
515
521
  manifestDigest: safeGet(value, "manifestDigest"),
516
522
  activationTime: safeGet(value, "activationTime"),
517
523
  deadlineTime: safeGet(value, "deadlineTime"),
@@ -519,6 +525,8 @@ function validateAcceptedCollectorReceipt(value) {
519
525
  finalSnapshotId: safeGet(value, "finalSnapshotId"),
520
526
  targetHead: safeGet(value, "targetHead"),
521
527
  groups,
528
+ ...unfinishedReasons.length > 0 ? { unfinishedReasons } : {},
529
+ ...submissionProjection === void 0 ? {} : { submissionProjection },
522
530
  requestAttempts: records(safeGet(value, "requestAttempts")),
523
531
  snapshots: records(safeGet(value, "snapshots")).map((snapshot) => ({
524
532
  snapshotId: safeGet(snapshot, "snapshotId"),
@@ -538,6 +546,30 @@ function validateAcceptedCollectorReceipt(value) {
538
546
  evidenceRecords: records(safeGet(value, "evidenceRecords")).map((record4) => ({ evidenceId: safeGet(record4, "evidenceId"), kind: safeGet(record4, "kind"), versionId: safeGet(record4, "versionId"), contentDigest: safeGet(record4, "contentDigest"), firstObservedAt: safeGet(record4, "firstObservedAt"), githubId: safeGet(record4, "githubId"), authorLogin: safeGet(record4, "authorLogin"), htmlUrl: safeGet(record4, "htmlUrl"), authoritativeTime: safeGet(record4, "authoritativeTime") }))
539
547
  };
540
548
  }
549
+ function projectSubmissionProjection(raw) {
550
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
551
+ const p = raw;
552
+ const out = {};
553
+ if (p["findingsSource"] === "absent" || p["findingsSource"] === "array" || p["findingsSource"] === "unreadable") {
554
+ out.findingsSource = p["findingsSource"];
555
+ }
556
+ if (typeof p["findingsProjectedCount"] === "number") {
557
+ out.findingsProjectedCount = p["findingsProjectedCount"];
558
+ }
559
+ if (typeof p["findingsUnprojected"] === "boolean") {
560
+ out.findingsUnprojected = p["findingsUnprojected"];
561
+ }
562
+ if (p["unfinishedReasonsSource"] === "absent" || p["unfinishedReasonsSource"] === "array" || p["unfinishedReasonsSource"] === "unreadable") {
563
+ out.unfinishedReasonsSource = p["unfinishedReasonsSource"];
564
+ }
565
+ if (typeof p["unfinishedReasonsProjectedCount"] === "number") {
566
+ out.unfinishedReasonsProjectedCount = p["unfinishedReasonsProjectedCount"];
567
+ }
568
+ if (typeof p["unfinishedReasonsUnprojected"] === "boolean") {
569
+ out.unfinishedReasonsUnprojected = p["unfinishedReasonsUnprojected"];
570
+ }
571
+ return Object.keys(out).length > 0 ? out : void 0;
572
+ }
541
573
  var COLLECTOR_OUTPUT_TOOL;
542
574
  var init_collector_output = __esm({
543
575
  "src/package-contracts/collector-output.ts"() {
@@ -8344,27 +8376,28 @@ function withInfrastructureFailureDeclaration(schema) {
8344
8376
  object.required = [];
8345
8377
  return object;
8346
8378
  }
8347
- var INFRASTRUCTURE_FAILURE_DECLARATION_KEY, INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY, infrastructureFailureDeclarationSchema;
8379
+ var INFRASTRUCTURE_FAILURE_DECLARATION_KEY, INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY, infrastructureFailureNested, infrastructureFailureDeclarationSchema;
8348
8380
  var init_terminating_infrastructure = __esm({
8349
8381
  "src/package-contracts/terminating-infrastructure.ts"() {
8350
8382
  "use strict";
8351
8383
  init_build();
8352
8384
  INFRASTRUCTURE_FAILURE_DECLARATION_KEY = "infrastructureFailure";
8353
8385
  INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY = "diagnostic";
8386
+ infrastructureFailureNested = typebox_exports.Object(
8387
+ {
8388
+ [INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY]: typebox_exports.Unknown({
8389
+ description: "\u975E\u7A7A\u57FA\u7840\u8BBE\u65BD\u5931\u8D25\u8BCA\u65AD\u5B57\u7B26\u4E32\u3002\u65E0\u5931\u8D25\u65F6\u5FC5\u987B\u7701\u7565\u6574\u4E2A infrastructureFailure\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002"
8390
+ })
8391
+ },
8392
+ {
8393
+ additionalProperties: true,
8394
+ description: "\u57FA\u7840\u8BBE\u65BD\u771F\u5B9E\u5931\u8D25\u58F0\u660E\uFF08\u5982\u9700\uFF09\u3002\u89C4\u8303\u5F62\uFF1A{ diagnostic: \u975E\u7A7A\u8BCA\u65AD\u5B57\u7B26\u4E32 }\uFF1B\u65E0\u5931\u8D25\u65F6\u5FC5\u987B\u7701\u7565\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002"
8395
+ }
8396
+ );
8397
+ infrastructureFailureNested.required = [];
8354
8398
  infrastructureFailureDeclarationSchema = typebox_exports.Object(
8355
8399
  {
8356
- [INFRASTRUCTURE_FAILURE_DECLARATION_KEY]: typebox_exports.Object(
8357
- {
8358
- [INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY]: typebox_exports.String({
8359
- minLength: 1,
8360
- description: "\u975E\u7A7A\u57FA\u7840\u8BBE\u65BD\u5931\u8D25\u8BCA\u65AD"
8361
- })
8362
- },
8363
- {
8364
- additionalProperties: true,
8365
- description: "\u57FA\u7840\u8BBE\u65BD\u5931\u8D25\u58F0\u660E"
8366
- }
8367
- )
8400
+ [INFRASTRUCTURE_FAILURE_DECLARATION_KEY]: infrastructureFailureNested
8368
8401
  },
8369
8402
  { additionalProperties: true }
8370
8403
  );
@@ -15420,16 +15453,24 @@ var init_institutional_resolution = __esm({
15420
15453
  function lookupHostDescription(host) {
15421
15454
  return Object.hasOwn(HOST_DESCRIPTIONS, host) ? HOST_DESCRIPTIONS[host] : void 0;
15422
15455
  }
15456
+ function lookupHeadlessHostDescription(host) {
15457
+ return Object.hasOwn(HEADLESS_HOST_DESCRIPTIONS, host) ? HEADLESS_HOST_DESCRIPTIONS[host] : void 0;
15458
+ }
15459
+ function lookupHostFamily(host) {
15460
+ if (lookupHostDescription(host) !== void 0) return "acp";
15461
+ if (lookupHeadlessHostDescription(host) !== void 0) return "headless";
15462
+ return void 0;
15463
+ }
15423
15464
  function packagedExternalHostNames() {
15424
- return Object.keys(HOST_DESCRIPTIONS);
15465
+ return [...Object.keys(HOST_DESCRIPTIONS), ...Object.keys(HEADLESS_HOST_DESCRIPTIONS)];
15425
15466
  }
15426
15467
  function assertRegisteredHostName(host) {
15427
- if (host === DEFAULT_ROLE_TURN_HOST || lookupHostDescription(host) !== void 0) {
15468
+ if (host === DEFAULT_ROLE_TURN_HOST || lookupHostFamily(host) !== void 0) {
15428
15469
  return host;
15429
15470
  }
15430
15471
  throw new Error(`unregistered host: ${host}`);
15431
15472
  }
15432
- var PRIVATE_COMPAT_ENV, DEFAULT_ROLE_TURN_HOST, HOST_DESCRIPTIONS;
15473
+ var PRIVATE_COMPAT_ENV, DEFAULT_ROLE_TURN_HOST, HOST_DESCRIPTIONS, HEADLESS_HOST_DESCRIPTIONS;
15433
15474
  var init_host_descriptions = __esm({
15434
15475
  "src/host-descriptions.ts"() {
15435
15476
  "use strict";
@@ -15481,6 +15522,33 @@ var init_host_descriptions = __esm({
15481
15522
  })
15482
15523
  })
15483
15524
  });
15525
+ HEADLESS_HOST_DESCRIPTIONS = Object.freeze({
15526
+ "claude": Object.freeze({
15527
+ binaryFromHome: Object.freeze([".local", "bin", "claude"]),
15528
+ sessionBindingFile: "claude-headless-session.json",
15529
+ fixedArgs: Object.freeze([
15530
+ // One result envelope (not stream-json): typed receipt only; no event-stream copy.
15531
+ "--output-format",
15532
+ "json",
15533
+ "--permission-mode",
15534
+ "bypassPermissions",
15535
+ // Empty sources: no user/project/local operator surface (envelope owns materials).
15536
+ "--setting-sources",
15537
+ "",
15538
+ // With adapter-supplied --mcp-config only (AK relay); drops operator + claude.ai MCP.
15539
+ "--strict-mcp-config"
15540
+ ]),
15541
+ promptFlag: "-p",
15542
+ modelFlag: "--model",
15543
+ effortFlag: "--effort",
15544
+ // File path keeps large role envelopes off ARG_MAX.
15545
+ systemPromptFlag: "--system-prompt-file",
15546
+ jsonSchemaFlag: "--json-schema",
15547
+ mcpConfigFlag: "--mcp-config",
15548
+ sessionIdFlag: "--session-id",
15549
+ resumeFlag: "--resume"
15550
+ })
15551
+ });
15484
15552
  }
15485
15553
  });
15486
15554
 
@@ -16121,6 +16189,50 @@ var init_load_production_acp_host = __esm({
16121
16189
  }
16122
16190
  });
16123
16191
 
16192
+ // src/public-cli/load-production-headless-host.ts
16193
+ import { existsSync as existsSync4 } from "node:fs";
16194
+ import { join as join8 } from "node:path";
16195
+ import { pathToFileURL as pathToFileURL2 } from "node:url";
16196
+ async function loadProductionHeadlessHostFactory(packageRoot2, host) {
16197
+ const description = lookupHeadlessHostDescription(host);
16198
+ if (description === void 0) {
16199
+ throw new Error(`unregistered headless host: ${host}`);
16200
+ }
16201
+ const built = join8(packageRoot2, "dist/headless-host/production-host.js");
16202
+ const source = join8(packageRoot2, "src/headless-host/production-host.ts");
16203
+ const target = existsSync4(built) ? built : source;
16204
+ const href = pathToFileURL2(target).href;
16205
+ const mod = await import(href);
16206
+ const create = mod.createProductionHeadlessRoleTurnHost;
16207
+ return (options) => create({ ...options, description });
16208
+ }
16209
+ var init_load_production_headless_host = __esm({
16210
+ "src/public-cli/load-production-headless-host.ts"() {
16211
+ "use strict";
16212
+ init_host_descriptions();
16213
+ }
16214
+ });
16215
+
16216
+ // src/public-cli/load-production-external-host.ts
16217
+ async function loadProductionExternalHostFactory(packageRoot2, host) {
16218
+ const family = lookupHostFamily(host);
16219
+ if (family === "acp") {
16220
+ return loadProductionAcpHostFactory(packageRoot2, host);
16221
+ }
16222
+ if (family === "headless") {
16223
+ return loadProductionHeadlessHostFactory(packageRoot2, host);
16224
+ }
16225
+ throw new Error(`unregistered host: ${host}`);
16226
+ }
16227
+ var init_load_production_external_host = __esm({
16228
+ "src/public-cli/load-production-external-host.ts"() {
16229
+ "use strict";
16230
+ init_host_descriptions();
16231
+ init_load_production_acp_host();
16232
+ init_load_production_headless_host();
16233
+ }
16234
+ });
16235
+
16124
16236
  // src/host-contracts.ts
16125
16237
  var ExplicitInternalActivationError;
16126
16238
  var init_host_contracts = __esm({
@@ -16188,12 +16300,12 @@ var init_sitian_contracts = __esm({
16188
16300
  import { createHash as createHash2, randomUUID } from "node:crypto";
16189
16301
  import {
16190
16302
  appendFileSync,
16191
- existsSync as existsSync4,
16303
+ existsSync as existsSync5,
16192
16304
  readFileSync as readFileSync2,
16193
16305
  unlinkSync,
16194
16306
  writeFileSync
16195
16307
  } from "node:fs";
16196
- import { basename as basename3, dirname as dirname5, join as join8, resolve as resolve3 } from "node:path";
16308
+ import { basename as basename3, dirname as dirname5, join as join9, resolve as resolve3 } from "node:path";
16197
16309
  function isRecord7(value) {
16198
16310
  return typeof value === "object" && value !== null && !Array.isArray(value);
16199
16311
  }
@@ -16208,14 +16320,14 @@ function createExclusiveFile(path, contents) {
16208
16320
  writeFileSync(path, contents, { encoding: "utf8", flag: "wx" });
16209
16321
  }
16210
16322
  function sealTornTail(recordFile) {
16211
- if (!existsSync4(recordFile)) return;
16323
+ if (!existsSync5(recordFile)) return;
16212
16324
  const buffer = readFileSync2(recordFile);
16213
16325
  if (buffer.length > 0 && buffer[buffer.length - 1] !== 10) {
16214
16326
  appendFileSync(recordFile, "\n", "utf8");
16215
16327
  }
16216
16328
  }
16217
16329
  function findIdentityPointer(recordFile, identity, kind, level) {
16218
- if (!existsSync4(recordFile)) return void 0;
16330
+ if (!existsSync5(recordFile)) return void 0;
16219
16331
  const text = readFileSync2(recordFile, "utf8");
16220
16332
  for (const line2 of text.split("\n")) {
16221
16333
  const trimmed = line2.trim();
@@ -16332,7 +16444,7 @@ function resolveSitianRecordPathInLedger(input, ledgerHome) {
16332
16444
  const category = resolveSitianVolumeCategory(input.kind);
16333
16445
  let sessionDir;
16334
16446
  if (input.sessionParent !== void 0 && input.sessionParent.length > 0 && physicallyContainedIn(ledgerHome, input.sessionParent)) {
16335
- sessionDir = join8(dirname5(input.sessionParent), category);
16447
+ sessionDir = join9(dirname5(input.sessionParent), category);
16336
16448
  } else {
16337
16449
  const bookKey = safeBookKey(cwd);
16338
16450
  const bookDir = activationBookDirectory(ledgerHome, bookKey);
@@ -16346,12 +16458,12 @@ function resolveSitianRecordPathInLedger(input, ledgerHome) {
16346
16458
  subjectStr = JSON.stringify(input.subject);
16347
16459
  }
16348
16460
  const digest = createHash2("sha256").update(subjectStr).digest("hex").slice(0, 32);
16349
- sessionDir = join8(bookDir, category, digest);
16461
+ sessionDir = join9(bookDir, category, digest);
16350
16462
  } else {
16351
- sessionDir = join8(bookDir, category);
16463
+ sessionDir = join9(bookDir, category);
16352
16464
  }
16353
16465
  }
16354
- const recordFile = join8(sessionDir, "records.jsonl");
16466
+ const recordFile = join9(sessionDir, "records.jsonl");
16355
16467
  return { sessionDir, recordFile, ledgerHome };
16356
16468
  }
16357
16469
  function resolveSitianRecordPath(input) {
@@ -16408,13 +16520,13 @@ var init_sitian_appender = __esm({
16408
16520
  });
16409
16521
 
16410
16522
  // src/sitian-reader.ts
16411
- import { existsSync as existsSync5 } from "node:fs";
16523
+ import { existsSync as existsSync6 } from "node:fs";
16412
16524
  import { readFile as readFile2 } from "node:fs/promises";
16413
16525
  function isRecord8(value) {
16414
16526
  return typeof value === "object" && value !== null && !Array.isArray(value);
16415
16527
  }
16416
16528
  async function readSitianRecords(recordFile) {
16417
- if (!existsSync5(recordFile)) {
16529
+ if (!existsSync6(recordFile)) {
16418
16530
  return { records: [], diagnostics: [] };
16419
16531
  }
16420
16532
  const text = await readFile2(recordFile, "utf8");
@@ -16472,12 +16584,12 @@ var init_sitian_facade = __esm({
16472
16584
  import { execFile, spawn } from "node:child_process";
16473
16585
  import { constants } from "node:fs";
16474
16586
  import { access, appendFile, readFile as readFile3, realpath } from "node:fs/promises";
16475
- import { delimiter as delimiter2, isAbsolute as isAbsolute3, join as join9, resolve as resolve4 } from "node:path";
16587
+ import { delimiter as delimiter2, isAbsolute as isAbsolute3, join as join10, resolve as resolve4 } from "node:path";
16476
16588
  import { platform } from "node:process";
16477
16589
  import { promisify } from "node:util";
16478
16590
  import { randomUUID as randomUUID2 } from "node:crypto";
16479
16591
  function resolveInternalRoleEntrypoint(packageRoot2) {
16480
- return join9(packageRoot2, INTERNAL_ROLE_ENTRYPOINT_RELATIVE2);
16592
+ return join10(packageRoot2, INTERNAL_ROLE_ENTRYPOINT_RELATIVE2);
16481
16593
  }
16482
16594
  function buildExplicitInternalActivationArgs(selectedRoleEntry, extraArgs = []) {
16483
16595
  return ["--no-extensions", "-e", selectedRoleEntry, ...extraArgs];
@@ -16532,8 +16644,7 @@ function buildActivationFlagArgs(activation) {
16532
16644
  "collector",
16533
16645
  "--ak-collector-repo",
16534
16646
  activation.repo,
16535
- "--ak-collector-pr",
16536
- activation.pr,
16647
+ ...activation.pr === void 0 ? [] : ["--ak-collector-pr", activation.pr],
16537
16648
  ...activation.requestManifestPath === void 0 ? [] : ["--ak-collector-request-manifest", activation.requestManifestPath]
16538
16649
  ];
16539
16650
  case "doctor":
@@ -16822,7 +16933,7 @@ var init_role_turn_host = __esm({
16822
16933
 
16823
16934
  // src/run-ticket-number.ts
16824
16935
  import { readFile as readFile4 } from "node:fs/promises";
16825
- import { join as join10 } from "node:path";
16936
+ import { join as join11 } from "node:path";
16826
16937
  function isEnoent(error) {
16827
16938
  return error instanceof Error && "code" in error && error.code === "ENOENT";
16828
16939
  }
@@ -16835,7 +16946,7 @@ function ticketFromRecord(record4) {
16835
16946
  }
16836
16947
  async function readPageTicketNumber(runDirectory, page) {
16837
16948
  try {
16838
- const raw = JSON.parse(await readFile4(join10(runDirectory, page), "utf8"));
16949
+ const raw = JSON.parse(await readFile4(join11(runDirectory, page), "utf8"));
16839
16950
  if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
16840
16951
  return void 0;
16841
16952
  }
@@ -17276,13 +17387,356 @@ async function loadCollectorManifest(path) {
17276
17387
  const canonicalJson2 = canonicalManifest(requests);
17277
17388
  return { requests, canonicalJson: canonicalJson2, digest: createHash3("sha256").update(canonicalJson2).digest("hex"), sourcePath: path };
17278
17389
  }
17279
- var COLLECTOR_OWNER_PATTERN, COLLECTOR_REPO_PATTERN, COLLECTOR_FIXED_KICKOFF;
17390
+ var COLLECTOR_OWNER_PATTERN, COLLECTOR_REPO_PATTERN;
17280
17391
  var init_collector_config = __esm({
17281
17392
  "src/collector-config.ts"() {
17282
17393
  "use strict";
17283
17394
  COLLECTOR_OWNER_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/;
17284
17395
  COLLECTOR_REPO_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,98}[A-Za-z0-9])?$/;
17285
- COLLECTOR_FIXED_KICKOFF = "\u91C7\u96C6\u76EE\u6807\u5DF2\u53D7\u7406\uFF0C\u672C\u5C40\u5F00\u59CB\u3002";
17396
+ }
17397
+ });
17398
+
17399
+ // src/collector-github.ts
17400
+ import { spawn as spawn2 } from "node:child_process";
17401
+ function isRecord9(value) {
17402
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17403
+ }
17404
+ function parseJson(text, label) {
17405
+ try {
17406
+ return JSON.parse(text);
17407
+ } catch (error) {
17408
+ throw new Error(`GitHub ${label} returned malformed JSON`, { cause: error });
17409
+ }
17410
+ }
17411
+ function parsePullRequestNumberList(raw, label) {
17412
+ if (!Array.isArray(raw)) {
17413
+ throw new Error(`GitHub ${label} payload is not a list`);
17414
+ }
17415
+ const numbers = [];
17416
+ for (const item of raw) {
17417
+ if (!isRecord9(item)) {
17418
+ throw new Error(`GitHub ${label} payload contains a non-object pull request entry`);
17419
+ }
17420
+ try {
17421
+ numbers.push(parseCollectorPrNumber(item["number"]));
17422
+ } catch (error) {
17423
+ throw new Error(`GitHub ${label} payload contains an invalid pull request number`, {
17424
+ cause: error
17425
+ });
17426
+ }
17427
+ }
17428
+ return numbers;
17429
+ }
17430
+ async function listPullRequestNumbersByHead(runner, input) {
17431
+ const head = `${input.headOwner}:${input.headRef}`;
17432
+ const path = `/repos/${input.owner}/${input.repo}/pulls?head=${encodeURIComponent(head)}&state=all&per_page=100`;
17433
+ const response = await runner(
17434
+ ["api", "--hostname", "github.com", "--include", "-X", "GET", path],
17435
+ input.signal === void 0 ? {} : { signal: input.signal }
17436
+ );
17437
+ if (response.status < 200 || response.status >= 300) {
17438
+ throw new Error(`GitHub ${path} failed with HTTP ${response.status}`, {
17439
+ cause: {
17440
+ endpoint: path,
17441
+ status: response.status,
17442
+ headers: response.headers,
17443
+ body: response.bodyText
17444
+ }
17445
+ });
17446
+ }
17447
+ return parsePullRequestNumberList(parseJson(response.bodyText, path), path);
17448
+ }
17449
+ async function listPullRequestNumbersByCommit(runner, input) {
17450
+ const path = `/repos/${input.owner}/${input.repo}/commits/${encodeURIComponent(input.commitSha)}/pulls`;
17451
+ const response = await runner(
17452
+ ["api", "--hostname", "github.com", "--include", "-X", "GET", path],
17453
+ input.signal === void 0 ? {} : { signal: input.signal }
17454
+ );
17455
+ if (response.status < 200 || response.status >= 300) {
17456
+ throw new Error(`GitHub ${path} failed with HTTP ${response.status}`, {
17457
+ cause: {
17458
+ endpoint: path,
17459
+ status: response.status,
17460
+ headers: response.headers,
17461
+ body: response.bodyText
17462
+ }
17463
+ });
17464
+ }
17465
+ return parsePullRequestNumberList(parseJson(response.bodyText, path), path);
17466
+ }
17467
+ function createGhApiRunner(options = {}) {
17468
+ const spawnImpl = options.spawnImpl ?? spawn2;
17469
+ return async (args, runOptions = {}) => {
17470
+ return await new Promise((resolve11, reject) => {
17471
+ const signal = runOptions.signal;
17472
+ if (signal?.aborted) {
17473
+ reject(signal.reason ?? new Error("aborted"));
17474
+ return;
17475
+ }
17476
+ const child = spawnImpl("gh", args, {
17477
+ env: options.env ?? process.env,
17478
+ stdio: ["pipe", "pipe", "pipe"]
17479
+ });
17480
+ let stdout = "";
17481
+ let stderr = "";
17482
+ let settled = false;
17483
+ const settle = (fn) => {
17484
+ if (settled) return;
17485
+ settled = true;
17486
+ if (signal !== void 0) {
17487
+ signal.removeEventListener("abort", onAbort);
17488
+ }
17489
+ fn();
17490
+ };
17491
+ const onAbort = () => {
17492
+ try {
17493
+ child.kill("SIGTERM");
17494
+ } catch (error) {
17495
+ settle(() => reject(error));
17496
+ return;
17497
+ }
17498
+ settle(() => {
17499
+ reject(signal?.reason ?? new Error("aborted"));
17500
+ });
17501
+ };
17502
+ if (signal !== void 0) {
17503
+ signal.addEventListener("abort", onAbort, { once: true });
17504
+ }
17505
+ child.stdout.setEncoding("utf8").on("data", (chunk) => {
17506
+ stdout += chunk;
17507
+ });
17508
+ child.stderr.setEncoding("utf8").on("data", (chunk) => {
17509
+ stderr += chunk;
17510
+ });
17511
+ child.on("error", (error) => {
17512
+ settle(() => reject(error));
17513
+ });
17514
+ child.stdin.on("error", (error) => {
17515
+ settle(() => {
17516
+ if (signal?.aborted) {
17517
+ reject(signal.reason ?? new Error("aborted"));
17518
+ return;
17519
+ }
17520
+ const err = error instanceof Error ? error : new Error(String(error));
17521
+ reject(Object.assign(err, { ambiguousGhFailure: true }));
17522
+ });
17523
+ });
17524
+ if (runOptions.stdin !== void 0) {
17525
+ child.stdin.write(runOptions.stdin);
17526
+ }
17527
+ child.stdin.end();
17528
+ child.on("close", (code, signal2) => {
17529
+ settle(() => {
17530
+ const match = stdout.match(/^HTTP\/[\d.]+\s+(\d+)[^\n]*\r?\n([\s\S]*?)\r?\n\r?\n([\s\S]*)$/);
17531
+ if (match) {
17532
+ const status = Number(match[1]);
17533
+ const headerText = match[2] ?? "";
17534
+ const bodyText = match[3] ?? "";
17535
+ const headers = {};
17536
+ for (const line2 of headerText.split(/\r?\n/)) {
17537
+ const idx = line2.indexOf(":");
17538
+ if (idx === -1) continue;
17539
+ const name = line2.slice(0, idx).trim().toLowerCase();
17540
+ const value = line2.slice(idx + 1).trim();
17541
+ headers[name] = value;
17542
+ }
17543
+ resolve11({ status, headers, bodyText });
17544
+ return;
17545
+ }
17546
+ if (code === 0) {
17547
+ resolve11({ status: 200, headers: {}, bodyText: stdout });
17548
+ return;
17549
+ }
17550
+ const failure = new Error(
17551
+ `gh api failed without a parseable HTTP response (code=${String(code)}): ${stderr || stdout}`,
17552
+ { cause: { code, signal: signal2, stderr, stdout } }
17553
+ );
17554
+ reject(Object.assign(failure, { ambiguousGhFailure: true, stderr, stdout, code, signal: signal2 }));
17555
+ });
17556
+ });
17557
+ });
17558
+ };
17559
+ }
17560
+ var init_collector_github = __esm({
17561
+ "src/collector-github.ts"() {
17562
+ "use strict";
17563
+ init_collector_config();
17564
+ }
17565
+ });
17566
+
17567
+ // src/public-cli/github-remote.ts
17568
+ function ownerFromGitHubRemoteUrl(remoteUrl) {
17569
+ const ownerRepo = ownerRepoFromGitHubRemoteUrl(remoteUrl);
17570
+ if (ownerRepo === void 0) return void 0;
17571
+ return ownerRepo.split("/")[0].toLowerCase();
17572
+ }
17573
+ function ownerRepoFromGitHubRemoteUrl(remoteUrl) {
17574
+ const trimmed = remoteUrl.trim();
17575
+ const scp = /^git@github\.com:([^/\s]+)\/([^/\s]+?)(?:\.git)?$/i.exec(trimmed);
17576
+ if (scp) {
17577
+ return `${scp[1]}/${stripGitSuffix(scp[2])}`;
17578
+ }
17579
+ const ssh = /^ssh:\/\/git@github\.com\/([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i.exec(
17580
+ trimmed
17581
+ );
17582
+ if (ssh) {
17583
+ return `${ssh[1]}/${stripGitSuffix(ssh[2])}`;
17584
+ }
17585
+ let parsed;
17586
+ try {
17587
+ parsed = new URL(trimmed);
17588
+ } catch {
17589
+ return void 0;
17590
+ }
17591
+ if (!/^github\.com$/i.test(parsed.hostname)) return void 0;
17592
+ if (parsed.search !== "" || parsed.hash !== "") return void 0;
17593
+ const parts = parsed.pathname.split("/").filter((p) => p.length > 0);
17594
+ if (parts.length !== 2) return void 0;
17595
+ return `${parts[0]}/${stripGitSuffix(parts[1])}`;
17596
+ }
17597
+ function stripGitSuffix(name) {
17598
+ return name.toLowerCase().endsWith(".git") ? name.slice(0, -4) : name;
17599
+ }
17600
+ var init_github_remote = __esm({
17601
+ "src/public-cli/github-remote.ts"() {
17602
+ "use strict";
17603
+ }
17604
+ });
17605
+
17606
+ // src/collector-target.ts
17607
+ import { execFileSync as execFileSync2 } from "node:child_process";
17608
+ function ambiguousTarget(detail, cause) {
17609
+ throw new CliUsageError(
17610
+ `collector target is ambiguous: ${detail}; pass an explicit --pr`,
17611
+ cause === void 0 ? void 0 : { cause }
17612
+ );
17613
+ }
17614
+ function gitFailure(detail, cause) {
17615
+ throw new Error(`collector git failed: ${detail}`, {
17616
+ cause: cause instanceof Error ? cause : new Error(String(cause))
17617
+ });
17618
+ }
17619
+ function gitText(projectRoot, args) {
17620
+ return execFileSync2("git", [...args], {
17621
+ cwd: projectRoot,
17622
+ encoding: "utf8",
17623
+ stdio: ["ignore", "pipe", "pipe"]
17624
+ }).trim();
17625
+ }
17626
+ function isGitConfigMissing(error) {
17627
+ if (typeof error !== "object" || error === null) return false;
17628
+ const status = error.status;
17629
+ return status === 1;
17630
+ }
17631
+ function readCurrentBranch(projectRoot) {
17632
+ try {
17633
+ return gitText(projectRoot, ["rev-parse", "--abbrev-ref", "HEAD"]);
17634
+ } catch (error) {
17635
+ gitFailure("cannot read current git branch", error);
17636
+ }
17637
+ }
17638
+ function readHeadSha(projectRoot) {
17639
+ try {
17640
+ return gitText(projectRoot, ["rev-parse", "HEAD"]);
17641
+ } catch (error) {
17642
+ gitFailure("cannot read current HEAD", error);
17643
+ }
17644
+ }
17645
+ function headRefFromMerge(merge) {
17646
+ const trimmed = merge.trim();
17647
+ if (trimmed.length === 0) return void 0;
17648
+ if (trimmed.startsWith("refs/heads/")) {
17649
+ const ref = trimmed.slice("refs/heads/".length);
17650
+ return ref.length > 0 ? ref : void 0;
17651
+ }
17652
+ if (trimmed.startsWith("refs/")) return void 0;
17653
+ return trimmed;
17654
+ }
17655
+ function readUpstreamHeadBinding(projectRoot, branch) {
17656
+ let remote;
17657
+ try {
17658
+ remote = gitText(projectRoot, ["config", "--get", `branch.${branch}.remote`]);
17659
+ } catch (error) {
17660
+ if (isGitConfigMissing(error)) remote = void 0;
17661
+ else gitFailure(`cannot read branch.${branch}.remote`, error);
17662
+ }
17663
+ if (remote === void 0 || remote.length === 0) return void 0;
17664
+ let merge;
17665
+ try {
17666
+ merge = gitText(projectRoot, ["config", "--get", `branch.${branch}.merge`]);
17667
+ } catch (error) {
17668
+ if (isGitConfigMissing(error)) merge = void 0;
17669
+ else gitFailure(`cannot read branch.${branch}.merge`, error);
17670
+ }
17671
+ if (merge === void 0 || merge.length === 0) return void 0;
17672
+ const headRef = headRefFromMerge(merge);
17673
+ if (headRef === void 0) return void 0;
17674
+ let remoteUrl;
17675
+ try {
17676
+ remoteUrl = gitText(projectRoot, ["remote", "get-url", remote]);
17677
+ } catch (error) {
17678
+ gitFailure(`cannot read remote URL for ${remote}`, error);
17679
+ }
17680
+ const headOwner = ownerFromGitHubRemoteUrl(remoteUrl);
17681
+ if (headOwner === void 0) return void 0;
17682
+ return { headOwner, headRef };
17683
+ }
17684
+ async function resolveCollectorTarget(input) {
17685
+ if (input.explicitPrNumber !== void 0) {
17686
+ return { kind: "bound", prNumber: input.explicitPrNumber };
17687
+ }
17688
+ const branch = readCurrentBranch(input.projectRoot);
17689
+ const detached = branch.length === 0 || branch === "HEAD";
17690
+ const runner = createGhApiRunner();
17691
+ const { owner, repo } = input.repository;
17692
+ const numbers = [];
17693
+ if (!detached) {
17694
+ const headSha = readHeadSha(input.projectRoot);
17695
+ const upstream = readUpstreamHeadBinding(input.projectRoot, branch);
17696
+ if (upstream !== void 0) {
17697
+ numbers.push(
17698
+ ...await listPullRequestNumbersByHead(runner, {
17699
+ owner,
17700
+ repo,
17701
+ headOwner: upstream.headOwner,
17702
+ headRef: upstream.headRef
17703
+ })
17704
+ );
17705
+ }
17706
+ numbers.push(
17707
+ ...await listPullRequestNumbersByCommit(runner, {
17708
+ owner,
17709
+ repo,
17710
+ commitSha: headSha
17711
+ })
17712
+ );
17713
+ } else {
17714
+ const headSha = readHeadSha(input.projectRoot);
17715
+ numbers.push(
17716
+ ...await listPullRequestNumbersByCommit(runner, {
17717
+ owner,
17718
+ repo,
17719
+ commitSha: headSha
17720
+ })
17721
+ );
17722
+ }
17723
+ const unique = [...new Set(numbers)];
17724
+ if (unique.length === 1) {
17725
+ return { kind: "bound", prNumber: unique[0] };
17726
+ }
17727
+ if (unique.length > 1) {
17728
+ ambiguousTarget(
17729
+ `multiple PRs associated with context: ${unique.join(", ")}`
17730
+ );
17731
+ }
17732
+ return { kind: "unbound" };
17733
+ }
17734
+ var init_collector_target = __esm({
17735
+ "src/collector-target.ts"() {
17736
+ "use strict";
17737
+ init_collector_github();
17738
+ init_cli_errors();
17739
+ init_github_remote();
17286
17740
  }
17287
17741
  });
17288
17742
 
@@ -17388,9 +17842,9 @@ var init_uuidv7 = __esm({
17388
17842
 
17389
17843
  // src/typed-provider-http.ts
17390
17844
  import { readFile as readFile7, unlink, writeFile as writeFile2 } from "node:fs/promises";
17391
- import { join as join11 } from "node:path";
17845
+ import { join as join12 } from "node:path";
17392
17846
  function typedProviderHttpPath(runDirectory) {
17393
- return join11(runDirectory, TYPED_HTTP_FILE);
17847
+ return join12(runDirectory, TYPED_HTTP_FILE);
17394
17848
  }
17395
17849
  async function clearTypedProviderHttpObservation(runDirectory) {
17396
17850
  try {
@@ -17435,7 +17889,7 @@ var init_typed_provider_http = __esm({
17435
17889
 
17436
17890
  // src/public-cli/run-lifecycle.ts
17437
17891
  import { chmod, open, readdir as readdir2, readFile as readFile8, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
17438
- import { isAbsolute as isAbsolute4, join as join12 } from "node:path";
17892
+ import { isAbsolute as isAbsolute4, join as join13 } from "node:path";
17439
17893
  function resumeRereadInstruction(materialPath, handbook) {
17440
17894
  return handbook ? `\u91CD\u65B0\u8BFB ${materialPath}\uFF0C\u518D\u7EC4\u88C5\u5916\u5305 argv` : `\u91CD\u65B0\u8BFB ${materialPath}`;
17441
17895
  }
@@ -17483,7 +17937,7 @@ function renderResumeCommand(runId) {
17483
17937
  async function writeRoleRunState(runDirectory, record4) {
17484
17938
  const payload = { ...record4, runDirectory };
17485
17939
  await writeFile3(
17486
- join12(runDirectory, RUN_STATE_FILE),
17940
+ join13(runDirectory, RUN_STATE_FILE),
17487
17941
  `${JSON.stringify(payload, null, 2)}
17488
17942
  `,
17489
17943
  "utf8"
@@ -17533,7 +17987,7 @@ function parseCurrentCourtState(raw) {
17533
17987
  async function readRoleRunStateDisk(runDirectory) {
17534
17988
  let raw;
17535
17989
  try {
17536
- raw = JSON.parse(await readFile8(join12(runDirectory, RUN_STATE_FILE), "utf8"));
17990
+ raw = JSON.parse(await readFile8(join13(runDirectory, RUN_STATE_FILE), "utf8"));
17537
17991
  } catch {
17538
17992
  return void 0;
17539
17993
  }
@@ -17600,7 +18054,7 @@ async function writeRoleRunStateDisk(runDirectory, disk) {
17600
18054
  ...disk.currentCourt === void 0 ? {} : { currentCourt: disk.currentCourt }
17601
18055
  };
17602
18056
  await writeFile3(
17603
- join12(runDirectory, RUN_STATE_FILE),
18057
+ join13(runDirectory, RUN_STATE_FILE),
17604
18058
  `${JSON.stringify(payload, null, 2)}
17605
18059
  `,
17606
18060
  "utf8"
@@ -17844,15 +18298,15 @@ async function acquireRunWriterLease(runDirectory, onCleanupFailure) {
17844
18298
  };
17845
18299
  const reportCleanupFailure = (error) => {
17846
18300
  reportDiagnostic(
17847
- `writer lease lock cleanup failed (release is best-effort; residual lock left in place) at ${join12(runDirectory, WRITER_LOCK_FILE)}: ${describeErrorIdentity(error)}`
18301
+ `writer lease lock cleanup failed (release is best-effort; residual lock left in place) at ${join13(runDirectory, WRITER_LOCK_FILE)}: ${describeErrorIdentity(error)}`
17848
18302
  );
17849
18303
  };
17850
18304
  const reportReadFailure = (error) => {
17851
18305
  reportDiagnostic(
17852
- `writer lease lock read failed (holder liveness unverifiable; lock left in place) at ${join12(runDirectory, WRITER_LOCK_FILE)}: ${describeErrorIdentity(error)}`
18306
+ `writer lease lock read failed (holder liveness unverifiable; lock left in place) at ${join13(runDirectory, WRITER_LOCK_FILE)}: ${describeErrorIdentity(error)}`
17853
18307
  );
17854
18308
  };
17855
- const lockPath = join12(runDirectory, WRITER_LOCK_FILE);
18309
+ const lockPath = join13(runDirectory, WRITER_LOCK_FILE);
17856
18310
  let lastAutopsy = { verdict: "absent" };
17857
18311
  let lastReclaimFailure;
17858
18312
  for (let reclaimsLeft = WRITER_LEASE_RECLAIM_ROUNDS; ; reclaimsLeft -= 1) {
@@ -17902,7 +18356,7 @@ async function acquireRunWriterLease(runDirectory, onCleanupFailure) {
17902
18356
  async function findRunDirectoryById(home, runId) {
17903
18357
  if (runId.trim() === "") return void 0;
17904
18358
  const ledgerHome = resolveActivationLedgerHome(home);
17905
- const booksRoot = join12(ledgerHome, "books");
18359
+ const booksRoot = join13(ledgerHome, "books");
17906
18360
  let bookKeys;
17907
18361
  try {
17908
18362
  bookKeys = await readdir2(booksRoot);
@@ -17910,7 +18364,7 @@ async function findRunDirectoryById(home, runId) {
17910
18364
  return void 0;
17911
18365
  }
17912
18366
  for (const bookKey of bookKeys) {
17913
- const runsDir = join12(activationBookDirectory(ledgerHome, bookKey), "runs");
18367
+ const runsDir = join13(activationBookDirectory(ledgerHome, bookKey), "runs");
17914
18368
  let entries;
17915
18369
  try {
17916
18370
  entries = await readdir2(runsDir);
@@ -17919,7 +18373,7 @@ async function findRunDirectoryById(home, runId) {
17919
18373
  }
17920
18374
  for (const entry of entries) {
17921
18375
  if (entry === `${runId}@judge` || entry.startsWith(`${runId}@`)) {
17922
- return join12(runsDir, entry);
18376
+ return join13(runsDir, entry);
17923
18377
  }
17924
18378
  }
17925
18379
  }
@@ -17934,7 +18388,7 @@ async function readRunParentPath(runDirectory) {
17934
18388
  let raw;
17935
18389
  try {
17936
18390
  raw = JSON.parse(
17937
- await readFile8(join12(runDirectory, "admitted-request.json"), "utf8")
18391
+ await readFile8(join13(runDirectory, "admitted-request.json"), "utf8")
17938
18392
  );
17939
18393
  } catch (error) {
17940
18394
  if (errorCodeOf2(error) === "ENOENT") return void 0;
@@ -17954,7 +18408,7 @@ async function readRunParentPath(runDirectory) {
17954
18408
  }
17955
18409
  async function findLatestRunIdForSeatTicket(input) {
17956
18410
  const ledgerHome = resolveActivationLedgerHome(input.home);
17957
- const runsDir = join12(
18411
+ const runsDir = join13(
17958
18412
  activationBookDirectory(ledgerHome, input.bookKey),
17959
18413
  "runs"
17960
18414
  );
@@ -17971,7 +18425,7 @@ async function findLatestRunIdForSeatTicket(input) {
17971
18425
  if (!entry.endsWith(suffix)) continue;
17972
18426
  const runId = entry.slice(0, entry.length - suffix.length);
17973
18427
  if (runId.length === 0) continue;
17974
- const runDirectory = join12(runsDir, entry);
18428
+ const runDirectory = join13(runsDir, entry);
17975
18429
  if (input.parentRunPath !== void 0) {
17976
18430
  const parentPath = await readRunParentPath(runDirectory);
17977
18431
  if (parentPath !== input.parentRunPath) continue;
@@ -18156,7 +18610,7 @@ async function loadResumableRunRecord(home, runId, authority) {
18156
18610
  let model;
18157
18611
  try {
18158
18612
  const invocationRaw = JSON.parse(
18159
- await readFile8(join12(run.runDirectory, "invocation.json"), "utf8")
18613
+ await readFile8(join13(run.runDirectory, "invocation.json"), "utf8")
18160
18614
  );
18161
18615
  if (invocationRaw !== null && typeof invocationRaw === "object" && !Array.isArray(invocationRaw)) {
18162
18616
  const rec = invocationRaw;
@@ -18439,7 +18893,7 @@ async function loadResumableCollectorRun(home, runId, authority) {
18439
18893
  );
18440
18894
  }
18441
18895
  const { prNumber, repository, repositoryDisplay, manifestDigest } = loaded.admittedFields;
18442
- if (prNumber === void 0 || repository === void 0 || repositoryDisplay === void 0 || manifestDigest === void 0) {
18896
+ if (repository === void 0 || repositoryDisplay === void 0 || manifestDigest === void 0) {
18443
18897
  throw new CliUsageError(
18444
18898
  `role run admitted collector repository identity is missing: ${runId}`
18445
18899
  );
@@ -18459,7 +18913,7 @@ async function loadResumableCollectorRun(home, runId, authority) {
18459
18913
  const admitted = {
18460
18914
  role: "collector",
18461
18915
  ...resumedBaseAdmitted(loaded),
18462
- prNumber,
18916
+ ...prNumber === void 0 ? {} : { prNumber },
18463
18917
  repository: parsedRepository,
18464
18918
  ...loaded.admittedFields.requestManifestPath === void 0 ? {} : { requestManifestPath: loaded.admittedFields.requestManifestPath },
18465
18919
  manifestDigest
@@ -18564,7 +19018,7 @@ __export(notary_source_run_exports, {
18564
19018
  loadNotarySourceRunLocator: () => loadNotarySourceRunLocator,
18565
19019
  resolveNotarySourceRunLocator: () => resolveNotarySourceRunLocator
18566
19020
  });
18567
- import { dirname as dirname7, isAbsolute as isAbsolute5, join as join13, resolve as resolve6, basename as basename4 } from "node:path";
19021
+ import { dirname as dirname7, isAbsolute as isAbsolute5, join as join14, resolve as resolve6, basename as basename4 } from "node:path";
18568
19022
  import { lstat as lstat2, realpath as realpath3 } from "node:fs/promises";
18569
19023
  function parseRunDirectoryName(name) {
18570
19024
  const match = RUN_DIR_NAME.exec(name);
@@ -18610,11 +19064,11 @@ async function resolveNotarySourceRunLocator(options) {
18610
19064
  }
18611
19065
  const ledgerHome = resolveActivationLedgerHome(options.home);
18612
19066
  const bookKey = resolveBookKeyFromGit(options.projectRoot);
18613
- const bookRunsRoot = join13(activationBookDirectory(ledgerHome, bookKey), "runs");
19067
+ const bookRunsRoot = join14(activationBookDirectory(ledgerHome, bookKey), "runs");
18614
19068
  let candidate;
18615
19069
  const bare = parseRunDirectoryName(raw);
18616
19070
  if (bare !== void 0 && !raw.includes("/") && !raw.includes("\\")) {
18617
- candidate = join13(bookRunsRoot, `${bare.runId}@${bare.role}`);
19071
+ candidate = join14(bookRunsRoot, `${bare.runId}@${bare.role}`);
18618
19072
  } else {
18619
19073
  candidate = isAbsolute5(raw) ? raw : resolve6(options.projectRoot, raw);
18620
19074
  }
@@ -19254,12 +19708,13 @@ var init_option_definitions = __esm({
19254
19708
  canonical: "--pr",
19255
19709
  aliases: [],
19256
19710
  valueMetavar: "number",
19257
- required: true,
19711
+ // #676 D1: optional when context uniquely determines the PR; ambiguous → require explicit.
19712
+ required: false,
19258
19713
  repeatable: false,
19259
19714
  form: "option",
19260
19715
  description: {
19261
- en: "Required positive GitHub pull request number.",
19262
- zh: "\u5FC5\u586B\uFF1B\u6B63\u6574\u6570 GitHub PR \u53F7\u3002"
19716
+ en: "Positive GitHub pull request number. Optional when unique branch/HEAD association binds the PR, or when the Collector role can decide the target from task materials via bind-target; multi-candidate git context or a role that cannot decide requires an explicit value.",
19717
+ zh: "\u6B63\u6574\u6570 GitHub PR \u53F7\u3002\u5206\u652F/HEAD \u552F\u4E00\u5173\u8054\u53EF\u7ED1\u5B9A\u65F6\u53EF\u7701\u7565\uFF1B\u4EA6\u53EF\u7531\u901A\u8FDB\u53F8\u4ECE\u4EFB\u52A1\u6750\u6599\u7ECF bind-target \u5224\u5B9A\u3002git \u591A\u5019\u9009\u6216\u89D2\u8272\u65E0\u6CD5\u5224\u5B9A\u65F6\u5FC5\u987B\u663E\u5F0F\u63D0\u4F9B\u3002"
19263
19718
  }
19264
19719
  },
19265
19720
  {
@@ -19578,9 +20033,10 @@ var init_option_definitions = __esm({
19578
20033
  collector: {
19579
20034
  command: "collector",
19580
20035
  summary: "Collect GitHub PR review evidence.",
19581
- usage: ["ak-role collector --pr <number> [options] [instruction]"],
20036
+ usage: ["ak-role collector [--pr <number>] [options] [instruction]"],
19582
20037
  examples: [
19583
20038
  "ak-role collector --pr 42 --repo owner/repository",
20039
+ 'ak-role collector --repo owner/repository "Collect findings for #42"',
19584
20040
  "ak-role collector --pr 42 --request-manifest ./requests.json"
19585
20041
  ]
19586
20042
  },
@@ -19730,7 +20186,7 @@ var init_option_definitions = __esm({
19730
20186
  });
19731
20187
 
19732
20188
  // src/public-cli/invocation.ts
19733
- import { execFileSync as execFileSync2 } from "node:child_process";
20189
+ import { execFileSync as execFileSync3 } from "node:child_process";
19734
20190
  import {
19735
20191
  lstat as lstat3,
19736
20192
  mkdir as mkdir2,
@@ -19738,11 +20194,11 @@ import {
19738
20194
  realpath as realpath4,
19739
20195
  writeFile as writeFile4
19740
20196
  } from "node:fs/promises";
19741
- import { basename as basename5, isAbsolute as isAbsolute6, join as join14, resolve as resolve7, sep as sep3 } from "node:path";
20197
+ import { basename as basename5, isAbsolute as isAbsolute6, join as join15, resolve as resolve7, sep as sep3 } from "node:path";
19742
20198
  function issueAdmissionPlacement(authority, request) {
19743
20199
  const principal = authority.issue(request);
19744
20200
  const { sessionDirectory, sessionFile } = authority.decode(principal);
19745
- const runDirectory = join14(sessionDirectory, "..");
20201
+ const runDirectory = join15(sessionDirectory, "..");
19746
20202
  const ledgerHome = resolveActivationLedgerHome(request.home);
19747
20203
  const bookKey = resolveBookKeyFromGit(request.cwd);
19748
20204
  return {
@@ -19790,14 +20246,14 @@ async function writeRoleInvocationLedger(source, role, effectiveModel) {
19790
20246
  ...effectiveModelLedgerFields(effectiveModel)
19791
20247
  };
19792
20248
  await writeFile4(
19793
- join14(source.runDirectory, "invocation.json"),
20249
+ join15(source.runDirectory, "invocation.json"),
19794
20250
  `${JSON.stringify(identity, null, 2)}
19795
20251
  `,
19796
20252
  "utf8"
19797
20253
  );
19798
20254
  }
19799
20255
  async function recordEffectiveInvocationModel(runDirectory, model, engine, host) {
19800
- const ledgerPath = join14(runDirectory, "invocation.json");
20256
+ const ledgerPath = join15(runDirectory, "invocation.json");
19801
20257
  const current = JSON.parse(await readFile9(ledgerPath, "utf8"));
19802
20258
  const next = { ...current };
19803
20259
  if (model !== void 0) {
@@ -19825,7 +20281,7 @@ async function recordEffectiveInvocationModel(runDirectory, model, engine, host)
19825
20281
  );
19826
20282
  }
19827
20283
  async function mergeInvocationIdentityPage(runDirectory, fields) {
19828
- const ledgerPath = join14(runDirectory, "invocation.json");
20284
+ const ledgerPath = join15(runDirectory, "invocation.json");
19829
20285
  const current = JSON.parse(await readFile9(ledgerPath, "utf8"));
19830
20286
  await writeFile4(
19831
20287
  ledgerPath,
@@ -19886,7 +20342,7 @@ async function recordLaunchedPiIdentity(runDirectory, identity) {
19886
20342
  async function observeLaunchedRolePackageIdentity(packageRoot2, selectedRoleEntry) {
19887
20343
  const rolePackageRoot = packageRoot2;
19888
20344
  const raw = JSON.parse(
19889
- await readFile9(join14(rolePackageRoot, "package.json"), "utf8")
20345
+ await readFile9(join15(rolePackageRoot, "package.json"), "utf8")
19890
20346
  );
19891
20347
  if (typeof raw.version !== "string" || raw.version.trim() === "") {
19892
20348
  throw new Error(
@@ -20133,7 +20589,7 @@ async function freezeRegularFileAttachment(sourcePath, destinationDir, index) {
20133
20589
  }
20134
20590
  const bytes = await readFile9(absolute);
20135
20591
  const name = `${String(index).padStart(2, "0")}-${basename5(absolute)}`;
20136
- const frozenPath = join14(destinationDir, name);
20592
+ const frozenPath = join15(destinationDir, name);
20137
20593
  await writeFile4(frozenPath, bytes);
20138
20594
  return {
20139
20595
  attachment: {
@@ -20161,7 +20617,7 @@ async function freezeAttachments(attachmentPaths, attachmentsDirectory) {
20161
20617
  async function freezeAttachmentsIntoRun(attachmentPaths, runDirectory, summonsKey = `s-${Date.now().toString(36)}`) {
20162
20618
  if (attachmentPaths.length === 0) return [];
20163
20619
  const ledgerHome = resolveActivationLedgerHome(homeFromRunDirectory(runDirectory));
20164
- const attachmentsDirectory = join14(runDirectory, "attachments", summonsKey);
20620
+ const attachmentsDirectory = join15(runDirectory, "attachments", summonsKey);
20165
20621
  ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
20166
20622
  return freezeAttachments(attachmentPaths, attachmentsDirectory);
20167
20623
  }
@@ -20187,7 +20643,7 @@ async function admitStandardMaterialInvocation(role, options) {
20187
20643
  role,
20188
20644
  home: options.home
20189
20645
  });
20190
- const attachmentsDirectory = join14(runDirectory, "attachments");
20646
+ const attachmentsDirectory = join15(runDirectory, "attachments");
20191
20647
  ensureRealDirectoryTree(ledgerHome, sessionDirectory);
20192
20648
  ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
20193
20649
  const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
@@ -20212,7 +20668,7 @@ async function admitStandardMaterialInvocation(role, options) {
20212
20668
  mediaKind: a.mediaKind
20213
20669
  }))
20214
20670
  };
20215
- const admittedRequestPath = join14(runDirectory, "admitted-request.json");
20671
+ const admittedRequestPath = join15(runDirectory, "admitted-request.json");
20216
20672
  await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
20217
20673
  sessionDirectory,
20218
20674
  sessionFile
@@ -20290,7 +20746,7 @@ async function admitCountersignInvocation(options) {
20290
20746
  role: "countersign",
20291
20747
  home: options.home
20292
20748
  });
20293
- const attachmentsDirectory = join14(runDirectory, "attachments");
20749
+ const attachmentsDirectory = join15(runDirectory, "attachments");
20294
20750
  ensureRealDirectoryTree(ledgerHome, sessionDirectory);
20295
20751
  ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
20296
20752
  const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
@@ -20314,7 +20770,7 @@ async function admitCountersignInvocation(options) {
20314
20770
  mediaKind: a.mediaKind
20315
20771
  }))
20316
20772
  };
20317
- const admittedRequestPath = join14(runDirectory, "admitted-request.json");
20773
+ const admittedRequestPath = join15(runDirectory, "admitted-request.json");
20318
20774
  await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
20319
20775
  sessionDirectory,
20320
20776
  sessionFile
@@ -20338,7 +20794,7 @@ function buildCountersignTransportPrompt(admitted, engineMaterial) {
20338
20794
  return buildInstructionTransportPrompt(admitted, engineMaterial);
20339
20795
  }
20340
20796
  async function ensureRunArtifactsDir(runDirectory) {
20341
- const dir = join14(runDirectory, "artifacts");
20797
+ const dir = join15(runDirectory, "artifacts");
20342
20798
  await mkdir2(dir, { recursive: true });
20343
20799
  return dir;
20344
20800
  }
@@ -20370,11 +20826,11 @@ async function admitCoderInvocation(options) {
20370
20826
  role: "coder",
20371
20827
  home: options.home
20372
20828
  });
20373
- const attachmentsDirectory = join14(runDirectory, "attachments");
20829
+ const attachmentsDirectory = join15(runDirectory, "attachments");
20374
20830
  ensureRealDirectoryTree(ledgerHome, sessionDirectory);
20375
20831
  ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
20376
20832
  const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
20377
- const taskPath = join14(runDirectory, "task.md");
20833
+ const taskPath = join15(runDirectory, "task.md");
20378
20834
  await writeFile4(taskPath, instruction, "utf8");
20379
20835
  const admitted = {
20380
20836
  role: "coder",
@@ -20395,7 +20851,7 @@ async function admitCoderInvocation(options) {
20395
20851
  mediaKind: a.mediaKind
20396
20852
  }))
20397
20853
  };
20398
- const admittedRequestPath = join14(runDirectory, "admitted-request.json");
20854
+ const admittedRequestPath = join15(runDirectory, "admitted-request.json");
20399
20855
  await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
20400
20856
  sessionDirectory,
20401
20857
  sessionFile
@@ -20476,13 +20932,13 @@ async function admitFixerInvocation(options) {
20476
20932
  role: "fixer",
20477
20933
  home: options.home
20478
20934
  });
20479
- const attachmentsDirectory = join14(runDirectory, "attachments");
20935
+ const attachmentsDirectory = join15(runDirectory, "attachments");
20480
20936
  ensureRealDirectoryTree(ledgerHome, sessionDirectory);
20481
20937
  ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
20482
20938
  const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
20483
20939
  let prerequisitesPath;
20484
20940
  if (prerequisitesSource !== void 0) {
20485
- prerequisitesPath = join14(runDirectory, "prerequisites.json");
20941
+ prerequisitesPath = join15(runDirectory, "prerequisites.json");
20486
20942
  await writeFile4(
20487
20943
  prerequisitesPath,
20488
20944
  `${JSON.stringify(prerequisites, null, 2)}
@@ -20490,7 +20946,7 @@ async function admitFixerInvocation(options) {
20490
20946
  "utf8"
20491
20947
  );
20492
20948
  }
20493
- const packetPath = join14(runDirectory, "fix-packet.md");
20949
+ const packetPath = join15(runDirectory, "fix-packet.md");
20494
20950
  await writeFile4(packetPath, instruction, "utf8");
20495
20951
  const admitted = {
20496
20952
  role: "fixer",
@@ -20516,7 +20972,7 @@ async function admitFixerInvocation(options) {
20516
20972
  mediaKind: a.mediaKind
20517
20973
  }))
20518
20974
  };
20519
- const admittedRequestPath = join14(runDirectory, "admitted-request.json");
20975
+ const admittedRequestPath = join15(runDirectory, "admitted-request.json");
20520
20976
  await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
20521
20977
  sessionDirectory,
20522
20978
  sessionFile
@@ -20610,7 +21066,7 @@ function parseCollectorArgv(args) {
20610
21066
  }
20611
21067
  options.assertRequired();
20612
21068
  return {
20613
- prNumber,
21069
+ ...prNumber === void 0 ? {} : { prNumber },
20614
21070
  instruction: positional.join(" "),
20615
21071
  attachmentPaths,
20616
21072
  ...project === void 0 ? {} : { project },
@@ -20621,16 +21077,21 @@ function parseCollectorArgv(args) {
20621
21077
  function resolveGitHubRemoteRepository(projectRoot) {
20622
21078
  let remoteUrl;
20623
21079
  try {
20624
- remoteUrl = execFileSync2("git", ["remote", "get-url", "origin"], {
21080
+ remoteUrl = execFileSync3("git", ["remote", "get-url", "origin"], {
20625
21081
  cwd: projectRoot,
20626
21082
  encoding: "utf8",
20627
21083
  stdio: ["ignore", "pipe", "pipe"]
20628
21084
  }).trim();
20629
21085
  } catch (error) {
20630
- throw new CliUsageError(
20631
- "collector requires a github.com origin remote or an explicit --repo owner/repo",
20632
- { cause: error }
20633
- );
21086
+ if (isGitRemoteMissing(error)) {
21087
+ throw new CliUsageError(
21088
+ "collector requires a github.com origin remote or an explicit --repo owner/repo",
21089
+ { cause: error }
21090
+ );
21091
+ }
21092
+ throw new Error("collector git failed: cannot read origin remote URL", {
21093
+ cause: error instanceof Error ? error : new Error(String(error))
21094
+ });
20634
21095
  }
20635
21096
  if (remoteUrl.length === 0) {
20636
21097
  throw new CliUsageError(
@@ -20650,43 +21111,23 @@ function resolveGitHubRemoteRepository(projectRoot) {
20650
21111
  throw new CliUsageError(detail, { cause: error });
20651
21112
  }
20652
21113
  }
20653
- function ownerRepoFromGitHubRemoteUrl(remoteUrl) {
20654
- const trimmed = remoteUrl.trim();
20655
- const scp = /^git@github\.com:([^/\s]+)\/([^/\s]+?)(?:\.git)?$/i.exec(trimmed);
20656
- if (scp) {
20657
- return `${scp[1]}/${stripGitSuffix(scp[2])}`;
20658
- }
20659
- const ssh = /^ssh:\/\/git@github\.com\/([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i.exec(
20660
- trimmed
20661
- );
20662
- if (ssh) {
20663
- return `${ssh[1]}/${stripGitSuffix(ssh[2])}`;
20664
- }
20665
- let parsed;
20666
- try {
20667
- parsed = new URL(trimmed);
20668
- } catch {
20669
- return void 0;
20670
- }
20671
- if (!/^github\.com$/i.test(parsed.hostname)) return void 0;
20672
- if (parsed.search !== "" || parsed.hash !== "") return void 0;
20673
- const parts = parsed.pathname.split("/").filter((p) => p.length > 0);
20674
- if (parts.length !== 2) return void 0;
20675
- return `${parts[0]}/${stripGitSuffix(parts[1])}`;
20676
- }
20677
- function stripGitSuffix(name) {
20678
- return name.toLowerCase().endsWith(".git") ? name.slice(0, -4) : name;
21114
+ function isGitRemoteMissing(error) {
21115
+ if (typeof error !== "object" || error === null) return false;
21116
+ const status = error.status;
21117
+ return status === 2;
20679
21118
  }
20680
21119
  async function admitCollectorInvocation(options) {
20681
21120
  if (options.project !== void 0) {
20682
21121
  requireOptionPath("--project", options.project);
20683
21122
  }
20684
- let prNumber;
20685
- try {
20686
- prNumber = parseCollectorPrNumber(options.prNumber);
20687
- } catch (error) {
20688
- const detail = error instanceof Error ? error.message : String(error);
20689
- throw new CliUsageError(detail, { cause: error });
21123
+ let explicitPrNumber;
21124
+ if (options.prNumber !== void 0) {
21125
+ try {
21126
+ explicitPrNumber = parseCollectorPrNumber(options.prNumber);
21127
+ } catch (error) {
21128
+ const detail = error instanceof Error ? error.message : String(error);
21129
+ throw new CliUsageError(detail, { cause: error });
21130
+ }
20690
21131
  }
20691
21132
  const projectRoot = resolve7(options.project ?? options.cwd);
20692
21133
  let repository;
@@ -20725,17 +21166,23 @@ async function admitCollectorInvocation(options) {
20725
21166
  role: "collector",
20726
21167
  home: options.home
20727
21168
  });
20728
- const attachmentsDirectory = join14(runDirectory, "attachments");
21169
+ const attachmentsDirectory = join15(runDirectory, "attachments");
20729
21170
  ensureRealDirectoryTree(ledgerHome, sessionDirectory);
20730
21171
  ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
20731
21172
  const attachments = await freezeAttachments(options.attachmentPaths ?? [], attachmentsDirectory);
21173
+ const instruction = options.instruction ?? "";
21174
+ const instructionEmpty = instruction.trim() === "";
21175
+ const target = await resolveCollectorTarget({
21176
+ projectRoot,
21177
+ repository,
21178
+ ...explicitPrNumber === void 0 ? {} : { explicitPrNumber }
21179
+ });
21180
+ const prNumber = target.kind === "bound" ? target.prNumber : void 0;
20732
21181
  let requestManifestPath;
20733
21182
  if (manifestCanonicalJson !== void 0) {
20734
- requestManifestPath = join14(runDirectory, "request-manifest.json");
21183
+ requestManifestPath = join15(runDirectory, "request-manifest.json");
20735
21184
  await writeFile4(requestManifestPath, manifestCanonicalJson, "utf8");
20736
21185
  }
20737
- const instruction = options.instruction ?? "";
20738
- const instructionEmpty = instruction.trim() === "";
20739
21186
  const admitted = {
20740
21187
  role: "collector",
20741
21188
  runId,
@@ -20745,7 +21192,7 @@ async function admitCollectorInvocation(options) {
20745
21192
  principal,
20746
21193
  instruction,
20747
21194
  instructionEmpty,
20748
- prNumber,
21195
+ ...prNumber === void 0 ? {} : { prNumber },
20749
21196
  repository: repository.canonical,
20750
21197
  repositoryDisplay: repository.display,
20751
21198
  ...requestManifestPath === void 0 ? {} : { requestManifestPath },
@@ -20758,7 +21205,7 @@ async function admitCollectorInvocation(options) {
20758
21205
  mediaKind: a.mediaKind
20759
21206
  }))
20760
21207
  };
20761
- const admittedRequestPath = join14(runDirectory, "admitted-request.json");
21208
+ const admittedRequestPath = join15(runDirectory, "admitted-request.json");
20762
21209
  await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
20763
21210
  sessionDirectory,
20764
21211
  sessionFile
@@ -20775,14 +21222,14 @@ async function admitCollectorInvocation(options) {
20775
21222
  runDirectory,
20776
21223
  principal,
20777
21224
  admittedRequestPath,
20778
- prNumber,
21225
+ ...prNumber === void 0 ? {} : { prNumber },
20779
21226
  repository,
20780
21227
  ...requestManifestPath === void 0 ? {} : { requestManifestPath },
20781
21228
  manifestDigest
20782
21229
  };
20783
21230
  }
20784
- function buildCollectorTransportPrompt(_admitted, engineMaterial) {
20785
- return appendEngineSessionMaterial([COLLECTOR_FIXED_KICKOFF], engineMaterial).join("\n");
21231
+ function buildCollectorTransportPrompt(admitted, engineMaterial) {
21232
+ return buildInstructionTransportPrompt(admitted, engineMaterial);
20786
21233
  }
20787
21234
  function parseDoctorIssueNumber(raw) {
20788
21235
  const trimmed = raw.trim();
@@ -20855,7 +21302,7 @@ function parseDoctorArgv(args) {
20855
21302
  }
20856
21303
  async function resolveDoctorCaseRunsPath(options) {
20857
21304
  const ledgerHome = resolveActivationLedgerHome(options.home);
20858
- const defaultRuns = join14(
21305
+ const defaultRuns = join15(
20859
21306
  activationBookDirectory(ledgerHome, options.bookKey),
20860
21307
  "issues",
20861
21308
  String(options.issueNumber),
@@ -20962,7 +21409,7 @@ async function admitDoctorInvocation(options) {
20962
21409
  { cause: error }
20963
21410
  );
20964
21411
  }
20965
- const attachmentsDirectory = join14(runDirectory, "attachments");
21412
+ const attachmentsDirectory = join15(runDirectory, "attachments");
20966
21413
  ensureRealDirectoryTree(ledgerHome, sessionDirectory);
20967
21414
  ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
20968
21415
  const attachments = await freezeAttachments(options.attachmentPaths ?? [], attachmentsDirectory);
@@ -20988,7 +21435,7 @@ async function admitDoctorInvocation(options) {
20988
21435
  mediaKind: a.mediaKind
20989
21436
  }))
20990
21437
  };
20991
- const admittedRequestPath = join14(runDirectory, "admitted-request.json");
21438
+ const admittedRequestPath = join15(runDirectory, "admitted-request.json");
20992
21439
  await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
20993
21440
  sessionDirectory,
20994
21441
  sessionFile
@@ -21120,7 +21567,7 @@ async function admitNotaryInvocation(options) {
21120
21567
  ...ticketFields,
21121
21568
  ...options.correlationId === void 0 ? {} : { correlationId: options.correlationId }
21122
21569
  };
21123
- const admittedRequestPath = join14(runDirectory, "admitted-request.json");
21570
+ const admittedRequestPath = join15(runDirectory, "admitted-request.json");
21124
21571
  await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
21125
21572
  sessionDirectory,
21126
21573
  sessionFile
@@ -21222,7 +21669,7 @@ async function admitGleanerLeftInvocation(options) {
21222
21669
  attachments: [],
21223
21670
  ...options.correlationId === void 0 ? {} : { correlationId: options.correlationId }
21224
21671
  };
21225
- const admittedRequestPath = join14(runDirectory, "admitted-request.json");
21672
+ const admittedRequestPath = join15(runDirectory, "admitted-request.json");
21226
21673
  await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
21227
21674
  sessionDirectory,
21228
21675
  sessionFile
@@ -21327,7 +21774,7 @@ async function admitReviewerInvocation(options) {
21327
21774
  role: "reviewer",
21328
21775
  home: options.home
21329
21776
  });
21330
- const attachmentsDirectory = join14(runDirectory, "attachments");
21777
+ const attachmentsDirectory = join15(runDirectory, "attachments");
21331
21778
  ensureRealDirectoryTree(ledgerHome, sessionDirectory);
21332
21779
  ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
21333
21780
  const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
@@ -21352,7 +21799,7 @@ async function admitReviewerInvocation(options) {
21352
21799
  mediaKind: a.mediaKind
21353
21800
  }))
21354
21801
  };
21355
- const admittedRequestPath = join14(runDirectory, "admitted-request.json");
21802
+ const admittedRequestPath = join15(runDirectory, "admitted-request.json");
21356
21803
  await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
21357
21804
  sessionDirectory,
21358
21805
  sessionFile
@@ -21479,7 +21926,7 @@ async function admitMergerInvocation(options) {
21479
21926
  role: "merger",
21480
21927
  home: options.home
21481
21928
  });
21482
- const attachmentsDirectory = join14(runDirectory, "attachments");
21929
+ const attachmentsDirectory = join15(runDirectory, "attachments");
21483
21930
  ensureRealDirectoryTree(ledgerHome, sessionDirectory);
21484
21931
  ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
21485
21932
  const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
@@ -21507,7 +21954,7 @@ async function admitMergerInvocation(options) {
21507
21954
  // Authorized checks remain available on the assignment; default none.
21508
21955
  authorizedChecks: []
21509
21956
  });
21510
- const mergerInputPath = join14(runDirectory, "merger-input.json");
21957
+ const mergerInputPath = join15(runDirectory, "merger-input.json");
21511
21958
  await writeFile4(
21512
21959
  mergerInputPath,
21513
21960
  `${JSON.stringify(mergerInput, null, 2)}
@@ -21539,7 +21986,7 @@ async function admitMergerInvocation(options) {
21539
21986
  mediaKind: a.mediaKind
21540
21987
  }))
21541
21988
  };
21542
- const admittedRequestPath = join14(runDirectory, "admitted-request.json");
21989
+ const admittedRequestPath = join15(runDirectory, "admitted-request.json");
21543
21990
  await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
21544
21991
  sessionDirectory,
21545
21992
  sessionFile
@@ -21802,6 +22249,8 @@ var init_invocation = __esm({
21802
22249
  init_run_ticket_number();
21803
22250
  init_doctor_evidence();
21804
22251
  init_collector_config();
22252
+ init_collector_target();
22253
+ init_github_remote();
21805
22254
  init_fixer_packet();
21806
22255
  init_merger_git_state();
21807
22256
  init_merger_contracts();
@@ -21830,7 +22279,7 @@ var init_invocation = __esm({
21830
22279
  // src/package-resources/method-skill.ts
21831
22280
  import { createHash as createHash4 } from "node:crypto";
21832
22281
  import { readFile as readFile10, realpath as realpath5 } from "node:fs/promises";
21833
- import { join as join15 } from "node:path";
22282
+ import { join as join16 } from "node:path";
21834
22283
  function gitBlobOid(bytes) {
21835
22284
  const body = typeof bytes === "string" ? Buffer.from(bytes, "utf8") : Buffer.from(bytes);
21836
22285
  const header = Buffer.from(`blob ${body.byteLength}\0`, "utf8");
@@ -21847,16 +22296,16 @@ function packagedMethodSkillRelativeDirectory(name) {
21847
22296
  return `${METHOD_SKILL_RELATIVE_ROOT}/${name}`;
21848
22297
  }
21849
22298
  function resolvePackagedMethodSkillRoot(packageRoot2, name) {
21850
- return join15(packageRoot2, packagedMethodSkillRelativeDirectory(name));
22299
+ return join16(packageRoot2, packagedMethodSkillRelativeDirectory(name));
21851
22300
  }
21852
22301
  function resolvePackagedMethodSkillPath(packageRoot2, name) {
21853
- return join15(resolvePackagedMethodSkillRoot(packageRoot2, name), "SKILL.md");
22302
+ return join16(resolvePackagedMethodSkillRoot(packageRoot2, name), "SKILL.md");
21854
22303
  }
21855
- function isRecord9(value) {
22304
+ function isRecord10(value) {
21856
22305
  return typeof value === "object" && value !== null && !Array.isArray(value);
21857
22306
  }
21858
22307
  function parseProvenance(raw, expectedName) {
21859
- if (!isRecord9(raw)) {
22308
+ if (!isRecord10(raw)) {
21860
22309
  throw new Error(`Packaged method provenance must be an object for ${expectedName}`);
21861
22310
  }
21862
22311
  if (raw.name !== expectedName) {
@@ -21870,7 +22319,7 @@ function parseProvenance(raw, expectedName) {
21870
22319
  if (typeof raw.packageAdaptation !== "string" || raw.packageAdaptation.trim() === "") {
21871
22320
  throw new Error(`Packaged method provenance packageAdaptation must be nonblank`);
21872
22321
  }
21873
- if (!isRecord9(raw.upstream)) {
22322
+ if (!isRecord10(raw.upstream)) {
21874
22323
  throw new Error(`Packaged method provenance upstream must be an object`);
21875
22324
  }
21876
22325
  const upstream = raw.upstream;
@@ -21897,12 +22346,12 @@ function parseProvenance(raw, expectedName) {
21897
22346
  `Packaged method provenance upstream must include nonblank tag or version`
21898
22347
  );
21899
22348
  }
21900
- if (!isRecord9(raw.files)) {
22349
+ if (!isRecord10(raw.files)) {
21901
22350
  throw new Error(`Packaged method provenance files must be an object`);
21902
22351
  }
21903
22352
  const files = {};
21904
22353
  for (const [rel, entry] of Object.entries(raw.files)) {
21905
- if (!isRecord9(entry)) {
22354
+ if (!isRecord10(entry)) {
21906
22355
  throw new Error(`Packaged method provenance file entry must be an object: ${rel}`);
21907
22356
  }
21908
22357
  if (typeof entry.sha256 !== "string" || !SHA256_RE.test(entry.sha256)) {
@@ -21944,8 +22393,8 @@ function parseProvenance(raw, expectedName) {
21944
22393
  }
21945
22394
  async function loadPackagedMethodSkillMaterial(packageRoot2, name) {
21946
22395
  const rootDirectory = resolvePackagedMethodSkillRoot(packageRoot2, name);
21947
- const skillPathConfigured = join15(rootDirectory, "SKILL.md");
21948
- const provenancePath = join15(rootDirectory, "provenance.json");
22396
+ const skillPathConfigured = join16(rootDirectory, "SKILL.md");
22397
+ const provenancePath = join16(rootDirectory, "provenance.json");
21949
22398
  let provenanceRaw;
21950
22399
  try {
21951
22400
  provenanceRaw = await readFile10(provenancePath, "utf8");
@@ -21962,7 +22411,7 @@ async function loadPackagedMethodSkillMaterial(packageRoot2, name) {
21962
22411
  }
21963
22412
  const provenance = parseProvenance(provenanceJson, name);
21964
22413
  for (const [rel, expected] of Object.entries(provenance.files)) {
21965
- const absolute = join15(rootDirectory, rel);
22414
+ const absolute = join16(rootDirectory, rel);
21966
22415
  let bytes;
21967
22416
  try {
21968
22417
  bytes = await readFile10(absolute);
@@ -22085,7 +22534,7 @@ var init_compliance_transport = __esm({
22085
22534
 
22086
22535
  // src/ledger-session-read.ts
22087
22536
  import { readFile as readFile11 } from "node:fs/promises";
22088
- function isRecord10(value) {
22537
+ function isRecord11(value) {
22089
22538
  return typeof value === "object" && value !== null && !Array.isArray(value);
22090
22539
  }
22091
22540
  async function readLedgerSessionJsonl(path) {
@@ -22109,7 +22558,7 @@ async function readLedgerSessionJsonl(path) {
22109
22558
  }
22110
22559
  break;
22111
22560
  }
22112
- if (!isRecord10(row)) {
22561
+ if (!isRecord11(row)) {
22113
22562
  const kind = row === null ? "null" : Array.isArray(row) ? "array" : typeof row;
22114
22563
  throw new LedgerSessionJsonlError(
22115
22564
  `complete non-object JSONL record in ${path} at line ${index + 1}: expected object, got ${kind}`,
@@ -22146,7 +22595,7 @@ function extractSessionModelSequence(rows) {
22146
22595
  if (row.type === "model_change" && typeof row.modelId === "string") {
22147
22596
  push(row.modelId);
22148
22597
  }
22149
- const message = isRecord10(row.message) ? row.message : void 0;
22598
+ const message = isRecord11(row.message) ? row.message : void 0;
22150
22599
  if (message?.role === "assistant" && typeof message.model === "string") {
22151
22600
  push(message.model);
22152
22601
  }
@@ -22162,11 +22611,11 @@ function extractSessionToolIntervals(rows) {
22162
22611
  const openById = /* @__PURE__ */ new Map();
22163
22612
  for (const row of rows) {
22164
22613
  const rowTimestamp = typeof row.timestamp === "string" ? row.timestamp : void 0;
22165
- const message = isRecord10(row.message) ? row.message : void 0;
22614
+ const message = isRecord11(row.message) ? row.message : void 0;
22166
22615
  if (message?.role === "assistant" && Array.isArray(message.content)) {
22167
22616
  const callTimestamp = typeof message.timestamp === "string" && message.timestamp ? message.timestamp : rowTimestamp;
22168
22617
  for (const part of message.content) {
22169
- if (!isRecord10(part) || part.type !== "toolCall") continue;
22618
+ if (!isRecord11(part) || part.type !== "toolCall") continue;
22170
22619
  if (typeof part.id !== "string" || part.id.length === 0) {
22171
22620
  throw new Error("toolCall frame missing string id");
22172
22621
  }
@@ -22179,7 +22628,7 @@ function extractSessionToolIntervals(rows) {
22179
22628
  if (openById.has(part.id)) {
22180
22629
  throw new Error(`duplicate toolCall id ${part.id}`);
22181
22630
  }
22182
- const args = isRecord10(part.arguments) ? part.arguments : void 0;
22631
+ const args = isRecord11(part.arguments) ? part.arguments : void 0;
22183
22632
  const command = part.name === "bash" && args !== void 0 && typeof args.command === "string" ? bashCommandFirstLine(args.command) : void 0;
22184
22633
  const interval = {
22185
22634
  toolCallId: part.id,
@@ -22264,8 +22713,8 @@ var init_ledger_session_read = __esm({
22264
22713
 
22265
22714
  // src/analyst-gate-cycles-read.ts
22266
22715
  import { readdir as readdir3 } from "node:fs/promises";
22267
- import { join as join16 } from "node:path";
22268
- function isRecord11(value) {
22716
+ import { join as join17 } from "node:path";
22717
+ function isRecord12(value) {
22269
22718
  return typeof value === "object" && value !== null && !Array.isArray(value);
22270
22719
  }
22271
22720
  function isParentAttemptBindingRow(row) {
@@ -22296,7 +22745,7 @@ function isGateTerminatingToolName(toolName) {
22296
22745
  function acceptedGateReceiptIds(rows) {
22297
22746
  const accepted = /* @__PURE__ */ new Set();
22298
22747
  for (const row of rows) {
22299
- const message = isRecord11(row.message) ? row.message : void 0;
22748
+ const message = isRecord12(row.message) ? row.message : void 0;
22300
22749
  if (message?.role !== "toolResult") continue;
22301
22750
  if (typeof message.toolCallId !== "string" || message.toolCallId.length === 0) continue;
22302
22751
  if (message.isError === false) accepted.add(message.toolCallId);
@@ -22335,7 +22784,7 @@ function nearestAttemptBindingBefore(rows, beforeIndex) {
22335
22784
  for (let i = beforeIndex - 1; i >= 0; i -= 1) {
22336
22785
  const row = rows[i];
22337
22786
  if (!isParentAttemptBindingRow(row)) continue;
22338
- if (!isRecord11(row.data) || !isRecord11(row.data.parent)) continue;
22787
+ if (!isRecord12(row.data) || !isRecord12(row.data.parent)) continue;
22339
22788
  const id = row.data.parent.attemptEntryId;
22340
22789
  const sessionFile = row.data.parent.sessionFile;
22341
22790
  return {
@@ -22350,10 +22799,10 @@ function extractAllAcceptedGateToolCalls(rows) {
22350
22799
  const out = [];
22351
22800
  for (let rowIndex = 0; rowIndex < rows.length; rowIndex += 1) {
22352
22801
  const row = rows[rowIndex];
22353
- const message = isRecord11(row.message) ? row.message : void 0;
22802
+ const message = isRecord12(row.message) ? row.message : void 0;
22354
22803
  if (message?.role !== "assistant" || !Array.isArray(message.content)) continue;
22355
22804
  for (const part of message.content) {
22356
- if (!isRecord11(part) || part.type !== "toolCall") continue;
22805
+ if (!isRecord12(part) || part.type !== "toolCall") continue;
22357
22806
  if (typeof part.id !== "string" || part.id.length === 0) continue;
22358
22807
  if (typeof part.name !== "string" || part.name.length === 0) continue;
22359
22808
  if (!isGateTerminatingToolName(part.name)) continue;
@@ -22361,7 +22810,7 @@ function extractAllAcceptedGateToolCalls(rows) {
22361
22810
  const binding = nearestAttemptBindingBefore(rows, rowIndex);
22362
22811
  out.push({
22363
22812
  toolName: part.name,
22364
- args: isRecord11(part.arguments) ? part.arguments : void 0,
22813
+ args: isRecord12(part.arguments) ? part.arguments : void 0,
22365
22814
  accepted: true,
22366
22815
  rowIndex,
22367
22816
  ...binding
@@ -22501,7 +22950,7 @@ async function resolveOfficerSessionFromPointerFile(pointerPath) {
22501
22950
  { cause: error }
22502
22951
  );
22503
22952
  }
22504
- if (!isRecord11(raw) || raw.kind !== "direct-officer-run-pointer" || raw.version !== 1) {
22953
+ if (!isRecord12(raw) || raw.kind !== "direct-officer-run-pointer" || raw.version !== 1) {
22505
22954
  throw new Error(`direct officer run pointer has unknown shape in ${pointerPath}`);
22506
22955
  }
22507
22956
  const sessionFile = raw.sessionFile;
@@ -22526,7 +22975,7 @@ async function readAnalystGateCyclesFromAuditorRoles(auditorRolesDirectory, opti
22526
22975
  throw error;
22527
22976
  }
22528
22977
  for (const name of names) {
22529
- const path = join16(directory, name);
22978
+ const path = join17(directory, name);
22530
22979
  const fromPointer = name.endsWith(".pointer.json");
22531
22980
  const sessionPath = fromPointer ? await resolveOfficerSessionFromPointerFile(path) : path;
22532
22981
  if (sessionPath === void 0) continue;
@@ -22569,21 +23018,21 @@ var init_analyst_gate_cycles_read = __esm({
22569
23018
 
22570
23019
  // src/run-terminal-artifacts.ts
22571
23020
  import { readdir as readdir4, readFile as readFile12 } from "node:fs/promises";
22572
- import { basename as basename6, dirname as dirname8, join as join17 } from "node:path";
23021
+ import { basename as basename6, dirname as dirname8, join as join18 } from "node:path";
22573
23022
  function isMissingPathError2(error) {
22574
23023
  return error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
22575
23024
  }
22576
23025
  function errorText2(error) {
22577
23026
  return error instanceof Error ? error.message : String(error);
22578
23027
  }
22579
- function isRecord12(value) {
23028
+ function isRecord13(value) {
22580
23029
  return typeof value === "object" && value !== null && !Array.isArray(value);
22581
23030
  }
22582
23031
  function readUsableTerminalArtifactBody(body) {
22583
23032
  if (body === null) {
22584
23033
  return { ok: false, reason: "terminal artifact JSON value is null" };
22585
23034
  }
22586
- if (!isRecord12(body)) {
23035
+ if (!isRecord13(body)) {
22587
23036
  return {
22588
23037
  ok: false,
22589
23038
  reason: `terminal artifact JSON value is not a typed object (${Array.isArray(body) ? "array" : typeof body})`
@@ -22644,7 +23093,7 @@ async function listUniqueErrorFallbackPaths(directories) {
22644
23093
  }
22645
23094
  for (const name of names.sort((a, b) => a.localeCompare(b))) {
22646
23095
  if (!UNIQUE_ERROR_FALLBACK_NAME.test(name)) continue;
22647
- found.push(join17(dir, name));
23096
+ found.push(join18(dir, name));
22648
23097
  }
22649
23098
  }
22650
23099
  return found;
@@ -22660,14 +23109,14 @@ function presentUniqueFallbackBoundToRun(body, expectedRunId) {
22660
23109
  return typeof body.runId === "string" && body.runId === expectedRunId;
22661
23110
  }
22662
23111
  async function readRunTerminalArtifact(runDirectory) {
22663
- const artifactsDir = join17(runDirectory, "artifacts");
23112
+ const artifactsDir = join18(runDirectory, "artifacts");
22664
23113
  for (const file of RUN_TERMINAL_ARTIFACT_FILES) {
22665
- const path = join17(artifactsDir, file);
23114
+ const path = join18(artifactsDir, file);
22666
23115
  const read3 = await readTerminalArtifactAtPath(path, file);
22667
23116
  if (read3 !== void 0) return read3;
22668
23117
  }
22669
23118
  for (const relative3 of RUN_TERMINAL_ERROR_FALLBACK_RELATIVE_PATHS) {
22670
- const path = join17(runDirectory, relative3);
23119
+ const path = join18(runDirectory, relative3);
22671
23120
  const read3 = await readTerminalArtifactAtPath(path, "error.json");
22672
23121
  if (read3 !== void 0) return read3;
22673
23122
  }
@@ -22805,14 +23254,14 @@ var init_submission_ledger = __esm({
22805
23254
  });
22806
23255
 
22807
23256
  // src/session-opening-materials.ts
22808
- import { existsSync as existsSync6 } from "node:fs";
23257
+ import { existsSync as existsSync7 } from "node:fs";
22809
23258
  import { readFile as readFile13 } from "node:fs/promises";
22810
- import { dirname as dirname9, join as join18 } from "node:path";
22811
- import { fileURLToPath, pathToFileURL as pathToFileURL2 } from "node:url";
23259
+ import { dirname as dirname9, join as join19 } from "node:path";
23260
+ import { fileURLToPath, pathToFileURL as pathToFileURL3 } from "node:url";
22812
23261
  function resolvePackageRootDir(moduleUrl = import.meta.url) {
22813
23262
  let dir = dirname9(fileURLToPath(moduleUrl));
22814
23263
  for (let i = 0; i < 8; i += 1) {
22815
- if (existsSync6(join18(dir, "package.json")) && existsSync6(join18(dir, "souls"))) {
23264
+ if (existsSync7(join19(dir, "package.json")) && existsSync7(join19(dir, "souls"))) {
22816
23265
  return dir;
22817
23266
  }
22818
23267
  const parent = dirname9(dir);
@@ -22836,7 +23285,7 @@ var init_session_opening_materials = __esm({
22836
23285
  "src/session-opening-materials.ts"() {
22837
23286
  "use strict";
22838
23287
  init_packaged_role_registry();
22839
- packageRootUrl = pathToFileURL2(resolvePackageRootDir() + "/").href;
23288
+ packageRootUrl = pathToFileURL3(resolvePackageRootDir() + "/").href;
22840
23289
  MAIN_ROLE_SESSION_MATERIALS = {
22841
23290
  ...Object.fromEntries(
22842
23291
  PUBLIC_ROLE_RECORDS.map((record4) => [record4.role, record4.sessionMaterials])
@@ -23092,12 +23541,12 @@ var init_reviewer_dispatch = __esm({
23092
23541
 
23093
23542
  // src/public-cli/reviewer-dispatch-rejection.ts
23094
23543
  import { readFile as readFile14, unlink as unlink3 } from "node:fs/promises";
23095
- import { join as join19 } from "node:path";
23544
+ import { join as join20 } from "node:path";
23096
23545
  function isReviewerPreflightViolation(value) {
23097
23546
  return typeof value === "string" && REVIEWER_PREFLIGHT_VIOLATIONS.includes(value);
23098
23547
  }
23099
23548
  function reviewerDispatchRejectionPath(runDirectory) {
23100
- return join19(runDirectory, REVIEWER_DISPATCH_REJECTION_FILE);
23549
+ return join20(runDirectory, REVIEWER_DISPATCH_REJECTION_FILE);
23101
23550
  }
23102
23551
  async function clearReviewerDispatchRejection(runDirectory) {
23103
23552
  try {
@@ -23156,20 +23605,22 @@ var init_collector_evidence = __esm({
23156
23605
  }
23157
23606
  });
23158
23607
 
23159
- // src/collector-github.ts
23160
- var init_collector_github = __esm({
23161
- "src/collector-github.ts"() {
23608
+ // src/collector-identity.ts
23609
+ var init_collector_identity = __esm({
23610
+ "src/collector-identity.ts"() {
23162
23611
  "use strict";
23612
+ init_submission_correctable_error();
23163
23613
  }
23164
23614
  });
23165
23615
 
23166
23616
  // src/collector-tool-schemas.ts
23167
- var collectorObserveArgsSchema, collectorRequestArgsSchema, collectorReadArgsSchema, collectorWaitArgsSchema, collectorFindingArgsSchema, collectorOutputBaseSchema, collectorOutputArgsSchema;
23617
+ var collectorObserveArgsSchema, collectorRequestArgsSchema, collectorReadArgsSchema, collectorWaitArgsSchema, collectorBindTargetArgsSchema, collectorFindingItemDeclaration, collectorOutputBaseSchema, collectorOutputArgsSchema;
23168
23618
  var init_collector_tool_schemas = __esm({
23169
23619
  "src/collector-tool-schemas.ts"() {
23170
23620
  "use strict";
23171
23621
  init_build();
23172
23622
  init_collector_evidence();
23623
+ init_open_tool_schema();
23173
23624
  init_terminating_infrastructure();
23174
23625
  collectorObserveArgsSchema = typebox_exports.Object({}, { additionalProperties: false });
23175
23626
  collectorRequestArgsSchema = typebox_exports.Object({
@@ -23182,36 +23633,70 @@ var init_collector_tool_schemas = __esm({
23182
23633
  collectorWaitArgsSchema = typebox_exports.Object({
23183
23634
  durationMs: typebox_exports.Integer({ minimum: 1, maximum: COLLECTOR_ELIGIBILITY_MS, description: "\u7B49\u5F85\u6BEB\u79D2\uFF1B\u5355\u6B21\u4E0A\u9650\u4E94\u5206\u949F\u4E14\u4E0D\u8D85\u5269\u4F59\u8D44\u683C" })
23184
23635
  }, { additionalProperties: false });
23185
- collectorFindingArgsSchema = typebox_exports.Object({
23186
- evidenceId: typebox_exports.String({ minLength: 1, description: "observe \u8FD4\u56DE\u7684\u6750\u6599\u8BC1\u636E id\uFF08evidenceId\uFF09" }),
23187
- category: typebox_exports.Optional(typebox_exports.String({ minLength: 1, maxLength: 200, description: "\u8BE5 finding \u7684\u7B80\u77ED\u5F52\u7C7B\u6807\u7B7E\uFF1B\u9700\u8981\u5934\u90E8\u4E4B\u5916\u7684\u6B63\u6587\u65F6\u5148\u7528 ak_collector_read \u5F00\u5377\u518D\u5224\u8BFB\uFF0C\u4E0D\u5F97\u8A8A\u5199\u8BC4\u8BBA\u6B63\u6587" }))
23188
- }, { additionalProperties: false });
23189
- collectorOutputBaseSchema = typebox_exports.Object({
23190
- findings: typebox_exports.Optional(typebox_exports.Array(collectorFindingArgsSchema, {
23191
- description: "\u672C\u6B21\u6536\u96C6\u5230\u7684\u9010\u6761 findings\uFF1B\u96F6 finding \u7684\u6A21\u677F\u901A\u77E5\u4E0D\u5F97\u8FDB\u5165\u3002\u6B63\u5E38\u5B8C\u5DE5\u65E0 finding \u65F6\u7701\u7565\u3002"
23636
+ collectorBindTargetArgsSchema = typebox_exports.Object({
23637
+ prNumber: typebox_exports.Optional(typebox_exports.Unknown({
23638
+ description: "\u89D2\u8272\u5224\u5B9A\u7684\u672C\u4ED3 PR \u53F7\uFF08\u6B63\u6574\u6570\uFF09\u3002\u4E0E issueNumber \u4E8C\u9009\u4E00\u6216\u540C\u6307\u552F\u4E00\u76EE\u6807\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002"
23639
+ })),
23640
+ issueNumber: typebox_exports.Optional(typebox_exports.Unknown({
23641
+ description: "\u89D2\u8272\u5224\u5B9A\u7684\u672C\u4ED3 issue \u53F7\uFF08\u6B63\u6574\u6570\uFF09\uFF1Bruntime \u7ECF\u7EBF\u4E0A\u5173\u8054\u89E3\u6790\u552F\u4E00 PR\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002"
23192
23642
  }))
23193
- }, { additionalProperties: true, description: "\u6B63\u5E38\u5B8C\u5DE5\u63D0\u4EA4\u7A7A\u5BF9\u8C61 {}\uFF1B\u4EC5\u5728\u57FA\u7840\u8BBE\u65BD\u771F\u5B9E\u5931\u8D25\u65F6\u624D\u586B\u5199 infrastructureFailure\uFF0C\u65E0\u5931\u8D25\u65F6\u5FC5\u987B\u7701\u7565\u8BE5\u5B57\u6BB5\u3002" });
23643
+ }, { additionalProperties: true });
23644
+ collectorFindingItemDeclaration = (() => {
23645
+ const item = typebox_exports.Object(
23646
+ {
23647
+ evidenceId: typebox_exports.Unknown({
23648
+ description: "observe \u8FD4\u56DE\u7684\u6750\u6599\u6307\u9488\uFF08\u5FC5\u586B\u8BED\u4E49\uFF09"
23649
+ }),
23650
+ category: typebox_exports.Unknown({
23651
+ description: "\u7B80\u77ED\u5F52\u7C7B\u6807\u7B7E\uFF0C\u4E0D\u662F\u6458\u8981"
23652
+ }),
23653
+ summary: typebox_exports.Unknown({
23654
+ description: "\u54EA\u4E2A bot\u3001\u4EC0\u4E48\u95EE\u9898\u7684\u6458\u8981\uFF1B\u4E0D\u8A8A\u6284\u6B63\u6587"
23655
+ })
23656
+ },
23657
+ {
23658
+ additionalProperties: true,
23659
+ description: "\u5355\u6761 finding \u6307\u9488\uFF1AevidenceId + \u53EF\u9009 category/summary\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002"
23660
+ }
23661
+ );
23662
+ item.required = [];
23663
+ return item;
23664
+ })();
23665
+ collectorOutputBaseSchema = openToolObject(
23666
+ typebox_exports.Object({
23667
+ // No root type:array — host must not shape-reject non-array findings (#676 C).
23668
+ // Nested item declarations ride `items` for registration preservation (ADR 0057).
23669
+ findings: typebox_exports.Unsafe({
23670
+ description: "\u672C\u6B21\u6536\u96C6\u5230\u7684\u9010\u6761 findings\uFF08\u6307\u9488\u6570\u7EC4\u4E3A\u89C4\u8303\u5F62\uFF09\u3002\u96F6 finding \u7684\u6A21\u677F\u901A\u77E5\u4E0D\u5F97\u8FDB\u5165\uFF1B\u6B63\u5E38\u5B8C\u5DE5\u65E0 finding \u65F6\u7701\u7565\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002",
23671
+ items: collectorFindingItemDeclaration
23672
+ }),
23673
+ unfinishedReasons: typebox_exports.Unknown({
23674
+ description: "\u672A\u5B8C\u6210\u539F\u56E0\u5B57\u7B26\u4E32\u6570\u7EC4\uFF08\u989D\u5EA6/\u6545\u969C/\u7B49\u5F85\u5C4A\u6EE1\u7B49\u73B0\u573A\u4F9D\u636E\uFF09\uFF1B\u4E0D\u5F97\u628A\u672A\u5B8C\u6210\u8868\u8FF0\u4E3A\u65E0\u95EE\u9898\u3002\u65E0\u53EF\u62A5\u544A\u65F6\u7701\u7565\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002"
23675
+ })
23676
+ })
23677
+ );
23194
23678
  collectorOutputArgsSchema = withInfrastructureFailureDeclaration(
23195
23679
  collectorOutputBaseSchema
23196
23680
  );
23197
- collectorOutputArgsSchema.required = [];
23198
23681
  }
23199
23682
  });
23200
23683
 
23201
23684
  // src/collector-ledger.ts
23202
- var COLLECTOR_OBSERVE_TOOL, COLLECTOR_READ_TOOL, COLLECTOR_REQUEST_TOOL, COLLECTOR_WAIT_TOOL;
23685
+ var COLLECTOR_OBSERVE_TOOL, COLLECTOR_READ_TOOL, COLLECTOR_REQUEST_TOOL, COLLECTOR_WAIT_TOOL, COLLECTOR_BIND_TARGET_TOOL;
23203
23686
  var init_collector_ledger = __esm({
23204
23687
  "src/collector-ledger.ts"() {
23205
23688
  "use strict";
23206
23689
  init_value2();
23207
23690
  init_collector_evidence();
23208
23691
  init_collector_github();
23692
+ init_collector_identity();
23209
23693
  init_collector_tool_schemas();
23210
23694
  init_collector_output();
23211
23695
  COLLECTOR_OBSERVE_TOOL = "ak_collector_observe";
23212
23696
  COLLECTOR_READ_TOOL = "ak_collector_read";
23213
23697
  COLLECTOR_REQUEST_TOOL = "ak_collector_request";
23214
23698
  COLLECTOR_WAIT_TOOL = "ak_collector_wait";
23699
+ COLLECTOR_BIND_TARGET_TOOL = "ak_collector_bind_target";
23215
23700
  }
23216
23701
  });
23217
23702
 
@@ -23323,11 +23808,11 @@ var init_navigator_invocation_identity = __esm({
23323
23808
  });
23324
23809
 
23325
23810
  // src/receipt-delivery-policy.ts
23326
- function isRecord13(value) {
23811
+ function isRecord14(value) {
23327
23812
  return typeof value === "object" && value !== null && !Array.isArray(value);
23328
23813
  }
23329
23814
  function parseNoReceiptLifecycleFacts(input) {
23330
- if (!isRecord13(input) || typeof input.terminalToolCalled !== "boolean" || input.deliveryTurns !== RECEIPT_DELIVERY_TURN_LIMIT || input.sessionCompletion !== "settled-without-accepted-receipt" || input.acceptedReceipt !== false || typeof input.runPointer !== "string" || input.runPointer.trim() === "" || typeof input.attemptPointer !== "string" || input.attemptPointer.trim() === "" || !Array.isArray(input.rejectedReceipts) || !input.rejectedReceipts.every((item) => isRecord13(item) && typeof item.reason === "string")) {
23815
+ if (!isRecord14(input) || typeof input.terminalToolCalled !== "boolean" || input.deliveryTurns !== RECEIPT_DELIVERY_TURN_LIMIT || input.sessionCompletion !== "settled-without-accepted-receipt" || input.acceptedReceipt !== false || typeof input.runPointer !== "string" || input.runPointer.trim() === "" || typeof input.attemptPointer !== "string" || input.attemptPointer.trim() === "" || !Array.isArray(input.rejectedReceipts) || !input.rejectedReceipts.every((item) => isRecord14(item) && typeof item.reason === "string")) {
23331
23816
  throw new TypeError("malformed no-receipt lifecycle facts");
23332
23817
  }
23333
23818
  return {
@@ -23513,7 +23998,7 @@ var init_terminal = __esm({
23513
23998
  // src/public-cli/settlement.ts
23514
23999
  import { randomUUID as randomUUID3 } from "node:crypto";
23515
24000
  import { appendFile as appendFile2, readFile as readFile15, readdir as readdir5, writeFile as writeFile5 } from "node:fs/promises";
23516
- import { dirname as dirname10, join as join20 } from "node:path";
24001
+ import { dirname as dirname10, join as join21 } from "node:path";
23517
24002
  function sealedLedgerHome(admitted) {
23518
24003
  return homeFromRunDirectory(admitted.runDirectory);
23519
24004
  }
@@ -23601,8 +24086,27 @@ function formatFailureStderrDiagnostic(failure) {
23601
24086
  const oneLine = selected.split(/\r?\n/).map((line2) => line2.trim()).find((line2) => line2.length > 0) ?? "failure";
23602
24087
  return formatCliDiagnostic(boundConciseDiagnostic(oneLine));
23603
24088
  }
24089
+ function formatErrorCauseDetail(cause) {
24090
+ if (cause instanceof Error) return cause.message;
24091
+ if (typeof cause === "object" && cause !== null) {
24092
+ try {
24093
+ return JSON.stringify(cause);
24094
+ } catch {
24095
+ return String(cause);
24096
+ }
24097
+ }
24098
+ return String(cause);
24099
+ }
23604
24100
  function presentStructuralRejection(error, io) {
23605
- io.stderr(formatCliDiagnostic(error.message));
24101
+ let message = error.message;
24102
+ const cause = error.cause;
24103
+ if (cause !== void 0) {
24104
+ const detail = formatErrorCauseDetail(cause);
24105
+ if (detail.trim().length > 0) {
24106
+ message = `${message}; cause: ${detail}`;
24107
+ }
24108
+ }
24109
+ io.stderr(formatCliDiagnostic(message));
23606
24110
  }
23607
24111
  function presentControlledFailure(failure, io) {
23608
24112
  io.stdout(`${JSON.stringify(failure, null, 2)}
@@ -23893,7 +24397,7 @@ async function readSitianRetainedAuditorProviderStop(sessionFile) {
23893
24397
  const { records: records2 } = await readSitianRecords(recordFile);
23894
24398
  for (let i = records2.length - 1; i >= 0; i -= 1) {
23895
24399
  const payload = records2[i]?.payload;
23896
- if (!isRecord14(payload) || !isRecord14(payload.response)) continue;
24400
+ if (!isRecord15(payload) || !isRecord15(payload.response)) continue;
23897
24401
  if (typeof payload.type === "string") continue;
23898
24402
  const stop = sessionProviderStopFromAssistant(payload.response);
23899
24403
  if (stop !== void 0) return stop;
@@ -23914,7 +24418,7 @@ async function readSessionProviderStop(sessionFile) {
23914
24418
  }
23915
24419
  }
23916
24420
  async function readBoundEvidenceChildKnownFailure(sessionFile) {
23917
- const childDirectory = join20(dirname10(sessionFile), "evidence-children");
24421
+ const childDirectory = join21(dirname10(sessionFile), "evidence-children");
23918
24422
  let names;
23919
24423
  try {
23920
24424
  names = await readdir5(childDirectory);
@@ -23925,12 +24429,12 @@ async function readBoundEvidenceChildKnownFailure(sessionFile) {
23925
24429
  for (const file of names.filter((name) => name.endsWith(".jsonl")).sort().reverse()) {
23926
24430
  let entries;
23927
24431
  try {
23928
- entries = await readBoundSessionEntries(join20(childDirectory, file));
24432
+ entries = await readBoundSessionEntries(join21(childDirectory, file));
23929
24433
  } catch (error) {
23930
24434
  throw sessionReadFailure(error, "failed to read discovered evidence-child session");
23931
24435
  }
23932
24436
  const header = entries.find((entry) => entry.type === "session");
23933
- if (!isRecord14(header) || header.parentSession !== sessionFile) continue;
24437
+ if (!isRecord15(header) || header.parentSession !== sessionFile) continue;
23934
24438
  const stop = extractSessionProviderStop(entries);
23935
24439
  if (stop === void 0) continue;
23936
24440
  const primary = knownFailureFromProviderStop(stop);
@@ -23962,12 +24466,12 @@ async function loadBoundAuditorVolumes(sessionFile) {
23962
24466
  return firstLine === RESUME_ENVELOPE;
23963
24467
  };
23964
24468
  const isResumeEnvelope = (msg) => {
23965
- if (!isRecord14(msg) || msg.role !== "user") return false;
24469
+ if (!isRecord15(msg) || msg.role !== "user") return false;
23966
24470
  const text = typeof msg.text === "string" ? msg.text : typeof msg.content === "string" ? msg.content : void 0;
23967
24471
  if (isResumeEnvelopeBytes(text)) return true;
23968
24472
  const content = msg.content;
23969
24473
  if (Array.isArray(content)) {
23970
- return content.some((p) => isRecord14(p) && (isResumeEnvelopeBytes(p.text) || isResumeEnvelopeBytes(p.content)));
24474
+ return content.some((p) => isRecord15(p) && (isResumeEnvelopeBytes(p.text) || isResumeEnvelopeBytes(p.content)));
23971
24475
  }
23972
24476
  return false;
23973
24477
  };
@@ -23979,7 +24483,7 @@ async function loadBoundAuditorVolumes(sessionFile) {
23979
24483
  latestParentUserIndex = i;
23980
24484
  break;
23981
24485
  }
23982
- const childDirectories = [join20(dirname10(sessionFile), "auditor-roles")];
24486
+ const childDirectories = [join21(dirname10(sessionFile), "auditor-roles")];
23983
24487
  const valid = [];
23984
24488
  let sawAnyDirectory = false;
23985
24489
  for (const childDirectory of childDirectories) {
@@ -23994,12 +24498,12 @@ async function loadBoundAuditorVolumes(sessionFile) {
23994
24498
  for (const file of names.filter((name) => name.endsWith(".jsonl")).sort().reverse()) {
23995
24499
  let entries;
23996
24500
  try {
23997
- entries = await readBoundSessionEntries(join20(childDirectory, file));
24501
+ entries = await readBoundSessionEntries(join21(childDirectory, file));
23998
24502
  } catch (error) {
23999
24503
  throw sessionReadFailure(error, "failed to read discovered auditor session");
24000
24504
  }
24001
24505
  const header = entries.find((entry) => entry.type === "session");
24002
- if (!isRecord14(header)) continue;
24506
+ if (!isRecord15(header)) continue;
24003
24507
  const bindingIndexes = [];
24004
24508
  for (let i = 0; i < entries.length; i += 1) {
24005
24509
  const entry = entries[i];
@@ -24013,7 +24517,7 @@ async function loadBoundAuditorVolumes(sessionFile) {
24013
24517
  end: idx + 1 < bindingIndexes.length ? bindingIndexes[idx + 1] : entries.length
24014
24518
  })) : [{ entry: void 0, start: 0, end: entries.length }];
24015
24519
  for (const { entry: bindingEntry, start, end } of bindingPasses) {
24016
- const bindingParent = bindingEntry !== void 0 && isRecord14(bindingEntry.data) && isRecord14(bindingEntry.data.parent) ? bindingEntry.data.parent : void 0;
24520
+ const bindingParent = bindingEntry !== void 0 && isRecord15(bindingEntry.data) && isRecord15(bindingEntry.data.parent) ? bindingEntry.data.parent : void 0;
24017
24521
  const attemptEntryId = typeof bindingParent?.attemptEntryId === "string" ? bindingParent.attemptEntryId : void 0;
24018
24522
  const attemptEntryIndex = attemptEntryId === void 0 ? -1 : parentEntries.findIndex((entry) => entry.id === attemptEntryId);
24019
24523
  const boundSessionFile = typeof bindingParent?.sessionFile === "string" ? bindingParent.sessionFile : typeof header.parentSession === "string" ? header.parentSession : void 0;
@@ -24040,11 +24544,11 @@ function complianceFailureFromAuditorVolumes(volumes) {
24040
24544
  if (stop === void 0) continue;
24041
24545
  for (let i = entries.length - 1; i >= 0; i -= 1) {
24042
24546
  const entry = entries[i];
24043
- if (entry?.type !== "custom" || entry.customType !== AUDITOR_COMPLIANCE_FAILURE_ENTRY_TYPE || !isRecord14(entry.data)) continue;
24044
- const parent = isRecord14(entry.data.parent) ? entry.data.parent : void 0;
24045
- const failure = isRecord14(entry.data.failure) ? entry.data.failure : void 0;
24547
+ if (entry?.type !== "custom" || entry.customType !== AUDITOR_COMPLIANCE_FAILURE_ENTRY_TYPE || !isRecord15(entry.data)) continue;
24548
+ const parent = isRecord15(entry.data.parent) ? entry.data.parent : void 0;
24549
+ const failure = isRecord15(entry.data.failure) ? entry.data.failure : void 0;
24046
24550
  if (parent?.sessionId !== parentId || parent.sessionFile !== sessionFile || parent.attemptEntryId !== attemptEntryId || failure?.cause !== "provider" && failure?.cause !== "unrecognized") continue;
24047
- const identity = isRecord14(failure.identity) ? failure.identity : void 0;
24551
+ const identity = isRecord15(failure.identity) ? failure.identity : void 0;
24048
24552
  return {
24049
24553
  cause: failure.cause === "provider" ? "provider" : "unrecognized",
24050
24554
  ...identity === void 0 ? {} : { identity: {
@@ -24052,7 +24556,7 @@ function complianceFailureFromAuditorVolumes(volumes) {
24052
24556
  ...typeof identity.code === "string" || typeof identity.code === "number" ? { code: identity.code } : {}
24053
24557
  } },
24054
24558
  ...typeof failure.diagnostic === "string" ? { diagnostic: failure.diagnostic } : {},
24055
- ...isRecord14(failure.details) ? { details: failure.details } : {}
24559
+ ...isRecord15(failure.details) ? { details: failure.details } : {}
24056
24560
  };
24057
24561
  }
24058
24562
  }
@@ -24099,9 +24603,9 @@ function typedFailedTerminatingToolKnownFailure(entries) {
24099
24603
  if (classification.kind !== "infrastructure") continue;
24100
24604
  if (typeof message.toolCallId !== "string" || typeof message.toolName !== "string") continue;
24101
24605
  if (boundRoleToolCallForResult(attemptEntries, i, message, message.toolName) === void 0) continue;
24102
- const textPart = Array.isArray(message.content) ? message.content.find((part) => isRecord14(part) && part.type === "text" && typeof part.text === "string") : void 0;
24103
- const diagnostic = isRecord14(textPart) ? textPart.text : void 0;
24104
- const details = isRecord14(message.details) ? message.details : classification.fact;
24606
+ const textPart = Array.isArray(message.content) ? message.content.find((part) => isRecord15(part) && part.type === "text" && typeof part.text === "string") : void 0;
24607
+ const diagnostic = isRecord15(textPart) ? textPart.text : void 0;
24608
+ const details = isRecord15(message.details) ? message.details : classification.fact;
24105
24609
  return {
24106
24610
  cause: "activation",
24107
24611
  identity: { name: message.toolName, code: message.toolCallId },
@@ -24259,7 +24763,7 @@ function controlledFailureInputFromResolution(resolution) {
24259
24763
  } : {}
24260
24764
  };
24261
24765
  }
24262
- function isRecord14(value) {
24766
+ function isRecord15(value) {
24263
24767
  return typeof value === "object" && value !== null && !Array.isArray(value);
24264
24768
  }
24265
24769
  function safelyRead(object, key) {
@@ -24301,6 +24805,22 @@ function toolResultText(message) {
24301
24805
  return "";
24302
24806
  }).join("").trim();
24303
24807
  }
24808
+ function extractCollectorTargetBindRejection(entries) {
24809
+ for (let i = entries.length - 1; i >= 0; i -= 1) {
24810
+ const entry = entries[i];
24811
+ if (entry?.type !== "message") continue;
24812
+ const message = entry.message;
24813
+ if (message?.role !== "toolResult") continue;
24814
+ if (message.toolName !== COLLECTOR_BIND_TARGET_TOOL) continue;
24815
+ if (message.isError !== true) return void 0;
24816
+ const diagnostic = toolResultText(message);
24817
+ if (diagnostic.length === 0) return void 0;
24818
+ const details = message.details;
24819
+ const code = isRecord15(details) && typeof details.code === "string" && details.code.trim() !== "" ? details.code : void 0;
24820
+ return code === void 0 ? { diagnostic } : { diagnostic, code };
24821
+ }
24822
+ return void 0;
24823
+ }
24304
24824
  function boundErroredToolCandidate(entries, resultIndex, message, toolName) {
24305
24825
  if (message.toolName !== toolName || message.isError !== true) return void 0;
24306
24826
  const bound = boundRoleToolCallForResult(entries, resultIndex, message, toolName);
@@ -24362,7 +24882,7 @@ function assertCollectorReceiptMatchesAdmitted(receipt, admitted) {
24362
24882
  `Collector receipt repository "${receipt.repository}" does not match admitted repository "${admitted.repository.canonical}"`
24363
24883
  );
24364
24884
  }
24365
- if (receipt.prNumber !== admitted.prNumber) {
24885
+ if (admitted.prNumber !== void 0 && receipt.prNumber !== admitted.prNumber) {
24366
24886
  throw collectorReceiptBindingFailure(
24367
24887
  `Collector receipt prNumber ${receipt.prNumber} does not match admitted prNumber ${admitted.prNumber}`
24368
24888
  );
@@ -24383,7 +24903,7 @@ function boundRoleToolCallForResult(entries, resultIndex, message, outputToolNam
24383
24903
  const candidateMessage = entries[index]?.message;
24384
24904
  if (candidateMessage?.role === "assistant" && Array.isArray(candidateMessage.content)) {
24385
24905
  for (const part of candidateMessage.content) {
24386
- if (!isRecord14(part) || part.type !== "toolCall" || part.id !== callId) {
24906
+ if (!isRecord15(part) || part.type !== "toolCall" || part.id !== callId) {
24387
24907
  continue;
24388
24908
  }
24389
24909
  if (part.name !== outputToolName) return void 0;
@@ -24455,7 +24975,7 @@ function parseNavigatorAttendanceDetails(details) {
24455
24975
  const advisoryDiagnostic = typeof details.routePlaybookReadFailure === "string" ? { advisoryDiagnostic: details.routePlaybookReadFailure } : {};
24456
24976
  if (disposition === "recommendation") {
24457
24977
  const next = details.next;
24458
- if (!isRecord14(next) || typeof next.role !== "string") {
24978
+ if (!isRecord15(next) || typeof next.role !== "string") {
24459
24979
  return {
24460
24980
  disposition: "unavailable",
24461
24981
  source: "unknown",
@@ -24463,7 +24983,7 @@ function parseNavigatorAttendanceDetails(details) {
24463
24983
  };
24464
24984
  }
24465
24985
  const reason = typeof details.reason === "string" ? details.reason : "";
24466
- const route = Array.isArray(details.route) ? details.route.filter(isRecord14).map((target) => ({
24986
+ const route = Array.isArray(details.route) ? details.route.filter(isRecord15).map((target) => ({
24467
24987
  role: String(target.role),
24468
24988
  phase: navigatorPhaseValue(target.phase)
24469
24989
  })) : void 0;
@@ -24526,8 +25046,8 @@ function projectTerminalGateFact(rounds) {
24526
25046
  };
24527
25047
  }
24528
25048
  async function extractGateFactFromSessionDirectory(sessionDirectory, options = {}) {
24529
- const directories = [join20(sessionDirectory, "auditor-roles")];
24530
- const parentSessionFile = options.parentSessionFile ?? join20(sessionDirectory, "session.jsonl");
25049
+ const directories = [join21(sessionDirectory, "auditor-roles")];
25050
+ const parentSessionFile = options.parentSessionFile ?? join21(sessionDirectory, "session.jsonl");
24531
25051
  const rounds = await readAnalystGateCyclesFromAuditorRoles(directories, {
24532
25052
  parentSessionFile
24533
25053
  });
@@ -24535,7 +25055,7 @@ async function extractGateFactFromSessionDirectory(sessionDirectory, options = {
24535
25055
  }
24536
25056
  async function withOptionalGateProjection(base, sessionDirectory, gateContext = {}) {
24537
25057
  const secondaryEvidence = base.roleOutcome.kind === "failure" ? base.roleOutcome.decisiveFacts.secondaryEvidence : void 0;
24538
- if (isRecord14(secondaryEvidence) && secondaryEvidence.kind === "role_infrastructure_failure" && (secondaryEvidence.stage === "gatekeeper" || secondaryEvidence.stage === "inspector" || secondaryEvidence.stage === "notary")) return base;
25058
+ if (isRecord15(secondaryEvidence) && secondaryEvidence.kind === "role_infrastructure_failure" && (secondaryEvidence.stage === "gatekeeper" || secondaryEvidence.stage === "inspector" || secondaryEvidence.stage === "notary")) return base;
24539
25059
  const gate = await extractGateFactFromSessionDirectory(sessionDirectory, gateContext);
24540
25060
  return gate === void 0 ? base : { ...base, gate };
24541
25061
  }
@@ -24575,7 +25095,7 @@ function extractNavigatorFact(entries) {
24575
25095
  const entry = entries[i];
24576
25096
  if (entry?.type === "custom_message" && entry.customType === "ak-navigator-attendance") {
24577
25097
  const details = entry.message?.details ?? entry.details;
24578
- if (!isRecord14(details)) {
25098
+ if (!isRecord15(details)) {
24579
25099
  return {
24580
25100
  disposition: "unavailable",
24581
25101
  source: "unknown",
@@ -24625,8 +25145,8 @@ async function extractNavigatorFactFromAdmittedSession(sessionFile) {
24625
25145
  async function publishJudgeArtifacts(admitted, roleOutcome, coordinates) {
24626
25146
  await appendRunAttemptHistory({ role: admitted.role, runId: admitted.runId, sessionFile: coordinates.sessionFile }, roleOutcome);
24627
25147
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
24628
- const reportPath = join20(artifactsDir, "report.json");
24629
- const evidencePath = join20(artifactsDir, "evidence.json");
25148
+ const reportPath = join21(artifactsDir, "report.json");
25149
+ const evidencePath = join21(artifactsDir, "evidence.json");
24630
25150
  await writeFile5(
24631
25151
  reportPath,
24632
25152
  `${JSON.stringify(
@@ -24670,8 +25190,8 @@ async function publishJudgeArtifacts(admitted, roleOutcome, coordinates) {
24670
25190
  async function publishCoderArtifacts(admitted, roleOutcome, coordinates, options = {}) {
24671
25191
  await appendRunAttemptHistory({ role: admitted.role, runId: admitted.runId, sessionFile: coordinates.sessionFile }, roleOutcome);
24672
25192
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
24673
- const reportPath = join20(artifactsDir, "report.json");
24674
- const evidencePath = join20(artifactsDir, "evidence.json");
25193
+ const reportPath = join21(artifactsDir, "report.json");
25194
+ const evidencePath = join21(artifactsDir, "evidence.json");
24675
25195
  await writeFile5(
24676
25196
  reportPath,
24677
25197
  `${JSON.stringify(
@@ -24822,8 +25342,8 @@ function extractFixerMethodInvocations(entries, options) {
24822
25342
  async function publishFixerArtifacts(admitted, roleOutcome, coordinates, options) {
24823
25343
  await appendRunAttemptHistory({ role: admitted.role, runId: admitted.runId, sessionFile: coordinates.sessionFile }, roleOutcome);
24824
25344
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
24825
- const reportPath = join20(artifactsDir, "report.json");
24826
- const evidencePath = join20(artifactsDir, "evidence.json");
25345
+ const reportPath = join21(artifactsDir, "report.json");
25346
+ const evidencePath = join21(artifactsDir, "evidence.json");
24827
25347
  await writeFile5(
24828
25348
  reportPath,
24829
25349
  `${JSON.stringify(
@@ -24913,8 +25433,8 @@ async function settleLawfulFixerTerminalResult(admitted, authority, options) {
24913
25433
  async function publishCollectorArtifacts(admitted, roleOutcome, coordinates, options = {}) {
24914
25434
  await appendRunAttemptHistory({ role: admitted.role, runId: admitted.runId, sessionFile: coordinates.sessionFile }, roleOutcome);
24915
25435
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
24916
- const reportPath = join20(artifactsDir, "report.json");
24917
- const evidencePath = join20(artifactsDir, "evidence.json");
25436
+ const reportPath = join21(artifactsDir, "report.json");
25437
+ const evidencePath = join21(artifactsDir, "evidence.json");
24918
25438
  await writeFile5(
24919
25439
  reportPath,
24920
25440
  `${JSON.stringify(
@@ -24936,7 +25456,7 @@ async function publishCollectorArtifacts(admitted, roleOutcome, coordinates, opt
24936
25456
  {
24937
25457
  runId: admitted.runId,
24938
25458
  role: "collector",
24939
- prNumber: admitted.prNumber,
25459
+ ...admitted.prNumber === void 0 ? {} : { prNumber: admitted.prNumber },
24940
25460
  repository: admitted.repository.canonical,
24941
25461
  manifestDigest: admitted.manifestDigest,
24942
25462
  sessionDirectory: coordinates.sessionDirectory,
@@ -24973,7 +25493,7 @@ async function settleLawfulCollectorTerminalResult(admitted, authority) {
24973
25493
  const residual = boundErroredToolCandidate(entries, index, message, COLLECTOR_WAIT_TOOL);
24974
25494
  if (residual === void 0) continue;
24975
25495
  const candidate = residual.candidate;
24976
- const duration = isRecord14(candidate) ? candidate.durationMs : void 0;
25496
+ const duration = isRecord15(candidate) ? candidate.durationMs : void 0;
24977
25497
  if (Number.isSafeInteger(duration) && duration >= 1 && duration <= 9e5) {
24978
25498
  continue;
24979
25499
  }
@@ -25021,8 +25541,8 @@ async function trySettleCollectorTerminalResult(admitted, authority) {
25021
25541
  async function publishDoctorArtifacts(admitted, roleOutcome, coordinates, options = {}) {
25022
25542
  await appendRunAttemptHistory({ role: admitted.role, runId: admitted.runId, sessionFile: coordinates.sessionFile }, roleOutcome);
25023
25543
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
25024
- const reportPath = join20(artifactsDir, "report.json");
25025
- const evidencePath = join20(artifactsDir, "evidence.json");
25544
+ const reportPath = join21(artifactsDir, "report.json");
25545
+ const evidencePath = join21(artifactsDir, "evidence.json");
25026
25546
  await writeFile5(
25027
25547
  reportPath,
25028
25548
  `${JSON.stringify(
@@ -25163,7 +25683,7 @@ async function settleLawfulSeatAcceptedTerminalResult(admitted, authority, spec,
25163
25683
  spec.toolName
25164
25684
  );
25165
25685
  if (residual !== void 0) {
25166
- const details = isRecord14(residual.candidate) ? residual.candidate : { candidate: residual.candidate };
25686
+ const details = isRecord15(residual.candidate) ? residual.candidate : { candidate: residual.candidate };
25167
25687
  return settleFailureTerminalResult(admitted, {
25168
25688
  cause: "output",
25169
25689
  diagnostic: residual.diagnostic,
@@ -25282,8 +25802,8 @@ function extractReviewerMethodInvocations(entries, options) {
25282
25802
  async function publishReviewerArtifacts(admitted, roleOutcome, coordinates, options) {
25283
25803
  await appendRunAttemptHistory({ role: admitted.role, runId: admitted.runId, sessionFile: coordinates.sessionFile }, roleOutcome);
25284
25804
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
25285
- const reportPath = join20(artifactsDir, "report.json");
25286
- const evidencePath = join20(artifactsDir, "evidence.json");
25805
+ const reportPath = join21(artifactsDir, "report.json");
25806
+ const evidencePath = join21(artifactsDir, "evidence.json");
25287
25807
  await writeFile5(
25288
25808
  reportPath,
25289
25809
  `${JSON.stringify(
@@ -25397,8 +25917,8 @@ function extractMergerMethodInvocations(entries, options) {
25397
25917
  async function publishMergerArtifacts(admitted, roleOutcome, coordinates, options) {
25398
25918
  await appendRunAttemptHistory({ role: admitted.role, runId: admitted.runId, sessionFile: coordinates.sessionFile }, roleOutcome);
25399
25919
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
25400
- const reportPath = join20(artifactsDir, "report.json");
25401
- const evidencePath = join20(artifactsDir, "evidence.json");
25920
+ const reportPath = join21(artifactsDir, "report.json");
25921
+ const evidencePath = join21(artifactsDir, "evidence.json");
25402
25922
  await writeFile5(
25403
25923
  reportPath,
25404
25924
  `${JSON.stringify(
@@ -25465,7 +25985,7 @@ async function settleLawfulMergerTerminalResult(admitted, authority, options) {
25465
25985
  if (message?.role !== "toolResult") continue;
25466
25986
  const residual = boundErroredToolCandidate(entries, index, message, MERGER_OUTPUT_TOOL_NAME);
25467
25987
  if (residual === void 0) continue;
25468
- const attemptId = isRecord14(residual.candidate) ? safelyRead(residual.candidate, "attemptId") : { readable: true, value: void 0 };
25988
+ const attemptId = isRecord15(residual.candidate) ? safelyRead(residual.candidate, "attemptId") : { readable: true, value: void 0 };
25469
25989
  if (!attemptId.readable || attemptId.value !== admitted.runId) continue;
25470
25990
  return {
25471
25991
  roleOutcome: buildResidualIncompleteTerminalOutcome({
@@ -25543,7 +26063,7 @@ function uniqueFailureFallbackDirs(runDirectory, baseDir) {
25543
26063
  return dirs;
25544
26064
  }
25545
26065
  async function resolveFailureArtifactsBase(runDirectory) {
25546
- const artifactsDir = join20(runDirectory, "artifacts");
26066
+ const artifactsDir = join21(runDirectory, "artifacts");
25547
26067
  try {
25548
26068
  await ensureRunArtifactsDir(runDirectory);
25549
26069
  return { baseDir: artifactsDir };
@@ -25559,7 +26079,7 @@ async function writeFailureJsonRetainingCause(preferredCandidates, uniqueFallbac
25559
26079
  const candidates = [
25560
26080
  ...preferredCandidates,
25561
26081
  // One unique name per fallback dir — collisions on fixed names cannot exhaust this.
25562
- ...uniqueFallbackDirs.map((dir) => join20(dir, `${stem}.${randomUUID3()}.json`))
26082
+ ...uniqueFallbackDirs.map((dir) => join21(dir, `${stem}.${randomUUID3()}.json`))
25563
26083
  ];
25564
26084
  for (let i = 0; i < candidates.length; i += 1) {
25565
26085
  const path = candidates[i];
@@ -25604,26 +26124,26 @@ async function publishFailureArtifacts(admitted, failure, authority) {
25604
26124
  } catch (error) {
25605
26125
  priorIssues.push(publicationAttemptFromError(sessionFile, error));
25606
26126
  }
25607
- const underArtifacts = baseDir === join20(admitted.runDirectory, "artifacts");
26127
+ const underArtifacts = baseDir === join21(admitted.runDirectory, "artifacts");
25608
26128
  const uniqueFallbackDirs = uniqueFailureFallbackDirs(
25609
26129
  admitted.runDirectory,
25610
26130
  baseDir
25611
26131
  );
25612
26132
  const errorCandidates = underArtifacts ? [
25613
- join20(baseDir, "error.json"),
25614
- join20(baseDir, "error.settlement.json"),
25615
- join20(admitted.runDirectory, "error.settlement.json")
26133
+ join21(baseDir, "error.json"),
26134
+ join21(baseDir, "error.settlement.json"),
26135
+ join21(admitted.runDirectory, "error.settlement.json")
25616
26136
  ] : [
25617
- join20(baseDir, "error.settlement.json"),
25618
- join20(baseDir, "error.json")
26137
+ join21(baseDir, "error.settlement.json"),
26138
+ join21(baseDir, "error.json")
25619
26139
  ];
25620
26140
  const evidenceCandidates = underArtifacts ? [
25621
- join20(baseDir, "evidence.json"),
25622
- join20(baseDir, "evidence.settlement.json"),
25623
- join20(admitted.runDirectory, "evidence.settlement.json")
26141
+ join21(baseDir, "evidence.json"),
26142
+ join21(baseDir, "evidence.settlement.json"),
26143
+ join21(admitted.runDirectory, "evidence.settlement.json")
25624
26144
  ] : [
25625
- join20(baseDir, "evidence.settlement.json"),
25626
- join20(baseDir, "evidence.json")
26145
+ join21(baseDir, "evidence.settlement.json"),
26146
+ join21(baseDir, "evidence.json")
25627
26147
  ];
25628
26148
  const errorPayloadBase = {
25629
26149
  kind: "error",
@@ -25725,7 +26245,18 @@ async function settleFailureTerminalResult(admitted, failure, authority, options
25725
26245
  try {
25726
26246
  const facts = parseNoReceiptLifecycleFacts(raw);
25727
26247
  if (facts.runPointer === admitted.runDirectory && facts.attemptPointer === `current:${admitted.runDirectory}`) {
25728
- const decisiveFacts2 = facts;
26248
+ let decisiveFacts2 = facts;
26249
+ if (admitted.role === "collector") {
26250
+ const bindRejection = extractCollectorTargetBindRejection(entries.slice(attemptStart));
26251
+ if (bindRejection !== void 0) {
26252
+ decisiveFacts2 = {
26253
+ ...facts,
26254
+ targetBindRejected: true,
26255
+ targetBindDiagnostic: bindRejection.diagnostic,
26256
+ ...bindRejection.code === void 0 ? {} : { targetBindCode: bindRejection.code }
26257
+ };
26258
+ }
26259
+ }
25729
26260
  return withOptionalGateProjection(
25730
26261
  {
25731
26262
  roleOutcome: { kind: "no_receipt", role: admitted.role, status: "no-accepted-receipt", ...facts, decisiveFacts: decisiveFacts2 },
@@ -25806,6 +26337,14 @@ function presentFailureTerminal(terminal, io) {
25806
26337
  cause: terminal.roleOutcome.cause,
25807
26338
  diagnostic: terminal.roleOutcome.diagnostic
25808
26339
  }));
26340
+ return;
26341
+ }
26342
+ const bindDiagnostic = terminal.roleOutcome.decisiveFacts.targetBindDiagnostic;
26343
+ if (typeof bindDiagnostic === "string" && bindDiagnostic.trim() !== "") {
26344
+ io.stderr(formatFailureStderrDiagnostic({
26345
+ cause: "output",
26346
+ diagnostic: bindDiagnostic
26347
+ }));
25809
26348
  }
25810
26349
  }
25811
26350
  var CONCISE_DIAGNOSTIC_MAX_CHARS, COLLECTOR_INFRASTRUCTURE_TOOLS, COLLECTOR_INFRASTRUCTURE_FAILURE_SPEC, ENGINE_DETOUR_INFRASTRUCTURE_FAILURE_SPEC, ATTEMPT_HISTORY_ENTRY_TYPE;
@@ -25906,7 +26445,7 @@ var init_ticket_provenance_contracts = __esm({
25906
26445
  });
25907
26446
 
25908
26447
  // src/ticket-provenance.ts
25909
- import { join as join21 } from "node:path";
26448
+ import { join as join22 } from "node:path";
25910
26449
  function ticketProvenanceSubject(ticketNumber) {
25911
26450
  if (!Number.isSafeInteger(ticketNumber) || ticketNumber < 1) {
25912
26451
  throw new Error(`ticket-provenance subject requires a positive ticket number, got ${String(ticketNumber)}`);
@@ -25924,7 +26463,7 @@ function resolveTicketProvenanceVolume(ticketNumber, cwd, home) {
25924
26463
  return {
25925
26464
  recordFile: path.recordFile,
25926
26465
  volumeDir: path.sessionDir,
25927
- humanViewFile: join21(path.sessionDir, TICKET_PROVENANCE_HUMAN_VIEW)
26466
+ humanViewFile: join22(path.sessionDir, TICKET_PROVENANCE_HUMAN_VIEW)
25928
26467
  };
25929
26468
  }
25930
26469
  var init_ticket_provenance = __esm({
@@ -25974,7 +26513,7 @@ var init_case_dossier_delivery = __esm({
25974
26513
 
25975
26514
  // src/host-transition-prior-native.ts
25976
26515
  import { access as access2, readdir as readdir6 } from "node:fs/promises";
25977
- import { dirname as dirname11, join as join22 } from "node:path";
26516
+ import { dirname as dirname11, join as join23 } from "node:path";
25978
26517
  function isEnoent2(error) {
25979
26518
  return typeof error === "object" && error !== null && error.code === "ENOENT";
25980
26519
  }
@@ -25999,7 +26538,7 @@ async function listSitianRecordPaths(sessionParent) {
25999
26538
  const recordPaths = [];
26000
26539
  for (const entry of entries) {
26001
26540
  if (!entry.isDirectory()) continue;
26002
- const recordFile = join22(sessionRoot, entry.name, "records.jsonl");
26541
+ const recordFile = join23(sessionRoot, entry.name, "records.jsonl");
26003
26542
  try {
26004
26543
  await access2(recordFile);
26005
26544
  recordPaths.push(recordFile);
@@ -26069,7 +26608,7 @@ var init_public_run_credentials = __esm({
26069
26608
  import { constants as fsConstants } from "node:fs";
26070
26609
  import { randomUUID as randomUUID4 } from "node:crypto";
26071
26610
  import { lstat as lstat5, mkdir as mkdir4, open as open2 } from "node:fs/promises";
26072
- import { join as join23 } from "node:path";
26611
+ import { join as join24 } from "node:path";
26073
26612
  function presentTerminal(terminal, io) {
26074
26613
  if (terminal.roleOutcome.kind === "failure" || terminal.roleOutcome.kind === "no_receipt") {
26075
26614
  presentFailureTerminal(terminal, io);
@@ -26088,7 +26627,7 @@ async function finalizeExceptionRunBestEffort(runDirectory, io) {
26088
26627
  }
26089
26628
  }
26090
26629
  function runArtifactsDirectory(runDirectory) {
26091
- return join23(runDirectory, "artifacts");
26630
+ return join24(runDirectory, "artifacts");
26092
26631
  }
26093
26632
  async function ensureRealArtifactsDirectory(runDirectory) {
26094
26633
  const runStat = await lstat5(runDirectory);
@@ -26171,7 +26710,7 @@ function jsonSafeReplacer() {
26171
26710
  }
26172
26711
  async function retainDispatchError(admitted, principalAuthority, sessionAppender, attempt, error) {
26173
26712
  const artifactsDir = await ensureRealArtifactsDirectory(admitted.runDirectory);
26174
- const filePath = join23(
26713
+ const filePath = join24(
26175
26714
  artifactsDir,
26176
26715
  `dispatch-error-attempt-${attempt}-${randomUUID4()}.json`
26177
26716
  );
@@ -26420,7 +26959,7 @@ var init_auto_resume = __esm({
26420
26959
  // src/public-cli/post-admission.ts
26421
26960
  import { randomUUID as randomUUID5 } from "node:crypto";
26422
26961
  import { readFile as readFile16, writeFile as writeFile6 } from "node:fs/promises";
26423
- import { isAbsolute as isAbsolute7, join as join24, resolve as resolve8 } from "node:path";
26962
+ import { isAbsolute as isAbsolute7, join as join25, resolve as resolve8 } from "node:path";
26424
26963
  function appendContinuationSection(continuation, section) {
26425
26964
  const prompt = `${continuation.prompt}
26426
26965
 
@@ -26429,7 +26968,7 @@ ${section}`;
26429
26968
  }
26430
26969
  async function readInvocationHost(runDirectory) {
26431
26970
  try {
26432
- const raw = JSON.parse(await readFile16(join24(runDirectory, "invocation.json"), "utf8"));
26971
+ const raw = JSON.parse(await readFile16(join25(runDirectory, "invocation.json"), "utf8"));
26433
26972
  return typeof raw.host === "string" && raw.host.trim() !== "" ? raw.host : void 0;
26434
26973
  } catch (error) {
26435
26974
  if (error.code === "ENOENT") return void 0;
@@ -26583,7 +27122,7 @@ async function dispatchPostAdmissionTurn(input) {
26583
27122
  }
26584
27123
  try {
26585
27124
  await writeFile6(
26586
- join24(admitted.runDirectory, "stderr.log"),
27125
+ join25(admitted.runDirectory, "stderr.log"),
26587
27126
  result2.stderr,
26588
27127
  "utf8"
26589
27128
  );
@@ -26692,7 +27231,7 @@ function resumeTurnRequestProjectionOptions(admitted, request, env, summonsPrepa
26692
27231
  }
26693
27232
  function isAlreadyFrozenSummonsAttachment(runDirectory, attachmentPath) {
26694
27233
  const absolute = isAbsolute7(attachmentPath) ? attachmentPath : resolve8(attachmentPath);
26695
- return pathContainedIn(join24(runDirectory, "attachments"), absolute);
27234
+ return pathContainedIn(join25(runDirectory, "attachments"), absolute);
26696
27235
  }
26697
27236
  async function prepareSummonsResumeMaterials(runDirectory, summons) {
26698
27237
  if (summons === void 0) return void 0;
@@ -27478,7 +28017,8 @@ function buildCollectorTurnRequest(admitted, options) {
27478
28017
  activation: {
27479
28018
  role: "collector",
27480
28019
  repo: admitted.repository.display,
27481
- pr: String(admitted.prNumber),
28020
+ // #676 A: omit pr when unbound — role binds via ak_collector_bind_target.
28021
+ ...admitted.prNumber === void 0 ? {} : { pr: String(admitted.prNumber) },
27482
28022
  ...admitted.requestManifestPath === void 0 ? {} : { requestManifestPath: admitted.requestManifestPath }
27483
28023
  }
27484
28024
  },
@@ -27493,7 +28033,7 @@ async function runPublicCollector(argv, env, io, parseCollectorArgv2) {
27493
28033
  home: env.home,
27494
28034
  principalAuthority: env.principalAuthority,
27495
28035
  cwd: env.cwd,
27496
- prNumber: parsed.prNumber,
28036
+ ...parsed.prNumber === void 0 ? {} : { prNumber: parsed.prNumber },
27497
28037
  instruction: parsed.instruction,
27498
28038
  attachmentPaths: parsed.attachmentPaths,
27499
28039
  ...parsed.project === void 0 ? {} : { project: parsed.project },
@@ -28860,7 +29400,7 @@ var init_judge_run = __esm({
28860
29400
 
28861
29401
  // src/public-cli/merger-run.ts
28862
29402
  import { mkdir as mkdir5, writeFile as writeFile7 } from "node:fs/promises";
28863
- import { join as join25, resolve as resolve9 } from "node:path";
29403
+ import { join as join26, resolve as resolve9 } from "node:path";
28864
29404
  function mergerMethods(packageRoot2) {
28865
29405
  return [
28866
29406
  {
@@ -28926,8 +29466,8 @@ async function admitMergerShellForActivationFailure(options) {
28926
29466
  expectedConflictPaths: [],
28927
29467
  resolutionScope: []
28928
29468
  };
28929
- const admittedRequestPath = join25(runDirectory, "admitted-request.json");
28930
- const mergerInputPath = join25(runDirectory, "merger-input.json");
29469
+ const admittedRequestPath = join26(runDirectory, "admitted-request.json");
29470
+ const mergerInputPath = join26(runDirectory, "merger-input.json");
28931
29471
  await writeFile7(
28932
29472
  admittedRequestPath,
28933
29473
  `${JSON.stringify(
@@ -29367,10 +29907,10 @@ var init_analyst_book_key = __esm({
29367
29907
  // src/atomic-write.ts
29368
29908
  import { randomUUID as randomUUID6 } from "node:crypto";
29369
29909
  import { rename, rm, writeFile as writeFile8 } from "node:fs/promises";
29370
- import { dirname as dirname12, join as join26 } from "node:path";
29910
+ import { dirname as dirname12, join as join27 } from "node:path";
29371
29911
  async function writeFileAtomically(destination, contents) {
29372
29912
  const parent = dirname12(destination);
29373
- const temporary = join26(parent, `.atomic-write-${randomUUID6()}.tmp`);
29913
+ const temporary = join27(parent, `.atomic-write-${randomUUID6()}.tmp`);
29374
29914
  try {
29375
29915
  await writeFile8(temporary, contents);
29376
29916
  await rename(temporary, destination);
@@ -29387,7 +29927,7 @@ var init_atomic_write = __esm({
29387
29927
 
29388
29928
  // src/analyst-index.ts
29389
29929
  import { open as open3, readFile as readFile17, unlink as unlink4 } from "node:fs/promises";
29390
- import { dirname as dirname13, join as join27 } from "node:path";
29930
+ import { dirname as dirname13, join as join28 } from "node:path";
29391
29931
  function sleep(ms) {
29392
29932
  return new Promise((resolve11) => {
29393
29933
  setTimeout(resolve11, ms);
@@ -29396,7 +29936,7 @@ function sleep(ms) {
29396
29936
  async function withAnalystLibraryIndexLock(ledgerHome, fn) {
29397
29937
  const indexPath = analystLibraryIndexPath(ledgerHome);
29398
29938
  ensureRealDirectoryTree(ledgerHome, dirname13(indexPath));
29399
- const lockPath = join27(dirname13(indexPath), LIBRARY_INDEX_LOCK_NAME);
29939
+ const lockPath = join28(dirname13(indexPath), LIBRARY_INDEX_LOCK_NAME);
29400
29940
  assertLedgerFileInsideHome(lockPath, ledgerHome);
29401
29941
  const startedAt = Date.now();
29402
29942
  while (true) {
@@ -29423,7 +29963,7 @@ async function withAnalystLibraryIndexLock(ledgerHome, fn) {
29423
29963
  }
29424
29964
  }
29425
29965
  function analystLibraryIndexPath(ledgerHome) {
29426
- return join27(ledgerHome, "analyst", "library-index.json");
29966
+ return join28(ledgerHome, "analyst", "library-index.json");
29427
29967
  }
29428
29968
  function rowFromIssueMetricsPage(page) {
29429
29969
  return {
@@ -29719,22 +30259,22 @@ var init_analyst_cohort = __esm({
29719
30259
 
29720
30260
  // src/analyst-ledger.ts
29721
30261
  import { readdir as readdir7, readFile as readFile18 } from "node:fs/promises";
29722
- import { join as join28 } from "node:path";
30262
+ import { join as join29 } from "node:path";
29723
30263
  function isMissingPathError5(error) {
29724
30264
  return error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
29725
30265
  }
29726
30266
  function errorText3(error) {
29727
30267
  return error instanceof Error ? error.message : String(error);
29728
30268
  }
29729
- function isRecord15(value) {
30269
+ function isRecord16(value) {
29730
30270
  return typeof value === "object" && value !== null && !Array.isArray(value);
29731
30271
  }
29732
30272
  async function readExistingRunLifecycleState(runDirectory) {
29733
30273
  try {
29734
30274
  const raw = JSON.parse(
29735
- await readFile18(join28(runDirectory, "run-state.json"), "utf8")
30275
+ await readFile18(join29(runDirectory, "run-state.json"), "utf8")
29736
30276
  );
29737
- if (!isRecord15(raw) || typeof raw.state !== "string") return void 0;
30277
+ if (!isRecord16(raw) || typeof raw.state !== "string") return void 0;
29738
30278
  return raw.state;
29739
30279
  } catch {
29740
30280
  return void 0;
@@ -29764,13 +30304,13 @@ async function listLedgerBookNames(booksRoot) {
29764
30304
  async function readInvocationScopeFields(runDirectory) {
29765
30305
  let raw;
29766
30306
  try {
29767
- raw = await readFile18(join28(runDirectory, "invocation.json"), "utf8");
30307
+ raw = await readFile18(join29(runDirectory, "invocation.json"), "utf8");
29768
30308
  } catch (error) {
29769
30309
  if (isMissingPathError5(error)) return void 0;
29770
30310
  throw error;
29771
30311
  }
29772
30312
  const parsed = JSON.parse(raw);
29773
- if (!isRecord15(parsed)) return void 0;
30313
+ if (!isRecord16(parsed)) return void 0;
29774
30314
  if (typeof parsed.projectRoot !== "string" || parsed.projectRoot.trim() === "") {
29775
30315
  return void 0;
29776
30316
  }
@@ -29796,15 +30336,15 @@ function decideIssueScope(input) {
29796
30336
  }
29797
30337
  async function resolveSessionFile(runDirectory) {
29798
30338
  try {
29799
- const raw = await readFile18(join28(runDirectory, "invocation.json"), "utf8");
30339
+ const raw = await readFile18(join29(runDirectory, "invocation.json"), "utf8");
29800
30340
  const parsed = JSON.parse(raw);
29801
- if (isRecord15(parsed) && typeof parsed.sessionFile === "string" && parsed.sessionFile.trim() !== "") {
30341
+ if (isRecord16(parsed) && typeof parsed.sessionFile === "string" && parsed.sessionFile.trim() !== "") {
29802
30342
  return parsed.sessionFile;
29803
30343
  }
29804
30344
  } catch (error) {
29805
30345
  if (!isMissingPathError5(error)) throw error;
29806
30346
  }
29807
- return join28(runDirectory, "session", "session.jsonl");
30347
+ return join29(runDirectory, "session", "session.jsonl");
29808
30348
  }
29809
30349
  function attributeSessionRowsForRun(input) {
29810
30350
  if (pathContainedIn(input.runDirectory, input.sessionFile)) {
@@ -29976,9 +30516,9 @@ async function classifyScopedRun(input) {
29976
30516
  }
29977
30517
  let gateCycles;
29978
30518
  try {
29979
- const parentSessionFile = join28(input.runDirectory, "session", "session.jsonl");
30519
+ const parentSessionFile = join29(input.runDirectory, "session", "session.jsonl");
29980
30520
  gateCycles = await readAnalystGateCyclesFromAuditorRoles(
29981
- join28(input.runDirectory, "session", "auditor-roles"),
30521
+ join29(input.runDirectory, "session", "auditor-roles"),
29982
30522
  { parentSessionFile }
29983
30523
  );
29984
30524
  } catch (error) {
@@ -30011,7 +30551,7 @@ async function classifyScopedRun(input) {
30011
30551
  async function scanAnalystIssueRuns(input) {
30012
30552
  const ledgerHome = resolveActivationLedgerHome(input.home);
30013
30553
  const scopeTicketNumber = input.ticketNumber;
30014
- const booksRoot = join28(ledgerHome, "books");
30554
+ const booksRoot = join29(ledgerHome, "books");
30015
30555
  let wholeBook = false;
30016
30556
  let scopeRootIdentity;
30017
30557
  let bookNames;
@@ -30043,7 +30583,7 @@ async function scanAnalystIssueRuns(input) {
30043
30583
  const unreadable = [];
30044
30584
  const scopeConflicts = [];
30045
30585
  for (const book of bookNames) {
30046
- const runsDir = join28(booksRoot, book, "runs");
30586
+ const runsDir = join29(booksRoot, book, "runs");
30047
30587
  let runNames;
30048
30588
  try {
30049
30589
  const entries = await readdir7(runsDir, { withFileTypes: true });
@@ -30055,7 +30595,7 @@ async function scanAnalystIssueRuns(input) {
30055
30595
  for (const runName of runNames) {
30056
30596
  const parsed = parseRunDirectoryName2(runName);
30057
30597
  if (parsed === void 0) continue;
30058
- const runDirectory = join28(runsDir, runName);
30598
+ const runDirectory = join29(runsDir, runName);
30059
30599
  let scopeFields;
30060
30600
  try {
30061
30601
  scopeFields = await readInvocationScopeFields(runDirectory);
@@ -30103,7 +30643,7 @@ var init_analyst_ledger = __esm({
30103
30643
  });
30104
30644
 
30105
30645
  // src/analyst-metric-families/acceptance-success-rework.ts
30106
- function isRecord16(value) {
30646
+ function isRecord17(value) {
30107
30647
  return typeof value === "object" && value !== null && !Array.isArray(value);
30108
30648
  }
30109
30649
  function wallMsFromSpan(span) {
@@ -30112,21 +30652,21 @@ function wallMsFromSpan(span) {
30112
30652
  function findCollectorGroups(body) {
30113
30653
  if (Array.isArray(body.groups)) return body.groups;
30114
30654
  const receipt = body.receipt;
30115
- if (isRecord16(receipt) && Array.isArray(receipt.groups)) return receipt.groups;
30655
+ if (isRecord17(receipt) && Array.isArray(receipt.groups)) return receipt.groups;
30116
30656
  const outcome = body.outcome;
30117
- if (isRecord16(outcome)) {
30657
+ if (isRecord17(outcome)) {
30118
30658
  const facts = outcome.decisiveFacts;
30119
- if (isRecord16(facts) && Array.isArray(facts.groups)) return facts.groups;
30659
+ if (isRecord17(facts) && Array.isArray(facts.groups)) return facts.groups;
30120
30660
  }
30121
30661
  return void 0;
30122
30662
  }
30123
30663
  function extractStatus(body) {
30124
30664
  const outcome = body.outcome;
30125
- if (isRecord16(outcome) && typeof outcome.status === "string" && outcome.status.trim() !== "") {
30665
+ if (isRecord17(outcome) && typeof outcome.status === "string" && outcome.status.trim() !== "") {
30126
30666
  return outcome.status;
30127
30667
  }
30128
30668
  const receipt = body.receipt;
30129
- if (isRecord16(receipt) && typeof receipt.status === "string" && receipt.status.trim() !== "") {
30669
+ if (isRecord17(receipt) && typeof receipt.status === "string" && receipt.status.trim() !== "") {
30130
30670
  return receipt.status;
30131
30671
  }
30132
30672
  if (typeof body.status === "string" && body.status.trim() !== "") {
@@ -30751,21 +31291,21 @@ var init_leg_wall_clock = __esm({
30751
31291
  });
30752
31292
 
30753
31293
  // src/analyst-metric-families/round-timeline.ts
30754
- function isRecord17(value) {
31294
+ function isRecord18(value) {
30755
31295
  return typeof value === "object" && value !== null && !Array.isArray(value);
30756
31296
  }
30757
31297
  function wallMsFromSpan2(startedAt, endedAt) {
30758
31298
  return Date.parse(endedAt) - Date.parse(startedAt);
30759
31299
  }
30760
31300
  function readOutcomeStatus(body) {
30761
- if (!isRecord17(body.outcome)) return void 0;
31301
+ if (!isRecord18(body.outcome)) return void 0;
30762
31302
  const status = body.outcome.status;
30763
31303
  if (typeof status !== "string" || status.trim() === "") return void 0;
30764
31304
  return status;
30765
31305
  }
30766
31306
  function readClassCount(body) {
30767
- if (!isRecord17(body.outcome)) return void 0;
30768
- if (!isRecord17(body.outcome.decisiveFacts)) return void 0;
31307
+ if (!isRecord18(body.outcome)) return void 0;
31308
+ if (!isRecord18(body.outcome.decisiveFacts)) return void 0;
30769
31309
  const classCount = body.outcome.decisiveFacts.classCount;
30770
31310
  if (typeof classCount !== "number" || !Number.isFinite(classCount)) {
30771
31311
  return void 0;
@@ -30909,7 +31449,7 @@ var init_analyst_metric_family = __esm({
30909
31449
 
30910
31450
  // src/analyst-page.ts
30911
31451
  import { createHash as createHash5 } from "node:crypto";
30912
- import { dirname as dirname14, join as join29 } from "node:path";
31452
+ import { dirname as dirname14, join as join30 } from "node:path";
30913
31453
  function analystIssuePageKey(address) {
30914
31454
  const parts = ["book", address.bookKey];
30915
31455
  if (address.issueNumber !== void 0) {
@@ -30920,7 +31460,7 @@ function analystIssuePageKey(address) {
30920
31460
  return createHash5("sha256").update(parts.join("\0")).digest("hex").slice(0, 32);
30921
31461
  }
30922
31462
  function analystIssuePagePath(ledgerHome, address) {
30923
- return join29(ledgerHome, "analyst", "issues", `${analystIssuePageKey(address)}.json`);
31463
+ return join30(ledgerHome, "analyst", "issues", `${analystIssuePageKey(address)}.json`);
30924
31464
  }
30925
31465
  function analystIssuePageAddressFromPage(page) {
30926
31466
  return {
@@ -31453,7 +31993,7 @@ __export(cli_exports, {
31453
31993
  runAkRole: () => runAkRole
31454
31994
  });
31455
31995
  import { realpath as realpath6 } from "node:fs/promises";
31456
- import { join as join30 } from "node:path";
31996
+ import { join as join31 } from "node:path";
31457
31997
  function takePublicGlobalFlag(argv, index, options) {
31458
31998
  const tokens = argv.slice(index);
31459
31999
  const taken = options.takeDashed(tokens);
@@ -31505,7 +32045,7 @@ function resolveRoleTurnHost(env, options) {
31505
32045
  ok: true,
31506
32046
  host: {
31507
32047
  executeTurn: async (request) => {
31508
- hostPromise ??= loadProductionAcpHostFactory(env.packageRoot, name).then(
32048
+ hostPromise ??= loadProductionExternalHostFactory(env.packageRoot, name).then(
31509
32049
  (create) => create({
31510
32050
  packageRoot: env.packageRoot,
31511
32051
  principalAuthority: options.principalAuthority
@@ -31592,7 +32132,7 @@ function resolveHome(env) {
31592
32132
  return env.home ?? packageMachineHome();
31593
32133
  }
31594
32134
  function resolveAgentDir(env, home) {
31595
- return env.agentDir ?? process.env.PI_CODING_AGENT_DIR ?? join30(home, ".pi", "agent");
32135
+ return env.agentDir ?? process.env.PI_CODING_AGENT_DIR ?? join31(home, ".pi", "agent");
31596
32136
  }
31597
32137
  function parseThinking(value) {
31598
32138
  return value;
@@ -32458,7 +32998,13 @@ async function runAkRole(argv, env) {
32458
32998
  return { exitCode: 2 };
32459
32999
  }
32460
33000
  if (error instanceof Error) {
32461
- const label = error.name !== "" && error.name !== "Error" ? `${error.name}: ${error.message}` : error.message;
33001
+ let label = error.name !== "" && error.name !== "Error" ? `${error.name}: ${error.message}` : error.message;
33002
+ if (error.cause !== void 0) {
33003
+ const detail = formatErrorCauseDetail(error.cause);
33004
+ if (detail.trim().length > 0) {
33005
+ label = `${label || error.name || "unrecognized exception"}; cause: ${detail}`;
33006
+ }
33007
+ }
32462
33008
  io.stderr(formatCliDiagnostic(label || error.name || "unrecognized exception"));
32463
33009
  return { exitCode: 1 };
32464
33010
  }
@@ -32479,7 +33025,7 @@ var init_cli = __esm({
32479
33025
  init_registry2();
32480
33026
  init_cli_errors();
32481
33027
  init_host_descriptions();
32482
- init_load_production_acp_host();
33028
+ init_load_production_external_host();
32483
33029
  init_role_turn_host();
32484
33030
  init_invocation();
32485
33031
  init_option_definitions();
@@ -32550,8 +33096,8 @@ var init_cli = __esm({
32550
33096
  });
32551
33097
 
32552
33098
  // src/public-cli/main.ts
32553
- import { existsSync as existsSync7 } from "node:fs";
32554
- import { dirname as dirname15, join as join31 } from "node:path";
33099
+ import { existsSync as existsSync8 } from "node:fs";
33100
+ import { dirname as dirname15, join as join32 } from "node:path";
32555
33101
  import { fileURLToPath as fileURLToPath2 } from "node:url";
32556
33102
 
32557
33103
  // src/public-cli/host-pi-runtime.ts
@@ -32640,13 +33186,14 @@ function linkPackage(packageRoot2, name, targetDir) {
32640
33186
  // src/public-cli/main.ts
32641
33187
  var here = dirname15(fileURLToPath2(import.meta.url));
32642
33188
  function resolvePackageRoot(binDir) {
32643
- const canonical = join31(binDir, "..", "..");
32644
- if (existsSync7(join31(canonical, "package.json"))) {
33189
+ const canonical = join32(binDir, "..", "..");
33190
+ if (existsSync8(join32(canonical, "package.json"))) {
32645
33191
  return canonical;
32646
33192
  }
32647
33193
  return binDir;
32648
33194
  }
32649
33195
  var packageRoot = resolvePackageRoot(here);
33196
+ process.env.AK_ROLE_PACKAGE_ROOT = packageRoot;
32650
33197
  ensureHostPiRuntimeResolvable(packageRoot);
32651
33198
  var { runAkRole: runAkRole2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
32652
33199
  var result = await runAkRole2(process.argv.slice(2), { packageRoot });