@akagilnc/pi-workflow-roles 0.1.1941 → 0.1.2004

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.
@@ -14273,7 +14273,13 @@ function listHelpCapabilities() {
14273
14273
  defaultPhase
14274
14274
  };
14275
14275
  });
14276
- return [...support, ...roles];
14276
+ const deterministic = PUBLIC_DETERMINISTIC_COMMANDS.map(
14277
+ (name) => ({
14278
+ kind: "deterministic",
14279
+ name
14280
+ })
14281
+ );
14282
+ return [...support, ...roles, ...deterministic];
14277
14283
  }
14278
14284
  function isPublicConfigurableSeat(value) {
14279
14285
  return PUBLIC_CONFIGURABLE_SEATS.includes(value);
@@ -14281,7 +14287,7 @@ function isPublicConfigurableSeat(value) {
14281
14287
  function isPublicCliSupportCommand(value) {
14282
14288
  return PUBLIC_CLI_SUPPORT_COMMANDS.includes(value);
14283
14289
  }
14284
- var INTERNAL_ROLE_ENTRYPOINT_RELATIVE, PUBLIC_CALLABLE_ROLES, AUTOMATIC_NAVIGATOR_SEAT, PUBLIC_CONFIGURABLE_SEATS, PUBLIC_CLI_SUPPORT_COMMANDS, STARTUP_CANDIDATES;
14290
+ var INTERNAL_ROLE_ENTRYPOINT_RELATIVE, PUBLIC_CALLABLE_ROLES, AUTOMATIC_NAVIGATOR_SEAT, PUBLIC_CONFIGURABLE_SEATS, PUBLIC_CLI_SUPPORT_COMMANDS, STARTUP_CANDIDATES, PUBLIC_DETERMINISTIC_COMMANDS;
14285
14291
  var init_registry2 = __esm({
14286
14292
  "src/public-cli/registry.ts"() {
14287
14293
  "use strict";
@@ -14335,6 +14341,7 @@ var init_registry2 = __esm({
14335
14341
  { provider: "xai", model: "grok-4.5", thinking: "high" }
14336
14342
  ]
14337
14343
  };
14344
+ PUBLIC_DETERMINISTIC_COMMANDS = ["taishi"];
14338
14345
  }
14339
14346
  });
14340
14347
 
@@ -14767,6 +14774,26 @@ function ensureRealDirectoryTree(root, targetDir) {
14767
14774
  );
14768
14775
  }
14769
14776
  }
14777
+ function assertLedgerFileInsideHome(ledgerPath, ledgerHome) {
14778
+ if (!isAbsolute(ledgerHome)) {
14779
+ throw new ActivationLedgerError(`activation ledger home must be absolute: ${ledgerHome}`);
14780
+ }
14781
+ const resolvedLedger = resolve(ledgerPath);
14782
+ try {
14783
+ if (!lstatSync2(resolvedLedger).isSymbolicLink()) return;
14784
+ throw new ActivationLedgerError(
14785
+ `activation ledger file is a symbolic link: ${resolvedLedger}`
14786
+ );
14787
+ } catch (error) {
14788
+ if (errnoCode(error) !== "ENOENT") {
14789
+ if (error instanceof ActivationLedgerError) throw error;
14790
+ throw new ActivationLedgerError(
14791
+ `activation ledger failed to stat ledger file (${resolvedLedger}): ${errorText(error)}`,
14792
+ { cause: error }
14793
+ );
14794
+ }
14795
+ }
14796
+ }
14770
14797
  var ActivationLedgerError;
