@akagilnc/pi-workflow-roles 0.1.2157 → 0.1.2173

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.
@@ -14505,6 +14505,9 @@ async function savePublicCliConfig(config, home = homedir()) {
14505
14505
  function setPersistentSeatConfig(config, seat, selection) {
14506
14506
  const previous = config.seats[seat];
14507
14507
  return {
14508
+ // Spread preserves sibling top-level keys such as autoResumeLimit (#422):
14509
+ // a seat write must never silently drop them.
14510
+ ...config,
14508
14511
  seats: {
14509
14512
  ...config.seats,
14510
14513
  [seat]: {
@@ -14528,6 +14531,7 @@ function setPersistentSeatEngine(config, seat, engine) {
14528
14531
  if (engine === void 0) {
14529
14532
  const { engine: _dropped, ...modelOnly } = previous;
14530
14533
  return {
14534
+ ...config,
14531
14535
  seats: {
14532
14536
  ...config.seats,
14533
14537
  [seat]: modelOnly
@@ -14535,12 +14539,24 @@ function setPersistentSeatEngine(config, seat, engine) {
14535
14539
  };
14536
14540
  }
14537
14541
  return {
14542
+ ...config,
14538
14543
  seats: {
14539
14544
  ...config.seats,
14540
14545
  [seat]: { ...previous, engine }
14541
14546
  }
14542
14547
  };
14543
14548
  }
14549
+ function parseAutoResumeLimit(value) {
14550
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
14551
+ throw new Error(
14552
+ `auto-resume limit must be a non-negative integer, got ${JSON.stringify(value)}`
14553
+ );
14554
+ }
14555
+ return value;
14556
+ }
14557
+ function setAutoResumeLimit(config, limit) {
14558
+ return { ...config, autoResumeLimit: parseAutoResumeLimit(limit) };
14559
+ }
14544
14560
  function seatModelOnly(seat) {
14545
14561
  return seat.thinking === void 0 ? { provider: seat.provider, model: seat.model } : { provider: seat.provider, model: seat.model, thinking: seat.thinking };
14546
14562
  }
@@ -14610,8 +14626,15 @@ function parsePublicCliConfig(value) {
14610
14626
  throw new Error("public CLI config must be an object");
14611
14627
  }
14612
14628
  const record4 = value;
14629
+ let autoResumeLimit;
14630
+ if (record4.autoResumeLimit !== void 0) {
14631
+ autoResumeLimit = parseAutoResumeLimit(record4.autoResumeLimit);
14632
+ }
14613
14633
  if (record4.seats === void 0) {
14614
- return { seats: {} };
14634
+ return {
14635
+ seats: {},
14636
+ ...autoResumeLimit === void 0 ? {} : { autoResumeLimit }
14637
+ };
14615
14638
  }
14616
14639
  if (record4.seats === null || typeof record4.seats !== "object" || Array.isArray(record4.seats)) {
14617
14640
  throw new Error("public CLI config.seats must be an object");
@@ -14625,7 +14648,10 @@ function parsePublicCliConfig(value) {
14625
14648
  }
14626
14649
  seats[key] = parseSeatModelConfig(raw, key);
14627
14650
  }
14628
- return { seats };
14651
+ return {
14652
+ seats,
14653
+ ...autoResumeLimit === void 0 ? {} : { autoResumeLimit }
14654
+ };
14629
14655
  }
14630
14656
  function parseSeatModelConfig(value, seat) {
14631
14657
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
@@ -16470,11 +16496,13 @@ var init_option_definitions = __esm({
16470
16496
  usage: [
16471
16497
  "ak-role config set <seat> <provider/model[:thinking]> [<seat> <spec> ...]",
16472
16498
  "ak-role config set-engine <seat> <name>",
16473
- "ak-role config unset-engine <seat>"
16499
+ "ak-role config unset-engine <seat>",
16500
+ "ak-role config set-auto-resume-limit <N>"
16474
16501
  ],
16475
16502
  examples: [
16476
16503
  "ak-role config set judge openai-codex/gpt-5.6-sol:high",
16477
- "ak-role config set-engine judge opus"
16504
+ "ak-role config set-engine judge opus",
16505
+ "ak-role config set-auto-resume-limit 3"
16478
16506
  ]
16479
16507
  },
16480
16508
  help: {
@@ -18866,7 +18894,22 @@ async function isSessionPrincipalAvailable(sessionFile) {
18866
18894
  return false;
18867
18895
  }
18868
18896
  }
18869
- async function acquireRunWriterLease(runDirectory) {
18897
+ function describeErrorIdentity(error) {
18898
+ const candidate = error;
18899
+ const name = typeof candidate?.name === "string" && candidate.name !== "" ? candidate.name : typeof error;
18900
+ const code = typeof candidate?.code === "string" || typeof candidate?.code === "number" ? ` code=${String(candidate.code)}` : "";
18901
+ const message = typeof candidate?.message === "string" && candidate.message !== "" ? `: ${candidate.message}` : "";
18902
+ return `${name}${code}${message}`;
18903
+ }
18904
+ async function acquireRunWriterLease(runDirectory, onCleanupFailure) {
18905
+ const reportCleanupFailure = (error) => {
18906
+ try {
18907
+ onCleanupFailure?.(
18908
+ `writer lease lock cleanup failed (best-effort continue; stale lock resurfaces as lease-held on next acquire) at ${join10(runDirectory, WRITER_LOCK_FILE)}: ${describeErrorIdentity(error)}`
18909
+ );
18910
+ } catch {
18911
+ }
18912
+ };
18870
18913
  const lockPath = join10(runDirectory, WRITER_LOCK_FILE);
18871
18914
  try {
18872
18915
  const handle = await open(lockPath, "wx");
@@ -18892,8 +18935,11 @@ async function acquireRunWriterLease(runDirectory) {
18892
18935
  try {
18893
18936
  await chmod(runDirectory, 493);
18894
18937
  await unlink3(lockPath);
18895
- } catch {
18938
+ } catch (retryError) {
18939
+ reportCleanupFailure(retryError);
18896
18940
  }
18941
+ } else {
18942
+ reportCleanupFailure(error);
18897
18943
  }
18898
18944
  }
18899
18945
  }
@@ -19886,7 +19932,8 @@ var init_navigator_invocation_identity = __esm({
19886
19932
 
19887
19933
  // src/public-cli/settlement.ts
19888
19934
  import { randomUUID } from "node:crypto";
19889
- import { lstat as lstat3, mkdir as mkdir3, open as open2, readFile as readFile9, readdir as readdir3, writeFile as writeFile5 } from "node:fs/promises";
19935
+ import { constants as fsConstants } from "node:fs";
19936
+ import { appendFile, lstat as lstat3, mkdir as mkdir3, open as open2, readFile as readFile9, readdir as readdir3, writeFile as writeFile5 } from "node:fs/promises";
19890
19937
  import { dirname as dirname6, join as join11 } from "node:path";
19891
19938
  function isChildDiagnosticFloodLine(line2) {
19892
19939
  if (/^at\s+/.test(line2)) return true;
@@ -20200,12 +20247,24 @@ async function readBoundAuditorKnownFailure(sessionFile) {
20200
20247
  }
20201
20248
  const parentId = parentEntries.find((entry) => entry.type === "session")?.id;
20202
20249
  if (parentId === void 0) return void 0;
20250
+ const RESUME_ENVELOPE = RESUME_TRANSPORT_ENVELOPE;
20251
+ const isResumeEnvelope = (msg) => {
20252
+ if (!isRecord5(msg) || msg.role !== "user") return false;
20253
+ const text = typeof msg.text === "string" ? msg.text : typeof msg.content === "string" ? msg.content : void 0;
20254
+ if (text === RESUME_ENVELOPE) return true;
20255
+ const content = msg.content;
20256
+ if (Array.isArray(content)) {
20257
+ return content.some((p) => isRecord5(p) && (p.text === RESUME_ENVELOPE || p.content === RESUME_ENVELOPE));
20258
+ }
20259
+ return false;
20260
+ };
20203
20261
  let latestParentUserIndex = -1;
20204
20262
  for (let i = parentEntries.length - 1; i >= 0; i -= 1) {
20205
- if (parentEntries[i]?.type === "message" && parentEntries[i]?.message?.role === "user") {
20206
- latestParentUserIndex = i;
20207
- break;
20208
- }
20263
+ const entry = parentEntries[i];
20264
+ if (entry?.type !== "message" || entry.message?.role !== "user") continue;
20265
+ if (isResumeEnvelope(entry.message)) continue;
20266
+ latestParentUserIndex = i;
20267
+ break;
20209
20268
  }
20210
20269
  const childDirectory = join11(dirname6(sessionFile), "auditor-roles");
20211
20270
  let names;
@@ -20215,6 +20274,7 @@ async function readBoundAuditorKnownFailure(sessionFile) {
20215
20274
  if (isMissingPathError2(error)) return void 0;
20216
20275
  throw sessionReadFailure(error, "failed to read bound auditor session directory");
20217
20276
  }
20277
+ const validAuditorFiles = [];
20218
20278
  for (const file of names.filter((name) => name.endsWith(".jsonl")).sort().reverse()) {
20219
20279
  let entries;
20220
20280
  try {
@@ -20229,6 +20289,9 @@ async function readBoundAuditorKnownFailure(sessionFile) {
20229
20289
  const attemptEntryId = typeof bindingParent?.attemptEntryId === "string" ? bindingParent.attemptEntryId : void 0;
20230
20290
  const attemptEntryIndex = attemptEntryId === void 0 ? -1 : parentEntries.findIndex((entry) => entry.id === attemptEntryId);
20231
20291
  if (bindingParent?.sessionId !== parentId || bindingParent.sessionFile !== sessionFile || attemptEntryIndex < latestParentUserIndex) continue;
20292
+ validAuditorFiles.push({ file, entries, ...attemptEntryId === void 0 ? {} : { attemptEntryId } });
20293
+ }
20294
+ for (const { entries, attemptEntryId } of validAuditorFiles) {
20232
20295
  const stop = extractSessionProviderStop(entries);
20233
20296
  if (stop === void 0) continue;
20234
20297
  for (let i = entries.length - 1; i >= 0; i -= 1) {
@@ -20248,6 +20311,10 @@ async function readBoundAuditorKnownFailure(sessionFile) {
20248
20311
  ...isRecord5(failure.details) ? { details: failure.details } : {}
20249
20312
  };
20250
20313
  }
20314
+ }
20315
+ for (const { entries } of validAuditorFiles) {
20316
+ const stop = extractSessionProviderStop(entries);
20317
+ if (stop === void 0) continue;
20251
20318
  const primary = knownFailureFromProviderStop(stop);
20252
20319
  return {
20253
20320
  ...primary,
@@ -20981,20 +21048,74 @@ async function ensureAuditEvidenceDirectory(runDirectory) {
20981
21048
  }
20982
21049
  return artifactsDir;
20983
21050
  }
21051
+ async function appendRunAttemptHistory(admitted, outcome) {
21052
+ const entries = await readBoundSessionEntries(admitted.sessionFile);
21053
+ let parentId = null;
21054
+ let priorEntries = 0;
21055
+ for (const entry of entries) {
21056
+ if (typeof entry.id === "string" && entry.type !== "session") parentId = entry.id;
21057
+ if (entry.type === "custom" && entry.customType === ATTEMPT_HISTORY_ENTRY_TYPE) {
21058
+ priorEntries += 1;
21059
+ }
21060
+ }
21061
+ const timestamp2 = (/* @__PURE__ */ new Date()).toISOString();
21062
+ const line2 = `${JSON.stringify({
21063
+ type: "custom",
21064
+ customType: ATTEMPT_HISTORY_ENTRY_TYPE,
21065
+ data: {
21066
+ sequence: priorEntries + 1,
21067
+ role: admitted.role,
21068
+ runId: admitted.runId,
21069
+ recordedAt: timestamp2,
21070
+ outcome
21071
+ },
21072
+ id: randomUUID(),
21073
+ parentId,
21074
+ timestamp: timestamp2
21075
+ })}
21076
+ `;
21077
+ await appendFile(admitted.sessionFile, line2, "utf8");
21078
+ }
20984
21079
  async function publishComplianceAuditIncompleteEvidence(admitted, outcome) {
21080
+ await appendRunAttemptHistory(admitted, outcome);
21081
+ if (typeof fsConstants.O_NOFOLLOW !== "number" || typeof fsConstants.O_NONBLOCK !== "number") {
21082
+ throw auditArtifactPublicationError(
21083
+ "audit evidence publication requires O_NOFOLLOW|O_NONBLOCK open-flag support (anti-symlink/anti-planted protection must not be silently dropped); refusing to publish",
21084
+ "ENOSYS"
21085
+ );
21086
+ }
20985
21087
  const artifactsDir = await ensureAuditEvidenceDirectory(admitted.runDirectory);
20986
21088
  const evidencePath = join11(artifactsDir, "audit-incomplete.json");
21089
+ let existing;
20987
21090
  try {
20988
- const existing = await lstat3(evidencePath);
20989
- throw auditArtifactPublicationError(
20990
- existing.isSymbolicLink() ? "audit evidence destination is a symlink" : "audit evidence destination collision",
20991
- existing.isSymbolicLink() ? "ELOOP" : "EEXIST"
20992
- );
21091
+ existing = await lstat3(evidencePath);
20993
21092
  } catch (error) {
20994
21093
  if (!isMissingPathError2(error)) throw error;
20995
21094
  }
20996
- const handle = await open2(evidencePath, "wx", 384);
21095
+ if (existing?.isSymbolicLink()) {
21096
+ throw auditArtifactPublicationError(
21097
+ "audit evidence destination is a symlink",
21098
+ "ELOOP"
21099
+ );
21100
+ }
21101
+ if (existing && !existing.isFile()) {
21102
+ throw auditArtifactPublicationError(
21103
+ "audit evidence destination is not a regular file",
21104
+ "EEXIST"
21105
+ );
21106
+ }
21107
+ const handle = await open2(
21108
+ evidencePath,
21109
+ fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_TRUNC | fsConstants.O_NOFOLLOW | fsConstants.O_NONBLOCK,
21110
+ 384
21111
+ );
20997
21112
  try {
21113
+ if (!(await handle.stat()).isFile()) {
21114
+ throw auditArtifactPublicationError(
21115
+ "audit evidence destination is not a regular file",
21116
+ "EEXIST"
21117
+ );
21118
+ }
20998
21119
  await handle.writeFile(`${JSON.stringify(outcome, null, 2)}
20999
21120
  `, "utf8");
21000
21121
  await handle.sync();
@@ -21247,6 +21368,7 @@ async function extractNavigatorFactFromAdmittedSession(admitted) {
21247
21368
  }
21248
21369
  }
21249
21370
  async function publishJudgeArtifacts(admitted, roleOutcome, sessionDirectory) {
21371
+ await appendRunAttemptHistory(admitted, roleOutcome);
21250
21372
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
21251
21373
  const reportPath = join11(artifactsDir, "report.json");
21252
21374
  const evidencePath = join11(artifactsDir, "evidence.json");
@@ -21291,6 +21413,7 @@ async function publishJudgeArtifacts(admitted, roleOutcome, sessionDirectory) {
21291
21413
  ];
21292
21414
  }
21293
21415
  async function publishCoderArtifacts(admitted, roleOutcome, sessionDirectory, options = {}) {
21416
+ await appendRunAttemptHistory(admitted, roleOutcome);
21294
21417
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
21295
21418
  const reportPath = join11(artifactsDir, "report.json");
21296
21419
  const evidencePath = join11(artifactsDir, "evidence.json");
@@ -21460,6 +21583,7 @@ function extractFixerMethodInvocations(entries, options) {
21460
21583
  return Object.freeze(observed);
21461
21584
  }
21462
21585
  async function publishFixerArtifacts(admitted, roleOutcome, sessionDirectory, options) {
21586
+ await appendRunAttemptHistory(admitted, roleOutcome);
21463
21587
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
21464
21588
  const reportPath = join11(artifactsDir, "report.json");
21465
21589
  const evidencePath = join11(artifactsDir, "evidence.json");
@@ -21571,6 +21695,7 @@ async function settleLawfulFixerTerminalResult(admitted, options) {
21571
21695
  };
21572
21696
  }
21573
21697
  async function publishCollectorArtifacts(admitted, roleOutcome, sessionDirectory, options = {}) {
21698
+ await appendRunAttemptHistory(admitted, roleOutcome);
21574
21699
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
21575
21700
  const reportPath = join11(artifactsDir, "report.json");
21576
21701
  const evidencePath = join11(artifactsDir, "evidence.json");
@@ -21690,6 +21815,7 @@ async function trySettleCollectorTerminalResult(admitted) {
21690
21815
  return settleLawfulCollectorTerminalResult(admitted);
21691
21816
  }
21692
21817
  async function publishDoctorArtifacts(admitted, roleOutcome, sessionDirectory, options = {}) {
21818
+ await appendRunAttemptHistory(admitted, roleOutcome);
21693
21819
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
21694
21820
  const reportPath = join11(artifactsDir, "report.json");
21695
21821
  const evidencePath = join11(artifactsDir, "evidence.json");
@@ -21857,6 +21983,7 @@ function extractReviewerMethodInvocations(entries, options) {
21857
21983
  return Object.freeze(observed);
21858
21984
  }
21859
21985
  async function publishReviewerArtifacts(admitted, roleOutcome, sessionDirectory, options) {
21986
+ await appendRunAttemptHistory(admitted, roleOutcome);
21860
21987
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
21861
21988
  const reportPath = join11(artifactsDir, "report.json");
21862
21989
  const evidencePath = join11(artifactsDir, "evidence.json");
@@ -22025,6 +22152,7 @@ function extractMergerMethodInvocations(entries, options) {
22025
22152
  return Object.freeze(observed);
22026
22153
  }
22027
22154
  async function publishMergerArtifacts(admitted, roleOutcome, sessionDirectory, options) {
22155
+ await appendRunAttemptHistory(admitted, roleOutcome);
22028
22156
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
22029
22157
  const reportPath = join11(artifactsDir, "report.json");
22030
22158
  const evidencePath = join11(artifactsDir, "evidence.json");
@@ -22246,6 +22374,15 @@ async function publishFailureArtifacts(admitted, failure) {
22246
22374
  admitted.runDirectory
22247
22375
  );
22248
22376
  const priorIssues = baseAttempt === void 0 ? [] : [baseAttempt];
22377
+ try {
22378
+ await appendRunAttemptHistory(admitted, {
22379
+ kind: "failure",
22380
+ role: admitted.role,
22381
+ ...failure
22382
+ });
22383
+ } catch (error) {
22384
+ priorIssues.push(publicationAttemptFromError(admitted.sessionFile, error));
22385
+ }
22249
22386
  const underArtifacts = baseDir === join11(admitted.runDirectory, "artifacts");
22250
22387
  const uniqueFallbackDirs = uniqueFailureFallbackDirs(
22251
22388
  admitted.runDirectory,
@@ -22442,7 +22579,7 @@ function presentFailureTerminal(terminal, io) {
22442
22579
  }));
22443
22580
  }
22444
22581
  }
22445
- var CONCISE_DIAGNOSTIC_MAX_CHARS, COLLECTOR_INFRASTRUCTURE_TOOLS, COLLECTOR_INFRASTRUCTURE_FAILURE_SPEC, ENGINE_DETOUR_INFRASTRUCTURE_FAILURE_SPEC;
22582
+ var CONCISE_DIAGNOSTIC_MAX_CHARS, COLLECTOR_INFRASTRUCTURE_TOOLS, COLLECTOR_INFRASTRUCTURE_FAILURE_SPEC, ENGINE_DETOUR_INFRASTRUCTURE_FAILURE_SPEC, ATTEMPT_HISTORY_ENTRY_TYPE;
22446
22583
  var init_settlement = __esm({
22447
22584
  "src/public-cli/settlement.ts"() {
22448
22585
  "use strict";
@@ -22485,18 +22622,31 @@ var init_settlement = __esm({
22485
22622
  cause: "output",
22486
22623
  identityName: "EngineDetourInfrastructureError"
22487
22624
  };
22625
+ ATTEMPT_HISTORY_ENTRY_TYPE = "ak_run_attempt_history";
22488
22626
  }
22489
22627
  });
22490
22628
 
22491
22629
  // src/public-cli/auto-resume.ts
22630
+ function presentTerminal(terminal, io) {
22631
+ if (terminal.roleOutcome.kind === "failure" || terminal.roleOutcome.kind === "no_receipt") {
22632
+ presentFailureTerminal(terminal, io);
22633
+ } else {
22634
+ io.stdout(formatTerminalResult(terminal));
22635
+ }
22636
+ }
22492
22637
  async function runWithAutoResumeLoop(options) {
22638
+ const limit = options.autoResumeLimit ?? AUTO_RESUME_LIMIT;
22639
+ parseAutoResumeLimit(limit);
22493
22640
  let autoResumeAttempts = 0;
22494
22641
  let isFirst = true;
22495
22642
  let currentExtraArgs = options.buildInitialArgs();
22496
22643
  while (true) {
22497
22644
  let lease;
22498
22645
  try {
22499
- lease = await acquireRunWriterLease(options.admitted.runDirectory);
22646
+ lease = await acquireRunWriterLease(
22647
+ options.admitted.runDirectory,
22648
+ (diagnostic) => options.io.stderr(diagnostic)
22649
+ );
22500
22650
  } catch (error) {
22501
22651
  if (error instanceof RunWriterLeaseHeldError) {
22502
22652
  presentStructuralRejection(error, options.io);
@@ -22516,39 +22666,12 @@ async function runWithAutoResumeLoop(options) {
22516
22666
  }
22517
22667
  return result2;
22518
22668
  }
22519
- if (terminal !== void 0 && (terminal.roleOutcome.kind === "incomplete" || terminal.roleOutcome.kind === "audit_incomplete")) {
22520
- if (terminal.roleOutcome.kind === "audit_incomplete") {
22521
- options.io.stdout(formatTerminalResult(terminal));
22522
- } else {
22523
- options.io.stdout(formatTerminalResult(terminal));
22524
- }
22525
- return result2;
22526
- }
22527
- if (terminal !== void 0 && terminal.roleOutcome.kind === "failure") {
22528
- const terminalJson = JSON.stringify(terminal);
22529
- if (terminalJson.includes("retentionFailure") || terminalJson.includes("ComplianceResponseRetentionError")) {
22530
- presentFailureTerminal(terminal, options.io);
22531
- return result2;
22532
- }
22533
- }
22534
- if (autoResumeAttempts >= AUTO_RESUME_LIMIT) {
22535
- if (terminal !== void 0) {
22536
- if (terminal.roleOutcome.kind === "failure" || terminal.roleOutcome.kind === "no_receipt") {
22537
- presentFailureTerminal(terminal, options.io);
22538
- } else {
22539
- options.io.stdout(formatTerminalResult(terminal));
22540
- }
22541
- }
22669
+ if (autoResumeAttempts >= limit) {
22670
+ if (terminal !== void 0) presentTerminal(terminal, options.io);
22542
22671
  return result2;
22543
22672
  }
22544
22673
  if (!await isSessionPrincipalAvailable(options.admitted.sessionFile)) {
22545
- if (terminal !== void 0) {
22546
- if (terminal.roleOutcome.kind === "failure" || terminal.roleOutcome.kind === "no_receipt") {
22547
- presentFailureTerminal(terminal, options.io);
22548
- } else {
22549
- options.io.stdout(formatTerminalResult(terminal));
22550
- }
22551
- }
22674
+ if (terminal !== void 0) presentTerminal(terminal, options.io);
22552
22675
  return result2;
22553
22676
  }
22554
22677
  autoResumeAttempts++;
@@ -22561,6 +22684,7 @@ var init_auto_resume = __esm({
22561
22684
  "src/public-cli/auto-resume.ts"() {
22562
22685
  "use strict";
22563
22686
  init_run_lifecycle();
22687
+ init_config2();
22564
22688
  init_terminal();
22565
22689
  init_settlement();
22566
22690
  dummyIo = { stdout: () => {
@@ -22837,6 +22961,8 @@ async function runPublicCoder(argv, env, io, parseCoderArgv2) {
22837
22961
  return runWithAutoResumeLoop({
22838
22962
  admitted,
22839
22963
  io,
22964
+ // #422: pass-through only; the loop entry resolves the default and validates the domain once.
22965
+ autoResumeLimit: env.autoResumeLimit,
22840
22966
  buildInitialArgs: () => buildCoderActivationExtraArgs(admitted, {
22841
22967
  packageRoot: env.packageRoot,
22842
22968
  ...env.model === void 0 ? {} : { model: env.model },
@@ -22891,7 +23017,7 @@ async function runPublicCoderResume(argv, env, io) {
22891
23017
  const { admitted } = loaded;
22892
23018
  let lease;
22893
23019
  try {
22894
- lease = await acquireRunWriterLease(admitted.runDirectory);
23020
+ lease = await acquireRunWriterLease(admitted.runDirectory, (diagnostic) => io.stderr(diagnostic));
22895
23021
  } catch (error) {
22896
23022
  if (error instanceof RunWriterLeaseHeldError) {
22897
23023
  io.stderr(formatCliDiagnostic(error.message));
@@ -23155,7 +23281,7 @@ async function runPublicCollector(argv, env, io, parseCollectorArgv2) {
23155
23281
  await markRunAdmitted(admitted);
23156
23282
  let lease;
23157
23283
  try {
23158
- lease = await acquireRunWriterLease(admitted.runDirectory);
23284
+ lease = await acquireRunWriterLease(admitted.runDirectory, (diagnostic) => io.stderr(diagnostic));
23159
23285
  } catch (error) {
23160
23286
  if (error instanceof RunWriterLeaseHeldError) {
23161
23287
  presentStructuralRejection(error, io);
@@ -23390,7 +23516,7 @@ async function runPublicDoctor(argv, env, io, parseDoctorArgv2) {
23390
23516
  await markRunAdmitted(admitted);
23391
23517
  let lease;
23392
23518
  try {
23393
- lease = await acquireRunWriterLease(admitted.runDirectory);
23519
+ lease = await acquireRunWriterLease(admitted.runDirectory, (diagnostic) => io.stderr(diagnostic));
23394
23520
  } catch (error) {
23395
23521
  if (error instanceof RunWriterLeaseHeldError) {
23396
23522
  presentStructuralRejection(error, io);
@@ -23721,6 +23847,8 @@ async function runPublicFixer(argv, env, io, parseFixerArgv2) {
23721
23847
  return runWithAutoResumeLoop({
23722
23848
  admitted,
23723
23849
  io,
23850
+ // #422: pass-through only; the loop entry resolves the default and validates the domain once.
23851
+ autoResumeLimit: env.autoResumeLimit,
23724
23852
  buildInitialArgs: () => buildFixerActivationExtraArgs(admitted, {
23725
23853
  packageRoot: env.packageRoot,
23726
23854
  ...env.model === void 0 ? {} : { model: env.model },
@@ -23775,7 +23903,7 @@ async function runPublicFixerResume(argv, env, io) {
23775
23903
  const { admitted } = loaded;
23776
23904
  let lease;
23777
23905
  try {
23778
- lease = await acquireRunWriterLease(admitted.runDirectory);
23906
+ lease = await acquireRunWriterLease(admitted.runDirectory, (diagnostic) => io.stderr(diagnostic));
23779
23907
  } catch (error) {
23780
23908
  if (error instanceof RunWriterLeaseHeldError) {
23781
23909
  io.stderr(formatCliDiagnostic(error.message));
@@ -24085,6 +24213,8 @@ async function runPublicJudge(argv, env, io, parseJudgeArgv2) {
24085
24213
  return runWithAutoResumeLoop({
24086
24214
  admitted,
24087
24215
  io,
24216
+ // #422: pass-through only; the loop entry resolves the default and validates the domain once.
24217
+ autoResumeLimit: env.autoResumeLimit,
24088
24218
  buildInitialArgs: () => buildJudgeActivationExtraArgs(admitted, {
24089
24219
  packageRoot: env.packageRoot,
24090
24220
  ...env.model === void 0 ? {} : { model: env.model },
@@ -24137,7 +24267,7 @@ async function runPublicResume(argv, env, io) {
24137
24267
  const { admitted } = loaded;
24138
24268
  let lease;
24139
24269
  try {
24140
- lease = await acquireRunWriterLease(admitted.runDirectory);
24270
+ lease = await acquireRunWriterLease(admitted.runDirectory, (diagnostic) => io.stderr(diagnostic));
24141
24271
  } catch (error) {
24142
24272
  if (error instanceof RunWriterLeaseHeldError) {
24143
24273
  io.stderr(formatCliDiagnostic(error.message));
@@ -24532,6 +24662,8 @@ async function runPublicMerger(argv, env, io, parseMergerArgv2) {
24532
24662
  return runWithAutoResumeLoop({
24533
24663
  admitted,
24534
24664
  io,
24665
+ // #422: pass-through only; the loop entry resolves the default and validates the domain once.
24666
+ autoResumeLimit: env.autoResumeLimit,
24535
24667
  buildInitialArgs: () => buildMergerActivationExtraArgs(admitted, {
24536
24668
  packageRoot: env.packageRoot,
24537
24669
  ...env.model === void 0 ? {} : { model: env.model },
@@ -24586,7 +24718,7 @@ async function runPublicMergerResume(argv, env, io) {
24586
24718
  const { admitted } = loaded;
24587
24719
  let lease;
24588
24720
  try {
24589
- lease = await acquireRunWriterLease(admitted.runDirectory);
24721
+ lease = await acquireRunWriterLease(admitted.runDirectory, (diagnostic) => io.stderr(diagnostic));
24590
24722
  } catch (error) {
24591
24723
  if (error instanceof RunWriterLeaseHeldError) {
24592
24724
  io.stderr(formatCliDiagnostic(error.message));
@@ -24948,6 +25080,8 @@ async function runPublicReviewer(argv, env, io, parseReviewerArgv2) {
24948
25080
  return runWithAutoResumeLoop({
24949
25081
  admitted,
24950
25082
  io,
25083
+ // #422: pass-through only; the loop entry resolves the default and validates the domain once.
25084
+ autoResumeLimit: env.autoResumeLimit,
24951
25085
  buildInitialArgs: () => buildReviewerActivationExtraArgs(admitted, {
24952
25086
  packageRoot: env.packageRoot,
24953
25087
  ...env.model === void 0 ? {} : { model: env.model },
@@ -25002,7 +25136,7 @@ async function runPublicReviewerResume(argv, env, io) {
25002
25136
  const { admitted } = loaded;
25003
25137
  let lease;
25004
25138
  try {
25005
- lease = await acquireRunWriterLease(admitted.runDirectory);
25139
+ lease = await acquireRunWriterLease(admitted.runDirectory, (diagnostic) => io.stderr(diagnostic));
25006
25140
  } catch (error) {
25007
25141
  if (error instanceof RunWriterLeaseHeldError) {
25008
25142
  io.stderr(formatCliDiagnostic(error.message));
@@ -27501,6 +27635,7 @@ function renderConfig(config) {
27501
27635
  lines.push(`${seat} ${formatModelSpec(selection)} ${engine}`);
27502
27636
  }
27503
27637
  }
27638
+ lines.push(`autoResumeLimit ${config.autoResumeLimit ?? AUTO_RESUME_LIMIT}`);
27504
27639
  return `${lines.join("\n")}
27505
27640
  `;
27506
27641
  }
@@ -27594,6 +27729,30 @@ async function runConfigCommand(args, home, packageRoot2, io) {
27594
27729
  io.stdout(renderConfig(config));
27595
27730
  return 0;
27596
27731
  }
27732
+ if (args[0] === "set-auto-resume-limit") {
27733
+ if (args.length !== 2) {
27734
+ throw new CliUsageError(
27735
+ "usage: ak-role config set-auto-resume-limit <N>"
27736
+ );
27737
+ }
27738
+ const raw = args[1];
27739
+ if (!/^[0-9]+$/.test(raw)) {
27740
+ throw new CliUsageError(
27741
+ `auto-resume limit must be a non-negative integer, got ${raw}`
27742
+ );
27743
+ }
27744
+ const converted = Number(raw);
27745
+ if (!Number.isFinite(converted) || BigInt(converted) !== BigInt(raw)) {
27746
+ throw new CliUsageError(
27747
+ `auto-resume limit ${raw} is not exactly representable as a number; refusing to silently round the value`
27748
+ );
27749
+ }
27750
+ let config = await loadAndValidateConfig(home, packageRoot2);
27751
+ config = setAutoResumeLimit(config, converted);
27752
+ await savePublicCliConfig(config, home);
27753
+ io.stdout(renderConfig(config));
27754
+ return 0;
27755
+ }
27597
27756
  throw new CliUsageError(`unknown config subcommand: ${args[0]}`);
27598
27757
  }
27599
27758
  async function runAkRole(argv, env) {
@@ -27803,7 +27962,9 @@ async function runAkRole(argv, env) {
27803
27962
  ...projectSeatEngine(seat),
27804
27963
  ...env.judgeExtraPiArgs === void 0 ? {} : { extraPiArgs: env.judgeExtraPiArgs },
27805
27964
  ...env.judgeTimeoutMs === void 0 ? {} : { timeoutMs: env.judgeTimeoutMs },
27806
- ...env.createRunId === void 0 ? {} : { createRunId: env.createRunId }
27965
+ ...env.createRunId === void 0 ? {} : { createRunId: env.createRunId },
27966
+ // #422: effective auto-resume ceiling resolved once here; the loop never re-reads disk.
27967
+ ...config.autoResumeLimit === void 0 ? {} : { autoResumeLimit: config.autoResumeLimit }
27807
27968
  },
27808
27969
  io,
27809
27970
  PUBLIC_ROLE_ARGV.judge.parse
@@ -27838,7 +27999,9 @@ async function runAkRole(argv, env) {
27838
27999
  ...projectSeatEngine(seat),
27839
28000
  ...env.coderExtraPiArgs === void 0 ? {} : { extraPiArgs: env.coderExtraPiArgs },
27840
28001
  ...env.coderTimeoutMs === void 0 ? {} : { timeoutMs: env.coderTimeoutMs },
27841
- ...env.createRunId === void 0 ? {} : { createRunId: env.createRunId }
28002
+ ...env.createRunId === void 0 ? {} : { createRunId: env.createRunId },
28003
+ // #422: effective auto-resume ceiling resolved once here; the loop never re-reads disk.
28004
+ ...config.autoResumeLimit === void 0 ? {} : { autoResumeLimit: config.autoResumeLimit }
27842
28005
  },
27843
28006
  io,
27844
28007
  PUBLIC_ROLE_ARGV.coder.parse
@@ -27873,7 +28036,9 @@ async function runAkRole(argv, env) {
27873
28036
  ...projectSeatEngine(seat),
27874
28037
  ...env.fixerExtraPiArgs === void 0 ? {} : { extraPiArgs: env.fixerExtraPiArgs },
27875
28038
  ...env.fixerTimeoutMs === void 0 ? {} : { timeoutMs: env.fixerTimeoutMs },
27876
- ...env.createRunId === void 0 ? {} : { createRunId: env.createRunId }
28039
+ ...env.createRunId === void 0 ? {} : { createRunId: env.createRunId },
28040
+ // #422: effective auto-resume ceiling resolved once here; the loop never re-reads disk.
28041
+ ...config.autoResumeLimit === void 0 ? {} : { autoResumeLimit: config.autoResumeLimit }
27877
28042
  },
27878
28043
  io,
27879
28044
  PUBLIC_ROLE_ARGV.fixer.parse
@@ -27943,7 +28108,9 @@ async function runAkRole(argv, env) {
27943
28108
  ...projectSeatEngine(seat),
27944
28109
  ...env.reviewerExtraPiArgs === void 0 ? {} : { extraPiArgs: env.reviewerExtraPiArgs },
27945
28110
  ...env.reviewerTimeoutMs === void 0 ? {} : { timeoutMs: env.reviewerTimeoutMs },
27946
- ...env.createRunId === void 0 ? {} : { createRunId: env.createRunId }
28111
+ ...env.createRunId === void 0 ? {} : { createRunId: env.createRunId },
28112
+ // #422: effective auto-resume ceiling resolved once here; the loop never re-reads disk.
28113
+ ...config.autoResumeLimit === void 0 ? {} : { autoResumeLimit: config.autoResumeLimit }
27947
28114
  },
27948
28115
  io,
27949
28116
  PUBLIC_ROLE_ARGV.reviewer.parse
@@ -28013,7 +28180,9 @@ async function runAkRole(argv, env) {
28013
28180
  ...projectSeatEngine(seat),
28014
28181
  ...env.mergerExtraPiArgs === void 0 ? {} : { extraPiArgs: env.mergerExtraPiArgs },
28015
28182
  ...env.mergerTimeoutMs === void 0 ? {} : { timeoutMs: env.mergerTimeoutMs },
28016
- ...env.createRunId === void 0 ? {} : { createRunId: env.createRunId }
28183
+ ...env.createRunId === void 0 ? {} : { createRunId: env.createRunId },
28184
+ // #422: effective auto-resume ceiling resolved once here; the loop never re-reads disk.
28185
+ ...config.autoResumeLimit === void 0 ? {} : { autoResumeLimit: config.autoResumeLimit }
28017
28186
  },
28018
28187
  io,
28019
28188
  PUBLIC_ROLE_ARGV.merger.parse
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akagilnc/pi-workflow-roles",
3
- "version": "0.1.2157",
3
+ "version": "0.1.2173",
4
4
  "description": "Soul-bound workflow roles for Pi",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",