@akagilnc/pi-workflow-roles 0.1.3671 → 0.1.3682

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.
@@ -3242,7 +3242,7 @@ function validateRecordedDiaristOutput(value) {
3242
3242
  } catch {
3243
3243
  throw new Error("Diarist output has no execution discriminator");
3244
3244
  }
3245
- if (status === "completed") {
3245
+ if (status === "completed" || status === "escalate") {
3246
3246
  return value;
3247
3247
  }
3248
3248
  throw new Error("Diarist output has no execution discriminator");
@@ -3274,7 +3274,7 @@ var init_diarist_contracts = __esm({
3274
3274
  DIARIST_SOURCES_FLAG = {
3275
3275
  name: "ak-diarist-sources",
3276
3276
  definition: {
3277
- description: "Frozen per-ticket source catalog the diarist selects from",
3277
+ description: "Frozen source catalog the diarist selects from (may be unbound until LLM asserts ticketNumber)",
3278
3278
  type: "string"
3279
3279
  }
3280
3280
  };
@@ -3496,7 +3496,7 @@ function validateAcceptedDetails(toolName, details) {
3496
3496
  [GATEKEEPER_OUTPUT_TOOL_NAME]: ["dispatch", "pass"],
3497
3497
  [NAVIGATOR_OUTPUT_TOOL_NAME]: ["advice"],
3498
3498
  [AUDITOR_OUTPUT_TOOL_NAME]: ["pass", "bounce", "escalate"],
3499
- [DIARIST_OUTPUT_TOOL_NAME]: ["completed"]
3499
+ [DIARIST_OUTPUT_TOOL_NAME]: ["completed", "escalate"]
3500
3500
  };
3501
3501
  const collectorDiscriminator = toolName === COLLECTOR_OUTPUT_TOOL && Array.isArray(candidate?.groups);
3502
3502
  const baseDiscriminator = discriminator;
@@ -4643,27 +4643,6 @@ async function findLatestRunIdForSeatTicket(input) {
4643
4643
  }
4644
4644
  return best;
4645
4645
  }
4646
- async function collectBookRunTicketNumbers(input) {
4647
- const ledgerHome = resolveActivationLedgerHome(input.home);
4648
- const runsDir = join11(
4649
- activationBookDirectory(ledgerHome, input.bookKey),
4650
- "runs"
4651
- );
4652
- let entries;
4653
- try {
4654
- entries = await readdir2(runsDir);
4655
- } catch (error) {
4656
- if (errorCodeOf2(error) === "ENOENT") return /* @__PURE__ */ new Set();
4657
- throw error;
4658
- }
4659
- const known = /* @__PURE__ */ new Set();
4660
- for (const entry of entries) {
4661
- if (!entry.includes("@")) continue;
4662
- const ticketNumber = await readRunTicketNumber(join11(runsDir, entry));
4663
- if (ticketNumber !== void 0) known.add(ticketNumber);
4664
- }
4665
- return known;
4666
- }
4667
4646
  function parsePersistedTicketIdentity(record4) {
4668
4647
  const correlationId = typeof record4.correlationId === "string" && record4.correlationId.trim() !== "" ? record4.correlationId : void 0;
4669
4648
  const ticketNumber = typeof record4.ticketNumber === "number" && Number.isSafeInteger(record4.ticketNumber) && record4.ticketNumber >= 1 ? record4.ticketNumber : void 0;
@@ -6158,6 +6137,7 @@ __export(invocation_exports, {
6158
6137
  admitNotaryInvocation: () => admitNotaryInvocation,
6159
6138
  admitReviewerInvocation: () => admitReviewerInvocation,
6160
6139
  bindAdmittedTicketNumber: () => bindAdmittedTicketNumber,
6140
+ bindTicketNumberOnRunDirectory: () => bindTicketNumberOnRunDirectory,
6161
6141
  buildCoderTransportPrompt: () => buildCoderTransportPrompt,
6162
6142
  buildCollectorTransportPrompt: () => buildCollectorTransportPrompt,
6163
6143
  buildCountersignTransportPrompt: () => buildCountersignTransportPrompt,
@@ -6206,6 +6186,7 @@ __export(invocation_exports, {
6206
6186
  resolveGitHubRemoteRepository: () => resolveGitHubRemoteRepository
6207
6187
  });
6208
6188
  import { execFileSync as execFileSync2 } from "node:child_process";
6189
+ import { existsSync as existsSync4 } from "node:fs";
6209
6190
  import {
6210
6191
  lstat as lstat3,
6211
6192
  mkdir,
@@ -6352,6 +6333,40 @@ async function bindAdmittedTicketNumber(admitted, ticketNumber) {
6352
6333
  "utf8"
6353
6334
  );
6354
6335
  }
6336
+ async function bindTicketNumberOnRunDirectory(runDirectory, ticketNumber) {
6337
+ if (!Number.isSafeInteger(ticketNumber) || ticketNumber < 1) {
6338
+ throw new Error(
6339
+ `bindTicketNumberOnRunDirectory requires a safe positive integer, got ${String(ticketNumber)}`
6340
+ );
6341
+ }
6342
+ const admittedPath = join13(runDirectory, "admitted-request.json");
6343
+ const invocationPath = join13(runDirectory, "invocation.json");
6344
+ const admitted = JSON.parse(await readFile9(admittedPath, "utf8"));
6345
+ const existing = admitted.ticketNumber;
6346
+ if (typeof existing === "number") {
6347
+ if (existing === ticketNumber) return;
6348
+ throw new Error(
6349
+ `bindTicketNumberOnRunDirectory refuses to replace existing ticket #${existing} with #${ticketNumber}`
6350
+ );
6351
+ }
6352
+ if (existsSync4(invocationPath)) {
6353
+ const invocation = JSON.parse(
6354
+ await readFile9(invocationPath, "utf8")
6355
+ );
6356
+ if (typeof invocation.ticketNumber === "number" && invocation.ticketNumber !== ticketNumber) {
6357
+ throw new Error(
6358
+ `bindTicketNumberOnRunDirectory refuses to replace invocation ticket #${invocation.ticketNumber} with #${ticketNumber}`
6359
+ );
6360
+ }
6361
+ }
6362
+ await writeFile4(
6363
+ admittedPath,
6364
+ `${JSON.stringify({ ...admitted, ticketNumber }, null, 2)}
6365
+ `,
6366
+ "utf8"
6367
+ );
6368
+ await mergeInvocationIdentityPage(runDirectory, { ticketNumber });
6369
+ }
6355
6370
  async function recordLaunchedPiIdentity(runDirectory, identity) {
6356
6371
  await mergeInvocationIdentityPage(runDirectory, {
6357
6372
  piExecutable: identity.executable,
@@ -8388,7 +8403,7 @@ var load_production_acp_host_exports = {};
8388
8403
  __export(load_production_acp_host_exports, {
8389
8404
  loadProductionAcpHostFactory: () => loadProductionAcpHostFactory
8390
8405
  });
8391
- import { existsSync as existsSync4 } from "node:fs";
8406
+ import { existsSync as existsSync5 } from "node:fs";
8392
8407
  import { join as join14 } from "node:path";
8393
8408
  import { pathToFileURL } from "node:url";
8394
8409
  async function loadProductionAcpHostFactory(packageRoot, host) {
@@ -8398,7 +8413,7 @@ async function loadProductionAcpHostFactory(packageRoot, host) {
8398
8413
  }
8399
8414
  const built = join14(packageRoot, "dist/acp-host/production-host.js");
8400
8415
  const source = join14(packageRoot, "src/acp-host/production-host.ts");
8401
- const target = existsSync4(built) ? built : source;
8416
+ const target = existsSync5(built) ? built : source;
8402
8417
  const href = pathToFileURL(target).href;
8403
8418
  const mod = await import(href);
8404
8419
  const create = mod.createProductionAcpRoleTurnHost;
@@ -9263,6 +9278,30 @@ var init_config = __esm({
9263
9278
  }
9264
9279
  });
9265
9280
 
9281
+ // src/public-cli/seat-ticket-binding.ts
9282
+ async function tryResumeSameTicketSeatRun(input) {
9283
+ if (input.freshSummons === true) return void 0;
9284
+ if (input.parentRunPath === void 0 && input.ticketNumber === void 0) {
9285
+ return void 0;
9286
+ }
9287
+ const previousRunId = await findLatestRunIdForSeatTicket({
9288
+ home: input.home,
9289
+ bookKey: resolveBookKeyFromGit(input.projectRoot),
9290
+ role: input.role,
9291
+ ...input.parentRunPath === void 0 ? {} : { parentRunPath: input.parentRunPath },
9292
+ ...input.ticketNumber === void 0 ? {} : { ticketNumber: input.ticketNumber }
9293
+ });
9294
+ if (previousRunId === void 0) return void 0;
9295
+ return await input.resume(previousRunId, input.summons);
9296
+ }
9297
+ var init_seat_ticket_binding = __esm({
9298
+ "src/public-cli/seat-ticket-binding.ts"() {
9299
+ "use strict";
9300
+ init_activation_ledger_git();
9301
+ init_run_lifecycle();
9302
+ }
9303
+ });
9304
+
9266
9305
  // src/ticket-provenance-contracts.ts
9267
9306
  function isRecord11(value) {
9268
9307
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -9356,7 +9395,7 @@ var init_ticket_provenance_contracts = __esm({
9356
9395
 
9357
9396
  // src/ticket-provenance.ts
9358
9397
  import { createHash as createHash5 } from "node:crypto";
9359
- import { appendFileSync as appendFileSync2, existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs";
9398
+ import { appendFileSync as appendFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs";
9360
9399
  import { join as join16 } from "node:path";
9361
9400
  function ticketProvenanceSubject(ticketNumber) {
9362
9401
  if (!Number.isSafeInteger(ticketNumber) || ticketNumber < 1) {
@@ -9421,7 +9460,7 @@ function resolveTicketProvenanceVolume(ticketNumber, cwd, home) {
9421
9460
  }
9422
9461
  function readOfferedIdentities(ticketNumber, cwd, home) {
9423
9462
  const { offeredWatermarkFile } = resolveTicketProvenanceVolume(ticketNumber, cwd, home);
9424
- if (!existsSync5(offeredWatermarkFile)) return /* @__PURE__ */ new Set();
9463
+ if (!existsSync6(offeredWatermarkFile)) return /* @__PURE__ */ new Set();
9425
9464
  let text;
9426
9465
  try {
9427
9466
  text = readFileSync2(offeredWatermarkFile, "utf8");
@@ -9632,91 +9671,6 @@ var init_ticket_provenance = __esm({
9632
9671
  }
9633
9672
  });
9634
9673
 
9635
- // src/public-cli/seat-ticket-binding.ts
9636
- import { existsSync as existsSync6 } from "node:fs";
9637
- function instructionTicketTokens(instruction) {
9638
- const tokens = /* @__PURE__ */ new Set();
9639
- for (const run of instruction.match(/\d+/g) ?? []) {
9640
- if (run.startsWith("0")) continue;
9641
- const parsed = Number(run);
9642
- if (!Number.isSafeInteger(parsed) || parsed < 1) continue;
9643
- tokens.add(parsed);
9644
- }
9645
- return [...tokens];
9646
- }
9647
- async function resolveKnownTicketNumber(input) {
9648
- const tokens = instructionTicketTokens(input.instruction);
9649
- if (tokens.length === 0) return void 0;
9650
- const known = [];
9651
- let runTickets;
9652
- for (const token of tokens) {
9653
- const volume = resolveTicketProvenanceVolume(
9654
- token,
9655
- input.projectRoot,
9656
- input.home
9657
- );
9658
- if (existsSync6(volume.volumeDir)) {
9659
- known.push(token);
9660
- continue;
9661
- }
9662
- if (runTickets === void 0) {
9663
- runTickets = await readBookRunTickets(input);
9664
- }
9665
- if (runTickets.has(token)) known.push(token);
9666
- }
9667
- return known.length === 1 ? known[0] : void 0;
9668
- }
9669
- async function readBookRunTickets(input) {
9670
- let bookKey;
9671
- try {
9672
- bookKey = input.bookKey ?? resolveBookKeyFromGit(input.projectRoot);
9673
- } catch (error) {
9674
- if (error instanceof ActivationGitRepositoryRequiredError) return /* @__PURE__ */ new Set();
9675
- throw error;
9676
- }
9677
- return await collectBookRunTicketNumbers({ home: input.home, bookKey });
9678
- }
9679
- async function bindReusedTicketNumber(admitted, ticketNumber) {
9680
- if (ticketNumber === void 0) return;
9681
- if (admitted.ticketNumber !== void 0) return;
9682
- await bindAdmittedTicketNumber(admitted, ticketNumber);
9683
- }
9684
- async function resolveSeatTicketBinding(admitted, env) {
9685
- if (admitted.ticketNumber !== void 0) return admitted.ticketNumber;
9686
- const ticketNumber = await resolveKnownTicketNumber({
9687
- instruction: admitted.instruction,
9688
- projectRoot: admitted.projectRoot,
9689
- home: env.home,
9690
- bookKey: admitted.bookKey
9691
- });
9692
- await bindReusedTicketNumber(admitted, ticketNumber);
9693
- return ticketNumber;
9694
- }
9695
- async function tryResumeSameTicketSeatRun(input) {
9696
- if (input.freshSummons === true) return void 0;
9697
- if (input.parentRunPath === void 0 && input.ticketNumber === void 0) {
9698
- return void 0;
9699
- }
9700
- const previousRunId = await findLatestRunIdForSeatTicket({
9701
- home: input.home,
9702
- bookKey: resolveBookKeyFromGit(input.projectRoot),
9703
- role: input.role,
9704
- ...input.parentRunPath === void 0 ? {} : { parentRunPath: input.parentRunPath },
9705
- ...input.ticketNumber === void 0 ? {} : { ticketNumber: input.ticketNumber }
9706
- });
9707
- if (previousRunId === void 0) return void 0;
9708
- return await input.resume(previousRunId, input.summons);
9709
- }
9710
- var init_seat_ticket_binding = __esm({
9711
- "src/public-cli/seat-ticket-binding.ts"() {
9712
- "use strict";
9713
- init_activation_ledger_git();
9714
- init_ticket_provenance();
9715
- init_invocation();
9716
- init_run_lifecycle();
9717
- }
9718
- });
9719
-
9720
9674
  // src/public-cli/case-dossier-delivery.ts
9721
9675
  import { stat as stat2 } from "node:fs/promises";
9722
9676
  async function describeDossierFile(path) {
@@ -16489,11 +16443,6 @@ async function runPublicInspector(argv, env, io, parseInspectorArgv2) {
16489
16443
  throw error;
16490
16444
  }
16491
16445
  const projectRoot = parsed.project ?? env.cwd;
16492
- const reusedTicketNumber = await resolveKnownTicketNumber({
16493
- instruction: parsed.instruction,
16494
- projectRoot,
16495
- home: env.home
16496
- });
16497
16446
  const parentRunPath = parentRunPathFromGatePointerInstruction(parsed.instruction);
16498
16447
  if (parentRunPath !== void 0) {
16499
16448
  const summons = {
@@ -16559,11 +16508,7 @@ async function runPublicInspector(argv, env, io, parseInspectorArgv2) {
16559
16508
  env,
16560
16509
  io,
16561
16510
  request: turnRequest,
16562
- adapters: inspectorAdapters({
16563
- beforeDispatch: async (admittedSeat) => {
16564
- await bindReusedTicketNumber(admittedSeat, reusedTicketNumber);
16565
- }
16566
- }),
16511
+ adapters: inspectorAdapters(),
16567
16512
  ...env.engine === void 0 ? {} : { effectiveEngine: env.engine }
16568
16513
  });
16569
16514
  }
@@ -16744,7 +16689,6 @@ async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
16744
16689
  let auditorSubject;
16745
16690
  let auditorSourceRun;
16746
16691
  let auditorSourceTicket;
16747
- let reusedTicketNumber;
16748
16692
  const projectRoot = parsed.project ?? env.cwd;
16749
16693
  if (role === "auditor") {
16750
16694
  if (parsed.subject !== "judge" && parsed.subject !== "doctor") {
@@ -16779,12 +16723,6 @@ async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
16779
16723
  );
16780
16724
  return { exitCode: 2 };
16781
16725
  }
16782
- } else {
16783
- reusedTicketNumber = await resolveKnownTicketNumber({
16784
- instruction: parsed.instruction,
16785
- projectRoot,
16786
- home: env.home
16787
- });
16788
16726
  }
16789
16727
  const summons = {
16790
16728
  instruction: parsed.instruction,
@@ -16810,21 +16748,6 @@ async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
16810
16748
  })
16811
16749
  });
16812
16750
  if (resumed !== void 0) return resumed;
16813
- } else if (reusedTicketNumber !== void 0) {
16814
- const resumed = await tryResumeSameTicketSeatRun({
16815
- home: env.home,
16816
- projectRoot,
16817
- role,
16818
- ticketNumber: reusedTicketNumber,
16819
- freshSummons: env.freshSummons,
16820
- summons,
16821
- resume: (runId, materials) => runPublicInstructionSeatResume(
16822
- { runId, ...materials === void 0 ? {} : { summons: materials } },
16823
- env,
16824
- io
16825
- )
16826
- });
16827
- if (resumed !== void 0) return resumed;
16828
16751
  }
16829
16752
  let admitted;
16830
16753
  try {
@@ -16882,8 +16805,6 @@ async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
16882
16805
  beforeDispatch: async (admittedSeat) => {
16883
16806
  if (auditorSourceTicket !== void 0) {
16884
16807
  await bindAdmittedTicketNumber(admittedSeat, auditorSourceTicket);
16885
- } else {
16886
- await bindReusedTicketNumber(admittedSeat, reusedTicketNumber);
16887
16808
  }
16888
16809
  }
16889
16810
  }),
@@ -16991,12 +16912,7 @@ async function runPublicJudge(argv, env, io, parseJudgeArgv2) {
16991
16912
  })
16992
16913
  }
16993
16914
  }),
16994
- adapters: {
16995
- ...judgeAdapters(),
16996
- beforeDispatch: async (admittedSeat) => {
16997
- await resolveSeatTicketBinding(admittedSeat, env);
16998
- }
16999
- },
16915
+ adapters: judgeAdapters(),
17000
16916
  ...env.engine === void 0 ? {} : { effectiveEngine: env.engine }
17001
16917
  });
17002
16918
  }
@@ -17020,7 +16936,6 @@ var init_judge_run = __esm({
17020
16936
  init_engine_material();
17021
16937
  init_cli_errors();
17022
16938
  init_invocation();
17023
- init_seat_ticket_binding();
17024
16939
  init_run_lifecycle();
17025
16940
  init_settlement();
17026
16941
  init_turn_request();
@@ -20446,8 +20361,18 @@ var init_diarist_role = __esm({
20446
20361
  openToolObject(
20447
20362
  Type23.Object({
20448
20363
  status: Type23.Unknown({
20449
- description: "completed \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8"
20364
+ description: "completed | escalate \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8"
20450
20365
  }),
20366
+ ticketNumber: Type23.Optional(
20367
+ Type23.Unknown({
20368
+ description: "\u672C\u5EAD\u5BF9\u8C61\u7968\u53F7\uFF08\u6B63\u6574\u6570\uFF09\u6216 null/\u7701\u7565\uFF1D\u771F\u65E0\u7968\uFF1B\u673A\u68B0\u9A8C\u771F\u540E\u4E0B\u6E38\u8D70 typed \u952E\uFF1B\u8BA4\u4E0D\u51FA\u7528 status=escalate\uFF0C\u4E0D\u6D17\u6210\u65E0\u5F55"
20369
+ })
20370
+ ),
20371
+ reason: Type23.Optional(
20372
+ Type23.String({
20373
+ description: "status \u4E3A escalate \u65F6\uFF1A\u8BA4\u4E0D\u51FA\u672C\u5EAD\u5BF9\u8C61\u7684\u539F\u56E0"
20374
+ })
20375
+ ),
20451
20376
  selections: Type23.Array(
20452
20377
  Type23.Object(
20453
20378
  {
@@ -20461,7 +20386,7 @@ var init_diarist_role = __esm({
20461
20386
  },
20462
20387
  { additionalProperties: true, description: "\u4E00\u6761\u5165\u5F55\u9009\u62E9" }
20463
20388
  ),
20464
- { description: "\u5165\u5F55\u9009\u62E9\uFF1B\u7A7A\u5217\u8868\u5408\u6CD5\u5B8C\u5C40" }
20389
+ { description: "\u5165\u5F55\u9009\u62E9\uFF1B\u7A7A\u5217\u8868\u5408\u6CD5\u5B8C\u5C40\uFF1Bescalate \u65F6\u53EF\u4E0D\u4EA4" }
20465
20390
  )
20466
20391
  })
20467
20392
  )
@@ -20469,8 +20394,8 @@ var init_diarist_role = __esm({
20469
20394
  DIARIST_TOOL_SPEC = {
20470
20395
  name: DIARIST_OUTPUT_TOOL_NAME,
20471
20396
  label: "\u8D77\u5C45\u90CE\u8F93\u51FA",
20472
- description: "\u8D77\u5C45\u90CE\u5165\u5F55\u9009\u62E9\u3002",
20473
- promptSnippet: "\u8D77\u5C45\u90CE\u5165\u5F55\u9009\u62E9",
20397
+ description: "\u8D77\u5C45\u90CE\u5165\u5F55\u9009\u62E9\u4E0E\u672C\u7968\u8EAB\u4EFD\u65AD\u8A00\uFF1B\u8BA4\u4E0D\u51FA\u672C\u5EAD\u5BF9\u8C61\u5219 escalate\u3002",
20398
+ promptSnippet: "\u8D77\u5C45\u90CE\u5165\u5F55\u9009\u62E9\u4E0E\u672C\u7968\u8EAB\u4EFD",
20474
20399
  parameters: diaristOutputSchema
20475
20400
  };
20476
20401
  }
@@ -20554,6 +20479,83 @@ var init_diarist_mechanical = __esm({
20554
20479
 
20555
20480
  // src/diarist.ts
20556
20481
  import { readFileSync as readFileSync4 } from "node:fs";
20482
+ import { execFileSync as execFileSync3 } from "node:child_process";
20483
+ function instructionContainsTicketNumber(instruction, ticketNumber) {
20484
+ if (!Number.isSafeInteger(ticketNumber) || ticketNumber < 1) return false;
20485
+ return new RegExp("(?<!\\d)" + String(ticketNumber) + "(?!\\d)").test(
20486
+ instruction
20487
+ );
20488
+ }
20489
+ function createGhTicketExistenceChecker(options) {
20490
+ const runner = options?.runner ?? createGhApiRunner();
20491
+ return async (input) => {
20492
+ const projected = await projectGhIssueBody(runner, {
20493
+ owner: input.owner,
20494
+ repo: input.repo,
20495
+ ticketNumber: input.ticketNumber,
20496
+ ...input.signal === void 0 ? {} : { signal: input.signal }
20497
+ });
20498
+ return projected.status === "available";
20499
+ };
20500
+ }
20501
+ async function verifyAssertedTicketNumber(input) {
20502
+ const n = input.ticketNumber;
20503
+ if (!Number.isSafeInteger(n) || n < 1) {
20504
+ throw new DiaristTicketVerificationError(
20505
+ "assertion-uninterpretable",
20506
+ `diarist ticket assertion must be a safe integer >= 1, got ${String(n)}`
20507
+ );
20508
+ }
20509
+ if (!instructionContainsTicketNumber(input.instruction, n)) {
20510
+ throw new DiaristTicketVerificationError(
20511
+ "number-not-in-instruction",
20512
+ `diarist ticket assertion #${n} complete decimal number does not appear in accepted instruction`
20513
+ );
20514
+ }
20515
+ const origin = resolveDiaristGithubOrigin(input.projectRoot);
20516
+ if (origin === void 0) {
20517
+ throw new DiaristTicketVerificationError(
20518
+ "origin-unresolved",
20519
+ `diarist ticket assertion #${n} requires a resolvable github.com origin remote for live verification`
20520
+ );
20521
+ }
20522
+ const checkExistence = input.checkExistence ?? createGhTicketExistenceChecker();
20523
+ let exists;
20524
+ try {
20525
+ exists = await checkExistence({
20526
+ owner: origin.owner,
20527
+ repo: origin.repo,
20528
+ ticketNumber: n,
20529
+ ...input.signal === void 0 ? {} : { signal: input.signal }
20530
+ });
20531
+ } catch (error) {
20532
+ throw new DiaristTicketVerificationError(
20533
+ "ticket-missing",
20534
+ `diarist ticket assertion #${n} live verification failed`,
20535
+ { cause: error }
20536
+ );
20537
+ }
20538
+ if (!exists) {
20539
+ throw new DiaristTicketVerificationError(
20540
+ "ticket-missing",
20541
+ `diarist ticket assertion #${n} does not exist as a live issue on ${origin.owner}/${origin.repo}`
20542
+ );
20543
+ }
20544
+ }
20545
+ function resolveDiaristGithubOrigin(projectRoot) {
20546
+ let remoteUrl;
20547
+ try {
20548
+ remoteUrl = execFileSync3("git", ["remote", "get-url", "origin"], {
20549
+ cwd: projectRoot,
20550
+ encoding: "utf8",
20551
+ stdio: ["ignore", "pipe", "pipe"]
20552
+ }).trim();
20553
+ } catch {
20554
+ return void 0;
20555
+ }
20556
+ if (remoteUrl.length === 0) return void 0;
20557
+ return parseGitHubOriginRemote(remoteUrl);
20558
+ }
20557
20559
  function blockEntryIdentity(ticketNumber, block) {
20558
20560
  return ticketProvenanceEntryIdentity({
20559
20561
  ticketNumber,
@@ -20568,8 +20570,20 @@ function loadDiaristSourceCatalog(path) {
20568
20570
  throw new Error(`diarist source catalog is not an object (${path})`);
20569
20571
  }
20570
20572
  const record4 = parsed;
20571
- if (typeof record4.ticketNumber !== "number" || typeof record4.cwd !== "string") {
20572
- throw new Error(`diarist source catalog is missing ticket coordinates (${path})`);
20573
+ if (typeof record4.cwd !== "string") {
20574
+ throw new Error(`diarist source catalog is missing cwd (${path})`);
20575
+ }
20576
+ if (typeof record4.instruction !== "string") {
20577
+ throw new Error(`diarist source catalog is missing instruction (${path})`);
20578
+ }
20579
+ if (typeof record4.runDirectory !== "string") {
20580
+ throw new Error(`diarist source catalog is missing runDirectory (${path})`);
20581
+ }
20582
+ if (typeof record4.projectRoot !== "string") {
20583
+ throw new Error(`diarist source catalog is missing projectRoot (${path})`);
20584
+ }
20585
+ if (record4.ticketNumber !== void 0 && (typeof record4.ticketNumber !== "number" || !Number.isSafeInteger(record4.ticketNumber) || record4.ticketNumber < 1)) {
20586
+ throw new Error(`diarist source catalog ticketNumber is not a safe ticket (${path})`);
20573
20587
  }
20574
20588
  if (!Array.isArray(record4.candidates)) {
20575
20589
  throw new Error(`diarist source catalog is missing candidates (${path})`);
@@ -20577,7 +20591,13 @@ function loadDiaristSourceCatalog(path) {
20577
20591
  return parsed;
20578
20592
  }
20579
20593
  async function commitDiaristSelections(input) {
20580
- const { ticketNumber, cwd } = input.catalog;
20594
+ const ticketNumber = input.catalog.ticketNumber;
20595
+ if (ticketNumber === void 0) {
20596
+ throw new Error(
20597
+ "commitDiaristSelections requires a bound ticketNumber on the catalog"
20598
+ );
20599
+ }
20600
+ const { cwd } = input.catalog;
20581
20601
  const homeOpt = input.catalog.home === void 0 ? {} : { home: input.catalog.home };
20582
20602
  const volumePaths = ensureTicketProvenanceVolume(ticketNumber, cwd, input.catalog.home);
20583
20603
  const anchors = buildDiaristAnchors({ ticketNumber });
@@ -20643,6 +20663,7 @@ async function commitDiaristSelections(input) {
20643
20663
  ]
20644
20664
  };
20645
20665
  }
20666
+ var DiaristTicketVerificationError;
20646
20667
  var init_diarist = __esm({
20647
20668
  "src/diarist.ts"() {
20648
20669
  "use strict";
@@ -20652,6 +20673,15 @@ var init_diarist = __esm({
20652
20673
  init_reviewer_pinned_git();
20653
20674
  init_ticket_provenance();
20654
20675
  init_sitian_facade();
20676
+ DiaristTicketVerificationError = class extends Error {
20677
+ code = "diarist-ticket-verification";
20678
+ reason;
20679
+ constructor(reason, message, options) {
20680
+ super(message, options);
20681
+ this.name = "DiaristTicketVerificationError";
20682
+ this.reason = reason;
20683
+ }
20684
+ };
20655
20685
  }
20656
20686
  });
20657
20687
 
@@ -21189,11 +21219,11 @@ var init_reviewer_role = __esm({
21189
21219
  });
21190
21220
 
21191
21221
  // src/worker-submission-gates.ts
21192
- import { execFileSync as execFileSync3 } from "node:child_process";
21222
+ import { execFileSync as execFileSync4 } from "node:child_process";
21193
21223
  import { existsSync as existsSync12, lstatSync as lstatSync3, readdirSync as readdirSync2, readFileSync as readFileSync5, rmdirSync, rmSync } from "node:fs";
21194
21224
  import { resolve as resolve18 } from "node:path";
21195
21225
  function git2(cwd, args) {
21196
- return execFileSync3("git", args, {
21226
+ return execFileSync4("git", args, {
21197
21227
  cwd,
21198
21228
  encoding: "utf8",
21199
21229
  stdio: ["ignore", "pipe", "pipe"],
@@ -21201,7 +21231,7 @@ function git2(cwd, args) {
21201
21231
  }).trim();
21202
21232
  }
21203
21233
  function gitFile(file, args) {
21204
- return execFileSync3("git", ["config", "--file", file, ...args], {
21234
+ return execFileSync4("git", ["config", "--file", file, ...args], {
21205
21235
  encoding: "utf8",
21206
21236
  stdio: ["ignore", "pipe", "pipe"],
21207
21237
  env: { ...process.env, GIT_DIR: void 0, GIT_WORK_TREE: void 0, GIT_COMMON_DIR: void 0 }
@@ -22288,6 +22318,26 @@ function createAuditorRoleRuntime(roleHost, dependencies) {
22288
22318
  }
22289
22319
  };
22290
22320
  }
22321
+ function readDiaristTicketAssertion(submitted) {
22322
+ if (submitted === void 0 || !("ticketNumber" in submitted)) {
22323
+ return { kind: "true-unbound" };
22324
+ }
22325
+ const raw = submitted.ticketNumber;
22326
+ if (raw === null) return { kind: "true-unbound" };
22327
+ if (typeof raw === "number" && Number.isSafeInteger(raw) && raw >= 1) {
22328
+ return { kind: "ticket", ticketNumber: raw };
22329
+ }
22330
+ if (typeof raw === "string" && /^[1-9]\d*$/.test(raw)) {
22331
+ const n = Number(raw);
22332
+ if (Number.isSafeInteger(n) && n >= 1) {
22333
+ return { kind: "ticket", ticketNumber: n };
22334
+ }
22335
+ }
22336
+ throw new DiaristTicketVerificationError(
22337
+ "assertion-uninterpretable",
22338
+ "diarist ticketNumber must be a safe integer >= 1, null, or absent"
22339
+ );
22340
+ }
22291
22341
  function createDiaristRoleRuntime(roleHost, dependencies, getSourcesFlag) {
22292
22342
  let catalog;
22293
22343
  const runtime = createFiledOfficerRuntime(
@@ -22299,17 +22349,72 @@ function createDiaristRoleRuntime(roleHost, dependencies, getSourcesFlag) {
22299
22349
  soulTag: "diarist",
22300
22350
  beforeAccept: async ({ parameters }) => {
22301
22351
  const submitted = parameters !== null && typeof parameters === "object" && !Array.isArray(parameters) ? parameters : void 0;
22352
+ if (submitted?.status === "escalate") {
22353
+ if (!("sitian" in submitted) && !("ticketNumber" in submitted)) {
22354
+ return submitted;
22355
+ }
22356
+ const stripped = { ...submitted };
22357
+ delete stripped.sitian;
22358
+ delete stripped.ticketNumber;
22359
+ return stripped;
22360
+ }
22361
+ const assertion = readDiaristTicketAssertion(submitted);
22302
22362
  if (catalog === void 0) {
22363
+ if (assertion.kind === "ticket") {
22364
+ throw new DiaristTicketVerificationError(
22365
+ "assertion-uninterpretable",
22366
+ `diarist asserted ticket #${assertion.ticketNumber} but no source catalog was frozen for this turn`
22367
+ );
22368
+ }
22303
22369
  if (submitted === void 0 || !("sitian" in submitted)) return void 0;
22304
22370
  const stripped = { ...submitted };
22305
22371
  delete stripped.sitian;
22306
22372
  return stripped;
22307
22373
  }
22374
+ if (catalog.ticketNumber !== void 0) {
22375
+ const facts2 = await commitDiaristSelections({
22376
+ catalog,
22377
+ selections: projectDiaristSelections(parameters)
22378
+ });
22379
+ return {
22380
+ ...submitted ?? { receipt: parameters },
22381
+ ticketNumber: catalog.ticketNumber,
22382
+ sitian: facts2
22383
+ };
22384
+ }
22385
+ if (assertion.kind === "true-unbound") {
22386
+ if (submitted === void 0 || !("sitian" in submitted)) {
22387
+ return { ...submitted ?? { receipt: parameters }, ticketNumber: null };
22388
+ }
22389
+ const stripped = {
22390
+ ...submitted,
22391
+ ticketNumber: null
22392
+ };
22393
+ delete stripped.sitian;
22394
+ return stripped;
22395
+ }
22396
+ await verifyAssertedTicketNumber({
22397
+ ticketNumber: assertion.ticketNumber,
22398
+ instruction: catalog.instruction,
22399
+ projectRoot: catalog.projectRoot
22400
+ });
22401
+ await bindTicketNumberOnRunDirectory(
22402
+ catalog.runDirectory,
22403
+ assertion.ticketNumber
22404
+ );
22405
+ const boundCatalog = {
22406
+ ...catalog,
22407
+ ticketNumber: assertion.ticketNumber
22408
+ };
22308
22409
  const facts = await commitDiaristSelections({
22309
- catalog,
22410
+ catalog: boundCatalog,
22310
22411
  selections: projectDiaristSelections(parameters)
22311
22412
  });
22312
- return { ...submitted ?? { receipt: parameters }, sitian: facts };
22413
+ return {
22414
+ ...submitted ?? { receipt: parameters },
22415
+ ticketNumber: assertion.ticketNumber,
22416
+ sitian: facts
22417
+ };
22313
22418
  }
22314
22419
  },
22315
22420
  dependencies
@@ -23100,6 +23205,7 @@ var init_role_runtime = __esm({
23100
23205
  init_diarist_role();
23101
23206
  init_diarist_contracts();
23102
23207
  init_diarist();
23208
+ init_invocation();
23103
23209
  init_gatekeeper_role();
23104
23210
  init_navigator_role();
23105
23211
  init_auditor_role();