14771
14798
  var init_activation_ledger_topology = __esm({
14772
14799
  "src/activation-ledger-topology.ts"() {
@@ -16769,7 +16796,260 @@ function buildMergerTransportPrompt(admitted) {
16769
16796
  }
16770
16797
  return lines.join("\n");
16771
16798
  }
16772
- var MergerEnvelopeDerivationError, DOCTOR_ISSUE_NUMBER_PATTERN, DOCTOR_CASE_RUNS_PATH_PATTERN;
16799
+ function parseTaishiTicketNumber(raw, flag = "--ticket") {
16800
+ const trimmed = raw.trim();
16801
+ if (!TAISHI_TICKET_NUMBER_PATTERN.test(trimmed)) {
16802
+ throw new CliUsageError(
16803
+ `taishi ${flag} must be a positive integer, got ${raw}`
16804
+ );
16805
+ }
16806
+ const value = Number(trimmed);
16807
+ if (!Number.isSafeInteger(value) || value < 1) {
16808
+ throw new CliUsageError(
16809
+ `taishi ${flag} must be a positive integer, got ${raw}`
16810
+ );
16811
+ }
16812
+ return value;
16813
+ }
16814
+ function parseTaishiIssueNumberList(raw, flag) {
16815
+ const trimmed = raw.trim();
16816
+ if (trimmed === "") {
16817
+ throw new CliUsageError(`${flag} requires a comma-separated positive integer list`);
16818
+ }
16819
+ const parts = trimmed.split(",").map((part) => part.trim());
16820
+ if (parts.some((part) => part === "")) {
16821
+ throw new CliUsageError(`${flag} requires a comma-separated positive integer list`);
16822
+ }
16823
+ return parts.map((part) => parseTaishiTicketNumber(part, flag));
16824
+ }
16825
+ function requireOptionValue(flag, value, what) {
16826
+ if (value === void 0 || value.trim() === "") {
16827
+ throw new CliUsageError(`${flag} requires ${what}`);
16828
+ }
16829
+ return value;
16830
+ }
16831
+ function parseTaishiArgv(args) {
16832
+ let query = "issue";
16833
+ let ticketRaw;
16834
+ const projectRoots = [];
16835
+ let groupALabel;
16836
+ let groupAIssuesRaw;
16837
+ let groupBLabel;
16838
+ let groupBIssuesRaw;
16839
+ let sweepToken = false;
16840
+ const attachmentPaths = [];
16841
+ const tokens = [...args];
16842
+ while (tokens.length > 0) {
16843
+ const token = tokens.shift();
16844
+ if (token === "--") {
16845
+ if (tokens.length > 0) {
16846
+ throw new CliUsageError(`unexpected taishi argument: ${tokens[0]}`);
16847
+ }
16848
+ break;
16849
+ }
16850
+ if (token === "--cohort") {
16851
+ if (query !== "issue") {
16852
+ throw new CliUsageError("taishi accepts only one of --cohort / --model-groups");
16853
+ }
16854
+ query = "cohort";
16855
+ continue;
16856
+ }
16857
+ if (token === "--model-groups") {
16858
+ if (query !== "issue") {
16859
+ throw new CliUsageError("taishi accepts only one of --cohort / --model-groups");
16860
+ }
16861
+ query = "model-groups";
16862
+ continue;
16863
+ }
16864
+ if (token === "--ticket") {
16865
+ const value = tokens.shift();
16866
+ if (value === void 0 || value.trim() === "") {
16867
+ throw new CliUsageError("taishi --ticket requires a positive integer");
16868
+ }
16869
+ ticketRaw = value;
16870
+ continue;
16871
+ }
16872
+ if (token.startsWith("--ticket=")) {
16873
+ ticketRaw = token.slice("--ticket=".length);
16874
+ if (ticketRaw.trim() === "") {
16875
+ throw new CliUsageError("taishi --ticket requires a positive integer");
16876
+ }
16877
+ continue;
16878
+ }
16879
+ if (token === "--project-root") {
16880
+ projectRoots.push(requireOptionPath("--project-root", tokens.shift()));
16881
+ continue;
16882
+ }
16883
+ if (token.startsWith("--project-root=")) {
16884
+ projectRoots.push(
16885
+ requireOptionPath("--project-root", token.slice("--project-root=".length))
16886
+ );
16887
+ continue;
16888
+ }
16889
+ if (token === "--group-a-label") {
16890
+ groupALabel = requireOptionValue("--group-a-label", tokens.shift(), "a label");
16891
+ continue;
16892
+ }
16893
+ if (token.startsWith("--group-a-label=")) {
16894
+ groupALabel = requireOptionValue(
16895
+ "--group-a-label",
16896
+ token.slice("--group-a-label=".length),
16897
+ "a label"
16898
+ );
16899
+ continue;
16900
+ }
16901
+ if (token === "--group-a-issues") {
16902
+ groupAIssuesRaw = requireOptionValue(
16903
+ "--group-a-issues",
16904
+ tokens.shift(),
16905
+ "a comma-separated positive integer list"
16906
+ );
16907
+ continue;
16908
+ }
16909
+ if (token.startsWith("--group-a-issues=")) {
16910
+ groupAIssuesRaw = requireOptionValue(
16911
+ "--group-a-issues",
16912
+ token.slice("--group-a-issues=".length),
16913
+ "a comma-separated positive integer list"
16914
+ );
16915
+ continue;
16916
+ }
16917
+ if (token === "--group-b-label") {
16918
+ groupBLabel = requireOptionValue("--group-b-label", tokens.shift(), "a label");
16919
+ continue;
16920
+ }
16921
+ if (token.startsWith("--group-b-label=")) {
16922
+ groupBLabel = requireOptionValue(
16923
+ "--group-b-label",
16924
+ token.slice("--group-b-label=".length),
16925
+ "a label"
16926
+ );
16927
+ continue;
16928
+ }
16929
+ if (token === "--group-b-issues") {
16930
+ groupBIssuesRaw = requireOptionValue(
16931
+ "--group-b-issues",
16932
+ tokens.shift(),
16933
+ "a comma-separated positive integer list"
16934
+ );
16935
+ continue;
16936
+ }
16937
+ if (token.startsWith("--group-b-issues=")) {
16938
+ groupBIssuesRaw = requireOptionValue(
16939
+ "--group-b-issues",
16940
+ token.slice("--group-b-issues=".length),
16941
+ "a comma-separated positive integer list"
16942
+ );
16943
+ continue;
16944
+ }
16945
+ if (token === "--attach") {
16946
+ attachmentPaths.push(requireOptionPath("--attach", tokens.shift()));
16947
+ continue;
16948
+ }
16949
+ if (token.startsWith("--attach=")) {
16950
+ attachmentPaths.push(
16951
+ requireOptionPath("--attach", token.slice("--attach=".length))
16952
+ );
16953
+ continue;
16954
+ }
16955
+ if (token.startsWith("-") && token !== "-") {
16956
+ throw new CliUsageError(`unknown taishi option: ${token}`);
16957
+ }
16958
+ if (token === "sweep") {
16959
+ if (sweepToken) {
16960
+ throw new CliUsageError("unexpected taishi argument: sweep");
16961
+ }
16962
+ sweepToken = true;
16963
+ continue;
16964
+ }
16965
+ throw new CliUsageError(`unexpected taishi argument: ${token}`);
16966
+ }
16967
+ const hasSweepFace = sweepToken || attachmentPaths.length > 0;
16968
+ const hasCohortFlags = groupALabel !== void 0 || groupAIssuesRaw !== void 0 || groupBLabel !== void 0 || groupBIssuesRaw !== void 0;
16969
+ if (query === "cohort") {
16970
+ if (groupALabel === void 0 || groupAIssuesRaw === void 0 || groupBLabel === void 0 || groupBIssuesRaw === void 0) {
16971
+ throw new CliUsageError(
16972
+ "usage: ak-role taishi --cohort --group-a-label <L> --group-a-issues <N[,N...]> --group-b-label <L> --group-b-issues <N[,N...]>"
16973
+ );
16974
+ }
16975
+ if (ticketRaw !== void 0 || projectRoots.length > 0) {
16976
+ throw new CliUsageError(
16977
+ "taishi --cohort does not accept --ticket or --project-root"
16978
+ );
16979
+ }
16980
+ if (hasSweepFace) {
16981
+ throw new CliUsageError(
16982
+ "taishi --cohort does not accept sweep --attach"
16983
+ );
16984
+ }
16985
+ return {
16986
+ query: "cohort",
16987
+ groups: [
16988
+ {
16989
+ groupLabel: groupALabel,
16990
+ issues: parseTaishiIssueNumberList(groupAIssuesRaw, "--group-a-issues")
16991
+ },
16992
+ {
16993
+ groupLabel: groupBLabel,
16994
+ issues: parseTaishiIssueNumberList(groupBIssuesRaw, "--group-b-issues")
16995
+ }
16996
+ ]
16997
+ };
16998
+ }
16999
+ if (query === "model-groups") {
17000
+ if (projectRoots.length === 0) {
17001
+ throw new CliUsageError(
17002
+ "usage: ak-role taishi --model-groups --project-root <P> [--project-root <P> ...]"
17003
+ );
17004
+ }
17005
+ if (ticketRaw !== void 0) {
17006
+ throw new CliUsageError("taishi --model-groups does not accept --ticket");
17007
+ }
17008
+ if (hasCohortFlags) {
17009
+ throw new CliUsageError("taishi --model-groups does not accept cohort group flags");
17010
+ }
17011
+ if (hasSweepFace) {
17012
+ throw new CliUsageError(
17013
+ "taishi --model-groups does not accept sweep --attach"
17014
+ );
17015
+ }
17016
+ return {
17017
+ query: "model-groups",
17018
+ projectRoots
17019
+ };
17020
+ }
17021
+ if (hasCohortFlags) {
17022
+ throw new CliUsageError("taishi issue query does not accept cohort group flags");
17023
+ }
17024
+ if (hasSweepFace) {
17025
+ if (ticketRaw !== void 0 || projectRoots.length > 0) {
17026
+ throw new CliUsageError(
17027
+ "taishi sweep --attach cannot combine with --ticket or --project-root"
17028
+ );
17029
+ }
17030
+ return {
17031
+ query: "sweep",
17032
+ attachmentPaths
17033
+ };
17034
+ }
17035
+ if (projectRoots.length > 1) {
17036
+ throw new CliUsageError(
17037
+ "taishi issue query accepts at most one --project-root (use --model-groups for many)"
17038
+ );
17039
+ }
17040
+ const projectRoot = projectRoots[0];
17041
+ if (ticketRaw === void 0 && projectRoot === void 0) {
17042
+ throw new CliUsageError(
17043
+ "usage: ak-role taishi ((--ticket <N> | --project-root <P>) | [sweep] --attach <sweep.json> | --cohort ... | --model-groups ...)"
17044
+ );
17045
+ }
17046
+ return {
17047
+ query: "issue",
17048
+ ...ticketRaw === void 0 ? {} : { ticket: parseTaishiTicketNumber(ticketRaw) },
17049
+ ...projectRoot === void 0 ? {} : { projectRoot }
17050
+ };
17051
+ }
17052
+ var MergerEnvelopeDerivationError, DOCTOR_ISSUE_NUMBER_PATTERN, DOCTOR_CASE_RUNS_PATH_PATTERN, TAISHI_TICKET_NUMBER_PATTERN;
16773
17053
  var init_invocation = __esm({
16774
17054
  "src/public-cli/invocation.ts"() {
16775
17055
  "use strict";
@@ -16796,6 +17076,7 @@ var init_invocation = __esm({
16796
17076
  };
16797
17077
  DOCTOR_ISSUE_NUMBER_PATTERN = /^[1-9]\d*$/;
16798
17078
  DOCTOR_CASE_RUNS_PATH_PATTERN = /\/\.ak-roles\/books\/[^/]+\/issues\/([1-9]\d*)\/runs$/;
17079
+ TAISHI_TICKET_NUMBER_PATTERN = /^[1-9]\d*$/;
16799
17080
  }
16800
17081
  });
16801
17082
 
@@ -18735,6 +19016,11 @@ function formatFailureStderrDiagnostic(failure) {
18735
19016
  function presentStructuralRejection(error, io) {
18736
19017
  io.stderr(formatCliDiagnostic(error.message));
18737
19018
  }
19019
+ function presentControlledFailure(failure, io) {
19020
+ io.stdout(`${JSON.stringify(failure, null, 2)}
19021
+ `);
19022
+ io.stderr(formatFailureStderrDiagnostic(failure));
19023
+ }
18738
19024
  async function inspectJudgeSession(sessionFile) {
18739
19025
  try {
18740
19026
  await readFile9(sessionFile, "utf8");
@@ -21385,7 +21671,7 @@ function buildCoderResumeActivationExtraArgs(admitted, options) {
21385
21671
  RESUME_TRANSPORT_ENVELOPE
21386
21672
  ];
21387
21673
  }
21388
- async function presentControlledFailure(admitted, failureInput, io) {
21674
+ async function presentControlledFailure2(admitted, failureInput, io) {
21389
21675
  const hasThrown = Object.hasOwn(failureInput, "thrown");
21390
21676
  const resumeObservation = await resolveControlledFailureResumeObservation({
21391
21677
  runDirectory: admitted.runDirectory,
@@ -21441,7 +21727,7 @@ async function dispatchAdmittedCoder(input) {
21441
21727
  env.credentials
21442
21728
  );
21443
21729
  if (missingCredential !== void 0) {
21444
- return await presentControlledFailure(
21730
+ return await presentControlledFailure2(
21445
21731
  admitted,
21446
21732
  missingCredential,
21447
21733
  io
@@ -21472,7 +21758,7 @@ async function dispatchAdmittedCoder(input) {
21472
21758
  ...env.piRunner === void 0 ? {} : { runner: env.piRunner }
21473
21759
  });
21474
21760
  } catch (error) {
21475
- return await presentControlledFailure(
21761
+ return await presentControlledFailure2(
21476
21762
  admitted,
21477
21763
  {
21478
21764
  timedOut: false,
@@ -21497,7 +21783,7 @@ async function dispatchAdmittedCoder(input) {
21497
21783
  ...methodProvenance === void 0 ? {} : { methodProvenance }
21498
21784
  });
21499
21785
  } catch (error) {
21500
- return await presentControlledFailure(
21786
+ return await presentControlledFailure2(
21501
21787
  admitted,
21502
21788
  {
21503
21789
  timedOut: false,
@@ -21528,7 +21814,7 @@ async function dispatchAdmittedCoder(input) {
21528
21814
  credential: credentialFailure,
21529
21815
  runDirectory: admitted.runDirectory
21530
21816
  });
21531
- return await presentControlledFailure(
21817
+ return await presentControlledFailure2(
21532
21818
  admitted,
21533
21819
  {
21534
21820
  timedOut: result2.timedOut,
@@ -21583,7 +21869,7 @@ async function runPublicCoder(argv, env, io, parseCoderArgv2) {
21583
21869
  methodProvenance = material.provenance;
21584
21870
  } catch (error) {
21585
21871
  await lease.release();
21586
- return await presentControlledFailure(
21872
+ return await presentControlledFailure2(
21587
21873
  admitted,
21588
21874
  {
21589
21875
  timedOut: false,
@@ -21660,7 +21946,7 @@ async function runPublicCoderResume(argv, env, io) {
21660
21946
  methodProvenance = material.provenance;
21661
21947
  } catch (error) {
21662
21948
  await lease.release();
21663
- return await presentControlledFailure(
21949
+ return await presentControlledFailure2(
21664
21950
  admitted,
21665
21951
  {
21666
21952
  timedOut: false,
@@ -21743,7 +22029,7 @@ function buildCollectorActivationExtraArgs(admitted, options = {}) {
21743
22029
  prompt
21744
22030
  ];
21745
22031
  }
21746
- async function presentControlledFailure2(admitted, failureInput, io) {
22032
+ async function presentControlledFailure3(admitted, failureInput, io) {
21747
22033
  const hasThrown = Object.hasOwn(failureInput, "thrown");
21748
22034
  const session = !hasThrown && !failureInput.timedOut && failureInput.knownFailure === void 0 && failureInput.knownCause === void 0 ? await inspectJudgeSession(admitted.sessionFile) : void 0;
21749
22035
  const failure = classifyPostAdmissionFailure({
@@ -21774,7 +22060,7 @@ async function dispatchAdmittedCollector(input) {
21774
22060
  env.credentials
21775
22061
  );
21776
22062
  if (missingCredential !== void 0) {
21777
- return await presentControlledFailure2(
22063
+ return await presentControlledFailure3(
21778
22064
  admitted,
21779
22065
  missingCredential,
21780
22066
  io
@@ -21805,7 +22091,7 @@ async function dispatchAdmittedCollector(input) {
21805
22091
  ...env.piRunner === void 0 ? {} : { runner: env.piRunner }
21806
22092
  });
21807
22093
  } catch (error) {
21808
- return await presentControlledFailure2(
22094
+ return await presentControlledFailure3(
21809
22095
  admitted,
21810
22096
  {
21811
22097
  timedOut: false,
@@ -21828,7 +22114,7 @@ async function dispatchAdmittedCollector(input) {
21828
22114
  try {
21829
22115
  lawful = await trySettleCollectorTerminalResult(admitted);
21830
22116
  } catch (error) {
21831
- return await presentControlledFailure2(
22117
+ return await presentControlledFailure3(
21832
22118
  admitted,
21833
22119
  {
21834
22120
  timedOut: false,
@@ -21866,7 +22152,7 @@ async function dispatchAdmittedCollector(input) {
21866
22152
  credential: credentialFailure,
21867
22153
  runDirectory: admitted.runDirectory
21868
22154
  });
21869
- return await presentControlledFailure2(
22155
+ return await presentControlledFailure3(
21870
22156
  admitted,
21871
22157
  {
21872
22158
  timedOut: result2.timedOut,
@@ -21977,7 +22263,7 @@ function buildDoctorActivationExtraArgs(admitted, options = {}) {
21977
22263
  prompt
21978
22264
  ];
21979
22265
  }
21980
- async function presentControlledFailure3(admitted, failureInput, io) {
22266
+ async function presentControlledFailure4(admitted, failureInput, io) {
21981
22267
  const hasThrown = Object.hasOwn(failureInput, "thrown");
21982
22268
  const session = !hasThrown && !failureInput.timedOut && failureInput.knownFailure === void 0 ? await inspectJudgeSession(admitted.sessionFile) : void 0;
21983
22269
  const failure = classifyPostAdmissionFailure({
@@ -22005,7 +22291,7 @@ async function dispatchAdmittedDoctor(input) {
22005
22291
  env.credentials
22006
22292
  );
22007
22293
  if (missingCredential !== void 0) {
22008
- return await presentControlledFailure3(
22294
+ return await presentControlledFailure4(
22009
22295
  admitted,
22010
22296
  missingCredential,
22011
22297
  io
@@ -22035,7 +22321,7 @@ async function dispatchAdmittedDoctor(input) {
22035
22321
  ...env.piRunner === void 0 ? {} : { runner: env.piRunner }
22036
22322
  });
22037
22323
  } catch (error) {
22038
- return await presentControlledFailure3(
22324
+ return await presentControlledFailure4(
22039
22325
  admitted,
22040
22326
  {
22041
22327
  timedOut: false,
@@ -22058,7 +22344,7 @@ async function dispatchAdmittedDoctor(input) {
22058
22344
  try {
22059
22345
  lawful = await trySettleDoctorTerminalResult(admitted);
22060
22346
  } catch (error) {
22061
- return await presentControlledFailure3(
22347
+ return await presentControlledFailure4(
22062
22348
  admitted,
22063
22349
  {
22064
22350
  timedOut: false,
@@ -22103,7 +22389,7 @@ async function dispatchAdmittedDoctor(input) {
22103
22389
  credential: credentialFailure,
22104
22390
  runDirectory: admitted.runDirectory
22105
22391
  });
22106
- return await presentControlledFailure3(
22392
+ return await presentControlledFailure4(
22107
22393
  admitted,
22108
22394
  {
22109
22395
  timedOut: result2.timedOut,
@@ -22257,7 +22543,7 @@ function buildFixerResumeActivationExtraArgs(admitted, options) {
22257
22543
  RESUME_TRANSPORT_ENVELOPE
22258
22544
  ];
22259
22545
  }
22260
- async function presentControlledFailure4(admitted, failureInput, io) {
22546
+ async function presentControlledFailure5(admitted, failureInput, io) {
22261
22547
  const hasThrown = Object.hasOwn(failureInput, "thrown");
22262
22548
  const resumeObservation = await resolveControlledFailureResumeObservation({
22263
22549
  runDirectory: admitted.runDirectory,
@@ -22310,7 +22596,7 @@ async function dispatchAdmittedFixer(input) {
22310
22596
  env.credentials
22311
22597
  );
22312
22598
  if (missingCredential !== void 0) {
22313
- return await presentControlledFailure4(
22599
+ return await presentControlledFailure5(
22314
22600
  admitted,
22315
22601
  missingCredential,
22316
22602
  io
@@ -22341,7 +22627,7 @@ async function dispatchAdmittedFixer(input) {
22341
22627
  ...env.piRunner === void 0 ? {} : { runner: env.piRunner }
22342
22628
  });
22343
22629
  } catch (error) {
22344
- return await presentControlledFailure4(
22630
+ return await presentControlledFailure5(
22345
22631
  admitted,
22346
22632
  {
22347
22633
  timedOut: false,
@@ -22371,7 +22657,7 @@ async function dispatchAdmittedFixer(input) {
22371
22657
  )
22372
22658
  });
22373
22659
  } catch (error) {
22374
- return await presentControlledFailure4(
22660
+ return await presentControlledFailure5(
22375
22661
  admitted,
22376
22662
  {
22377
22663
  timedOut: false,
@@ -22416,7 +22702,7 @@ async function dispatchAdmittedFixer(input) {
22416
22702
  credential: credentialFailure,
22417
22703
  runDirectory: admitted.runDirectory
22418
22704
  });
22419
- return await presentControlledFailure4(
22705
+ return await presentControlledFailure5(
22420
22706
  admitted,
22421
22707
  {
22422
22708
  timedOut: result2.timedOut,
@@ -22470,7 +22756,7 @@ async function runPublicFixer(argv, env, io, parseFixerArgv2) {
22470
22756
  methodMaterial = await loadFixerMethodMaterial(env.packageRoot);
22471
22757
  } catch (error) {
22472
22758
  await lease.release();
22473
- return await presentControlledFailure4(
22759
+ return await presentControlledFailure5(
22474
22760
  admitted,
22475
22761
  {
22476
22762
  timedOut: false,
@@ -22540,7 +22826,7 @@ async function runPublicFixerResume(argv, env, io) {
22540
22826
  methodMaterial = await loadFixerMethodMaterial(env.packageRoot);
22541
22827
  } catch (error) {
22542
22828
  await lease.release();
22543
- return await presentControlledFailure4(
22829
+ return await presentControlledFailure5(
22544
22830
  admitted,
22545
22831
  {
22546
22832
  timedOut: false,
@@ -22636,7 +22922,7 @@ function buildJudgeResumeActivationExtraArgs(admitted, options = {}) {
22636
22922
  RESUME_TRANSPORT_ENVELOPE
22637
22923
  ];
22638
22924
  }
22639
- async function presentControlledFailure5(admitted, failureInput, io) {
22925
+ async function presentControlledFailure6(admitted, failureInput, io) {
22640
22926
  const hasThrown = Object.hasOwn(failureInput, "thrown");
22641
22927
  const resumeObservation = await resolveControlledFailureResumeObservation({
22642
22928
  runDirectory: admitted.runDirectory,
@@ -22689,7 +22975,7 @@ async function dispatchAdmittedJudge(input) {
22689
22975
  env.credentials
22690
22976
  );
22691
22977
  if (missingCredential !== void 0) {
22692
- return await presentControlledFailure5(
22978
+ return await presentControlledFailure6(
22693
22979
  admitted,
22694
22980
  missingCredential,
22695
22981
  io
@@ -22722,7 +23008,7 @@ async function dispatchAdmittedJudge(input) {
22722
23008
  ...env.piRunner === void 0 ? {} : { runner: env.piRunner }
22723
23009
  });
22724
23010
  } catch (error) {
22725
- return await presentControlledFailure5(
23011
+ return await presentControlledFailure6(
22726
23012
  admitted,
22727
23013
  {
22728
23014
  timedOut: false,
@@ -22745,7 +23031,7 @@ async function dispatchAdmittedJudge(input) {
22745
23031
  try {
22746
23032
  lawful = await trySettleJudgeTerminalResult(admitted);
22747
23033
  } catch (error) {
22748
- return await presentControlledFailure5(
23034
+ return await presentControlledFailure6(
22749
23035
  admitted,
22750
23036
  {
22751
23037
  timedOut: false,
@@ -22790,7 +23076,7 @@ async function dispatchAdmittedJudge(input) {
22790
23076
  credential: credentialFailure,
22791
23077
  runDirectory: admitted.runDirectory
22792
23078
  });
22793
- return await presentControlledFailure5(
23079
+ return await presentControlledFailure6(
22794
23080
  admitted,
22795
23081
  {
22796
23082
  timedOut: result2.timedOut,
@@ -22983,7 +23269,7 @@ function buildMergerResumeActivationExtraArgs(admitted, options) {
22983
23269
  RESUME_TRANSPORT_ENVELOPE
22984
23270
  ];
22985
23271
  }
22986
- async function presentControlledFailure6(admitted, failureInput, io) {
23272
+ async function presentControlledFailure7(admitted, failureInput, io) {
22987
23273
  const hasThrown = Object.hasOwn(failureInput, "thrown");
22988
23274
  const resumeObservation = await resolveControlledFailureResumeObservation({
22989
23275
  runDirectory: admitted.runDirectory,
@@ -23039,7 +23325,7 @@ async function dispatchAdmittedMerger(input) {
23039
23325
  env.credentials
23040
23326
  );
23041
23327
  if (missingCredential !== void 0) {
23042
- return await presentControlledFailure6(
23328
+ return await presentControlledFailure7(
23043
23329
  admitted,
23044
23330
  missingCredential,
23045
23331
  io
@@ -23070,7 +23356,7 @@ async function dispatchAdmittedMerger(input) {
23070
23356
  ...env.piRunner === void 0 ? {} : { runner: env.piRunner }
23071
23357
  });
23072
23358
  } catch (error) {
23073
- return await presentControlledFailure6(
23359
+ return await presentControlledFailure7(
23074
23360
  admitted,
23075
23361
  {
23076
23362
  timedOut: false,
@@ -23100,7 +23386,7 @@ async function dispatchAdmittedMerger(input) {
23100
23386
  )
23101
23387
  });
23102
23388
  } catch (error) {
23103
- return await presentControlledFailure6(
23389
+ return await presentControlledFailure7(
23104
23390
  admitted,
23105
23391
  {
23106
23392
  timedOut: false,
@@ -23131,7 +23417,7 @@ async function dispatchAdmittedMerger(input) {
23131
23417
  credential: credentialFailure,
23132
23418
  runDirectory: admitted.runDirectory
23133
23419
  });
23134
- return await presentControlledFailure6(
23420
+ return await presentControlledFailure7(
23135
23421
  admitted,
23136
23422
  {
23137
23423
  timedOut: result2.timedOut,
@@ -23237,7 +23523,7 @@ async function runPublicMerger(argv, env, io, parseMergerArgv2) {
23237
23523
  ...env.createRunId === void 0 ? {} : { createRunId: env.createRunId }
23238
23524
  });
23239
23525
  await markRunAdmitted(shell);
23240
- return await presentControlledFailure6(
23526
+ return await presentControlledFailure7(
23241
23527
  shell,
23242
23528
  {
23243
23529
  timedOut: false,
@@ -23268,7 +23554,7 @@ async function runPublicMerger(argv, env, io, parseMergerArgv2) {
23268
23554
  methodMaterial = await loadMergerMethodMaterial(env.packageRoot);
23269
23555
  } catch (error) {
23270
23556
  await lease.release();
23271
- return await presentControlledFailure6(
23557
+ return await presentControlledFailure7(
23272
23558
  admitted,
23273
23559
  {
23274
23560
  timedOut: false,
@@ -23339,7 +23625,7 @@ async function runPublicMergerResume(argv, env, io) {
23339
23625
  methodMaterial = await loadMergerMethodMaterial(env.packageRoot);
23340
23626
  } catch (error) {
23341
23627
  await lease.release();
23342
- return await presentControlledFailure6(
23628
+ return await presentControlledFailure7(
23343
23629
  admitted,
23344
23630
  {
23345
23631
  timedOut: false,
@@ -23458,7 +23744,7 @@ function buildReviewerResumeActivationExtraArgs(admitted, options) {
23458
23744
  RESUME_TRANSPORT_ENVELOPE
23459
23745
  ];
23460
23746
  }
23461
- async function presentControlledFailure7(admitted, failureInput, io) {
23747
+ async function presentControlledFailure8(admitted, failureInput, io) {
23462
23748
  const hasThrown = Object.hasOwn(failureInput, "thrown");
23463
23749
  const resumeObservation = await resolveControlledFailureResumeObservation({
23464
23750
  runDirectory: admitted.runDirectory,
@@ -23511,7 +23797,7 @@ async function dispatchAdmittedReviewer(input) {
23511
23797
  env.credentials
23512
23798
  );
23513
23799
  if (missingCredential !== void 0) {
23514
- return await presentControlledFailure7(
23800
+ return await presentControlledFailure8(
23515
23801
  admitted,
23516
23802
  missingCredential,
23517
23803
  io
@@ -23543,7 +23829,7 @@ async function dispatchAdmittedReviewer(input) {
23543
23829
  ...env.piRunner === void 0 ? {} : { runner: env.piRunner }
23544
23830
  });
23545
23831
  } catch (error) {
23546
- return await presentControlledFailure7(
23832
+ return await presentControlledFailure8(
23547
23833
  admitted,
23548
23834
  {
23549
23835
  timedOut: false,
@@ -23573,7 +23859,7 @@ async function dispatchAdmittedReviewer(input) {
23573
23859
  )
23574
23860
  });
23575
23861
  } catch (error) {
23576
- return await presentControlledFailure7(
23862
+ return await presentControlledFailure8(
23577
23863
  admitted,
23578
23864
  {
23579
23865
  timedOut: false,
@@ -23618,7 +23904,7 @@ async function dispatchAdmittedReviewer(input) {
23618
23904
  credential: credentialFailure,
23619
23905
  runDirectory: admitted.runDirectory
23620
23906
  });
23621
- return await presentControlledFailure7(
23907
+ return await presentControlledFailure8(
23622
23908
  admitted,
23623
23909
  {
23624
23910
  timedOut: result2.timedOut,
@@ -23672,7 +23958,7 @@ async function runPublicReviewer(argv, env, io, parseReviewerArgv2) {
23672
23958
  methodMaterial = await loadReviewerMethodMaterial(env.packageRoot);
23673
23959
  } catch (error) {
23674
23960
  await lease.release();
23675
- return await presentControlledFailure7(
23961
+ return await presentControlledFailure8(
23676
23962
  admitted,
23677
23963
  {
23678
23964
  timedOut: false,
@@ -23742,7 +24028,7 @@ async function runPublicReviewerResume(argv, env, io) {
23742
24028
  methodMaterial = await loadReviewerMethodMaterial(env.packageRoot);
23743
24029
  } catch (error) {
23744
24030
  await lease.release();
23745
- return await presentControlledFailure7(
24031
+ return await presentControlledFailure8(
23746
24032
  admitted,
23747
24033
  {
23748
24034
  timedOut: false,
@@ -23784,31 +24070,2089 @@ var init_reviewer_run = __esm({
23784
24070
  }
23785
24071
  });
23786
24072
 
23787
- // src/public-cli/cli.ts
23788
- var cli_exports = {};
23789
- __export(cli_exports, {
23790
- CliUsageError: () => CliUsageError,
23791
- PUBLIC_ROLE_ARGV: () => PUBLIC_ROLE_ARGV,
23792
- buildExplicitInternalActivationArgs: () => buildExplicitInternalActivationArgs,
23793
- helpDocument: () => helpDocument,
23794
- resolveInternalRoleEntrypoint: () => resolveInternalRoleEntrypoint,
23795
- runAkRole: () => runAkRole
23796
- });
23797
- import { realpath as realpath5 } from "node:fs/promises";
23798
- import { homedir as homedir3 } from "node:os";
23799
- import { join as join18 } from "node:path";
23800
- function takePublicGlobalFlag(argv, index) {
23801
- const token = argv[index];
23802
- if (token === void 0) return void 0;
23803
- if (token === "--help" || token === "-h") {
23804
- return { flag: "help", consume: 1 };
24073
+ // src/atomic-write.ts
24074
+ import { randomUUID as randomUUID2 } from "node:crypto";
24075
+ import { rename, rm, writeFile as writeFile13 } from "node:fs/promises";
24076
+ import { dirname as dirname7, join as join18 } from "node:path";
24077
+ async function writeFileAtomically(destination, contents) {
24078
+ const parent = dirname7(destination);
24079
+ const temporary = join18(parent, `.atomic-write-${randomUUID2()}.tmp`);
24080
+ try {
24081
+ await writeFile13(temporary, contents);
24082
+ await rename(temporary, destination);
24083
+ } catch (error) {
24084
+ await rm(temporary, { force: true }).catch(() => void 0);
24085
+ throw error;
23805
24086
  }
23806
- if (token === "--model") {
23807
- const value = argv[index + 1];
23808
- if (value === void 0) {
23809
- return { flag: "model", consume: 1, value: void 0 };
24087
+ }
24088
+ var init_atomic_write = __esm({
24089
+ "src/atomic-write.ts"() {
24090
+ "use strict";
24091
+ }
24092
+ });
24093
+
24094
+ // src/taishi-index.ts
24095
+ import { open as open3, readFile as readFile10, unlink as unlink4 } from "node:fs/promises";
24096
+ import { dirname as dirname8, join as join19 } from "node:path";
24097
+ function sleep(ms) {
24098
+ return new Promise((resolve9) => {
24099
+ setTimeout(resolve9, ms);
24100
+ });
24101
+ }
24102
+ async function withTaishiLibraryIndexLock(ledgerHome, fn) {
24103
+ const indexPath = taishiLibraryIndexPath(ledgerHome);
24104
+ ensureRealDirectoryTree(ledgerHome, dirname8(indexPath));
24105
+ const lockPath = join19(dirname8(indexPath), LIBRARY_INDEX_LOCK_NAME);
24106
+ assertLedgerFileInsideHome(lockPath, ledgerHome);
24107
+ const startedAt = Date.now();
24108
+ while (true) {
24109
+ try {
24110
+ const handle = await open3(lockPath, "wx");
24111
+ try {
24112
+ await handle.writeFile(`${process.pid}
24113
+ `, "utf8");
24114
+ return await fn();
24115
+ } finally {
24116
+ await handle.close().catch(() => void 0);
24117
+ await unlink4(lockPath).catch(() => void 0);
24118
+ }
24119
+ } catch (error) {
24120
+ const code = error instanceof Error && "code" in error ? error.code : void 0;
24121
+ if (code !== "EEXIST") throw error;
24122
+ if (Date.now() - startedAt > LIBRARY_INDEX_LOCK_TIMEOUT_MS) {
24123
+ throw new Error(
24124
+ `taishi library-index lock timeout after ${LIBRARY_INDEX_LOCK_TIMEOUT_MS}ms: ${lockPath}`
24125
+ );
24126
+ }
24127
+ await sleep(LIBRARY_INDEX_LOCK_RETRY_MS);
23810
24128
  }
23811
- return { flag: "model", consume: 2, value };
24129
+ }
24130
+ }
24131
+ function taishiLibraryIndexPath(ledgerHome) {
24132
+ return join19(ledgerHome, "taishi", "library-index.json");
24133
+ }
24134
+ function rowFromIssueMetricsPage(page) {
24135
+ return {
24136
+ projectRoot: page.projectRoot,
24137
+ // exactOptionalPropertyTypes: only materialize when page carries it.
24138
+ ...page.issueNumber === void 0 ? {} : { issueNumber: page.issueNumber },
24139
+ totalElapsedMs: page.totalElapsedMs,
24140
+ changedLines: page.changedLines,
24141
+ msPerKLines: page.msPerKLines,
24142
+ lastActivityAt: page.lastActivityAt
24143
+ };
24144
+ }
24145
+ function sortRows(rows) {
24146
+ return [...rows].sort((a, b) => {
24147
+ const byRoot = a.projectRoot.localeCompare(b.projectRoot);
24148
+ if (byRoot !== 0) return byRoot;
24149
+ const aNum = a.issueNumber;
24150
+ const bNum = b.issueNumber;
24151
+ if (aNum === void 0 && bNum === void 0) return 0;
24152
+ if (aNum === void 0) return 1;
24153
+ if (bNum === void 0) return -1;
24154
+ return aNum - bNum;
24155
+ });
24156
+ }
24157
+ function buildTaishiLibraryIndexPage(rows) {
24158
+ return {
24159
+ kind: "taishi-library-index",
24160
+ rows: sortRows(rows)
24161
+ };
24162
+ }
24163
+ function findTaishiLibraryIndexRow(index, issueNumber) {
24164
+ if (index === void 0) return void 0;
24165
+ return index.rows.find((row) => row.issueNumber === issueNumber);
24166
+ }
24167
+ function upsertTaishiLibraryIndexRows(existing, upserts) {
24168
+ const byRoot = /* @__PURE__ */ new Map();
24169
+ const rootByIssue = /* @__PURE__ */ new Map();
24170
+ const ingest = (row) => {
24171
+ if (row.issueNumber !== void 0) {
24172
+ const priorRoot = rootByIssue.get(row.issueNumber);
24173
+ if (priorRoot !== void 0 && priorRoot !== row.projectRoot) {
24174
+ byRoot.delete(priorRoot);
24175
+ }
24176
+ }
24177
+ const prior = byRoot.get(row.projectRoot);
24178
+ if (prior !== void 0 && prior.issueNumber !== void 0 && prior.issueNumber !== row.issueNumber) {
24179
+ rootByIssue.delete(prior.issueNumber);
24180
+ }
24181
+ byRoot.set(row.projectRoot, row);
24182
+ if (row.issueNumber !== void 0) {
24183
+ rootByIssue.set(row.issueNumber, row.projectRoot);
24184
+ }
24185
+ };
24186
+ if (existing !== void 0) {
24187
+ for (const row of existing.rows) {
24188
+ ingest(row);
24189
+ }
24190
+ }
24191
+ for (const row of upserts) {
24192
+ ingest(row);
24193
+ }
24194
+ return buildTaishiLibraryIndexPage([...byRoot.values()]);
24195
+ }
24196
+ async function readTaishiLibraryIndexPage(ledgerHome) {
24197
+ const path = taishiLibraryIndexPath(ledgerHome);
24198
+ let raw;
24199
+ try {
24200
+ raw = await readFile10(path, "utf8");
24201
+ } catch (error) {
24202
+ if (error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
24203
+ return void 0;
24204
+ }
24205
+ throw error;
24206
+ }
24207
+ return JSON.parse(raw);
24208
+ }
24209
+ async function writeTaishiLibraryIndexPage(ledgerHome, page) {
24210
+ const path = taishiLibraryIndexPath(ledgerHome);
24211
+ ensureRealDirectoryTree(ledgerHome, dirname8(path));
24212
+ assertLedgerFileInsideHome(path, ledgerHome);
24213
+ await writeFileAtomically(path, `${JSON.stringify(page, null, 2)}
24214
+ `);
24215
+ return path;
24216
+ }
24217
+ async function mergeTaishiLibraryIndexRows(ledgerHome, upserts) {
24218
+ return withTaishiLibraryIndexLock(ledgerHome, async () => {
24219
+ const existing = await readTaishiLibraryIndexPage(ledgerHome);
24220
+ const index = upsertTaishiLibraryIndexRows(existing, upserts);
24221
+ const indexPath = await writeTaishiLibraryIndexPage(ledgerHome, index);
24222
+ return { index, indexPath };
24223
+ });
24224
+ }
24225
+ var LIBRARY_INDEX_LOCK_NAME, LIBRARY_INDEX_LOCK_TIMEOUT_MS, LIBRARY_INDEX_LOCK_RETRY_MS;
24226
+ var init_taishi_index = __esm({
24227
+ "src/taishi-index.ts"() {
24228
+ "use strict";
24229
+ init_atomic_write();
24230
+ init_activation_ledger_topology();
24231
+ LIBRARY_INDEX_LOCK_NAME = ".library-index.lock";
24232
+ LIBRARY_INDEX_LOCK_TIMEOUT_MS = 3e4;
24233
+ LIBRARY_INDEX_LOCK_RETRY_MS = 15;
24234
+ }
24235
+ });
24236
+
24237
+ // src/taishi-median.ts
24238
+ function medianNumber(values) {
24239
+ if (values.length === 0) return void 0;
24240
+ const sorted = [...values].sort((a, b) => a - b);
24241
+ const mid = Math.floor(sorted.length / 2);
24242
+ if (sorted.length % 2 === 1) {
24243
+ return sorted[mid];
24244
+ }
24245
+ return (sorted[mid - 1] + sorted[mid]) / 2;
24246
+ }
24247
+ var init_taishi_median = __esm({
24248
+ "src/taishi-median.ts"() {
24249
+ "use strict";
24250
+ }
24251
+ });
24252
+
24253
+ // src/taishi-cohort.ts
24254
+ function presentMetric(value) {
24255
+ return { status: "present", value };
24256
+ }
24257
+ function rateMetric(numerator, denominator) {
24258
+ if (denominator === 0) return ABSENT;
24259
+ return presentMetric(numerator / denominator);
24260
+ }
24261
+ function optionalMedian(values) {
24262
+ const median = medianNumber(values);
24263
+ return median === void 0 ? ABSENT : presentMetric(median);
24264
+ }
24265
+ function emptyRoleAccum() {
24266
+ return {
24267
+ convergenceRounds: [],
24268
+ firstPassLaneCount: 0,
24269
+ appearanceLaneCount: 0,
24270
+ successCount: 0,
24271
+ successEligibleCount: 0
24272
+ };
24273
+ }
24274
+ function absorbRole(accum, stats) {
24275
+ accum.convergenceRounds.push(...stats.convergenceRounds);
24276
+ accum.firstPassLaneCount += stats.firstPassLaneCount;
24277
+ accum.appearanceLaneCount += stats.appearanceLaneCount;
24278
+ accum.successCount += stats.successCount;
24279
+ accum.successEligibleCount += stats.successEligibleCount;
24280
+ }
24281
+ function finishRole(role, accum) {
24282
+ return {
24283
+ role,
24284
+ convergenceRounds: accum.convergenceRounds,
24285
+ convergenceRoundsMedian: optionalMedian(accum.convergenceRounds),
24286
+ firstPassRate: rateMetric(accum.firstPassLaneCount, accum.appearanceLaneCount),
24287
+ successRate: rateMetric(accum.successCount, accum.successEligibleCount)
24288
+ };
24289
+ }
24290
+ async function aggregateGroup(index, input, ensureIssuePage) {
24291
+ const issueEntries = [];
24292
+ const roleAccums = /* @__PURE__ */ new Map();
24293
+ let reworkWallMs = 0;
24294
+ let totalWallMs = 0;
24295
+ let hasReworkSample = false;
24296
+ const legWalls = [];
24297
+ for (const issueNumber of input.issues) {
24298
+ const row = findTaishiLibraryIndexRow(index, issueNumber);
24299
+ if (row === void 0) {
24300
+ issueEntries.push({ issueNumber, status: "absent" });
24301
+ continue;
24302
+ }
24303
+ const page = await ensureIssuePage({
24304
+ projectRoot: row.projectRoot,
24305
+ issueNumber
24306
+ });
24307
+ issueEntries.push({
24308
+ issueNumber,
24309
+ status: "present",
24310
+ projectRoot: row.projectRoot
24311
+ });
24312
+ const acceptance = page.acceptanceSuccessRework;
24313
+ if (acceptance !== void 0) {
24314
+ for (const roleStats of acceptance.byRole) {
24315
+ const accum = roleAccums.get(roleStats.role) ?? emptyRoleAccum();
24316
+ absorbRole(accum, roleStats);
24317
+ roleAccums.set(roleStats.role, accum);
24318
+ }
24319
+ reworkWallMs += acceptance.rework.reworkWallMs;
24320
+ totalWallMs += acceptance.rework.totalWallMs;
24321
+ hasReworkSample = true;
24322
+ }
24323
+ const legWallClock = page.legWallClock;
24324
+ if (legWallClock !== void 0) {
24325
+ for (const leg of legWallClock.ranking) {
24326
+ legWalls.push(leg.wallMs);
24327
+ }
24328
+ }
24329
+ }
24330
+ const byRole = [...roleAccums.keys()].sort((a, b) => a.localeCompare(b)).map((role) => finishRole(role, roleAccums.get(role)));
24331
+ return {
24332
+ groupLabel: input.groupLabel,
24333
+ issues: issueEntries,
24334
+ byRole,
24335
+ reworkRatio: hasReworkSample ? rateMetric(reworkWallMs, totalWallMs) : ABSENT,
24336
+ medianWallMs: optionalMedian(legWalls)
24337
+ };
24338
+ }
24339
+ async function runTaishiCohortMode(ledgerHome, input, ensureIssuePage) {
24340
+ const index = await readTaishiLibraryIndexPage(ledgerHome);
24341
+ const group0 = await aggregateGroup(index, input.groups[0], ensureIssuePage);
24342
+ const group1 = await aggregateGroup(index, input.groups[1], ensureIssuePage);
24343
+ return {
24344
+ mode: "cohort",
24345
+ groups: [group0, group1]
24346
+ };
24347
+ }
24348
+ var ABSENT;
24349
+ var init_taishi_cohort = __esm({
24350
+ "src/taishi-cohort.ts"() {
24351
+ "use strict";
24352
+ init_taishi_index();
24353
+ init_taishi_median();
24354
+ ABSENT = { status: "absent" };
24355
+ }
24356
+ });
24357
+
24358
+ // src/ledger-session-read.ts
24359
+ import { readFile as readFile11 } from "node:fs/promises";
24360
+ function isRecord6(value) {
24361
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24362
+ }
24363
+ async function readLedgerSessionJsonl(path) {
24364
+ const text = await readFile11(path, "utf8");
24365
+ const lines = text.split("\n");
24366
+ const rows = [];
24367
+ for (let index = 0; index < lines.length; index += 1) {
24368
+ const line2 = lines[index];
24369
+ if (!line2.trim()) continue;
24370
+ let row;
24371
+ try {
24372
+ row = JSON.parse(line2);
24373
+ } catch (error) {
24374
+ if (!(error instanceof SyntaxError)) throw error;
24375
+ const completedByTerminator = index < lines.length - 1;
24376
+ if (completedByTerminator) {
24377
+ throw new LedgerSessionJsonlError(
24378
+ `malformed JSONL record in ${path} at line ${index + 1}: ${error.message}`,
24379
+ { path, line: index + 1, prefixRows: rows }
24380
+ );
24381
+ }
24382
+ break;
24383
+ }
24384
+ if (!isRecord6(row)) {
24385
+ const kind = row === null ? "null" : Array.isArray(row) ? "array" : typeof row;
24386
+ throw new LedgerSessionJsonlError(
24387
+ `complete non-object JSONL record in ${path} at line ${index + 1}: expected object, got ${kind}`,
24388
+ { path, line: index + 1, prefixRows: rows }
24389
+ );
24390
+ }
24391
+ rows.push(row);
24392
+ }
24393
+ return rows;
24394
+ }
24395
+ function extractSessionTimestampSpan(rows) {
24396
+ let startedAt;
24397
+ let endedAt;
24398
+ for (const row of rows) {
24399
+ if (typeof row.timestamp !== "string" || !row.timestamp) continue;
24400
+ if (startedAt === void 0) startedAt = row.timestamp;
24401
+ endedAt = row.timestamp;
24402
+ }
24403
+ return {
24404
+ ...startedAt !== void 0 ? { startedAt } : {},
24405
+ ...endedAt !== void 0 ? { endedAt } : {}
24406
+ };
24407
+ }
24408
+ function extractSessionModelSequence(rows) {
24409
+ const seen = /* @__PURE__ */ new Set();
24410
+ const ordered = [];
24411
+ const push = (raw) => {
24412
+ const model = raw.trim();
24413
+ if (model === "" || seen.has(model)) return;
24414
+ seen.add(model);
24415
+ ordered.push(model);
24416
+ };
24417
+ for (const row of rows) {
24418
+ if (row.type === "model_change" && typeof row.modelId === "string") {
24419
+ push(row.modelId);
24420
+ }
24421
+ const message = isRecord6(row.message) ? row.message : void 0;
24422
+ if (message?.role === "assistant" && typeof message.model === "string") {
24423
+ push(message.model);
24424
+ }
24425
+ }
24426
+ return ordered;
24427
+ }
24428
+ function bashCommandFirstLine(command) {
24429
+ const match = /^[^\r\n]*/.exec(command);
24430
+ return match?.[0] ?? "";
24431
+ }
24432
+ function extractSessionToolIntervals(rows) {
24433
+ const order = [];
24434
+ const openById = /* @__PURE__ */ new Map();
24435
+ for (const row of rows) {
24436
+ const rowTimestamp = typeof row.timestamp === "string" ? row.timestamp : void 0;
24437
+ const message = isRecord6(row.message) ? row.message : void 0;
24438
+ if (message?.role === "assistant" && Array.isArray(message.content)) {
24439
+ const callTimestamp = typeof message.timestamp === "string" && message.timestamp ? message.timestamp : rowTimestamp;
24440
+ for (const part of message.content) {
24441
+ if (!isRecord6(part) || part.type !== "toolCall") continue;
24442
+ if (typeof part.id !== "string" || part.id.length === 0) {
24443
+ throw new Error("toolCall frame missing string id");
24444
+ }
24445
+ if (typeof part.name !== "string" || part.name.length === 0) {
24446
+ throw new Error(`toolCall ${part.id} missing string name`);
24447
+ }
24448
+ if (callTimestamp === void 0 || callTimestamp.length === 0) {
24449
+ throw new Error(`toolCall ${part.id} missing timestamp`);
24450
+ }
24451
+ if (openById.has(part.id)) {
24452
+ throw new Error(`duplicate toolCall id ${part.id}`);
24453
+ }
24454
+ const args = isRecord6(part.arguments) ? part.arguments : void 0;
24455
+ const command = part.name === "bash" && args !== void 0 && typeof args.command === "string" ? bashCommandFirstLine(args.command) : void 0;
24456
+ const interval = {
24457
+ toolCallId: part.id,
24458
+ toolName: part.name,
24459
+ startedAt: callTimestamp,
24460
+ ...command !== void 0 ? { command } : {}
24461
+ };
24462
+ order.push(interval);
24463
+ openById.set(part.id, interval);
24464
+ }
24465
+ }
24466
+ if (message?.role === "toolResult") {
24467
+ if (typeof message.toolCallId !== "string" || message.toolCallId.length === 0) {
24468
+ throw new Error("toolResult frame missing string toolCallId");
24469
+ }
24470
+ const resultTimestamp = typeof message.timestamp === "string" && message.timestamp ? message.timestamp : rowTimestamp;
24471
+ if (resultTimestamp === void 0 || resultTimestamp.length === 0) {
24472
+ throw new Error(`toolResult ${message.toolCallId} missing timestamp`);
24473
+ }
24474
+ const open4 = openById.get(message.toolCallId);
24475
+ if (open4 === void 0) {
24476
+ const toolName = typeof message.toolName === "string" && message.toolName.length > 0 ? message.toolName : "unknown";
24477
+ order.push({
24478
+ toolCallId: message.toolCallId,
24479
+ toolName,
24480
+ startedAt: resultTimestamp,
24481
+ endedAt: resultTimestamp
24482
+ });
24483
+ continue;
24484
+ }
24485
+ if (open4.endedAt !== void 0) {
24486
+ throw new Error(`duplicate toolResult for toolCallId ${message.toolCallId}`);
24487
+ }
24488
+ open4.endedAt = resultTimestamp;
24489
+ }
24490
+ }
24491
+ return order.map((interval) => {
24492
+ const base = {
24493
+ toolCallId: interval.toolCallId,
24494
+ toolName: interval.toolName,
24495
+ startedAt: interval.startedAt,
24496
+ ...interval.command !== void 0 ? { command: interval.command } : {}
24497
+ };
24498
+ return interval.endedAt === void 0 ? base : { ...base, endedAt: interval.endedAt };
24499
+ });
24500
+ }
24501
+ var LedgerSessionJsonlError;
24502
+ var init_ledger_session_read = __esm({
24503
+ "src/ledger-session-read.ts"() {
24504
+ "use strict";
24505
+ LedgerSessionJsonlError = class extends Error {
24506
+ path;
24507
+ line;
24508
+ prefixRows;
24509
+ constructor(message, init) {
24510
+ super(message);
24511
+ this.name = "LedgerSessionJsonlError";
24512
+ this.path = init.path;
24513
+ this.line = init.line;
24514
+ this.prefixRows = init.prefixRows;
24515
+ }
24516
+ };
24517
+ }
24518
+ });
24519
+
24520
+ // src/run-terminal-artifacts.ts
24521
+ import { readdir as readdir4, readFile as readFile12 } from "node:fs/promises";
24522
+ import { basename as basename4, dirname as dirname9, join as join20 } from "node:path";
24523
+ function isMissingPathError3(error) {
24524
+ return error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
24525
+ }
24526
+ function errorText2(error) {
24527
+ return error instanceof Error ? error.message : String(error);
24528
+ }
24529
+ function isRecord7(value) {
24530
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24531
+ }
24532
+ function readUsableTerminalArtifactBody(body) {
24533
+ if (body === null) {
24534
+ return { ok: false, reason: "terminal artifact JSON value is null" };
24535
+ }
24536
+ if (!isRecord7(body)) {
24537
+ return {
24538
+ ok: false,
24539
+ reason: `terminal artifact JSON value is not a typed object (${Array.isArray(body) ? "array" : typeof body})`
24540
+ };
24541
+ }
24542
+ if (typeof body.role !== "string" || body.role.trim() === "") {
24543
+ return {
24544
+ ok: false,
24545
+ reason: "terminal artifact missing nonblank producer-owned role field"
24546
+ };
24547
+ }
24548
+ return { ok: true, body };
24549
+ }
24550
+ async function readTerminalArtifactAtPath(path, file) {
24551
+ let raw;
24552
+ try {
24553
+ raw = await readFile12(path, "utf8");
24554
+ } catch (error) {
24555
+ if (isMissingPathError3(error)) return void 0;
24556
+ return {
24557
+ status: "unreadable",
24558
+ file,
24559
+ path,
24560
+ reason: errorText2(error)
24561
+ };
24562
+ }
24563
+ let parsed;
24564
+ try {
24565
+ parsed = JSON.parse(raw);
24566
+ } catch (error) {
24567
+ return {
24568
+ status: "unreadable",
24569
+ file,
24570
+ path,
24571
+ reason: error instanceof Error ? error.message : `terminal artifact JSON parse failed: ${String(error)}`
24572
+ };
24573
+ }
24574
+ const usable = readUsableTerminalArtifactBody(parsed);
24575
+ if (!usable.ok) {
24576
+ return {
24577
+ status: "unreadable",
24578
+ file,
24579
+ path,
24580
+ reason: usable.reason
24581
+ };
24582
+ }
24583
+ return { status: "present", file, path, body: usable.body };
24584
+ }
24585
+ async function listUniqueErrorFallbackPaths(directories) {
24586
+ const found = [];
24587
+ for (const dir of directories) {
24588
+ let names;
24589
+ try {
24590
+ names = await readdir4(dir);
24591
+ } catch (error) {
24592
+ if (isMissingPathError3(error)) continue;
24593
+ throw error;
24594
+ }
24595
+ for (const name of names.sort((a, b) => a.localeCompare(b))) {
24596
+ if (!UNIQUE_ERROR_FALLBACK_NAME.test(name)) continue;
24597
+ found.push(join20(dir, name));
24598
+ }
24599
+ }
24600
+ return found;
24601
+ }
24602
+ function runIdFromRunDirectory(runDirectory) {
24603
+ const name = basename4(runDirectory);
24604
+ const at = name.lastIndexOf("@");
24605
+ if (at <= 0 || at === name.length - 1) return void 0;
24606
+ return name.slice(0, at);
24607
+ }
24608
+ function presentUniqueFallbackBoundToRun(body, expectedRunId) {
24609
+ if (expectedRunId === void 0) return false;
24610
+ return typeof body.runId === "string" && body.runId === expectedRunId;
24611
+ }
24612
+ async function readRunTerminalArtifact(runDirectory) {
24613
+ const artifactsDir = join20(runDirectory, "artifacts");
24614
+ for (const file of RUN_TERMINAL_ARTIFACT_FILES) {
24615
+ const path = join20(artifactsDir, file);
24616
+ const read3 = await readTerminalArtifactAtPath(path, file);
24617
+ if (read3 !== void 0) return read3;
24618
+ }
24619
+ for (const relative3 of RUN_TERMINAL_ERROR_FALLBACK_RELATIVE_PATHS) {
24620
+ const path = join20(runDirectory, relative3);
24621
+ const read3 = await readTerminalArtifactAtPath(path, "error.json");
24622
+ if (read3 !== void 0) return read3;
24623
+ }
24624
+ for (const path of await listUniqueErrorFallbackPaths([artifactsDir, runDirectory])) {
24625
+ const read3 = await readTerminalArtifactAtPath(path, "error.json");
24626
+ if (read3 !== void 0) return read3;
24627
+ }
24628
+ const expectedRunId = runIdFromRunDirectory(runDirectory);
24629
+ for (const path of await listUniqueErrorFallbackPaths([dirname9(runDirectory)])) {
24630
+ const read3 = await readTerminalArtifactAtPath(path, "error.json");
24631
+ if (read3 === void 0) continue;
24632
+ if (read3.status === "present") {
24633
+ if (!presentUniqueFallbackBoundToRun(read3.body, expectedRunId)) continue;
24634
+ return read3;
24635
+ }
24636
+ }
24637
+ return { status: "absent" };
24638
+ }
24639
+ var RUN_TERMINAL_ARTIFACT_FILES, RUN_TERMINAL_ERROR_FALLBACK_RELATIVE_PATHS, UNIQUE_ERROR_FALLBACK_NAME;
24640
+ var init_run_terminal_artifacts = __esm({
24641
+ "src/run-terminal-artifacts.ts"() {
24642
+ "use strict";
24643
+ RUN_TERMINAL_ARTIFACT_FILES = [
24644
+ "report.json",
24645
+ "error.json",
24646
+ "audit-incomplete.json"
24647
+ ];
24648
+ RUN_TERMINAL_ERROR_FALLBACK_RELATIVE_PATHS = [
24649
+ "artifacts/error.settlement.json",
24650
+ "error.settlement.json"
24651
+ ];
24652
+ UNIQUE_ERROR_FALLBACK_NAME = /^error\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.json$/i;
24653
+ }
24654
+ });
24655
+
24656
+ // src/taishi-ledger.ts
24657
+ import { readdir as readdir5, readFile as readFile13 } from "node:fs/promises";
24658
+ import { join as join21 } from "node:path";
24659
+ function isMissingPathError4(error) {
24660
+ return error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
24661
+ }
24662
+ function errorText3(error) {
24663
+ return error instanceof Error ? error.message : String(error);
24664
+ }
24665
+ function isRecord8(value) {
24666
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24667
+ }
24668
+ async function readExistingRunLifecycleState(runDirectory) {
24669
+ try {
24670
+ const raw = JSON.parse(
24671
+ await readFile13(join21(runDirectory, "run-state.json"), "utf8")
24672
+ );
24673
+ if (!isRecord8(raw) || typeof raw.state !== "string") return void 0;
24674
+ return raw.state;
24675
+ } catch {
24676
+ return void 0;
24677
+ }
24678
+ }
24679
+ function parseRunDirectoryName(name) {
24680
+ const at = name.lastIndexOf("@");
24681
+ if (at <= 0 || at === name.length - 1) return void 0;
24682
+ return { runId: name.slice(0, at), role: name.slice(at + 1) };
24683
+ }
24684
+ async function readInvocationScopeFields(runDirectory) {
24685
+ let raw;
24686
+ try {
24687
+ raw = await readFile13(join21(runDirectory, "invocation.json"), "utf8");
24688
+ } catch (error) {
24689
+ if (isMissingPathError4(error)) return void 0;
24690
+ throw error;
24691
+ }
24692
+ const parsed = JSON.parse(raw);
24693
+ if (!isRecord8(parsed)) return void 0;
24694
+ if (typeof parsed.projectRoot !== "string" || parsed.projectRoot.trim() === "") {
24695
+ return void 0;
24696
+ }
24697
+ const projectRoot = parsed.projectRoot;
24698
+ if (typeof parsed.ticketNumber === "number" && Number.isInteger(parsed.ticketNumber) && parsed.ticketNumber >= 1) {
24699
+ return { projectRoot, ticketNumber: parsed.ticketNumber };
24700
+ }
24701
+ return { projectRoot };
24702
+ }
24703
+ function decideIssueScope(input) {
24704
+ const projectRootMatch = input.runProjectRootIdentity === input.scopeProjectRootIdentity;
24705
+ if (input.scopeTicketNumber !== void 0 && input.runTicketNumber !== void 0) {
24706
+ if (input.runTicketNumber === input.scopeTicketNumber) {
24707
+ return { inScope: true, conflict: !projectRootMatch };
24708
+ }
24709
+ return { inScope: false, conflict: false };
24710
+ }
24711
+ return { inScope: projectRootMatch, conflict: false };
24712
+ }
24713
+ async function resolveSessionFile(runDirectory) {
24714
+ try {
24715
+ const raw = await readFile13(join21(runDirectory, "invocation.json"), "utf8");
24716
+ const parsed = JSON.parse(raw);
24717
+ if (isRecord8(parsed) && typeof parsed.sessionFile === "string" && parsed.sessionFile.trim() !== "") {
24718
+ return parsed.sessionFile;
24719
+ }
24720
+ } catch (error) {
24721
+ if (!isMissingPathError4(error)) throw error;
24722
+ }
24723
+ return join21(runDirectory, "session", "session.jsonl");
24724
+ }
24725
+ async function classifyScopedRun(input) {
24726
+ const missingSources = [];
24727
+ const reasons = [];
24728
+ let frameSpan;
24729
+ let toolIntervals;
24730
+ let terminal;
24731
+ let models = [];
24732
+ let partialFirstFrameAt = { status: "absent" };
24733
+ let partialLastFrameAt = { status: "absent" };
24734
+ const sessionFile = await resolveSessionFile(input.runDirectory);
24735
+ let rows;
24736
+ try {
24737
+ rows = await readLedgerSessionJsonl(sessionFile);
24738
+ models = extractSessionModelSequence(rows);
24739
+ const span = extractSessionTimestampSpan(rows);
24740
+ if (span.startedAt === void 0 || span.endedAt === void 0) {
24741
+ missingSources.push("session-timeline");
24742
+ reasons.push("session timeline has no usable timestamps");
24743
+ if (span.startedAt !== void 0) {
24744
+ partialFirstFrameAt = { status: "present", at: span.startedAt };
24745
+ }
24746
+ if (span.endedAt !== void 0) {
24747
+ partialLastFrameAt = { status: "present", at: span.endedAt };
24748
+ }
24749
+ } else {
24750
+ const startedMs = Date.parse(span.startedAt);
24751
+ const endedMs = Date.parse(span.endedAt);
24752
+ if (!Number.isFinite(startedMs) || !Number.isFinite(endedMs)) {
24753
+ missingSources.push("session-timeline");
24754
+ reasons.push("session timeline timestamps are not parseable instants");
24755
+ partialFirstFrameAt = { status: "present", at: span.startedAt };
24756
+ partialLastFrameAt = { status: "present", at: span.endedAt };
24757
+ } else if (endedMs < startedMs) {
24758
+ missingSources.push("session-timeline");
24759
+ reasons.push("session timeline end is earlier than start");
24760
+ partialFirstFrameAt = { status: "present", at: span.startedAt };
24761
+ partialLastFrameAt = { status: "present", at: span.endedAt };
24762
+ } else {
24763
+ frameSpan = { startedAt: span.startedAt, endedAt: span.endedAt };
24764
+ }
24765
+ }
24766
+ } catch (error) {
24767
+ missingSources.push("session-timeline");
24768
+ reasons.push(errorText3(error));
24769
+ if (error instanceof LedgerSessionJsonlError) {
24770
+ const span = extractSessionTimestampSpan(error.prefixRows);
24771
+ if (span.startedAt !== void 0) {
24772
+ partialFirstFrameAt = { status: "present", at: span.startedAt };
24773
+ }
24774
+ if (span.endedAt !== void 0) {
24775
+ partialLastFrameAt = { status: "present", at: span.endedAt };
24776
+ }
24777
+ models = extractSessionModelSequence(error.prefixRows);
24778
+ }
24779
+ }
24780
+ if (rows !== void 0 && !missingSources.includes("session-timeline")) {
24781
+ try {
24782
+ toolIntervals = extractSessionToolIntervals(rows);
24783
+ } catch (error) {
24784
+ missingSources.push("tool-association");
24785
+ reasons.push(errorText3(error));
24786
+ }
24787
+ }
24788
+ try {
24789
+ const artifact = await readRunTerminalArtifact(input.runDirectory);
24790
+ if (artifact.status === "unreadable") {
24791
+ missingSources.push("terminal-artifact");
24792
+ reasons.push(`${artifact.file}: ${artifact.reason}`);
24793
+ } else if (artifact.status === "absent") {
24794
+ const lifecycle = await readExistingRunLifecycleState(input.runDirectory);
24795
+ if (lifecycle !== void 0 && LIVE_RUN_STATES.has(lifecycle)) {
24796
+ return { kind: "live" };
24797
+ }
24798
+ terminal = { status: "absent" };
24799
+ } else {
24800
+ terminal = {
24801
+ status: "present",
24802
+ file: artifact.file,
24803
+ body: artifact.body,
24804
+ role: artifact.body.role
24805
+ };
24806
+ }
24807
+ } catch (error) {
24808
+ missingSources.push("terminal-artifact");
24809
+ reasons.push(errorText3(error));
24810
+ }
24811
+ if (missingSources.length > 0) {
24812
+ const firstFrameAt = frameSpan !== void 0 ? { status: "present", at: frameSpan.startedAt } : partialFirstFrameAt;
24813
+ const lastFrameAt = frameSpan !== void 0 ? { status: "present", at: frameSpan.endedAt } : partialLastFrameAt;
24814
+ return {
24815
+ kind: "unreadable",
24816
+ entry: {
24817
+ runId: input.runId,
24818
+ book: input.book,
24819
+ missingSources,
24820
+ reason: reasons.join("; "),
24821
+ firstFrameAt,
24822
+ lastFrameAt
24823
+ }
24824
+ };
24825
+ }
24826
+ if (frameSpan === void 0 || toolIntervals === void 0 || terminal === void 0) {
24827
+ throw new Error(
24828
+ `classifyScopedRun internal invariant: missing retained facts for ${input.runId}`
24829
+ );
24830
+ }
24831
+ return {
24832
+ kind: "readable",
24833
+ facts: {
24834
+ runId: input.runId,
24835
+ book: input.book,
24836
+ role: input.role,
24837
+ frameSpan,
24838
+ toolIntervals,
24839
+ terminal,
24840
+ models
24841
+ }
24842
+ };
24843
+ }
24844
+ async function scanTaishiIssueRuns(input) {
24845
+ const ledgerHome = resolveActivationLedgerHome();
24846
+ const scopeIdentity = physicalPathIdentity(input.projectRoot);
24847
+ const scopeTicketNumber = input.ticketNumber;
24848
+ const booksRoot = join21(ledgerHome, "books");
24849
+ let bookNames;
24850
+ try {
24851
+ const entries = await readdir5(booksRoot, { withFileTypes: true });
24852
+ bookNames = entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();
24853
+ } catch (error) {
24854
+ if (isMissingPathError4(error)) {
24855
+ return { runs: [], unreadable: [], scopeConflicts: [] };
24856
+ }
24857
+ throw error;
24858
+ }
24859
+ const runs = [];
24860
+ const unreadable = [];
24861
+ const scopeConflicts = [];
24862
+ for (const book of bookNames) {
24863
+ const runsDir = join21(booksRoot, book, "runs");
24864
+ let runNames;
24865
+ try {
24866
+ const entries = await readdir5(runsDir, { withFileTypes: true });
24867
+ runNames = entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();
24868
+ } catch (error) {
24869
+ if (isMissingPathError4(error)) continue;
24870
+ throw error;
24871
+ }
24872
+ for (const runName of runNames) {
24873
+ const parsed = parseRunDirectoryName(runName);
24874
+ if (parsed === void 0) continue;
24875
+ const runDirectory = join21(runsDir, runName);
24876
+ let scopeFields;
24877
+ try {
24878
+ scopeFields = await readInvocationScopeFields(runDirectory);
24879
+ } catch (error) {
24880
+ if (error instanceof SyntaxError) continue;
24881
+ throw error;
24882
+ }
24883
+ if (scopeFields === void 0) continue;
24884
+ const runProjectRootIdentity = physicalPathIdentity(scopeFields.projectRoot);
24885
+ const decision = decideIssueScope({
24886
+ scopeProjectRootIdentity: scopeIdentity,
24887
+ scopeTicketNumber,
24888
+ runProjectRootIdentity,
24889
+ runTicketNumber: scopeFields.ticketNumber
24890
+ });
24891
+ if (!decision.inScope) continue;
24892
+ if (decision.conflict) {
24893
+ scopeConflicts.push({
24894
+ runId: parsed.runId,
24895
+ ticketNumber: scopeFields.ticketNumber,
24896
+ projectRoot: runProjectRootIdentity,
24897
+ fact: "typed-ticketNumber-over-projectRoot"
24898
+ });
24899
+ }
24900
+ const classified = await classifyScopedRun({
24901
+ book,
24902
+ runId: parsed.runId,
24903
+ role: parsed.role,
24904
+ runDirectory
24905
+ });
24906
+ if (classified.kind === "readable") runs.push(classified.facts);
24907
+ else if (classified.kind === "unreadable") unreadable.push(classified.entry);
24908
+ }
24909
+ }
24910
+ return {
24911
+ runs,
24912
+ unreadable,
24913
+ scopeConflicts
24914
+ };
24915
+ }
24916
+ var LIVE_RUN_STATES;
24917
+ var init_taishi_ledger = __esm({
24918
+ "src/taishi-ledger.ts"() {
24919
+ "use strict";
24920
+ init_activation_ledger_topology();
24921
+ init_ledger_session_read();
24922
+ init_run_terminal_artifacts();
24923
+ LIVE_RUN_STATES = /* @__PURE__ */ new Set(["admitted", "running", "resumable"]);
24924
+ }
24925
+ });
24926
+
24927
+ // src/taishi-metric-families/acceptance-success-rework.ts
24928
+ function isRecord9(value) {
24929
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24930
+ }
24931
+ function wallMsFromSpan(span) {
24932
+ return Date.parse(span.endedAt) - Date.parse(span.startedAt);
24933
+ }
24934
+ function findCollectorGroups(body) {
24935
+ if (Array.isArray(body.groups)) return body.groups;
24936
+ const receipt = body.receipt;
24937
+ if (isRecord9(receipt) && Array.isArray(receipt.groups)) return receipt.groups;
24938
+ const outcome = body.outcome;
24939
+ if (isRecord9(outcome)) {
24940
+ const facts = outcome.decisiveFacts;
24941
+ if (isRecord9(facts) && Array.isArray(facts.groups)) return facts.groups;
24942
+ }
24943
+ return void 0;
24944
+ }
24945
+ function extractStatus(body) {
24946
+ const outcome = body.outcome;
24947
+ if (isRecord9(outcome) && typeof outcome.status === "string" && outcome.status.trim() !== "") {
24948
+ return outcome.status;
24949
+ }
24950
+ const receipt = body.receipt;
24951
+ if (isRecord9(receipt) && typeof receipt.status === "string" && receipt.status.trim() !== "") {
24952
+ return receipt.status;
24953
+ }
24954
+ if (typeof body.status === "string" && body.status.trim() !== "") {
24955
+ return body.status;
24956
+ }
24957
+ return void 0;
24958
+ }
24959
+ function mapTerminal(role, terminal) {
24960
+ if (terminal.status === "absent") {
24961
+ return {
24962
+ terminalLabel: "no-receipt",
24963
+ accepted: false,
24964
+ success: false,
24965
+ successEligible: false,
24966
+ noReceipt: true
24967
+ };
24968
+ }
24969
+ const body = terminal.body;
24970
+ if (role === "collector") {
24971
+ const groups = findCollectorGroups(body);
24972
+ if (Array.isArray(groups)) {
24973
+ return {
24974
+ terminalLabel: "groups",
24975
+ accepted: true,
24976
+ success: true,
24977
+ successEligible: true,
24978
+ noReceipt: false
24979
+ };
24980
+ }
24981
+ return {
24982
+ terminalLabel: "non-accepted",
24983
+ accepted: false,
24984
+ success: false,
24985
+ successEligible: false,
24986
+ noReceipt: false
24987
+ };
24988
+ }
24989
+ const status = extractStatus(body);
24990
+ if (status === void 0) {
24991
+ return {
24992
+ terminalLabel: "non-accepted",
24993
+ accepted: false,
24994
+ success: false,
24995
+ successEligible: false,
24996
+ noReceipt: false
24997
+ };
24998
+ }
24999
+ const acceptedSet = ACCEPTED_STATUS[role];
25000
+ if (acceptedSet === void 0 || !acceptedSet.has(status)) {
25001
+ return {
25002
+ terminalLabel: status,
25003
+ accepted: false,
25004
+ success: false,
25005
+ successEligible: false,
25006
+ noReceipt: false
25007
+ };
25008
+ }
25009
+ const plannedDuty = WORKER_ROLES.has(role) && status === "planned";
25010
+ const successSet = SUCCESS_STATUS[role] ?? /* @__PURE__ */ new Set();
25011
+ const success = !plannedDuty && successSet.has(status);
25012
+ const successEligible = !plannedDuty;
25013
+ return {
25014
+ terminalLabel: status,
25015
+ accepted: true,
25016
+ success,
25017
+ successEligible,
25018
+ noReceipt: false
25019
+ };
25020
+ }
25021
+ function projectLegs(runs) {
25022
+ const sorted = [...runs].sort((a, b) => {
25023
+ if (a.book !== b.book) return a.book.localeCompare(b.book);
25024
+ if (a.role !== b.role) return a.role.localeCompare(b.role);
25025
+ if (a.frameSpan.startedAt !== b.frameSpan.startedAt) {
25026
+ return a.frameSpan.startedAt.localeCompare(b.frameSpan.startedAt);
25027
+ }
25028
+ return a.runId.localeCompare(b.runId);
25029
+ });
25030
+ const ordinalByKey = /* @__PURE__ */ new Map();
25031
+ const legs = [];
25032
+ for (const run of sorted) {
25033
+ const key = `${run.book}\0${run.role}`;
25034
+ const ordinal = (ordinalByKey.get(key) ?? 0) + 1;
25035
+ ordinalByKey.set(key, ordinal);
25036
+ const mapped = mapTerminal(run.role, run.terminal);
25037
+ legs.push({
25038
+ runId: run.runId,
25039
+ book: run.book,
25040
+ role: run.role,
25041
+ startedAt: run.frameSpan.startedAt,
25042
+ wallMs: wallMsFromSpan(run.frameSpan),
25043
+ terminalLabel: mapped.terminalLabel,
25044
+ accepted: mapped.accepted,
25045
+ success: mapped.success,
25046
+ successEligible: mapped.successEligible,
25047
+ noReceipt: mapped.noReceipt,
25048
+ ordinalInLaneRole: ordinal,
25049
+ rework: ordinal >= 2
25050
+ });
25051
+ }
25052
+ return legs.sort((a, b) => {
25053
+ if (a.book !== b.book) return a.book.localeCompare(b.book);
25054
+ if (a.role !== b.role) return a.role.localeCompare(b.role);
25055
+ return a.runId.localeCompare(b.runId);
25056
+ });
25057
+ }
25058
+ function aggregateByRole(legs) {
25059
+ const roles = [...new Set(legs.map((leg) => leg.role))].sort((a, b) => a.localeCompare(b));
25060
+ return roles.map((role) => {
25061
+ const roleLegs = legs.filter((leg) => leg.role === role);
25062
+ const acceptedCount = roleLegs.filter((leg) => leg.accepted).length;
25063
+ const successEligibleCount = roleLegs.filter((leg) => leg.successEligible).length;
25064
+ const successCount = roleLegs.filter((leg) => leg.success).length;
25065
+ const noReceiptCount = roleLegs.filter((leg) => leg.noReceipt).length;
25066
+ const byBook = /* @__PURE__ */ new Map();
25067
+ for (const leg of roleLegs) {
25068
+ const list = byBook.get(leg.book) ?? [];
25069
+ list.push(leg);
25070
+ byBook.set(leg.book, list);
25071
+ }
25072
+ const books = [...byBook.keys()].sort((a, b) => a.localeCompare(b));
25073
+ const convergenceRounds = [];
25074
+ let firstPassLaneCount = 0;
25075
+ for (const book of books) {
25076
+ const laneLegs = [...byBook.get(book)].sort((a, b) => {
25077
+ if (a.startedAt !== b.startedAt) return a.startedAt.localeCompare(b.startedAt);
25078
+ return a.runId.localeCompare(b.runId);
25079
+ });
25080
+ convergenceRounds.push(laneLegs.length);
25081
+ const first = laneLegs[0];
25082
+ if (first.accepted) firstPassLaneCount += 1;
25083
+ }
25084
+ const appearanceLaneCount = books.length;
25085
+ return {
25086
+ role,
25087
+ acceptedCount,
25088
+ successEligibleCount,
25089
+ successCount,
25090
+ noReceiptCount,
25091
+ successRate: successEligibleCount === 0 ? void 0 : successCount / successEligibleCount,
25092
+ appearanceLaneCount,
25093
+ firstPassLaneCount,
25094
+ firstPassRate: appearanceLaneCount === 0 ? void 0 : firstPassLaneCount / appearanceLaneCount,
25095
+ convergenceRounds,
25096
+ convergenceRoundsMedian: medianNumber(convergenceRounds)
25097
+ };
25098
+ });
25099
+ }
25100
+ function reworkLens(legs) {
25101
+ let reworkWallMs = 0;
25102
+ let totalWallMs = 0;
25103
+ let reworkLegCount = 0;
25104
+ for (const leg of legs) {
25105
+ totalWallMs += leg.wallMs;
25106
+ if (leg.rework) {
25107
+ reworkWallMs += leg.wallMs;
25108
+ reworkLegCount += 1;
25109
+ }
25110
+ }
25111
+ return {
25112
+ reworkWallMs,
25113
+ totalWallMs,
25114
+ reworkRatio: totalWallMs === 0 ? void 0 : reworkWallMs / totalWallMs,
25115
+ reworkLegCount,
25116
+ totalLegCount: legs.length
25117
+ };
25118
+ }
25119
+ function buildAcceptanceSuccessReworkSection(runs) {
25120
+ if (runs.length === 0) return void 0;
25121
+ const legs = projectLegs(runs);
25122
+ return {
25123
+ kind: "taishi-acceptance-success-rework",
25124
+ legs,
25125
+ byRole: aggregateByRole(legs),
25126
+ rework: reworkLens(legs)
25127
+ };
25128
+ }
25129
+ var WORKER_ROLES, ACCEPTED_STATUS, SUCCESS_STATUS, acceptanceSuccessReworkFamily, acceptance_success_rework_default;
25130
+ var init_acceptance_success_rework = __esm({
25131
+ "src/taishi-metric-families/acceptance-success-rework.ts"() {
25132
+ "use strict";
25133
+ init_taishi_median();
25134
+ WORKER_ROLES = /* @__PURE__ */ new Set(["coder", "fixer"]);
25135
+ ACCEPTED_STATUS = {
25136
+ coder: /* @__PURE__ */ new Set(["completed", "refused", "partially_completed", "unfinished", "planned"]),
25137
+ fixer: /* @__PURE__ */ new Set(["completed", "refused", "partially_completed", "unfinished", "planned"]),
25138
+ judge: /* @__PURE__ */ new Set(["converged", "continue", "escalate"]),
25139
+ reviewer: /* @__PURE__ */ new Set(["completed", "refused"]),
25140
+ doctor: /* @__PURE__ */ new Set(["completed", "refused"]),
25141
+ merger: /* @__PURE__ */ new Set(["completed", "escalate"])
25142
+ };
25143
+ SUCCESS_STATUS = {
25144
+ coder: /* @__PURE__ */ new Set(["completed"]),
25145
+ fixer: /* @__PURE__ */ new Set(["completed"]),
25146
+ // Judge: producing any of the three verdicts completes the duty.
25147
+ judge: /* @__PURE__ */ new Set(["converged", "continue", "escalate"]),
25148
+ reviewer: /* @__PURE__ */ new Set(["completed"]),
25149
+ doctor: /* @__PURE__ */ new Set(["completed"]),
25150
+ merger: /* @__PURE__ */ new Set(["completed"])
25151
+ };
25152
+ acceptanceSuccessReworkFamily = {
25153
+ id: "acceptance-success-rework",
25154
+ contribute(input) {
25155
+ const section = buildAcceptanceSuccessReworkSection(input.runs);
25156
+ if (section === void 0) return void 0;
25157
+ return { acceptanceSuccessRework: section };
25158
+ }
25159
+ };
25160
+ acceptance_success_rework_default = acceptanceSuccessReworkFamily;
25161
+ }
25162
+ });
25163
+
25164
+ // src/taishi-model-groups.ts
25165
+ function taishiModelGroupKey(models) {
25166
+ if (models.length === 0) return void 0;
25167
+ if (models.length === 1) return models[0];
25168
+ return `mixed:${models.join("+")}`;
25169
+ }
25170
+ function rate(numerator, denominator) {
25171
+ if (denominator === 0) return void 0;
25172
+ return numerator / denominator;
25173
+ }
25174
+ function displayNameFor(rawGroupKey, combinationMapping) {
25175
+ if (combinationMapping === void 0) return rawGroupKey;
25176
+ const aliased = combinationMapping[rawGroupKey];
25177
+ return aliased === void 0 ? rawGroupKey : aliased;
25178
+ }
25179
+ function sortUnreadable(unreadable) {
25180
+ return [...unreadable].sort((a, b) => {
25181
+ if (a.book !== b.book) return a.book.localeCompare(b.book);
25182
+ return a.runId.localeCompare(b.runId);
25183
+ });
25184
+ }
25185
+ function modelIdentityAbsentEntry(run) {
25186
+ return {
25187
+ runId: run.runId,
25188
+ book: run.book,
25189
+ missingSources: ["session-model"],
25190
+ reason: "session has no usable model identity",
25191
+ firstFrameAt: { status: "present", at: run.frameSpan.startedAt },
25192
+ // Readable legs already admitted a full span — retain end edge for lastActivityAt.
25193
+ lastFrameAt: { status: "present", at: run.frameSpan.endedAt }
25194
+ };
25195
+ }
25196
+ function buildTaishiModelGroupsPage(input) {
25197
+ const groupedRuns = [];
25198
+ const modelAbsent = [];
25199
+ for (const run of input.runs) {
25200
+ const rawGroupKey = taishiModelGroupKey(run.models);
25201
+ if (rawGroupKey === void 0) {
25202
+ modelAbsent.push(modelIdentityAbsentEntry(run));
25203
+ } else {
25204
+ groupedRuns.push({ run, rawGroupKey });
25205
+ }
25206
+ }
25207
+ const acceptance = buildAcceptanceSuccessReworkSection(
25208
+ groupedRuns.map(({ run }) => run)
25209
+ );
25210
+ const legByRunId = new Map(
25211
+ (acceptance?.legs ?? []).map((leg) => [leg.runId, leg])
25212
+ );
25213
+ const byRaw = /* @__PURE__ */ new Map();
25214
+ for (const { run, rawGroupKey } of groupedRuns) {
25215
+ const leg = legByRunId.get(run.runId);
25216
+ if (leg === void 0) {
25217
+ throw new Error(
25218
+ `taishi model-groups: missing acceptance projection for run ${run.runId}`
25219
+ );
25220
+ }
25221
+ let acc = byRaw.get(rawGroupKey);
25222
+ if (acc === void 0) {
25223
+ acc = {
25224
+ acceptedCount: 0,
25225
+ successCount: 0,
25226
+ successEligibleCount: 0,
25227
+ noReceiptCount: 0,
25228
+ walls: []
25229
+ };
25230
+ byRaw.set(rawGroupKey, acc);
25231
+ }
25232
+ if (leg.accepted) acc.acceptedCount += 1;
25233
+ if (leg.success) acc.successCount += 1;
25234
+ if (leg.successEligible) acc.successEligibleCount += 1;
25235
+ if (leg.noReceipt) acc.noReceiptCount += 1;
25236
+ acc.walls.push(leg.wallMs);
25237
+ }
25238
+ const rawKeys = [...byRaw.keys()].sort((a, b) => a.localeCompare(b));
25239
+ const groups = rawKeys.map((rawGroupKey) => {
25240
+ const acc = byRaw.get(rawGroupKey);
25241
+ const legCount = acc.walls.length;
25242
+ return {
25243
+ rawGroupKey,
25244
+ displayName: displayNameFor(rawGroupKey, input.combinationMapping),
25245
+ legCount,
25246
+ acceptedCount: acc.acceptedCount,
25247
+ acceptanceRate: rate(acc.acceptedCount, legCount),
25248
+ successCount: acc.successCount,
25249
+ successEligibleCount: acc.successEligibleCount,
25250
+ successRate: rate(acc.successCount, acc.successEligibleCount),
25251
+ noReceiptCount: acc.noReceiptCount,
25252
+ noReceiptRate: rate(acc.noReceiptCount, legCount),
25253
+ wallClockMedianMs: medianNumber(acc.walls)
25254
+ };
25255
+ });
25256
+ const unreadable = sortUnreadable([...input.unreadable, ...modelAbsent]);
25257
+ return {
25258
+ kind: "taishi-model-groups",
25259
+ mode: "model-groups",
25260
+ projectRoots: [...input.projectRoots].sort((a, b) => a.localeCompare(b)),
25261
+ groups,
25262
+ legCount: groupedRuns.length,
25263
+ unreadableCount: unreadable.length,
25264
+ unreadable
25265
+ };
25266
+ }
25267
+ var init_taishi_model_groups = __esm({
25268
+ "src/taishi-model-groups.ts"() {
25269
+ "use strict";
25270
+ init_acceptance_success_rework();
25271
+ init_taishi_median();
25272
+ }
25273
+ });
25274
+
25275
+ // src/taishi-metric-families/b2-frame-buckets-actions.ts
25276
+ function timestampMs(iso) {
25277
+ const ms = Date.parse(iso);
25278
+ if (!Number.isFinite(ms)) {
25279
+ throw new Error(`unparseable timestamp: ${iso}`);
25280
+ }
25281
+ return ms;
25282
+ }
25283
+ function toIso(ms) {
25284
+ return new Date(ms).toISOString();
25285
+ }
25286
+ function closedTools(intervals) {
25287
+ const out = [];
25288
+ for (const interval of intervals) {
25289
+ if (interval.endedAt === void 0) continue;
25290
+ const startMs = timestampMs(interval.startedAt);
25291
+ const endMs = timestampMs(interval.endedAt);
25292
+ if (endMs <= startMs) continue;
25293
+ out.push({
25294
+ toolCallId: interval.toolCallId,
25295
+ toolName: interval.toolName,
25296
+ startedAt: interval.startedAt,
25297
+ endedAt: interval.endedAt,
25298
+ startMs,
25299
+ endMs,
25300
+ ...interval.command !== void 0 ? { command: interval.command } : {}
25301
+ });
25302
+ }
25303
+ return out;
25304
+ }
25305
+ function clipToolsToFrame(tools, frameStartMs, frameEndMs) {
25306
+ if (frameEndMs <= frameStartMs) return [];
25307
+ const out = [];
25308
+ for (const tool2 of tools) {
25309
+ const startMs = Math.max(tool2.startMs, frameStartMs);
25310
+ const endMs = Math.min(tool2.endMs, frameEndMs);
25311
+ if (endMs <= startMs) continue;
25312
+ out.push({
25313
+ toolCallId: tool2.toolCallId,
25314
+ toolName: tool2.toolName,
25315
+ startMs,
25316
+ endMs,
25317
+ startedAt: startMs === tool2.startMs ? tool2.startedAt : toIso(startMs),
25318
+ endedAt: endMs === tool2.endMs ? tool2.endedAt : toIso(endMs),
25319
+ ...tool2.command !== void 0 ? { command: tool2.command } : {}
25320
+ });
25321
+ }
25322
+ return out;
25323
+ }
25324
+ function mergeUnion(intervals) {
25325
+ if (intervals.length === 0) return [];
25326
+ const sorted = [...intervals].sort(
25327
+ (a, b) => a.startMs - b.startMs || a.endMs - b.endMs
25328
+ );
25329
+ const merged = [
25330
+ { startMs: sorted[0].startMs, endMs: sorted[0].endMs }
25331
+ ];
25332
+ for (let i = 1; i < sorted.length; i += 1) {
25333
+ const cur = sorted[i];
25334
+ const last = merged[merged.length - 1];
25335
+ if (cur.startMs <= last.endMs) {
25336
+ last.endMs = Math.max(last.endMs, cur.endMs);
25337
+ } else {
25338
+ merged.push({ startMs: cur.startMs, endMs: cur.endMs });
25339
+ }
25340
+ }
25341
+ return merged;
25342
+ }
25343
+ function modelMaximalIntervals(frameStartMs, frameEndMs, toolUnion) {
25344
+ if (frameEndMs <= frameStartMs) return [];
25345
+ const gaps = [];
25346
+ let cursor = frameStartMs;
25347
+ for (const interval of toolUnion) {
25348
+ if (interval.startMs > cursor) {
25349
+ gaps.push({ startMs: cursor, endMs: interval.startMs });
25350
+ }
25351
+ cursor = Math.max(cursor, interval.endMs);
25352
+ }
25353
+ if (cursor < frameEndMs) {
25354
+ gaps.push({ startMs: cursor, endMs: frameEndMs });
25355
+ }
25356
+ return gaps;
25357
+ }
25358
+ function toolAction(tool2) {
25359
+ const action = {
25360
+ kind: "tool",
25361
+ toolCallId: tool2.toolCallId,
25362
+ toolName: tool2.toolName,
25363
+ durationMs: tool2.endMs - tool2.startMs,
25364
+ startedAt: tool2.startedAt,
25365
+ endedAt: tool2.endedAt
25366
+ };
25367
+ if (tool2.toolName === "bash" && tool2.command !== void 0) {
25368
+ return {
25369
+ ...action,
25370
+ commandSummary: tool2.command
25371
+ };
25372
+ }
25373
+ return action;
25374
+ }
25375
+ function modelAction(gap) {
25376
+ return {
25377
+ kind: "model",
25378
+ durationMs: gap.endMs - gap.startMs,
25379
+ startedAt: toIso(gap.startMs),
25380
+ endedAt: toIso(gap.endMs)
25381
+ };
25382
+ }
25383
+ function sortActionsDescending(actions) {
25384
+ return [...actions].sort((a, b) => {
25385
+ if (b.durationMs !== a.durationMs) return b.durationMs - a.durationMs;
25386
+ if (a.startedAt !== b.startedAt) return a.startedAt.localeCompare(b.startedAt);
25387
+ if (a.kind !== b.kind) return a.kind.localeCompare(b.kind);
25388
+ if (a.kind === "tool" && b.kind === "tool") {
25389
+ return a.toolCallId.localeCompare(b.toolCallId);
25390
+ }
25391
+ return 0;
25392
+ });
25393
+ }
25394
+ function computeTaishiB2RunMetrics(facts) {
25395
+ const frameStartMs = timestampMs(facts.frameSpan.startedAt);
25396
+ const frameEndMs = timestampMs(facts.frameSpan.endedAt);
25397
+ const wallMs = Math.max(0, frameEndMs - frameStartMs);
25398
+ const tools = clipToolsToFrame(closedTools(facts.toolIntervals), frameStartMs, frameEndMs);
25399
+ const toolUnion = mergeUnion(tools);
25400
+ const toolBucketMs = toolUnion.reduce(
25401
+ (sum, interval) => sum + (interval.endMs - interval.startMs),
25402
+ 0
25403
+ );
25404
+ const modelBucketMs = wallMs - toolBucketMs;
25405
+ const modelGaps = modelMaximalIntervals(frameStartMs, frameEndMs, toolUnion);
25406
+ const actions = sortActionsDescending([
25407
+ ...tools.map(toolAction),
25408
+ ...modelGaps.map(modelAction)
25409
+ ]);
25410
+ const actionDurationMedianMs = medianNumber(actions.map((action) => action.durationMs));
25411
+ return {
25412
+ runId: facts.runId,
25413
+ book: facts.book,
25414
+ role: facts.role,
25415
+ wallMs,
25416
+ toolBucketMs,
25417
+ modelBucketMs,
25418
+ actions,
25419
+ actionDurationMedianMs
25420
+ };
25421
+ }
25422
+ var b2FrameBucketsActionsFamily, b2_frame_buckets_actions_default;
25423
+ var init_b2_frame_buckets_actions = __esm({
25424
+ "src/taishi-metric-families/b2-frame-buckets-actions.ts"() {
25425
+ "use strict";
25426
+ init_taishi_median();
25427
+ b2FrameBucketsActionsFamily = {
25428
+ id: "b2-frame-buckets-actions",
25429
+ contribute(input) {
25430
+ if (input.runs.length === 0) return void 0;
25431
+ const runs = [...input.runs].map(computeTaishiB2RunMetrics).sort((a, b) => {
25432
+ if (a.book !== b.book) return a.book.localeCompare(b.book);
25433
+ if (a.role !== b.role) return a.role.localeCompare(b.role);
25434
+ return a.runId.localeCompare(b.runId);
25435
+ });
25436
+ const section = {
25437
+ kind: "taishi-b2-frame-buckets-actions",
25438
+ runs
25439
+ };
25440
+ return { b2FrameBucketsActions: section };
25441
+ }
25442
+ };
25443
+ b2_frame_buckets_actions_default = b2FrameBucketsActionsFamily;
25444
+ }
25445
+ });
25446
+
25447
+ // src/taishi-metric-families/leg-wall-clock.ts
25448
+ function frameSpanWallMs(span) {
25449
+ return Date.parse(span.endedAt) - Date.parse(span.startedAt);
25450
+ }
25451
+ function projectEntry(facts) {
25452
+ return {
25453
+ runId: facts.runId,
25454
+ book: facts.book,
25455
+ role: facts.role,
25456
+ wallMs: frameSpanWallMs(facts.frameSpan)
25457
+ };
25458
+ }
25459
+ function compareRankingDesc(a, b) {
25460
+ if (b.wallMs !== a.wallMs) return b.wallMs - a.wallMs;
25461
+ if (a.book !== b.book) return a.book.localeCompare(b.book);
25462
+ if (a.role !== b.role) return a.role.localeCompare(b.role);
25463
+ return a.runId.localeCompare(b.runId);
25464
+ }
25465
+ var legWallClockFamily, leg_wall_clock_default;
25466
+ var init_leg_wall_clock = __esm({
25467
+ "src/taishi-metric-families/leg-wall-clock.ts"() {
25468
+ "use strict";
25469
+ init_taishi_median();
25470
+ legWallClockFamily = {
25471
+ id: "leg-wall-clock",
25472
+ contribute(input) {
25473
+ if (input.runs.length === 0) {
25474
+ return void 0;
25475
+ }
25476
+ const ranking = input.runs.map(projectEntry).sort(compareRankingDesc);
25477
+ const walls = ranking.map((leg) => leg.wallMs);
25478
+ const medianWallMs = medianNumber(walls);
25479
+ if (medianWallMs === void 0) {
25480
+ return void 0;
25481
+ }
25482
+ let totalElapsedMs = 0;
25483
+ for (const wallMs of walls) totalElapsedMs += wallMs;
25484
+ const section = {
25485
+ kind: "taishi-leg-wall-clock",
25486
+ ranking,
25487
+ medianWallMs,
25488
+ totalElapsedMs
25489
+ };
25490
+ return { legWallClock: section };
25491
+ }
25492
+ };
25493
+ leg_wall_clock_default = legWallClockFamily;
25494
+ }
25495
+ });
25496
+
25497
+ // src/taishi-metric-families/round-timeline.ts
25498
+ function isRecord10(value) {
25499
+ return typeof value === "object" && value !== null && !Array.isArray(value);
25500
+ }
25501
+ function wallMsFromSpan2(startedAt, endedAt) {
25502
+ return Date.parse(endedAt) - Date.parse(startedAt);
25503
+ }
25504
+ function readOutcomeStatus(body) {
25505
+ if (!isRecord10(body.outcome)) return void 0;
25506
+ const status = body.outcome.status;
25507
+ if (typeof status !== "string" || status.trim() === "") return void 0;
25508
+ return status;
25509
+ }
25510
+ function readClassCount(body) {
25511
+ if (!isRecord10(body.outcome)) return void 0;
25512
+ if (!isRecord10(body.outcome.decisiveFacts)) return void 0;
25513
+ const classCount = body.outcome.decisiveFacts.classCount;
25514
+ if (typeof classCount !== "number" || !Number.isFinite(classCount)) {
25515
+ return void 0;
25516
+ }
25517
+ return classCount;
25518
+ }
25519
+ function projectTerminal(facts) {
25520
+ if (facts.terminal.status === "absent") {
25521
+ return { kind: "death", channel: "no-receipt" };
25522
+ }
25523
+ if (facts.terminal.file === "error.json") {
25524
+ return { kind: "death", channel: "error" };
25525
+ }
25526
+ if (facts.terminal.file === "audit-incomplete.json") {
25527
+ return { kind: "death", channel: "audit-incomplete" };
25528
+ }
25529
+ const status = readOutcomeStatus(facts.terminal.body);
25530
+ const classCount = readClassCount(facts.terminal.body);
25531
+ const receiptStatus = status ?? "unparsed";
25532
+ if (classCount === void 0) {
25533
+ return { kind: "receipt", status: receiptStatus };
25534
+ }
25535
+ return { kind: "receipt", status: receiptStatus, classCount };
25536
+ }
25537
+ function projectRunRow(facts) {
25538
+ const { startedAt, endedAt } = facts.frameSpan;
25539
+ return {
25540
+ kind: "run",
25541
+ runId: facts.runId,
25542
+ book: facts.book,
25543
+ role: facts.role,
25544
+ startedAt,
25545
+ endedAt,
25546
+ wallMs: wallMsFromSpan2(startedAt, endedAt),
25547
+ terminal: projectTerminal(facts)
25548
+ };
25549
+ }
25550
+ function projectUnreadableRow(entry) {
25551
+ return {
25552
+ kind: "unreadable",
25553
+ runId: entry.runId,
25554
+ book: entry.book,
25555
+ missingSources: entry.missingSources,
25556
+ reason: entry.reason,
25557
+ firstFrameAt: entry.firstFrameAt
25558
+ };
25559
+ }
25560
+ function rowSortStartedAt(row) {
25561
+ if (row.kind === "run") return row.startedAt;
25562
+ if (row.firstFrameAt.status === "present") return row.firstFrameAt.at;
25563
+ return void 0;
25564
+ }
25565
+ function compareRows(a, b) {
25566
+ const aStart = rowSortStartedAt(a);
25567
+ const bStart = rowSortStartedAt(b);
25568
+ if (aStart === void 0 && bStart === void 0) {
25569
+ return a.runId.localeCompare(b.runId);
25570
+ }
25571
+ if (aStart === void 0) return 1;
25572
+ if (bStart === void 0) return -1;
25573
+ if (aStart !== bStart) return aStart.localeCompare(bStart);
25574
+ return a.runId.localeCompare(b.runId);
25575
+ }
25576
+ function buildLanes(runs, unreadable) {
25577
+ const byLane = /* @__PURE__ */ new Map();
25578
+ const push = (lane, row) => {
25579
+ const list = byLane.get(lane);
25580
+ if (list === void 0) byLane.set(lane, [row]);
25581
+ else list.push(row);
25582
+ };
25583
+ for (const facts of runs) {
25584
+ push(facts.book, projectRunRow(facts));
25585
+ }
25586
+ for (const entry of unreadable) {
25587
+ push(entry.book, projectUnreadableRow(entry));
25588
+ }
25589
+ return [...byLane.keys()].sort((a, b) => a.localeCompare(b)).map((lane) => ({
25590
+ lane,
25591
+ rows: [...byLane.get(lane) ?? []].sort(compareRows)
25592
+ }));
25593
+ }
25594
+ var roundTimelineFamily, round_timeline_default;
25595
+ var init_round_timeline = __esm({
25596
+ "src/taishi-metric-families/round-timeline.ts"() {
25597
+ "use strict";
25598
+ roundTimelineFamily = {
25599
+ id: "round-timeline",
25600
+ contribute(input) {
25601
+ if (input.runs.length === 0 && input.unreadable.length === 0) {
25602
+ return void 0;
25603
+ }
25604
+ const section = {
25605
+ kind: "taishi-round-timeline",
25606
+ lanes: buildLanes(input.runs, input.unreadable)
25607
+ };
25608
+ return { roundTimeline: section };
25609
+ }
25610
+ };
25611
+ round_timeline_default = roundTimelineFamily;
25612
+ }
25613
+ });
25614
+
25615
+ // src/taishi-metric-families.ts
25616
+ async function loadTaishiIssueMetricFamilies() {
25617
+ return ISSUE_METRIC_FAMILIES;
25618
+ }
25619
+ var ISSUE_METRIC_FAMILIES;
25620
+ var init_taishi_metric_families = __esm({
25621
+ "src/taishi-metric-families.ts"() {
25622
+ "use strict";
25623
+ init_acceptance_success_rework();
25624
+ init_b2_frame_buckets_actions();
25625
+ init_leg_wall_clock();
25626
+ init_round_timeline();
25627
+ ISSUE_METRIC_FAMILIES = [
25628
+ acceptance_success_rework_default,
25629
+ b2_frame_buckets_actions_default,
25630
+ leg_wall_clock_default,
25631
+ round_timeline_default
25632
+ ].sort((a, b) => a.id.localeCompare(b.id));
25633
+ }
25634
+ });
25635
+
25636
+ // src/taishi-metric-family.ts
25637
+ function composeTaishiMetricFamilySections(families, input) {
25638
+ const sections = {};
25639
+ for (const family of families) {
25640
+ const piece = family.contribute(input);
25641
+ if (piece === void 0) continue;
25642
+ Object.assign(sections, piece);
25643
+ }
25644
+ return sections;
25645
+ }
25646
+ var init_taishi_metric_family = __esm({
25647
+ "src/taishi-metric-family.ts"() {
25648
+ "use strict";
25649
+ }
25650
+ });
25651
+
25652
+ // src/taishi-page.ts
25653
+ import { createHash as createHash4 } from "node:crypto";
25654
+ import { dirname as dirname10, join as join22 } from "node:path";
25655
+ function taishiIssuePageKey(projectRoot) {
25656
+ const identity = physicalPathIdentity(projectRoot);
25657
+ return createHash4("sha256").update(identity).digest("hex").slice(0, 32);
25658
+ }
25659
+ function taishiIssuePagePath(ledgerHome, projectRoot) {
25660
+ return join22(ledgerHome, "taishi", "issues", `${taishiIssuePageKey(projectRoot)}.json`);
25661
+ }
25662
+ function sortLegs(legs) {
25663
+ return [...legs].sort((a, b) => {
25664
+ if (a.book !== b.book) return a.book.localeCompare(b.book);
25665
+ if (a.role !== b.role) return a.role.localeCompare(b.role);
25666
+ return a.runId.localeCompare(b.runId);
25667
+ });
25668
+ }
25669
+ function sortUnreadable2(unreadable) {
25670
+ return [...unreadable].sort((a, b) => {
25671
+ if (a.book !== b.book) return a.book.localeCompare(b.book);
25672
+ return a.runId.localeCompare(b.runId);
25673
+ });
25674
+ }
25675
+ function sortScopeConflicts(conflicts) {
25676
+ return [...conflicts].sort((a, b) => {
25677
+ const aRun = a.runId ?? "";
25678
+ const bRun = b.runId ?? "";
25679
+ if (aRun !== bRun) return aRun.localeCompare(bRun);
25680
+ return a.projectRoot.localeCompare(b.projectRoot);
25681
+ });
25682
+ }
25683
+ function assertTaishiChangedLinesInput(changedLines) {
25684
+ if (changedLines === void 0) return;
25685
+ if (typeof changedLines !== "number" || !Number.isFinite(changedLines) || changedLines < 0) {
25686
+ throw new Error(
25687
+ `taishi changedLines must be a finite non-negative number, got ${String(changedLines)}`
25688
+ );
25689
+ }
25690
+ }
25691
+ function normalizeTaishiChangedLines(changedLines) {
25692
+ assertTaishiChangedLinesInput(changedLines);
25693
+ if (changedLines === void 0 || changedLines === 0) {
25694
+ return { status: "absent" };
25695
+ }
25696
+ return { status: "present", value: changedLines };
25697
+ }
25698
+ function computeTaishiMsPerKLines(totalElapsedMs, changedLines) {
25699
+ if (changedLines.status === "absent") return { status: "absent" };
25700
+ return {
25701
+ status: "present",
25702
+ value: totalElapsedMs / (changedLines.value / 1e3)
25703
+ };
25704
+ }
25705
+ function frameSpanWallMs2(span) {
25706
+ return Date.parse(span.endedAt) - Date.parse(span.startedAt);
25707
+ }
25708
+ function summarizeTaishiRunEfficiency(runs, unreadable = []) {
25709
+ let totalElapsedMs = 0;
25710
+ let latestEndedAt;
25711
+ for (const run of runs) {
25712
+ totalElapsedMs += frameSpanWallMs2(run.frameSpan);
25713
+ const endedAt = run.frameSpan.endedAt;
25714
+ if (latestEndedAt === void 0 || endedAt > latestEndedAt) {
25715
+ latestEndedAt = endedAt;
25716
+ }
25717
+ }
25718
+ for (const entry of unreadable) {
25719
+ if (entry.lastFrameAt.status !== "present") continue;
25720
+ const endedAt = entry.lastFrameAt.at;
25721
+ if (latestEndedAt === void 0 || endedAt > latestEndedAt) {
25722
+ latestEndedAt = endedAt;
25723
+ }
25724
+ }
25725
+ const lastActivityAt = latestEndedAt === void 0 ? { status: "absent" } : { status: "present", at: latestEndedAt };
25726
+ return { totalElapsedMs, lastActivityAt };
25727
+ }
25728
+ async function buildTaishiIssueMetricsPage(input) {
25729
+ const families = await loadTaishiIssueMetricFamilies();
25730
+ const legs = sortLegs(
25731
+ input.runs.map((run) => ({
25732
+ runId: run.runId,
25733
+ book: run.book,
25734
+ role: run.role
25735
+ }))
25736
+ );
25737
+ const unreadable = sortUnreadable2(input.unreadable);
25738
+ const scopeConflicts = sortScopeConflicts(input.scopeConflicts ?? []);
25739
+ const projectRoot = physicalPathIdentity(input.projectRoot);
25740
+ const { totalElapsedMs, lastActivityAt } = summarizeTaishiRunEfficiency(
25741
+ input.runs,
25742
+ unreadable
25743
+ );
25744
+ const changedLines = normalizeTaishiChangedLines(input.changedLines);
25745
+ const msPerKLines = computeTaishiMsPerKLines(totalElapsedMs, changedLines);
25746
+ const envelope = {
25747
+ kind: "taishi-issue-metrics",
25748
+ mode: "issue",
25749
+ projectRoot,
25750
+ // exactOptionalPropertyTypes: only materialize when caller supplied it.
25751
+ ...input.issueNumber === void 0 ? {} : { issueNumber: input.issueNumber },
25752
+ legs,
25753
+ unreadable,
25754
+ unreadableCount: unreadable.length,
25755
+ scopeConflicts,
25756
+ totalElapsedMs,
25757
+ changedLines,
25758
+ msPerKLines,
25759
+ lastActivityAt
25760
+ };
25761
+ const sections = composeTaishiMetricFamilySections(families, {
25762
+ projectRoot,
25763
+ runs: input.runs,
25764
+ unreadable
25765
+ });
25766
+ return { ...envelope, ...sections };
25767
+ }
25768
+ async function writeTaishiIssueMetricsPage(ledgerHome, page) {
25769
+ const path = taishiIssuePagePath(ledgerHome, page.projectRoot);
25770
+ ensureRealDirectoryTree(ledgerHome, dirname10(path));
25771
+ assertLedgerFileInsideHome(path, ledgerHome);
25772
+ await writeFileAtomically(path, `${JSON.stringify(page, null, 2)}
25773
+ `);
25774
+ return path;
25775
+ }
25776
+ var init_taishi_page = __esm({
25777
+ "src/taishi-page.ts"() {
25778
+ "use strict";
25779
+ init_atomic_write();
25780
+ init_activation_ledger_topology();
25781
+ init_taishi_metric_families();
25782
+ init_taishi_metric_family();
25783
+ }
25784
+ });
25785
+
25786
+ // src/taishi-entry.ts
25787
+ import { readFile as readFile14 } from "node:fs/promises";
25788
+ function isMissingPathError5(error) {
25789
+ return error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
25790
+ }
25791
+ function cachedPageMatchesRequestedScope(page, input) {
25792
+ const requestedTicket = input.ticketNumber ?? input.issueNumber;
25793
+ if (requestedTicket === void 0) {
25794
+ return page.issueNumber === void 0;
25795
+ }
25796
+ return page.issueNumber === requestedTicket;
25797
+ }
25798
+ async function readOrComputeTaishiIssuePage(input) {
25799
+ const ledgerHome = resolveActivationLedgerHome();
25800
+ const projectRoot = physicalPathIdentity(input.projectRoot);
25801
+ const pagePath = taishiIssuePagePath(ledgerHome, projectRoot);
25802
+ try {
25803
+ const raw = await readFile14(pagePath, "utf8");
25804
+ const page = JSON.parse(raw);
25805
+ if (cachedPageMatchesRequestedScope(page, input)) {
25806
+ return { mode: "issue", page, pagePath };
25807
+ }
25808
+ } catch (error) {
25809
+ if (!isMissingPathError5(error)) {
25810
+ throw new TaishiIssueComputeError({
25811
+ projectRoot,
25812
+ ...input.issueNumber === void 0 ? {} : { issueNumber: input.issueNumber },
25813
+ cause: error
25814
+ });
25815
+ }
25816
+ }
25817
+ try {
25818
+ return await runTaishiIssueMode(input);
25819
+ } catch (error) {
25820
+ if (error instanceof TaishiIssueComputeError) throw error;
25821
+ throw new TaishiIssueComputeError({
25822
+ projectRoot,
25823
+ ...input.issueNumber === void 0 ? {} : { issueNumber: input.issueNumber },
25824
+ cause: error
25825
+ });
25826
+ }
25827
+ }
25828
+ async function runTaishiIssueMode(input, precomputedScan) {
25829
+ assertTaishiChangedLinesInput(input.changedLines);
25830
+ const ledgerHome = resolveActivationLedgerHome();
25831
+ const projectRoot = input.projectRoot;
25832
+ const ticketNumber = "ticketNumber" in input ? input.ticketNumber : void 0;
25833
+ const scan = precomputedScan ?? (ticketNumber === void 0 ? await scanTaishiIssueRuns({ projectRoot }) : await scanTaishiIssueRuns({ projectRoot, ticketNumber }));
25834
+ const issueNumber = "issueNumber" in input ? input.issueNumber : void 0;
25835
+ const conflictingProjectRoot = "conflictingProjectRoot" in input ? input.conflictingProjectRoot : void 0;
25836
+ const scopeConflicts = [...scan.scopeConflicts];
25837
+ if (conflictingProjectRoot !== void 0 && ticketNumber !== void 0) {
25838
+ const losingRoot = physicalPathIdentity(conflictingProjectRoot);
25839
+ const winningRoot = physicalPathIdentity(projectRoot);
25840
+ if (losingRoot !== winningRoot) {
25841
+ scopeConflicts.push({
25842
+ ticketNumber,
25843
+ projectRoot: losingRoot,
25844
+ fact: "typed-ticketNumber-over-projectRoot"
25845
+ });
25846
+ }
25847
+ }
25848
+ const page = await buildTaishiIssueMetricsPage({
25849
+ projectRoot,
25850
+ runs: scan.runs,
25851
+ unreadable: scan.unreadable,
25852
+ scopeConflicts,
25853
+ ...input.changedLines === void 0 ? {} : { changedLines: input.changedLines },
25854
+ ...issueNumber === void 0 ? {} : { issueNumber }
25855
+ });
25856
+ const pagePath = await writeTaishiIssueMetricsPage(ledgerHome, page);
25857
+ if (issueNumber !== void 0) {
25858
+ await mergeTaishiLibraryIndexRows(ledgerHome, [
25859
+ rowFromIssueMetricsPage(page)
25860
+ ]);
25861
+ }
25862
+ return { mode: "issue", page, pagePath };
25863
+ }
25864
+ async function runTaishiSweepMode(input) {
25865
+ const ledgerHome = resolveActivationLedgerHome();
25866
+ const issuePages = [];
25867
+ for (const entry of input.mergedPullRequests) {
25868
+ issuePages.push(await runTaishiIssueMode(entry));
25869
+ }
25870
+ const upserts = issuePages.map((result2) => rowFromIssueMetricsPage(result2.page));
25871
+ const { index, indexPath } = await mergeTaishiLibraryIndexRows(ledgerHome, upserts);
25872
+ return { mode: "sweep", issuePages, index, indexPath };
25873
+ }
25874
+ async function runTaishiModelGroupsMode(input) {
25875
+ const ledgerHome = resolveActivationLedgerHome();
25876
+ const runs = [];
25877
+ const unreadable = [];
25878
+ const seen = /* @__PURE__ */ new Set();
25879
+ const projectRoots = [];
25880
+ for (const root of input.projectRoots) {
25881
+ const identity = physicalPathIdentity(root);
25882
+ if (seen.has(identity)) continue;
25883
+ seen.add(identity);
25884
+ projectRoots.push(identity);
25885
+ }
25886
+ for (const projectRoot of projectRoots) {
25887
+ const scan = await scanTaishiIssueRuns({ projectRoot });
25888
+ runs.push(...scan.runs);
25889
+ unreadable.push(...scan.unreadable);
25890
+ const pagePath = taishiIssuePagePath(ledgerHome, projectRoot);
25891
+ try {
25892
+ const raw = await readFile14(pagePath, "utf8");
25893
+ JSON.parse(raw);
25894
+ } catch (error) {
25895
+ if (!isMissingPathError5(error)) {
25896
+ throw new TaishiIssueComputeError({ projectRoot, cause: error });
25897
+ }
25898
+ try {
25899
+ await runTaishiIssueMode({ mode: "issue", projectRoot }, scan);
25900
+ } catch (computeError) {
25901
+ if (computeError instanceof TaishiIssueComputeError) throw computeError;
25902
+ throw new TaishiIssueComputeError({ projectRoot, cause: computeError });
25903
+ }
25904
+ }
25905
+ }
25906
+ const page = input.combinationMapping === void 0 ? buildTaishiModelGroupsPage({ projectRoots, runs, unreadable }) : buildTaishiModelGroupsPage({
25907
+ projectRoots,
25908
+ runs,
25909
+ unreadable,
25910
+ combinationMapping: input.combinationMapping
25911
+ });
25912
+ return { mode: "model-groups", page };
25913
+ }
25914
+ async function runTaishi(input) {
25915
+ if (input.mode === "sweep") {
25916
+ return runTaishiSweepMode(input);
25917
+ }
25918
+ if (input.mode === "cohort") {
25919
+ const ledgerHome = resolveActivationLedgerHome();
25920
+ return runTaishiCohortMode(ledgerHome, input, async ({ projectRoot, issueNumber }) => {
25921
+ const ensured = await readOrComputeTaishiIssuePage({
25922
+ mode: "issue",
25923
+ projectRoot,
25924
+ issueNumber
25925
+ });
25926
+ return ensured.page;
25927
+ });
25928
+ }
25929
+ if (input.mode === "model-groups") {
25930
+ return runTaishiModelGroupsMode(input);
25931
+ }
25932
+ return runTaishiIssueMode(input);
25933
+ }
25934
+ var TaishiIssueComputeError, taishiSweepModeInputSchema;
25935
+ var init_taishi_entry = __esm({
25936
+ "src/taishi-entry.ts"() {
25937
+ "use strict";
25938
+ init_build();
25939
+ init_activation_ledger_topology();
25940
+ init_taishi_cohort();
25941
+ init_taishi_ledger();
25942
+ init_taishi_index();
25943
+ init_taishi_model_groups();
25944
+ init_taishi_page();
25945
+ TaishiIssueComputeError = class extends Error {
25946
+ code = "taishi-issue-compute-failed";
25947
+ projectRoot;
25948
+ issueNumber;
25949
+ constructor(input) {
25950
+ const root = physicalPathIdentity(input.projectRoot);
25951
+ const causeText = input.cause instanceof Error ? input.cause.message || input.cause.name : String(input.cause);
25952
+ const issueFace = input.issueNumber === void 0 ? `projectRoot ${root}` : `issue ${input.issueNumber} (projectRoot ${root})`;
25953
+ super(`taishi compute failed for ${issueFace}: ${causeText}`, {
25954
+ cause: input.cause
25955
+ });
25956
+ this.name = "TaishiIssueComputeError";
25957
+ this.projectRoot = root;
25958
+ if (input.issueNumber !== void 0) {
25959
+ this.issueNumber = input.issueNumber;
25960
+ }
25961
+ }
25962
+ };
25963
+ taishiSweepModeInputSchema = typebox_exports.Object(
25964
+ {
25965
+ mode: typebox_exports.Literal("sweep"),
25966
+ mergedPullRequests: typebox_exports.Array(
25967
+ typebox_exports.Object(
25968
+ {
25969
+ projectRoot: typebox_exports.String(),
25970
+ /** 排除后改动行数 — omit or 0 → typed 空缺; finite ≥ 0 only. */
25971
+ changedLines: typebox_exports.Optional(
25972
+ typebox_exports.Number({ minimum: 0, maximum: Number.MAX_VALUE })
25973
+ )
25974
+ },
25975
+ { additionalProperties: false }
25976
+ )
25977
+ )
25978
+ },
25979
+ { additionalProperties: false }
25980
+ );
25981
+ }
25982
+ });
25983
+
25984
+ // src/public-cli/taishi-run.ts
25985
+ import { readFile as readFile15 } from "node:fs/promises";
25986
+ import { isAbsolute as isAbsolute5, resolve as resolve8 } from "node:path";
25987
+ async function buildTaishiIssueModeInputFromPublicArgv(parsed, ledgerHome) {
25988
+ const ticket = parsed.ticket;
25989
+ const directRoot = parsed.projectRoot;
25990
+ if (ticket === void 0) {
25991
+ return {
25992
+ mode: "issue",
25993
+ projectRoot: directRoot
25994
+ };
25995
+ }
25996
+ const index = await readTaishiLibraryIndexPage(ledgerHome);
25997
+ const row = findTaishiLibraryIndexRow(index, ticket);
25998
+ let projectRoot;
25999
+ if (row !== void 0) {
26000
+ projectRoot = row.projectRoot;
26001
+ } else if (directRoot !== void 0) {
26002
+ projectRoot = directRoot;
26003
+ } else {
26004
+ throw new CliUsageError(
26005
+ `taishi library index has no row for ticket ${ticket}`
26006
+ );
26007
+ }
26008
+ const dualParamConflict = row !== void 0 && directRoot !== void 0 && physicalPathIdentity(directRoot) !== physicalPathIdentity(projectRoot);
26009
+ return {
26010
+ mode: "issue",
26011
+ projectRoot,
26012
+ ticketNumber: ticket,
26013
+ issueNumber: ticket,
26014
+ ...dualParamConflict ? { conflictingProjectRoot: directRoot } : {}
26015
+ };
26016
+ }
26017
+ function parseTaishiSweepModeInputFromJsonValue(value) {
26018
+ if (!value_exports.Check(taishiSweepModeInputSchema, value)) {
26019
+ throw new CliUsageError(
26020
+ "taishi sweep attachment must match TaishiSweepModeInput"
26021
+ );
26022
+ }
26023
+ return value;
26024
+ }
26025
+ async function buildTaishiSweepModeInputFromAttachmentPaths(attachmentPaths) {
26026
+ if (attachmentPaths.length !== 1) {
26027
+ throw new CliUsageError(
26028
+ "taishi sweep requires exactly one --attach typed JSON attachment"
26029
+ );
26030
+ }
26031
+ const sourcePath = attachmentPaths[0];
26032
+ const absolute = isAbsolute5(sourcePath) ? sourcePath : resolve8(sourcePath);
26033
+ let bytes;
26034
+ try {
26035
+ bytes = await readFile15(absolute);
26036
+ } catch (error) {
26037
+ throw new CliUsageError(
26038
+ `taishi sweep attachment is not a readable regular file: ${sourcePath}`,
26039
+ { cause: error }
26040
+ );
26041
+ }
26042
+ let text;
26043
+ try {
26044
+ text = exactUtf8(bytes, "taishi sweep attachment");
26045
+ } catch (error) {
26046
+ const detail = error instanceof Error ? error.message : String(error);
26047
+ throw new CliUsageError(detail, { cause: error });
26048
+ }
26049
+ let parsed;
26050
+ try {
26051
+ parsed = JSON.parse(text);
26052
+ } catch (error) {
26053
+ throw new CliUsageError(
26054
+ "taishi sweep attachment is not valid JSON",
26055
+ { cause: error }
26056
+ );
26057
+ }
26058
+ return parseTaishiSweepModeInputFromJsonValue(parsed);
26059
+ }
26060
+ async function runPublicTaishi(argv, _env, io, parseTaishiArgv2) {
26061
+ try {
26062
+ const parsed = parseTaishiArgv2(argv);
26063
+ const ledgerHome = resolveActivationLedgerHome();
26064
+ if (parsed.query === "sweep") {
26065
+ const input2 = await buildTaishiSweepModeInputFromAttachmentPaths(
26066
+ parsed.attachmentPaths
26067
+ );
26068
+ const result3 = await runTaishi(input2);
26069
+ io.stdout(`${JSON.stringify(result3, null, 2)}
26070
+ `);
26071
+ return { exitCode: 0 };
26072
+ }
26073
+ if (parsed.query === "cohort") {
26074
+ const result3 = await runTaishi({
26075
+ mode: "cohort",
26076
+ groups: parsed.groups
26077
+ });
26078
+ io.stdout(`${JSON.stringify(result3, null, 2)}
26079
+ `);
26080
+ return { exitCode: 0 };
26081
+ }
26082
+ if (parsed.query === "model-groups") {
26083
+ const result3 = await runTaishi({
26084
+ mode: "model-groups",
26085
+ projectRoots: parsed.projectRoots
26086
+ });
26087
+ io.stdout(`${JSON.stringify(result3, null, 2)}
26088
+ `);
26089
+ return { exitCode: 0 };
26090
+ }
26091
+ const input = await buildTaishiIssueModeInputFromPublicArgv(parsed, ledgerHome);
26092
+ const result2 = await readOrComputeTaishiIssuePage(input);
26093
+ io.stdout(`${JSON.stringify(result2, null, 2)}
26094
+ `);
26095
+ return { exitCode: 0 };
26096
+ } catch (error) {
26097
+ if (error instanceof CliUsageError) {
26098
+ presentStructuralRejection(error, io);
26099
+ return { exitCode: 2 };
26100
+ }
26101
+ if (error instanceof TaishiIssueComputeError) {
26102
+ const code = errnoCode(error.cause);
26103
+ presentControlledFailure({
26104
+ cause: "output",
26105
+ diagnostic: error.message,
26106
+ ...code === void 0 ? {} : { identity: { code } },
26107
+ details: {
26108
+ code: error.code,
26109
+ projectRoot: error.projectRoot,
26110
+ ...error.issueNumber === void 0 ? {} : { issueNumber: error.issueNumber }
26111
+ }
26112
+ }, io);
26113
+ return { exitCode: 1 };
26114
+ }
26115
+ throw error;
26116
+ }
26117
+ }
26118
+ var init_taishi_run = __esm({
26119
+ "src/public-cli/taishi-run.ts"() {
26120
+ "use strict";
26121
+ init_value2();
26122
+ init_activation_ledger_topology();
26123
+ init_exact_utf8();
26124
+ init_taishi_index();
26125
+ init_taishi_entry();
26126
+ init_cli_errors();
26127
+ init_settlement();
26128
+ }
26129
+ });
26130
+
26131
+ // src/public-cli/cli.ts
26132
+ var cli_exports = {};
26133
+ __export(cli_exports, {
26134
+ CliUsageError: () => CliUsageError,
26135
+ PUBLIC_ROLE_ARGV: () => PUBLIC_ROLE_ARGV,
26136
+ buildExplicitInternalActivationArgs: () => buildExplicitInternalActivationArgs,
26137
+ helpDocument: () => helpDocument,
26138
+ resolveInternalRoleEntrypoint: () => resolveInternalRoleEntrypoint,
26139
+ runAkRole: () => runAkRole
26140
+ });
26141
+ import { realpath as realpath5 } from "node:fs/promises";
26142
+ import { homedir as homedir3 } from "node:os";
26143
+ import { join as join23 } from "node:path";
26144
+ function takePublicGlobalFlag(argv, index) {
26145
+ const token = argv[index];
26146
+ if (token === void 0) return void 0;
26147
+ if (token === "--help" || token === "-h") {
26148
+ return { flag: "help", consume: 1 };
26149
+ }
26150
+ if (token === "--model") {
26151
+ const value = argv[index + 1];
26152
+ if (value === void 0) {
26153
+ return { flag: "model", consume: 1, value: void 0 };
26154
+ }
26155
+ return { flag: "model", consume: 2, value };
23812
26156
  }
23813
26157
  if (token.startsWith("--model=")) {
23814
26158
  return {
@@ -23847,7 +26191,7 @@ function resolveHome(env) {
23847
26191
  return env.home ?? process.env.HOME ?? homedir3();
23848
26192
  }
23849
26193
  function resolveAgentDir(env, home) {
23850
- return env.agentDir ?? process.env.PI_CODING_AGENT_DIR ?? join18(home, ".pi", "agent");
26194
+ return env.agentDir ?? process.env.PI_CODING_AGENT_DIR ?? join23(home, ".pi", "agent");
23851
26195
  }
23852
26196
  function parseThinking(value) {
23853
26197
  if (!THINKING_LEVELS2.has(value)) {
@@ -23933,6 +26277,12 @@ function renderHelp() {
23933
26277
  lines.push(` ${cap.name} \u2014 ${phaseText}`);
23934
26278
  }
23935
26279
  }
26280
+ lines.push("", "Deterministic commands:");
26281
+ for (const cap of doc.capabilities) {
26282
+ if (cap.kind === "deterministic") {
26283
+ lines.push(` ${cap.name}`);
26284
+ }
26285
+ }
23936
26286
  lines.push(
23937
26287
  "",
23938
26288
  "Global options: --model provider/model --thinking level",
@@ -24030,6 +26380,9 @@ async function runAkRole(argv, env) {
24030
26380
  }
24031
26381
  if (match.kind === "support") {
24032
26382
  io.stdout(`command ${match.name} kind support
26383
+ `);
26384
+ } else if (match.kind === "deterministic") {
26385
+ io.stdout(`command ${match.name} kind deterministic
24033
26386
  `);
24034
26387
  } else {
24035
26388
  io.stdout(
@@ -24433,6 +26786,15 @@ async function runAkRole(argv, env) {
24433
26786
  ...result2.terminal === void 0 ? {} : { terminal: result2.terminal }
24434
26787
  };
24435
26788
  }
26789
+ if (parsed.command === "taishi") {
26790
+ const result2 = await runPublicTaishi(
26791
+ parsed.args,
26792
+ { home },
26793
+ io,
26794
+ PUBLIC_ROLE_ARGV.taishi.parse
26795
+ );
26796
+ return { exitCode: result2.exitCode };
26797
+ }
24436
26798
  throw new CliUsageError(`unknown command: ${parsed.command}`);
24437
26799
  } catch (error) {
24438
26800
  if (error instanceof CliUsageError) {
@@ -24463,6 +26825,7 @@ var init_cli = __esm({
24463
26825
  init_judge_run();
24464
26826
  init_merger_run();
24465
26827
  init_reviewer_run();
26828
+ init_taishi_run();
24466
26829
  init_run_lifecycle();
24467
26830
  init_registry2();
24468
26831
  init_settlement();
@@ -24475,7 +26838,9 @@ var init_cli = __esm({
24475
26838
  collector: { parse: parseCollectorArgv },
24476
26839
  doctor: { parse: parseDoctorArgv },
24477
26840
  merger: { parse: parseMergerArgv },
24478
- reviewer: { parse: parseReviewerArgv }
26841
+ reviewer: { parse: parseReviewerArgv },
26842
+ /** Deterministic analysis seat (#336) — argv parse only; no LLM admission. */
26843
+ taishi: { parse: parseTaishiArgv }
24479
26844
  };
24480
26845
  THINKING_LEVELS2 = /* @__PURE__ */ new Set([
24481
26846
  "off",
@@ -24490,7 +26855,8 @@ var init_cli = __esm({
24490
26855
  });
24491
26856
 
24492
26857
  // src/public-cli/main.ts
24493
- import { dirname as dirname7, join as join19 } from "node:path";
26858
+ import { existsSync as existsSync2 } from "node:fs";
26859
+ import { dirname as dirname11, join as join24 } from "node:path";
24494
26860
  import { fileURLToPath as fileURLToPath2 } from "node:url";
24495
26861
 
24496
26862
  // src/public-cli/host-pi-runtime.ts
@@ -24577,8 +26943,15 @@ function linkPackage(packageRoot2, name, targetDir) {
24577
26943
  }
24578
26944
 
24579
26945
  // src/public-cli/main.ts
24580
- var here = dirname7(fileURLToPath2(import.meta.url));
24581
- var packageRoot = join19(here, "..", "..");
26946
+ var here = dirname11(fileURLToPath2(import.meta.url));
26947
+ function resolvePackageRoot(binDir) {
26948
+ const canonical = join24(binDir, "..", "..");
26949
+ if (existsSync2(join24(canonical, "package.json"))) {
26950
+ return canonical;
26951
+ }
26952
+ return binDir;
26953
+ }
26954
+ var packageRoot = resolvePackageRoot(here);
24582
26955
  ensureHostPiRuntimeResolvable(packageRoot);
24583
26956
  var { runAkRole: runAkRole2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
24584
26957
  var result = await runAkRole2(process.argv.slice(2), { packageRoot });