@akagilnc/pi-workflow-roles 0.1.2521 → 0.1.2535

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.
@@ -14416,6 +14416,15 @@ var init_notary_contracts = __esm({
14416
14416
  }
14417
14417
  });
14418
14418
 
14419
+ // src/inspector-contracts.ts
14420
+ var INSPECTOR_OUTPUT_TOOL_NAME;
14421
+ var init_inspector_contracts = __esm({
14422
+ "src/inspector-contracts.ts"() {
14423
+ "use strict";
14424
+ INSPECTOR_OUTPUT_TOOL_NAME = "ak_inspector_output";
14425
+ }
14426
+ });
14427
+
14419
14428
  // src/packaged-role-registry.ts
14420
14429
  var PACKAGED_ROLE_REGISTRY;
14421
14430
  var init_packaged_role_registry = __esm({
@@ -14428,6 +14437,7 @@ var init_packaged_role_registry = __esm({
14428
14437
  init_doctor_contracts();
14429
14438
  init_merger_contracts();
14430
14439
  init_notary_contracts();
14440
+ init_inspector_contracts();
14431
14441
  PACKAGED_ROLE_REGISTRY = [
14432
14442
  { role: "judge", phases: [null], outputTool: JUDGE_OUTPUT_TOOL_NAME, inputFlag: void 0, phaseFlag: void 0, activationStage: "load-and-install" },
14433
14443
  { role: "fixer", phases: ["plan", "apply"], outputTool: FIXER_OUTPUT_TOOL_NAME, inputFlag: "ak-fix-packet", phaseFlag: "ak-fixer-phase", activationStage: "load-and-install" },
@@ -14437,7 +14447,8 @@ var init_packaged_role_registry = __esm({
14437
14447
  { role: "collector", phases: [null], outputTool: COLLECTOR_OUTPUT_TOOL, inputFlag: void 0, phaseFlag: void 0, activationStage: "load-and-install" },
14438
14448
  { role: "doctor", phases: [null], outputTool: DOCTOR_OUTPUT_TOOL_NAME, inputFlag: "ak-doctor-case", phaseFlag: void 0, activationStage: "load-and-install" },
14439
14449
  { role: "merger", phases: [null], outputTool: MERGER_OUTPUT_TOOL_NAME, inputFlag: "ak-merger-input", phaseFlag: void 0, activationStage: "prepare-git-and-install" },
14440
- { role: "notary", phases: [null], outputTool: NOTARY_OUTPUT_TOOL_NAME, inputFlag: "ak-notary-source-run", phaseFlag: void 0, activationStage: "load-and-install" }
14450
+ { role: "notary", phases: [null], outputTool: NOTARY_OUTPUT_TOOL_NAME, inputFlag: "ak-notary-source-run", phaseFlag: void 0, activationStage: "load-and-install" },
14451
+ { role: "inspector", phases: [null], outputTool: INSPECTOR_OUTPUT_TOOL_NAME, inputFlag: void 0, phaseFlag: void 0, activationStage: "load-and-install" }
14441
14452
  ];
14442
14453
  }
14443
14454
  });
@@ -14481,7 +14492,7 @@ function isPublicConfigurableSeat(value) {
14481
14492
  function isPublicCliSupportCommand(value) {
14482
14493
  return PUBLIC_CLI_SUPPORT_COMMANDS.includes(value);
14483
14494
  }
14484
- var INTERNAL_ROLE_ENTRYPOINT_RELATIVE, PUBLIC_CALLABLE_ROLES, AUTOMATIC_NAVIGATOR_SEAT, AUTOMATIC_GATEKEEPER_SEAT, AUTOMATIC_INSPECTOR_SEAT, AUTOMATIC_CONFIGURABLE_SEATS, PUBLIC_CONFIGURABLE_SEATS, PUBLIC_CLI_SUPPORT_COMMANDS, STARTUP_CANDIDATES, PUBLIC_DETERMINISTIC_COMMANDS;
14495
+ var INTERNAL_ROLE_ENTRYPOINT_RELATIVE, PUBLIC_CALLABLE_ROLES, AUTOMATIC_NAVIGATOR_SEAT, AUTOMATIC_GATEKEEPER_SEAT, AUTOMATIC_CONFIGURABLE_SEATS, PUBLIC_CONFIGURABLE_SEATS, PUBLIC_CLI_SUPPORT_COMMANDS, STARTUP_CANDIDATES, PUBLIC_DETERMINISTIC_COMMANDS;
14485
14496
  var init_registry2 = __esm({
14486
14497
  "src/public-cli/registry.ts"() {
14487
14498
  "use strict";
@@ -14492,10 +14503,8 @@ var init_registry2 = __esm({
14492
14503
  );
14493
14504
  AUTOMATIC_NAVIGATOR_SEAT = "navigator";
14494
14505
  AUTOMATIC_GATEKEEPER_SEAT = "gatekeeper";
14495
- AUTOMATIC_INSPECTOR_SEAT = "inspector";
14496
14506
  AUTOMATIC_CONFIGURABLE_SEATS = [
14497
14507
  AUTOMATIC_GATEKEEPER_SEAT,
14498
- AUTOMATIC_INSPECTOR_SEAT,
14499
14508
  AUTOMATIC_NAVIGATOR_SEAT
14500
14509
  ];
14501
14510
  PUBLIC_CONFIGURABLE_SEATS = [
@@ -14601,12 +14610,12 @@ function setPersistentSeatConfig(config, seat, selection) {
14601
14610
  function clearPersistentSeatConfig(config, seat) {
14602
14611
  const previous = config.seats[seat];
14603
14612
  if (previous === void 0) return config;
14604
- if (seat === "notary" && previous.engine !== void 0) {
14613
+ if ((seat === "notary" || seat === "inspector") && previous.engine !== void 0) {
14605
14614
  return {
14606
14615
  ...config,
14607
14616
  seats: {
14608
14617
  ...config.seats,
14609
- notary: { engine: previous.engine }
14618
+ [seat]: { engine: previous.engine }
14610
14619
  }
14611
14620
  };
14612
14621
  }
@@ -14767,7 +14776,7 @@ function parseSeatModelConfig(value, seat) {
14767
14776
  throw new Error(`config seat ${seat} engine must be a string`);
14768
14777
  }
14769
14778
  if (!hasProvider) {
14770
- if (seat === "notary" && typeof raw.engine === "string") {
14779
+ if ((seat === "notary" || seat === "inspector") && typeof raw.engine === "string") {
14771
14780
  if (raw.thinking !== void 0) {
14772
14781
  throw new Error(`config seat ${seat} thinking requires provider/model`);
14773
14782
  }
@@ -15413,7 +15422,8 @@ function validateAcceptedDetails(toolName, details) {
15413
15422
  [COLLECTOR_OUTPUT_TOOL]: [],
15414
15423
  [DOCTOR_OUTPUT_TOOL_NAME]: ["completed", "refused"],
15415
15424
  [MERGER_OUTPUT_TOOL_NAME]: ["completed", "escalate"],
15416
- [NOTARY_OUTPUT_TOOL_NAME]: ["pass", "bounce"]
15425
+ [NOTARY_OUTPUT_TOOL_NAME]: ["pass", "bounce"],
15426
+ [INSPECTOR_OUTPUT_TOOL_NAME]: ["pass", "bounce"]
15417
15427
  };
15418
15428
  const collectorDiscriminator = toolName === COLLECTOR_OUTPUT_TOOL && Array.isArray(candidate?.groups);
15419
15429
  const baseDiscriminator = discriminator;
@@ -15439,6 +15449,8 @@ function validateAcceptedDetails(toolName, details) {
15439
15449
  return validateMergerOutput(details);
15440
15450
  case NOTARY_OUTPUT_TOOL_NAME:
15441
15451
  return validateRecordedNotaryOutput(details);
15452
+ case INSPECTOR_OUTPUT_TOOL_NAME:
15453
+ return candidate;
15442
15454
  }
15443
15455
  } catch (error) {
15444
15456
  if (error instanceof Error && error.constructor === Error) throw new AcceptedDetailsContractError(error.message, { cause: error });
@@ -15452,6 +15464,7 @@ function acceptedFacts(toolName, details) {
15452
15464
  case REVIEWER_OUTPUT_TOOL_NAME:
15453
15465
  case DOCTOR_OUTPUT_TOOL_NAME:
15454
15466
  case NOTARY_OUTPUT_TOOL_NAME:
15467
+ case INSPECTOR_OUTPUT_TOOL_NAME:
15455
15468
  return { status: details.status };
15456
15469
  case JUDGE_OUTPUT_TOOL_NAME:
15457
15470
  return { status: details.judgeStatus };
@@ -15472,6 +15485,7 @@ var init_terminating_tools = __esm({
15472
15485
  init_judge_output();
15473
15486
  init_reviewer_output();
15474
15487
  init_audit_escalation();
15488
+ init_inspector_contracts();
15475
15489
  init_doctor_contracts();
15476
15490
  init_merger_contracts();
15477
15491
  init_notary_contracts();
@@ -15484,7 +15498,8 @@ var init_terminating_tools = __esm({
15484
15498
  COLLECTOR_OUTPUT_TOOL,
15485
15499
  DOCTOR_OUTPUT_TOOL_NAME,
15486
15500
  MERGER_OUTPUT_TOOL_NAME,
15487
- NOTARY_OUTPUT_TOOL_NAME
15501
+ NOTARY_OUTPUT_TOOL_NAME,
15502
+ INSPECTOR_OUTPUT_TOOL_NAME
15488
15503
  ];
15489
15504
  AcceptedDetailsContractError = class extends Error {
15490
15505
  constructor(message, options) {
@@ -15914,7 +15929,7 @@ async function readRoleRunState(runDirectory) {
15914
15929
  if (typeof record4.runId !== "string" || record4.runId.trim() === "") {
15915
15930
  return void 0;
15916
15931
  }
15917
- if (record4.role !== "judge" && record4.role !== "coder" && record4.role !== "fixer" && record4.role !== "collector" && record4.role !== "doctor" && record4.role !== "reviewer" && record4.role !== "merger" && record4.role !== "notary") {
15932
+ if (record4.role !== "judge" && record4.role !== "coder" && record4.role !== "fixer" && record4.role !== "collector" && record4.role !== "doctor" && record4.role !== "reviewer" && record4.role !== "merger" && record4.role !== "notary" && record4.role !== "inspector") {
15918
15933
  return void 0;
15919
15934
  }
15920
15935
  if (record4.state !== "admitted" && record4.state !== "running" && record4.state !== "resumable" && record4.state !== "terminal") {
@@ -16111,14 +16126,19 @@ async function createWriterLease(lockPath, runDirectory, reportCleanupFailure) {
16111
16126
  };
16112
16127
  }
16113
16128
  async function acquireRunWriterLease(runDirectory, onCleanupFailure) {
16114
- const reportCleanupFailure = (error) => {
16129
+ const reportDiagnostic = (diagnostic) => {
16130
+ const line2 = diagnostic.endsWith("\n") ? diagnostic : `${diagnostic}
16131
+ `;
16115
16132
  try {
16116
- onCleanupFailure?.(
16117
- `writer lease lock cleanup failed (best-effort continue; stale lock is reclaimed by the next acquire's holder autopsy) at ${join7(runDirectory, WRITER_LOCK_FILE)}: ${describeErrorIdentity(error)}`
16118
- );
16133
+ onCleanupFailure?.(line2);
16119
16134
  } catch {
16120
16135
  }
16121
16136
  };
16137
+ const reportCleanupFailure = (error) => {
16138
+ reportDiagnostic(
16139
+ `writer lease lock cleanup failed (best-effort continue; stale lock is reclaimed by the next acquire's holder autopsy) at ${join7(runDirectory, WRITER_LOCK_FILE)}: ${describeErrorIdentity(error)}`
16140
+ );
16141
+ };
16122
16142
  const lockPath = join7(runDirectory, WRITER_LOCK_FILE);
16123
16143
  let lastAutopsy = { verdict: "absent" };
16124
16144
  for (let reclaimsLeft = WRITER_LEASE_RECLAIM_ROUNDS; ; reclaimsLeft -= 1) {
@@ -16149,6 +16169,9 @@ async function acquireRunWriterLease(runDirectory, onCleanupFailure) {
16149
16169
  `stale writer lease reclaim failed at ${lockPath} (autopsy: ${describeAutopsy(lastAutopsy)}): ${describeErrorIdentity(reclaimError)}`
16150
16170
  );
16151
16171
  }
16172
+ reportDiagnostic(
16173
+ `stale writer lease reclaimed at ${lockPath} (holder pid ${lastAutopsy.pid} verified dead): the killed holder may have left an orphaned pi child still writing this run \u2014 check for a surviving pi process on this run before continuing`
16174
+ );
16152
16175
  }
16153
16176
  throw new RunWriterLeaseHeldError(
16154
16177
  `role run writer lease stayed contested at ${lockPath} after ${WRITER_LEASE_RECLAIM_ROUNDS} reclaims (last autopsy: ${describeAutopsy(lastAutopsy)})`
@@ -16929,7 +16952,7 @@ function renderHumanOwnerOptionLines(owner, locale2 = "en") {
16929
16952
  }
16930
16953
  return lines;
16931
16954
  }
16932
- var ANALYST_REQUIRE_ANY_OF, ANALYST_DEFAULT_MODE, REJECTED_PUBLIC_SPELLINGS, GLOBAL_OPTIONS, SHARED_PROJECT_SEMANTICS, SHARED_ATTACH_SEMANTICS, JUDGE_OPTIONS, CODER_OPTIONS, FIXER_OPTIONS, REVIEWER_OPTIONS, COLLECTOR_OPTIONS, DOCTOR_OPTIONS, NOTARY_OPTIONS, MERGER_OPTIONS, ANALYST_OPTIONS, PUBLIC_OPTION_TABLE, PUBLIC_NAVIGATOR_HELP_NOTE, TOP_LEVEL_HELP, ROLE_COMMAND_HELP, SUPPORT_COMMAND_HELP, PUBLIC_COMMAND_HELP;
16955
+ var ANALYST_REQUIRE_ANY_OF, ANALYST_DEFAULT_MODE, REJECTED_PUBLIC_SPELLINGS, GLOBAL_OPTIONS, SHARED_PROJECT_SEMANTICS, SHARED_ATTACH_SEMANTICS, JUDGE_OPTIONS, INSPECTOR_OPTIONS, CODER_OPTIONS, FIXER_OPTIONS, REVIEWER_OPTIONS, COLLECTOR_OPTIONS, DOCTOR_OPTIONS, NOTARY_OPTIONS, MERGER_OPTIONS, ANALYST_OPTIONS, PUBLIC_OPTION_TABLE, PUBLIC_NAVIGATOR_HELP_NOTE, TOP_LEVEL_HELP, ROLE_COMMAND_HELP, SUPPORT_COMMAND_HELP, PUBLIC_COMMAND_HELP;
16933
16956
  var init_option_definitions = __esm({
16934
16957
  "src/public-cli/option-definitions.ts"() {
16935
16958
  "use strict";
@@ -17058,6 +17081,10 @@ var init_option_definitions = __esm({
17058
17081
  bindOwner("judge", SHARED_PROJECT_SEMANTICS),
17059
17082
  bindOwner("judge", SHARED_ATTACH_SEMANTICS)
17060
17083
  ];
17084
+ INSPECTOR_OPTIONS = [
17085
+ bindOwner("inspector", SHARED_PROJECT_SEMANTICS),
17086
+ bindOwner("inspector", SHARED_ATTACH_SEMANTICS)
17087
+ ];
17061
17088
  CODER_OPTIONS = [
17062
17089
  {
17063
17090
  id: "phase",
@@ -17398,6 +17425,7 @@ var init_option_definitions = __esm({
17398
17425
  doctor: DOCTOR_OPTIONS,
17399
17426
  merger: MERGER_OPTIONS,
17400
17427
  notary: NOTARY_OPTIONS,
17428
+ inspector: INSPECTOR_OPTIONS,
17401
17429
  analyst: ANALYST_OPTIONS
17402
17430
  };
17403
17431
  PUBLIC_NAVIGATOR_HELP_NOTE = "Navigator attends automatically on every run; configure with `ak-role config set navigator <provider/model[:thinking]>` (not a caller command).";
@@ -17482,6 +17510,12 @@ var init_option_definitions = __esm({
17482
17510
  "ak-role notary --source-run 01a034f1-75bf-71a6-bcf5-d1299145b1a5@judge"
17483
17511
  ]
17484
17512
  },
17513
+ inspector: {
17514
+ command: "inspector",
17515
+ summary: "Direct complexity and test-quality inspection.",
17516
+ usage: ["ak-role inspector [options] [instruction]"],
17517
+ examples: ['ak-role inspector --attach ./change.patch "Review this material."']
17518
+ },
17485
17519
  analyst: {
17486
17520
  command: "analyst",
17487
17521
  summary: "Deterministic analysis seat (issue / sweep / cohort).",
@@ -17681,13 +17715,12 @@ function requireAuthorityRef(value) {
17681
17715
  }
17682
17716
  return value;
17683
17717
  }
17684
- function parseJudgeArgv(args) {
17718
+ function parseStandardMaterialArgv(owner, args) {
17685
17719
  const attachmentPaths = [];
17686
17720
  let project;
17687
17721
  const positional = [];
17688
17722
  const tokens = [...args];
17689
- const definitions = roleOptions("judge");
17690
- const options = createTypedOptionConsumer(definitions);
17723
+ const options = createTypedOptionConsumer(roleOptions(owner));
17691
17724
  while (tokens.length > 0) {
17692
17725
  if (tokens[0] === "--") {
17693
17726
  tokens.shift();
@@ -17696,33 +17729,26 @@ function parseJudgeArgv(args) {
17696
17729
  }
17697
17730
  const taken = options.takeDashed(tokens);
17698
17731
  if (taken !== void 0) {
17699
- if (taken.def.id === "attach") {
17700
- attachmentPaths.push(requireOptionPath(taken.def.canonical, taken.value));
17701
- continue;
17702
- }
17703
- if (taken.def.id === "project") {
17704
- project = requireOptionPath(taken.def.canonical, taken.value);
17705
- continue;
17706
- }
17707
- throw new CliUsageError(`unknown judge option: ${taken.def.canonical}`);
17732
+ if (taken.def.id === "attach") attachmentPaths.push(requireOptionPath(taken.def.canonical, taken.value));
17733
+ else if (taken.def.id === "project") project = requireOptionPath(taken.def.canonical, taken.value);
17734
+ else throw new CliUsageError(`unknown ${owner} option: ${taken.def.canonical}`);
17735
+ continue;
17708
17736
  }
17709
17737
  const token = tokens.shift();
17710
- if (isRejectedPublicSpelling("judge", token)) {
17711
- throw new CliUsageError(
17712
- "judge does not accept a public burden selector; Judge infers its own burden"
17713
- );
17714
- }
17715
- if (token.startsWith("-") && token !== "-") {
17716
- throw new CliUsageError(`unknown judge option: ${token}`);
17738
+ if (owner === "judge" && isRejectedPublicSpelling("judge", token)) {
17739
+ throw new CliUsageError("judge does not accept a public burden selector; Judge infers its own burden");
17717
17740
  }
17741
+ if (token.startsWith("-") && token !== "-") throw new CliUsageError(`unknown ${owner} option: ${token}`);
17718
17742
  positional.push(token);
17719
17743
  }
17720
17744
  options.assertRequired();
17721
- return {
17722
- instruction: positional.join(" "),
17723
- attachmentPaths,
17724
- ...project === void 0 ? {} : { project }
17725
- };
17745
+ return { instruction: positional.join(" "), attachmentPaths, ...project === void 0 ? {} : { project } };
17746
+ }
17747
+ function parseJudgeArgv(args) {
17748
+ return parseStandardMaterialArgv("judge", args);
17749
+ }
17750
+ function parseInspectorArgv(args) {
17751
+ return parseStandardMaterialArgv("inspector", args);
17726
17752
  }
17727
17753
  function parseCoderArgv(args) {
17728
17754
  const attachmentPaths = [];
@@ -17862,25 +17888,19 @@ async function freezeAttachmentsWithTicketNumber(attachmentPaths, attachmentsDir
17862
17888
  function ticketAdmissionFields(ticketNumber) {
17863
17889
  return ticketNumber === void 0 ? {} : { ticketNumber };
17864
17890
  }
17865
- async function admitJudgeInvocation(options) {
17866
- if (options.project !== void 0) {
17867
- requireOptionPath("--project", options.project);
17868
- }
17891
+ async function admitStandardMaterialInvocation(role, options) {
17892
+ if (options.project !== void 0) requireOptionPath("--project", options.project);
17869
17893
  const projectRoot = resolve5(options.project ?? options.cwd);
17870
17894
  const runId = (options.createRunId ?? uuidv7)();
17871
- const { ledgerHome, bookKey, runDirectory, sessionDirectory, sessionFile } = roleRunSessionCoordinates({ cwd: projectRoot, runId, role: "judge", home: options.home });
17895
+ const { ledgerHome, bookKey, runDirectory, sessionDirectory, sessionFile } = roleRunSessionCoordinates({ cwd: projectRoot, runId, role, home: options.home });
17872
17896
  const attachmentsDirectory = join9(runDirectory, "attachments");
17873
17897
  ensureRealDirectoryTree(ledgerHome, sessionDirectory);
17874
17898
  ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
17875
- const { attachments, ticketNumber } = await freezeAttachmentsWithTicketNumber(
17876
- options.attachmentPaths,
17877
- attachmentsDirectory
17878
- );
17899
+ const { attachments, ticketNumber } = await freezeAttachmentsWithTicketNumber(options.attachmentPaths, attachmentsDirectory);
17879
17900
  const ticketFields = ticketAdmissionFields(ticketNumber);
17880
17901
  const instruction = options.instruction;
17881
- const instructionEmpty = instruction.trim() === "";
17882
17902
  const admitted = {
17883
- role: "judge",
17903
+ role,
17884
17904
  runId,
17885
17905
  bookKey,
17886
17906
  projectRoot,
@@ -17889,45 +17909,34 @@ async function admitJudgeInvocation(options) {
17889
17909
  sessionFile,
17890
17910
  ...ticketFields,
17891
17911
  instruction,
17892
- instructionEmpty,
17893
- attachments: attachments.map((a) => ({
17894
- provenancePath: a.provenancePath,
17895
- frozenPath: a.frozenPath,
17896
- byteLength: a.byteLength,
17897
- sha256: a.sha256,
17898
- mediaKind: a.mediaKind
17899
- }))
17912
+ instructionEmpty: instruction.trim() === "",
17913
+ attachments: attachments.map((attachment) => ({ ...attachment }))
17900
17914
  };
17901
17915
  const admittedRequestPath = join9(runDirectory, "admitted-request.json");
17902
17916
  await writeFile4(admittedRequestPath, `${JSON.stringify(admitted, null, 2)}
17903
17917
  `, "utf8");
17904
- await writeRoleInvocationLedger(admitted, admitted.role, options.model);
17905
- return {
17906
- role: "judge",
17907
- runId,
17908
- bookKey,
17909
- projectRoot,
17910
- instruction,
17911
- instructionEmpty,
17912
- attachments,
17913
- runDirectory,
17914
- sessionDirectory,
17915
- sessionFile,
17916
- admittedRequestPath,
17917
- ...ticketFields
17918
- };
17918
+ await writeRoleInvocationLedger(admitted, role, options.model);
17919
+ return { ...admitted, attachments, admittedRequestPath };
17919
17920
  }
17920
- function buildJudgeTransportPrompt(admitted, engineMaterial) {
17921
+ async function admitJudgeInvocation(options) {
17922
+ return admitStandardMaterialInvocation("judge", options);
17923
+ }
17924
+ async function admitInspectorInvocation(options) {
17925
+ return admitStandardMaterialInvocation("inspector", options);
17926
+ }
17927
+ function buildStandardMaterialTransportPrompt(admitted, engineMaterial) {
17921
17928
  const lines = [admitted.instructionEmpty ? "" : admitted.instruction];
17922
17929
  if (admitted.attachments.length > 0) {
17923
- lines.push("");
17924
- lines.push("\u5DF2\u53D7\u7406\u9644\u4EF6\uFF08\u51BB\u7ED3\u5FEB\u7167\u8DEF\u5F84\uFF09\uFF1A");
17925
- for (const attachment of admitted.attachments) {
17926
- lines.push(`- ${attachment.frozenPath}`);
17927
- }
17930
+ lines.push("", "\u5DF2\u53D7\u7406\u9644\u4EF6\uFF08\u51BB\u7ED3\u5FEB\u7167\u8DEF\u5F84\uFF09\uFF1A", ...admitted.attachments.map((attachment) => `- ${attachment.frozenPath}`));
17928
17931
  }
17929
17932
  return appendEngineSessionMaterial(lines, engineMaterial).join("\n");
17930
17933
  }
17934
+ function buildInspectorTransportPrompt(admitted, engineMaterial) {
17935
+ return buildStandardMaterialTransportPrompt(admitted, engineMaterial);
17936
+ }
17937
+ function buildJudgeTransportPrompt(admitted, engineMaterial) {
17938
+ return buildStandardMaterialTransportPrompt(admitted, engineMaterial);
17939
+ }
17931
17940
  async function ensureRunArtifactsDir(runDirectory) {
17932
17941
  const dir = join9(runDirectory, "artifacts");
17933
17942
  await mkdir2(dir, { recursive: true });
@@ -22657,6 +22666,60 @@ async function settleLawfulDoctorTerminalResult(admitted) {
22657
22666
  async function trySettleDoctorTerminalResult(admitted) {
22658
22667
  return settleLawfulDoctorTerminalResult(admitted);
22659
22668
  }
22669
+ function extractInspectorRoleOutcome(entries) {
22670
+ if (!isReceiptSettlementBindingClear(entries)) return void 0;
22671
+ for (let index = entries.length - 1; index >= 0; index -= 1) {
22672
+ const message = entries[index]?.message;
22673
+ if (message?.role !== "toolResult" || message.toolName !== INSPECTOR_OUTPUT_TOOL_NAME) continue;
22674
+ if (!isAcceptedPackagedRoleTerminalResult(message)) continue;
22675
+ const details = message.details;
22676
+ if (typeof details !== "object" || details === null) continue;
22677
+ const status = Reflect.get(details, "status");
22678
+ if (status !== "pass" && status !== "bounce") continue;
22679
+ const findings = Reflect.get(details, "findings");
22680
+ return { kind: "accepted", role: "inspector", status, decisiveFacts: { findings } };
22681
+ }
22682
+ return void 0;
22683
+ }
22684
+ function findUnusableOutputReceipt(entries, toolName, isUsable, diagnostic) {
22685
+ let acceptedNonUsable;
22686
+ for (let index = entries.length - 1; index >= 0; index -= 1) {
22687
+ const message = entries[index]?.message;
22688
+ if (message?.role !== "toolResult") continue;
22689
+ const residual = boundErroredToolCandidate(entries, index, message, toolName);
22690
+ if (residual !== void 0) {
22691
+ return { candidate: residual.candidate, diagnostic: residual.diagnostic };
22692
+ }
22693
+ if (acceptedNonUsable === void 0 && message.toolName === toolName && isAcceptedPackagedRoleTerminalResult(message) && !isUsable(message.details)) {
22694
+ acceptedNonUsable = message.details;
22695
+ }
22696
+ }
22697
+ return acceptedNonUsable === void 0 ? void 0 : { candidate: acceptedNonUsable, diagnostic };
22698
+ }
22699
+ async function trySettleInspectorTerminalResult(admitted) {
22700
+ const entries = await readLawfulSettlementEntries(admitted);
22701
+ if (entries === void 0) return void 0;
22702
+ const outcome = extractInspectorRoleOutcome(entries);
22703
+ if (outcome !== void 0) {
22704
+ return withOptionalGateProjection({
22705
+ roleOutcome: outcome,
22706
+ navigator: extractNavigatorFact(entries),
22707
+ artifacts: [],
22708
+ runId: admitted.runId
22709
+ }, admitted.sessionDirectory);
22710
+ }
22711
+ const unusable = findUnusableOutputReceipt(
22712
+ entries,
22713
+ INSPECTOR_OUTPUT_TOOL_NAME,
22714
+ (candidate) => isRecord8(candidate) && (candidate.status === "pass" || candidate.status === "bounce"),
22715
+ "\u7ED9\u4E8B\u4E2D\u56DE\u6267\u65E0\u663E\u5F0F pass/bounce"
22716
+ );
22717
+ return unusable === void 0 ? void 0 : settleFailureTerminalResult(admitted, {
22718
+ cause: "output",
22719
+ diagnostic: unusable.diagnostic,
22720
+ details: { candidate: unusable.candidate, acceptedReceipt: false }
22721
+ });
22722
+ }
22660
22723
  function extractNotaryRoleOutcome(entries) {
22661
22724
  if (!isReceiptSettlementBindingClear(entries)) return void 0;
22662
22725
  for (let i = entries.length - 1; i >= 0; i -= 1) {
@@ -22686,39 +22749,24 @@ async function settleLawfulNotaryTerminalResult(admitted) {
22686
22749
  if (entries === void 0) return void 0;
22687
22750
  const extracted = extractNotaryRoleOutcome(entries);
22688
22751
  if (extracted === void 0) {
22689
- let acceptedNonUsable;
22690
- for (let index = entries.length - 1; index >= 0; index -= 1) {
22691
- const message = entries[index]?.message;
22692
- if (message?.role !== "toolResult") continue;
22693
- const residual = boundErroredToolCandidate(
22694
- entries,
22695
- index,
22696
- message,
22697
- NOTARY_OUTPUT_TOOL_NAME
22698
- );
22699
- if (residual !== void 0) {
22700
- return settleFailureTerminalResult(admitted, {
22701
- cause: "output",
22702
- diagnostic: residual.diagnostic,
22703
- details: { candidate: residual.candidate, acceptedReceipt: false }
22704
- });
22705
- }
22706
- if (acceptedNonUsable === void 0 && message.toolName === NOTARY_OUTPUT_TOOL_NAME && isAcceptedPackagedRoleTerminalResult(message)) {
22752
+ const unusable = findUnusableOutputReceipt(
22753
+ entries,
22754
+ NOTARY_OUTPUT_TOOL_NAME,
22755
+ (candidate) => {
22707
22756
  try {
22708
- validateRecordedNotaryOutput(message.details);
22757
+ validateRecordedNotaryOutput(candidate);
22758
+ return true;
22709
22759
  } catch {
22710
- acceptedNonUsable = message.details;
22760
+ return false;
22711
22761
  }
22712
- }
22713
- }
22714
- if (acceptedNonUsable !== void 0) {
22715
- return settleFailureTerminalResult(admitted, {
22716
- cause: "output",
22717
- diagnostic: "\u7B26\u5B9D\u90CE\u56DE\u6267\u65E0\u663E\u5F0F pass/bounce",
22718
- details: { candidate: acceptedNonUsable, acceptedReceipt: false }
22719
- });
22720
- }
22721
- return void 0;
22762
+ },
22763
+ "\u7B26\u5B9D\u90CE\u56DE\u6267\u65E0\u663E\u5F0F pass/bounce"
22764
+ );
22765
+ return unusable === void 0 ? void 0 : settleFailureTerminalResult(admitted, {
22766
+ cause: "output",
22767
+ diagnostic: unusable.diagnostic,
22768
+ details: { candidate: unusable.candidate, acceptedReceipt: false }
22769
+ });
22722
22770
  }
22723
22771
  const navigator = extractNavigatorFact(entries);
22724
22772
  return withOptionalGateProjection(
@@ -23397,6 +23445,7 @@ var init_settlement = __esm({
23397
23445
  init_method_skill();
23398
23446
  init_navigator_invocation_identity();
23399
23447
  init_receipt_delivery_policy();
23448
+ init_inspector_contracts();
23400
23449
  init_invocation();
23401
23450
  init_terminal();
23402
23451
  CONCISE_DIAGNOSTIC_MAX_CHARS = 480;
@@ -25082,6 +25131,73 @@ var init_notary_run = __esm({
25082
25131
  }
25083
25132
  });
25084
25133
 
25134
+ // src/public-cli/inspector-run.ts
25135
+ function buildInspectorActivationExtraArgs(admitted, options = {}) {
25136
+ return [
25137
+ "--no-skills",
25138
+ "--no-prompt-templates",
25139
+ "--no-themes",
25140
+ "--no-context-files",
25141
+ "--session",
25142
+ admitted.sessionFile,
25143
+ "--session-dir",
25144
+ admitted.sessionDirectory,
25145
+ ...options.extraPiArgs ?? [],
25146
+ "--ak-role",
25147
+ "inspector",
25148
+ "--mode",
25149
+ "json",
25150
+ ...buildSeatModelCliArgs(options.model),
25151
+ buildInspectorTransportPrompt(admitted, engineSessionMaterialFromOptions(options))
25152
+ ];
25153
+ }
25154
+ async function runPublicInspector(argv, env, io, parse) {
25155
+ let admitted;
25156
+ try {
25157
+ const parsed = parse(argv);
25158
+ admitted = await admitInspectorInvocation({
25159
+ home: env.home,
25160
+ cwd: env.cwd,
25161
+ instruction: parsed.instruction,
25162
+ attachmentPaths: parsed.attachmentPaths,
25163
+ ...parsed.project === void 0 ? {} : { project: parsed.project },
25164
+ ...env.createRunId === void 0 ? {} : { createRunId: env.createRunId },
25165
+ ...env.model === void 0 ? {} : { model: env.model }
25166
+ });
25167
+ } catch (error) {
25168
+ if (error instanceof CliUsageError) {
25169
+ presentStructuralRejection(error, io);
25170
+ return { exitCode: 2 };
25171
+ }
25172
+ throw error;
25173
+ }
25174
+ const extraArgs = buildInspectorActivationExtraArgs(admitted, {
25175
+ packageRoot: env.packageRoot,
25176
+ ...env.model === void 0 ? {} : { model: env.model },
25177
+ ...env.engine === void 0 ? {} : { engine: env.engine },
25178
+ ...env.extraPiArgs === void 0 ? {} : { extraPiArgs: env.extraPiArgs }
25179
+ });
25180
+ return runAdmittedOneShotRole({
25181
+ admitted,
25182
+ env,
25183
+ io,
25184
+ extraArgs,
25185
+ adapters: { trySettle: trySettleInspectorTerminalResult, shouldPresentSettled: () => true },
25186
+ ...env.engine === void 0 ? {} : { effectiveEngine: env.engine }
25187
+ });
25188
+ }
25189
+ var init_inspector_run = __esm({
25190
+ "src/public-cli/inspector-run.ts"() {
25191
+ "use strict";
25192
+ init_engine_material();
25193
+ init_cli_errors();
25194
+ init_invocation();
25195
+ init_config2();
25196
+ init_one_shot_dispatch();
25197
+ init_settlement();
25198
+ }
25199
+ });
25200
+
25085
25201
  // src/public-cli/judge-run.ts
25086
25202
  import { writeFile as writeFile10 } from "node:fs/promises";
25087
25203
  import { join as join19 } from "node:path";
@@ -29321,6 +29437,26 @@ async function runAkRole(argv, env) {
29321
29437
  ...result2.terminal === void 0 ? {} : { terminal: result2.terminal }
29322
29438
  };
29323
29439
  }
29440
+ if (parsed.command === "inspector") {
29441
+ const agentDir = resolveAgentDir(env, home);
29442
+ const cwd = env.cwd ?? process.cwd();
29443
+ const config = await loadAndValidateConfig(home, env.packageRoot);
29444
+ const credentials = env.credentials ?? await loadCredentialProviders(agentDir);
29445
+ const seat = resolveEffectiveSeat(config, "inspector", credentials, invocationFromParsed(parsed));
29446
+ const result2 = await runPublicInspector(parsed.args, {
29447
+ home,
29448
+ agentDir,
29449
+ packageRoot: env.packageRoot,
29450
+ cwd,
29451
+ credentials,
29452
+ ...env.correlationId === void 0 ? {} : { correlationId: env.correlationId },
29453
+ ...env.piRunner === void 0 ? {} : { piRunner: env.piRunner },
29454
+ ...seat.selection === void 0 ? {} : { model: seat.selection },
29455
+ ...projectSeatEngine(seat),
29456
+ ...env.createRunId === void 0 ? {} : { createRunId: env.createRunId }
29457
+ }, io, PUBLIC_ROLE_ARGV.inspector.parse);
29458
+ return { exitCode: result2.exitCode, ...result2.terminal === void 0 ? {} : { terminal: result2.terminal } };
29459
+ }
29324
29460
  if (parsed.command === "merger") {
29325
29461
  const agentDir = resolveAgentDir(env, home);
29326
29462
  const cwd = env.cwd ?? process.cwd();
@@ -29397,6 +29533,7 @@ var init_cli = __esm({
29397
29533
  init_doctor_run();
29398
29534
  init_fixer_run();
29399
29535
  init_notary_run();
29536
+ init_inspector_run();
29400
29537
  init_judge_run();
29401
29538
  init_merger_run();
29402
29539
  init_reviewer_run();
@@ -29414,6 +29551,7 @@ var init_cli = __esm({
29414
29551
  doctor: { parse: parseDoctorArgv, options: optionsForOwner("doctor") },
29415
29552
  merger: { parse: parseMergerArgv, options: optionsForOwner("merger") },
29416
29553
  notary: { parse: parseNotaryArgv, options: optionsForOwner("notary") },
29554
+ inspector: { parse: parseInspectorArgv, options: optionsForOwner("inspector") },
29417
29555
  reviewer: { parse: parseReviewerArgv, options: optionsForOwner("reviewer") },
29418
29556
  /** Deterministic analysis seat (#336) — argv parse only; no LLM admission. */
29419
29557
  analyst: { parse: parseAnalystArgv, options: optionsForOwner("analyst") }
@@ -8,13 +8,11 @@ export const INTERNAL_ROLE_ENTRYPOINT_RELATIVE = "extensions/role-runtime.ts";
8
8
  export const PUBLIC_CALLABLE_ROLES = PACKAGED_ROLE_REGISTRY.map((entry) => entry.role);
9
9
  /** Automatic attendance seat — configurable, never a caller-selected command. */
10
10
  export const AUTOMATIC_NAVIGATOR_SEAT = "navigator";
11
- /** Automatic gate seats — configurable model only; never caller commands (#453). */
11
+ /** Automatic province seat — configurable model only; never a caller command. */
12
12
  export const AUTOMATIC_GATEKEEPER_SEAT = "gatekeeper";
13
- export const AUTOMATIC_INSPECTOR_SEAT = "inspector";
14
- /** All automatic configurable seats (no independent public activation command). */
13
+ /** Automatic-only configurable seats. Inspector remains automatic-capable via its callable seat. */
15
14
  export const AUTOMATIC_CONFIGURABLE_SEATS = [
16
15
  AUTOMATIC_GATEKEEPER_SEAT,
17
- AUTOMATIC_INSPECTOR_SEAT,
18
16
  AUTOMATIC_NAVIGATOR_SEAT,
19
17
  ];
20
18
  export const PUBLIC_CONFIGURABLE_SEATS = [
@@ -44,7 +44,7 @@ import {
44
44
  packagedRoleMetadata,
45
45
  } from "../src/packaged-role-registry.ts";
46
46
  import { createPiJudgeAuditor } from "../src/judge-auditor.ts";
47
- import { loadMainRoleSessionMaterials } from "../src/session-opening-materials.ts";
47
+ import { loadGatekeeperSessionMaterials, loadMainRoleSessionMaterials } from "../src/session-opening-materials.ts";
48
48
  const extensionPath = fileURLToPath(import.meta.url);
49
49
  const packageRoot = fileURLToPath(new URL("..", import.meta.url));
50
50
  const navigatorRoutePlaybookPath = fileURLToPath(new URL("../resources/navigator-route-playbook.md", import.meta.url));
@@ -265,6 +265,7 @@ export default function roleRuntime(pi: ExtensionAPI): void {
265
265
  loadDoctorCase,
266
266
  auditDoctorCompliance: createPiDoctorAuditor(),
267
267
  loadNotarySoul: () => loadMainRoleSessionMaterials("notary"),
268
+ loadInspectorSoul: () => loadGatekeeperSessionMaterials("inspector"),
268
269
  loadNotarySourceRun: loadNotarySourceRunLocator,
269
270
  loadNavigatorWorkContext: (options) => loadNavigatorWorkContext(pi, options),
270
271
  createNavigatorAttendance: (options) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akagilnc/pi-workflow-roles",
3
- "version": "0.1.2521",
3
+ "version": "0.1.2535",
4
4
  "description": "Soul-bound workflow roles for Pi",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -5,9 +5,10 @@ import { executeAuditorChild, type AuditorCompletion, type AuditorDecisionTool }
5
5
  import { openToolObject } from "./open-tool-schema.ts";
6
6
  import type { NoReceiptLifecycleFacts } from "./receipt-delivery-policy.ts";
7
7
  import { loadGatekeeperSessionMaterials } from "./session-opening-materials.ts";
8
+ import { INSPECTOR_OUTPUT_TOOL_NAME } from "./inspector-contracts.ts";
8
9
 
9
10
  export const GATEKEEPER_OUTPUT_TOOL = "ak_gatekeeper_output";
10
- export const INSPECTOR_OUTPUT_TOOL = "ak_inspector_output";
11
+ export const INSPECTOR_OUTPUT_TOOL = INSPECTOR_OUTPUT_TOOL_NAME;
11
12
  export const NOTARY_OUTPUT_TOOL = "ak_notary_output";
12
13
  const SUBJECT_TOOL = "ak_gatekeeper_subject";
13
14
 
@@ -0,0 +1 @@
1
+ export const INSPECTOR_OUTPUT_TOOL_NAME = "ak_inspector_output" as const;