@akagilnc/pi-workflow-roles 0.1.3708 → 0.1.3716

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +4 -0
  2. package/README.zh-CN.md +4 -0
  3. package/dist/acp-host/production-host.js +262 -518
  4. package/dist/adr-path-refs.js +1 -1
  5. package/dist/diarist-contracts.js +31 -21
  6. package/dist/diarist-role.js +17 -8
  7. package/dist/diarist.js +39 -388
  8. package/dist/package-contracts/terminating-tools.js +1 -1
  9. package/dist/packaged-role-registry.js +4 -8
  10. package/dist/pi/role-turn-host.js +1 -7
  11. package/dist/public-cli/config.js +106 -2
  12. package/dist/public-cli/main.js +263 -1488
  13. package/dist/public-cli/option-definitions.js +3 -0
  14. package/dist/role-runtime.js +60 -88
  15. package/dist/ticket-provenance-contracts.js +0 -5
  16. package/dist/ticket-provenance.js +2 -149
  17. package/package.json +1 -1
  18. package/resources/diarist-collect.md +21 -11
  19. package/src/acp-host/role-envelope.ts +1 -1
  20. package/src/adr-path-refs.ts +1 -1
  21. package/src/diarist-contracts.ts +48 -32
  22. package/src/diarist-role.ts +31 -16
  23. package/src/diarist.ts +54 -635
  24. package/src/host-contracts.ts +1 -5
  25. package/src/package-contracts/terminating-tools.ts +1 -1
  26. package/src/packaged-role-registry.ts +4 -8
  27. package/src/pi/role-turn-host.ts +1 -7
  28. package/src/public-cli/cli.ts +54 -0
  29. package/src/public-cli/config.ts +157 -1
  30. package/src/public-cli/countersign-run.ts +2 -3
  31. package/src/public-cli/diarist-run.ts +15 -117
  32. package/src/public-cli/option-definitions.ts +3 -0
  33. package/src/role-runtime.ts +73 -105
  34. package/src/ticket-provenance-contracts.ts +6 -12
  35. package/src/ticket-provenance.ts +1 -207
  36. package/dist/diarist-mechanical.js +0 -411
  37. package/src/diarist-mechanical.ts +0 -571
@@ -15045,18 +15045,11 @@ function validateRecordedDiaristOutput(value) {
15045
15045
  }
15046
15046
  throw new Error("Diarist output has no execution discriminator");
15047
15047
  }
15048
- var DIARIST_OUTPUT_TOOL_NAME, DIARIST_SOURCES_FLAG;
15048
+ var DIARIST_OUTPUT_TOOL_NAME;
15049
15049
  var init_diarist_contracts = __esm({
15050
15050
  "src/diarist-contracts.ts"() {
15051
15051
  "use strict";
15052
15052
  DIARIST_OUTPUT_TOOL_NAME = "ak_diarist_output";
15053
- DIARIST_SOURCES_FLAG = {
15054
- name: "ak-diarist-sources",
15055
- definition: {
15056
- description: "Frozen source catalog the diarist selects from (may be unbound until LLM asserts ticketNumber)",
15057
- type: "string"
15058
- }
15059
- };
15060
15053
  }
15061
15054
  });
15062
15055
 
@@ -15265,14 +15258,13 @@ var init_packaged_role_registry = __esm({
15265
15258
  activationStage: "load-and-install",
15266
15259
  sessionMaterials: AUDITOR_PUBLIC_SESSION_MATERIALS
15267
15260
  },
15268
- // #708 / ADR 0075 `diarist-is-role`: 起居郎 is a seat like any other. The
15269
- // frozen source catalog rides the shared input-flag seam; it is absent for a
15270
- // true-unbound summons (no ticket → no diary).
15261
+ // #708 / ADR 0075 `diarist-is-role` / #779: 起居郎 is a seat like any other.
15262
+ // No input flag — LLM finds materials itself (caller-transparent).
15271
15263
  {
15272
15264
  role: "diarist",
15273
15265
  phases: [null],
15274
15266
  outputTool: DIARIST_OUTPUT_TOOL_NAME,
15275
- inputFlag: DIARIST_SOURCES_FLAG.name,
15267
+ inputFlag: void 0,
15276
15268
  phaseFlag: void 0,
15277
15269
  activationStage: "load-and-install",
15278
15270
  sessionMaterials: [
@@ -15592,6 +15584,50 @@ function parseAutoResumeLimit(value) {
15592
15584
  function setAutoResumeLimit(config, limit) {
15593
15585
  return { ...config, autoResumeLimit: parseAutoResumeLimit(limit) };
15594
15586
  }
15587
+ function requireNonEmptyToken(value, label) {
15588
+ const trimmed = value.trim();
15589
+ if (trimmed === "") {
15590
+ throw new Error(`${label} must be a non-empty string`);
15591
+ }
15592
+ return trimmed;
15593
+ }
15594
+ function setProviderHostAlias(config, provider, host, alias) {
15595
+ const from = requireNonEmptyToken(provider, "provider");
15596
+ const hostName = requireNonEmptyToken(host, "host");
15597
+ const to = requireNonEmptyToken(alias, "alias");
15598
+ const previous = config.providerAliases ?? {};
15599
+ return {
15600
+ ...config,
15601
+ providerAliases: {
15602
+ ...previous,
15603
+ [from]: {
15604
+ ...previous[from] ?? {},
15605
+ [hostName]: to
15606
+ }
15607
+ }
15608
+ };
15609
+ }
15610
+ function unsetProviderHostAlias(config, provider, host) {
15611
+ const from = requireNonEmptyToken(provider, "provider");
15612
+ const hostName = requireNonEmptyToken(host, "host");
15613
+ const previous = config.providerAliases;
15614
+ if (previous === void 0 || previous[from] === void 0) return config;
15615
+ const { [hostName]: _dropped, ...restHosts } = previous[from];
15616
+ const nextForProvider = Object.keys(restHosts).length === 0 ? void 0 : restHosts;
15617
+ const { [from]: _provider, ...restProviders } = previous;
15618
+ const nextAliases = nextForProvider === void 0 ? restProviders : { ...restProviders, [from]: nextForProvider };
15619
+ if (Object.keys(nextAliases).length === 0) {
15620
+ const { providerAliases: _gone, ...rest } = config;
15621
+ return rest;
15622
+ }
15623
+ return { ...config, providerAliases: nextAliases };
15624
+ }
15625
+ function applyProviderHostAlias(selection, host, aliases) {
15626
+ if (selection === void 0 || aliases === void 0) return selection;
15627
+ const mapped = aliases[selection.provider]?.[host];
15628
+ if (mapped === void 0) return selection;
15629
+ return { ...selection, provider: mapped };
15630
+ }
15595
15631
  function validatePublicCliConfigAxes(config, _packageRoot) {
15596
15632
  for (const seat of Object.keys(config.seats)) {
15597
15633
  const row = config.seats[seat];
@@ -15651,9 +15687,44 @@ function serializePublicCliConfig(config) {
15651
15687
  ...config.unknownSeats ?? {},
15652
15688
  ...config.seats
15653
15689
  },
15654
- ...config.autoResumeLimit === void 0 ? {} : { autoResumeLimit: config.autoResumeLimit }
15690
+ ...config.autoResumeLimit === void 0 ? {} : { autoResumeLimit: config.autoResumeLimit },
15691
+ ...config.providerAliases === void 0 || Object.keys(config.providerAliases).length === 0 ? {} : { providerAliases: config.providerAliases }
15655
15692
  };
15656
15693
  }
15694
+ function parseProviderHostAliases(value) {
15695
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
15696
+ throw new Error("public CLI config.providerAliases must be an object");
15697
+ }
15698
+ const out = {};
15699
+ for (const [provider, byHost] of Object.entries(value)) {
15700
+ if (provider.trim() === "") {
15701
+ throw new Error("public CLI config.providerAliases provider key must be non-empty");
15702
+ }
15703
+ if (byHost === null || typeof byHost !== "object" || Array.isArray(byHost)) {
15704
+ throw new Error(
15705
+ `public CLI config.providerAliases[${provider}] must be an object`
15706
+ );
15707
+ }
15708
+ const hosts = {};
15709
+ for (const [host, alias] of Object.entries(byHost)) {
15710
+ if (host.trim() === "") {
15711
+ throw new Error(
15712
+ `public CLI config.providerAliases[${provider}] host key must be non-empty`
15713
+ );
15714
+ }
15715
+ if (typeof alias !== "string" || alias.trim() === "") {
15716
+ throw new Error(
15717
+ `public CLI config.providerAliases[${provider}][${host}] must be a non-empty string`
15718
+ );
15719
+ }
15720
+ hosts[host] = alias;
15721
+ }
15722
+ if (Object.keys(hosts).length > 0) {
15723
+ out[provider] = hosts;
15724
+ }
15725
+ }
15726
+ return out;
15727
+ }
15657
15728
  function parsePublicCliConfig(value) {
15658
15729
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
15659
15730
  throw new Error("public CLI config must be an object");
@@ -15663,6 +15734,13 @@ function parsePublicCliConfig(value) {
15663
15734
  if (record4.autoResumeLimit !== void 0) {
15664
15735
  autoResumeLimit = parseAutoResumeLimit(record4.autoResumeLimit);
15665
15736
  }
15737
+ let providerAliases;
15738
+ if (record4.providerAliases !== void 0) {
15739
+ const parsed = parseProviderHostAliases(record4.providerAliases);
15740
+ if (Object.keys(parsed).length > 0) {
15741
+ providerAliases = parsed;
15742
+ }
15743
+ }
15666
15744
  const unknownSeats = {};
15667
15745
  if (record4.unknownSeats !== void 0) {
15668
15746
  if (record4.unknownSeats === null || typeof record4.unknownSeats !== "object" || Array.isArray(record4.unknownSeats)) {
@@ -15673,6 +15751,7 @@ function parsePublicCliConfig(value) {
15673
15751
  const withOpaque = (seats2) => ({
15674
15752
  seats: seats2,
15675
15753
  ...autoResumeLimit === void 0 ? {} : { autoResumeLimit },
15754
+ ...providerAliases === void 0 ? {} : { providerAliases },
15676
15755
  ...Object.keys(unknownSeats).length === 0 ? {} : { unknownSeats }
15677
15756
  });
15678
15757
  if (record4.seats === void 0) {
@@ -15849,7 +15928,21 @@ function resolveEffectiveSeat(config, seat, credentials, invocation) {
15849
15928
  };
15850
15929
  }
15851
15930
  }
15852
- return attachHostAxis(attachEngineAxis(modelSeat, config, invocation), config, invocation);
15931
+ const withAxes = attachHostAxis(
15932
+ attachEngineAxis(modelSeat, config, invocation),
15933
+ config,
15934
+ invocation
15935
+ );
15936
+ const selection = applyProviderHostAlias(
15937
+ withAxes.selection,
15938
+ withAxes.host,
15939
+ config.providerAliases
15940
+ );
15941
+ if (selection === void 0) {
15942
+ const { selection: _dropped, ...rest } = withAxes;
15943
+ return rest;
15944
+ }
15945
+ return { ...withAxes, selection };
15853
15946
  }
15854
15947
  function effectiveSeatConfigurations(config, credentials, invocation) {
15855
15948
  return PUBLIC_CONFIGURABLE_SEATS.map(
@@ -16378,11 +16471,7 @@ function buildActivationFlagArgs(activation) {
16378
16471
  case "auditor":
16379
16472
  return ["--ak-role", "auditor"];
16380
16473
  case "diarist":
16381
- return [
16382
- "--ak-role",
16383
- "diarist",
16384
- ...activation.sourcesPath === void 0 ? [] : ["--ak-diarist-sources", activation.sourcesPath]
16385
- ];
16474
+ return ["--ak-role", "diarist"];
16386
16475
  default: {
16387
16476
  const _exhaustive = activation;
16388
16477
  return _exhaustive;
@@ -19501,14 +19590,17 @@ var init_option_definitions = __esm({
19501
19590
  "ak-role config unset-engine <seat>",
19502
19591
  "ak-role config set-host <seat> <name>",
19503
19592
  "ak-role config unset-host <seat>",
19504
- "ak-role config set-auto-resume-limit <N>"
19593
+ "ak-role config set-auto-resume-limit <N>",
19594
+ "ak-role config set-provider-alias <provider> <host> <alias>",
19595
+ "ak-role config unset-provider-alias <provider> <host>"
19505
19596
  ],
19506
19597
  examples: [
19507
19598
  "ak-role config set judge openai-codex/gpt-5.6-sol:high",
19508
19599
  "ak-role config unset gatekeeper",
19509
19600
  "ak-role config set-engine judge opus",
19510
19601
  "ak-role config set-host judge grok-build",
19511
- "ak-role config set-auto-resume-limit 3"
19602
+ "ak-role config set-auto-resume-limit 3",
19603
+ "ak-role config set-provider-alias xai hermes xai-oauth"
19512
19604
  ]
19513
19605
  },
19514
19606
  help: {
@@ -22818,22 +22910,9 @@ var init_known_failure = __esm({
22818
22910
  });
22819
22911
 
22820
22912
  // src/adr-path-refs.ts
22821
- function extractReferencedAdrPaths(text) {
22822
- const seen = /* @__PURE__ */ new Set();
22823
- const paths = [];
22824
- for (const match of text.matchAll(ADR_PATH_IN_BODY)) {
22825
- const path = match[0];
22826
- if (seen.has(path)) continue;
22827
- seen.add(path);
22828
- paths.push(path);
22829
- }
22830
- return Object.freeze(paths);
22831
- }
22832
- var ADR_PATH_IN_BODY;
22833
22913
  var init_adr_path_refs = __esm({
22834
22914
  "src/adr-path-refs.ts"() {
22835
22915
  "use strict";
22836
- ADR_PATH_IN_BODY = /docs\/adr\/(?:[A-Za-z0-9][A-Za-z0-9._-]*\/)*[A-Za-z0-9][A-Za-z0-9._-]*\.md/g;
22837
22916
  }
22838
22917
  });
22839
22918
 
@@ -22854,35 +22933,6 @@ var init_reviewer_preflight_error = __esm({
22854
22933
  // src/reviewer-pinned-git.ts
22855
22934
  import { execFile as execFile3 } from "node:child_process";
22856
22935
  import { promisify as promisify3 } from "node:util";
22857
- function parseGitHubOriginRemote(remoteUrl) {
22858
- const trimmed = remoteUrl.trim();
22859
- if (trimmed.length === 0) return void 0;
22860
- const scp = /^git@github\.com:([^/\s]+)\/([^/\s]+?)(?:\.git)?$/i.exec(trimmed);
22861
- if (scp) return normalizeOrigin(scp[1], scp[2]);
22862
- const ssh = /^ssh:\/\/git@github\.com\/([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i.exec(trimmed);
22863
- if (ssh) return normalizeOrigin(ssh[1], ssh[2]);
22864
- let parsed;
22865
- try {
22866
- parsed = new URL(trimmed);
22867
- } catch {
22868
- return void 0;
22869
- }
22870
- if (!/^github\.com$/i.test(parsed.hostname)) return void 0;
22871
- if (parsed.search !== "" || parsed.hash !== "") return void 0;
22872
- const parts = parsed.pathname.split("/").filter((p) => p.length > 0);
22873
- if (parts.length !== 2) return void 0;
22874
- return normalizeOrigin(parts[0], parts[1]);
22875
- }
22876
- function normalizeOrigin(ownerRaw, repoRaw) {
22877
- const owner = ownerRaw.trim();
22878
- const repo = stripGitSuffix2(repoRaw.trim());
22879
- if (owner.length === 0 || repo.length === 0) return void 0;
22880
- if (/[/?#@\\]/.test(owner) || /[/?#@\\]/.test(repo)) return void 0;
22881
- return Object.freeze({ owner, repo });
22882
- }
22883
- function stripGitSuffix2(name) {
22884
- return name.toLowerCase().endsWith(".git") ? name.slice(0, -4) : name;
22885
- }
22886
22936
  var execFileAsync3;
22887
22937
  var init_reviewer_pinned_git = __esm({
22888
22938
  "src/reviewer-pinned-git.ts"() {
@@ -23016,457 +23066,9 @@ var init_collector_evidence = __esm({
23016
23066
  });
23017
23067
 
23018
23068
  // src/collector-github.ts
23019
- import { spawn as spawn2 } from "node:child_process";
23020
- function isRecord13(value) {
23021
- return typeof value === "object" && value !== null && !Array.isArray(value);
23022
- }
23023
- function requireString(value, label) {
23024
- if (typeof value !== "string") {
23025
- throw new Error(`GitHub payload missing string ${label}`);
23026
- }
23027
- return value;
23028
- }
23029
- function requireNumber(value, label) {
23030
- if (typeof value !== "number" || !Number.isFinite(value)) {
23031
- throw new Error(`GitHub payload missing number ${label}`);
23032
- }
23033
- return value;
23034
- }
23035
- function optionalString(value) {
23036
- return typeof value === "string" ? value : null;
23037
- }
23038
- function parseLinkNext(linkHeader) {
23039
- if (linkHeader === void 0 || linkHeader.length === 0) return void 0;
23040
- for (const part of linkHeader.split(",")) {
23041
- const match = part.trim().match(/^<([^>]+)>\s*;\s*rel="next"$/i);
23042
- if (match?.[1]) return match[1];
23043
- }
23044
- return void 0;
23045
- }
23046
- function parseJson(text, label) {
23047
- try {
23048
- return JSON.parse(text);
23049
- } catch (error) {
23050
- throw new Error(`GitHub ${label} returned malformed JSON`, { cause: error });
23051
- }
23052
- }
23053
- function commentFailureCause(error) {
23054
- return {
23055
- name: error instanceof Error ? error.name : typeof error,
23056
- message: error instanceof Error ? error.message : String(error),
23057
- evidenceId: `github-comment-failure-${++commentFailureEvidence}`
23058
- };
23059
- }
23060
- function requireUserLogin(raw) {
23061
- if (!isRecord13(raw) || typeof raw["login"] !== "string") {
23062
- throw new Error("GitHub payload missing user.login");
23063
- }
23064
- return raw["login"];
23065
- }
23066
- function optionalUserLogin(raw) {
23067
- if (raw === null) return null;
23068
- if (!isRecord13(raw) || typeof raw["login"] !== "string") {
23069
- throw new Error("GitHub payload missing user.login");
23070
- }
23071
- return raw["login"];
23072
- }
23073
- function machineIdentity(raw) {
23074
- const user = raw["user"];
23075
- if (!isRecord13(user) || typeof user["type"] !== "string" || typeof user["id"] !== "number") {
23076
- return null;
23077
- }
23078
- const app = raw["performed_via_github_app"];
23079
- const appId = isRecord13(app) && typeof app["id"] === "number" ? app["id"] : void 0;
23080
- return {
23081
- userType: user["type"],
23082
- userId: user["id"],
23083
- ...appId === void 0 ? {} : { appId }
23084
- };
23085
- }
23086
- function normalizePullRequest(raw) {
23087
- if (!isRecord13(raw)) throw new Error("GitHub pull request payload must be an object");
23088
- const head = raw["head"];
23089
- if (!isRecord13(head) || typeof head["sha"] !== "string" || head["sha"].length === 0) {
23090
- throw new Error("GitHub pull request payload missing head.sha");
23091
- }
23092
- const number = requireNumber(raw["number"], "number");
23093
- const state = requireString(raw["state"], "state").toUpperCase();
23094
- const htmlUrl = typeof raw["html_url"] === "string" ? raw["html_url"] : `https://github.com/unknown/unknown/pull/${number}`;
23095
- return {
23096
- number,
23097
- state: state === "OPEN" || state === "open" ? "OPEN" : state,
23098
- headOid: head["sha"],
23099
- ...typeof raw["updated_at"] === "string" ? { updatedAt: raw["updated_at"] } : {},
23100
- url: htmlUrl,
23101
- raw
23102
- };
23103
- }
23104
- function normalizePullRequestReaction(raw) {
23105
- if (!isRecord13(raw)) throw new Error("GitHub reaction payload must be an object");
23106
- return {
23107
- id: requireNumber(raw["id"], "reaction.id"),
23108
- userLogin: optionalUserLogin(raw["user"]),
23109
- machineIdentity: machineIdentity(raw),
23110
- content: requireString(raw["content"], "reaction.content"),
23111
- createdAt: requireString(raw["created_at"], "reaction.created_at"),
23112
- raw
23113
- };
23114
- }
23115
- function normalizeReview(raw) {
23116
- if (!isRecord13(raw)) throw new Error("GitHub review payload must be an object");
23117
- return {
23118
- id: requireNumber(raw["id"], "review.id"),
23119
- ...typeof raw["node_id"] === "string" ? { nodeId: raw["node_id"] } : {},
23120
- userLogin: optionalUserLogin(raw["user"]),
23121
- machineIdentity: machineIdentity(raw),
23122
- state: requireString(raw["state"], "review.state").toUpperCase(),
23123
- body: typeof raw["body"] === "string" ? raw["body"] : "",
23124
- commitId: optionalString(raw["commit_id"]),
23125
- submittedAt: optionalString(raw["submitted_at"]),
23126
- htmlUrl: typeof raw["html_url"] === "string" ? raw["html_url"] : "",
23127
- raw
23128
- };
23129
- }
23130
- function normalizeIssueComment(raw) {
23131
- if (!isRecord13(raw)) throw new Error("GitHub issue comment payload must be an object");
23132
- return {
23133
- id: requireNumber(raw["id"], "comment.id"),
23134
- userLogin: optionalUserLogin(raw["user"]),
23135
- machineIdentity: machineIdentity(raw),
23136
- body: typeof raw["body"] === "string" ? raw["body"] : "",
23137
- createdAt: requireString(raw["created_at"], "comment.created_at"),
23138
- updatedAt: requireString(raw["updated_at"], "comment.updated_at"),
23139
- htmlUrl: typeof raw["html_url"] === "string" ? raw["html_url"] : "",
23140
- raw
23141
- };
23142
- }
23143
- function normalizeReviewComment(raw) {
23144
- if (!isRecord13(raw)) throw new Error("GitHub review comment payload must be an object");
23145
- return {
23146
- id: requireNumber(raw["id"], "review_comment.id"),
23147
- pullRequestReviewId: typeof raw["pull_request_review_id"] === "number" ? raw["pull_request_review_id"] : null,
23148
- userLogin: optionalUserLogin(raw["user"]),
23149
- machineIdentity: machineIdentity(raw),
23150
- body: typeof raw["body"] === "string" ? raw["body"] : "",
23151
- path: requireString(raw["path"], "review_comment.path"),
23152
- line: typeof raw["line"] === "number" ? raw["line"] : null,
23153
- originalLine: typeof raw["original_line"] === "number" ? raw["original_line"] : null,
23154
- side: optionalString(raw["side"]),
23155
- position: typeof raw["position"] === "number" ? raw["position"] : null,
23156
- originalPosition: typeof raw["original_position"] === "number" ? raw["original_position"] : null,
23157
- commitId: optionalString(raw["commit_id"]),
23158
- originalCommitId: optionalString(raw["original_commit_id"]),
23159
- createdAt: requireString(raw["created_at"], "review_comment.created_at"),
23160
- updatedAt: requireString(raw["updated_at"], "review_comment.updated_at"),
23161
- htmlUrl: typeof raw["html_url"] === "string" ? raw["html_url"] : "",
23162
- raw
23163
- };
23164
- }
23165
- function createGhApiRunner(options = {}) {
23166
- const spawnImpl = options.spawnImpl ?? spawn2;
23167
- return async (args, runOptions = {}) => {
23168
- return await new Promise((resolve12, reject) => {
23169
- const signal = runOptions.signal;
23170
- if (signal?.aborted) {
23171
- reject(signal.reason ?? new Error("aborted"));
23172
- return;
23173
- }
23174
- const child = spawnImpl("gh", args, {
23175
- env: options.env ?? process.env,
23176
- stdio: ["pipe", "pipe", "pipe"]
23177
- });
23178
- let stdout = "";
23179
- let stderr = "";
23180
- let settled = false;
23181
- const settle = (fn) => {
23182
- if (settled) return;
23183
- settled = true;
23184
- if (signal !== void 0) {
23185
- signal.removeEventListener("abort", onAbort);
23186
- }
23187
- fn();
23188
- };
23189
- const onAbort = () => {
23190
- try {
23191
- child.kill("SIGTERM");
23192
- } catch (error) {
23193
- settle(() => reject(error));
23194
- return;
23195
- }
23196
- settle(() => {
23197
- reject(signal?.reason ?? new Error("aborted"));
23198
- });
23199
- };
23200
- if (signal !== void 0) {
23201
- signal.addEventListener("abort", onAbort, { once: true });
23202
- }
23203
- child.stdout.setEncoding("utf8").on("data", (chunk) => {
23204
- stdout += chunk;
23205
- });
23206
- child.stderr.setEncoding("utf8").on("data", (chunk) => {
23207
- stderr += chunk;
23208
- });
23209
- child.on("error", (error) => {
23210
- settle(() => reject(error));
23211
- });
23212
- child.stdin.on("error", (error) => {
23213
- settle(() => {
23214
- if (signal?.aborted) {
23215
- reject(signal.reason ?? new Error("aborted"));
23216
- return;
23217
- }
23218
- const err = error instanceof Error ? error : new Error(String(error));
23219
- reject(Object.assign(err, { ambiguousGhFailure: true }));
23220
- });
23221
- });
23222
- if (runOptions.stdin !== void 0) {
23223
- child.stdin.write(runOptions.stdin);
23224
- }
23225
- child.stdin.end();
23226
- child.on("close", (code, signal2) => {
23227
- settle(() => {
23228
- const match = stdout.match(/^HTTP\/[\d.]+\s+(\d+)[^\n]*\r?\n([\s\S]*?)\r?\n\r?\n([\s\S]*)$/);
23229
- if (match) {
23230
- const status = Number(match[1]);
23231
- const headerText = match[2] ?? "";
23232
- const bodyText = match[3] ?? "";
23233
- const headers = {};
23234
- for (const line2 of headerText.split(/\r?\n/)) {
23235
- const idx = line2.indexOf(":");
23236
- if (idx === -1) continue;
23237
- const name = line2.slice(0, idx).trim().toLowerCase();
23238
- const value = line2.slice(idx + 1).trim();
23239
- headers[name] = value;
23240
- }
23241
- resolve12({ status, headers, bodyText });
23242
- return;
23243
- }
23244
- if (code === 0) {
23245
- resolve12({ status: 200, headers: {}, bodyText: stdout });
23246
- return;
23247
- }
23248
- const failure = new Error(
23249
- `gh api failed without a parseable HTTP response (code=${String(code)}): ${stderr || stdout}`,
23250
- { cause: { code, signal: signal2, stderr, stdout } }
23251
- );
23252
- reject(Object.assign(failure, { ambiguousGhFailure: true, stderr, stdout, code, signal: signal2 }));
23253
- });
23254
- });
23255
- });
23256
- };
23257
- }
23258
- function isAmbiguousGhFailure(error) {
23259
- return typeof error === "object" && error !== null && error.ambiguousGhFailure === true;
23260
- }
23261
- function isGhProcessStartFailure(error) {
23262
- if (typeof error !== "object" || error === null) return false;
23263
- const code = error.code;
23264
- if (code === "ENOENT") return true;
23265
- const syscall = error.syscall;
23266
- return typeof syscall === "string" && (syscall === "spawn" || syscall.startsWith("spawn "));
23267
- }
23268
- async function projectGhIssueBody(runner, input) {
23269
- const path = `repos/${input.owner}/${input.repo}/issues/${input.ticketNumber}`;
23270
- let response;
23271
- try {
23272
- response = await runner(
23273
- ["api", "--hostname", "github.com", "--include", "-X", "GET", path],
23274
- input.signal === void 0 ? {} : { signal: input.signal }
23275
- );
23276
- } catch (error) {
23277
- if (isAmbiguousGhFailure(error) || isGhProcessStartFailure(error)) {
23278
- return { status: "unavailable", reason: "transport", cause: error };
23279
- }
23280
- throw error;
23281
- }
23282
- if (response.status < 200 || response.status >= 300) {
23283
- return {
23284
- status: "unavailable",
23285
- reason: "http-non-2xx",
23286
- httpStatus: response.status
23287
- };
23288
- }
23289
- let parsed;
23290
- try {
23291
- parsed = JSON.parse(response.bodyText);
23292
- } catch (error) {
23293
- return { status: "invalid", reason: "not-json", cause: error };
23294
- }
23295
- if (typeof parsed !== "object" || parsed === null) {
23296
- return { status: "invalid", reason: "not-object" };
23297
- }
23298
- if (Object.hasOwn(parsed, "pull_request")) {
23299
- return { status: "unavailable", reason: "pull-request" };
23300
- }
23301
- const bodyRaw = parsed.body;
23302
- if (bodyRaw !== void 0 && bodyRaw !== null && typeof bodyRaw !== "string") {
23303
- return { status: "invalid", reason: "body-invalid" };
23304
- }
23305
- const body = typeof bodyRaw === "string" ? bodyRaw : "";
23306
- return { status: "available", body };
23307
- }
23308
- function createGhCollectorGitHubTransport(runner = createGhApiRunner()) {
23309
- const hostnameArgs = ["api", "--hostname", "github.com", "--include"];
23310
- async function apiGet(path, signal) {
23311
- return await runner(
23312
- [...hostnameArgs, "-X", "GET", path],
23313
- signal === void 0 ? {} : { signal }
23314
- );
23315
- }
23316
- async function paginate(path, mapItem, options = {}) {
23317
- const { signal, retainPage } = options;
23318
- const items = [];
23319
- const pages = [];
23320
- let nextPath = path;
23321
- let page = 1;
23322
- const seen = /* @__PURE__ */ new Set();
23323
- while (nextPath !== void 0) {
23324
- if (signal?.aborted) {
23325
- throw signal.reason ?? new Error("aborted");
23326
- }
23327
- if (seen.has(nextPath)) {
23328
- throw new Error(`GitHub pagination repeated page: ${nextPath}`);
23329
- }
23330
- seen.add(nextPath);
23331
- const response = await apiGet(nextPath, signal);
23332
- const diagnostics = {
23333
- path: nextPath,
23334
- page,
23335
- status: response.status,
23336
- itemCount: 0,
23337
- ...response.headers["link"] === void 0 ? {} : { linkHeader: response.headers["link"] }
23338
- };
23339
- if (response.status === 429) {
23340
- throw Object.assign(
23341
- new Error(`GitHub API rate limited on ${nextPath} (HTTP 429)`),
23342
- { githubStatus: 429, page: diagnostics }
23343
- );
23344
- }
23345
- if (response.status < 200 || response.status >= 300) {
23346
- throw Object.assign(
23347
- new Error(`GitHub API ${nextPath} failed with HTTP ${response.status}`),
23348
- { githubStatus: response.status, page: diagnostics }
23349
- );
23350
- }
23351
- const parsed = parseJson(response.bodyText, nextPath);
23352
- if (!Array.isArray(parsed)) {
23353
- throw new Error(`GitHub API ${nextPath} did not return a JSON array`);
23354
- }
23355
- diagnostics.itemCount = parsed.length;
23356
- pages.push(diagnostics);
23357
- const pageItems = parsed.map((entry) => mapItem(entry));
23358
- retainPage?.(pageItems);
23359
- for (const item of pageItems) items.push(item);
23360
- const nextUrl = parseLinkNext(response.headers["link"]);
23361
- if (nextUrl === void 0) {
23362
- nextPath = void 0;
23363
- } else {
23364
- if (nextUrl.startsWith("/")) {
23365
- nextPath = nextUrl;
23366
- } else {
23367
- const url = new URL(nextUrl);
23368
- if (url.hostname !== "api.github.com" && url.hostname !== "github.com") {
23369
- throw new Error(`unexpected pagination host ${url.hostname}`);
23370
- }
23371
- nextPath = `${url.pathname}${url.search}`;
23372
- if (nextPath.startsWith("/api/v3/")) {
23373
- nextPath = nextPath.slice("/api/v3".length);
23374
- }
23375
- }
23376
- }
23377
- page += 1;
23378
- }
23379
- return { items, pages };
23380
- }
23381
- return {
23382
- async getAuthenticatedUser(options = {}) {
23383
- const response = await apiGet("/user", options.signal);
23384
- if (response.status < 200 || response.status >= 300) {
23385
- throw new Error(`GitHub /user failed with HTTP ${response.status}`, { cause: { endpoint: "/user", status: response.status, headers: response.headers, body: response.bodyText } });
23386
- }
23387
- const raw = parseJson(response.bodyText, "/user");
23388
- return { login: requireUserLogin(raw).toLowerCase(), raw };
23389
- },
23390
- async getPullRequest(input) {
23391
- const path = `/repos/${input.owner}/${input.repo}/pulls/${input.prNumber}`;
23392
- const response = await apiGet(path, input.signal);
23393
- if (response.status < 200 || response.status >= 300) {
23394
- throw new Error(`GitHub ${path} failed with HTTP ${response.status}`, { cause: { endpoint: path, status: response.status, headers: response.headers, body: response.bodyText } });
23395
- }
23396
- return normalizePullRequest(parseJson(response.bodyText, path));
23397
- },
23398
- async listPullRequestReviews(input) {
23399
- const path = `/repos/${input.owner}/${input.repo}/pulls/${input.prNumber}/reviews?per_page=100`;
23400
- return await paginate(path, normalizeReview, {
23401
- ...input.signal === void 0 ? {} : { signal: input.signal },
23402
- ...input.retainPage === void 0 ? {} : { retainPage: input.retainPage }
23403
- });
23404
- },
23405
- async listPullRequestReactions(input) {
23406
- const path = `/repos/${input.owner}/${input.repo}/issues/${input.prNumber}/reactions?per_page=100`;
23407
- return await paginate(path, normalizePullRequestReaction, {
23408
- ...input.signal === void 0 ? {} : { signal: input.signal },
23409
- ...input.retainPage === void 0 ? {} : { retainPage: input.retainPage }
23410
- });
23411
- },
23412
- async listIssueComments(input) {
23413
- const path = `/repos/${input.owner}/${input.repo}/issues/${input.prNumber}/comments?per_page=100`;
23414
- return await paginate(path, normalizeIssueComment, {
23415
- ...input.signal === void 0 ? {} : { signal: input.signal },
23416
- ...input.retainPage === void 0 ? {} : { retainPage: input.retainPage }
23417
- });
23418
- },
23419
- async listReviewComments(input) {
23420
- const path = `/repos/${input.owner}/${input.repo}/pulls/${input.prNumber}/comments?per_page=100`;
23421
- return await paginate(path, normalizeReviewComment, {
23422
- ...input.signal === void 0 ? {} : { signal: input.signal },
23423
- ...input.retainPage === void 0 ? {} : { retainPage: input.retainPage }
23424
- });
23425
- },
23426
- async createIssueComment(input) {
23427
- const path = `/repos/${input.owner}/${input.repo}/issues/${input.prNumber}/comments`;
23428
- try {
23429
- const response = await runner(
23430
- [...hostnameArgs, "-X", "POST", path, "--input", "-"],
23431
- input.signal === void 0 ? { stdin: JSON.stringify({ body: input.body }) } : { stdin: JSON.stringify({ body: input.body }), signal: input.signal }
23432
- );
23433
- if (response.status >= 200 && response.status < 300) {
23434
- try {
23435
- return {
23436
- kind: "success",
23437
- comment: normalizeIssueComment(parseJson(response.bodyText, path))
23438
- };
23439
- } catch (error) {
23440
- const cause = commentFailureCause(error);
23441
- return { kind: "ambiguous_loss", diagnostics: cause.message, cause };
23442
- }
23443
- }
23444
- return {
23445
- kind: "rejected",
23446
- status: response.status,
23447
- diagnostics: `HTTP ${response.status}: ${response.bodyText.slice(0, 500)}`
23448
- };
23449
- } catch (error) {
23450
- if (input.signal?.aborted) {
23451
- throw error;
23452
- }
23453
- if (isRecord13(error) && error["ambiguousGhFailure"] === true) {
23454
- const cause = commentFailureCause(error);
23455
- return { kind: "ambiguous_loss", diagnostics: cause.message, cause };
23456
- }
23457
- if (isRecord13(error) && error["name"] === "AbortError") {
23458
- throw error;
23459
- }
23460
- throw error;
23461
- }
23462
- }
23463
- };
23464
- }
23465
- var commentFailureEvidence;
23466
23069
  var init_collector_github = __esm({
23467
23070
  "src/collector-github.ts"() {
23468
23071
  "use strict";
23469
- commentFailureEvidence = 0;
23470
23072
  }
23471
23073
  });
23472
23074
 
@@ -23630,11 +23232,11 @@ var init_navigator_invocation_identity = __esm({
23630
23232
  });
23631
23233
 
23632
23234
  // src/receipt-delivery-policy.ts
23633
- function isRecord14(value) {
23235
+ function isRecord13(value) {
23634
23236
  return typeof value === "object" && value !== null && !Array.isArray(value);
23635
23237
  }
23636
23238
  function parseNoReceiptLifecycleFacts(input) {
23637
- if (!isRecord14(input) || typeof input.terminalToolCalled !== "boolean" || input.deliveryTurns !== RECEIPT_DELIVERY_TURN_LIMIT || input.sessionCompletion !== "settled-without-accepted-receipt" || input.acceptedReceipt !== false || typeof input.runPointer !== "string" || input.runPointer.trim() === "" || typeof input.attemptPointer !== "string" || input.attemptPointer.trim() === "" || !Array.isArray(input.rejectedReceipts) || !input.rejectedReceipts.every((item) => isRecord14(item) && typeof item.reason === "string")) {
23239
+ if (!isRecord13(input) || typeof input.terminalToolCalled !== "boolean" || input.deliveryTurns !== RECEIPT_DELIVERY_TURN_LIMIT || input.sessionCompletion !== "settled-without-accepted-receipt" || input.acceptedReceipt !== false || typeof input.runPointer !== "string" || input.runPointer.trim() === "" || typeof input.attemptPointer !== "string" || input.attemptPointer.trim() === "" || !Array.isArray(input.rejectedReceipts) || !input.rejectedReceipts.every((item) => isRecord13(item) && typeof item.reason === "string")) {
23638
23240
  throw new TypeError("malformed no-receipt lifecycle facts");
23639
23241
  }
23640
23242
  return {
@@ -24200,7 +23802,7 @@ async function readSitianRetainedAuditorProviderStop(sessionFile) {
24200
23802
  const { records: records2 } = await readSitianRecords(recordFile);
24201
23803
  for (let i = records2.length - 1; i >= 0; i -= 1) {
24202
23804
  const payload = records2[i]?.payload;
24203
- if (!isRecord15(payload) || !isRecord15(payload.response)) continue;
23805
+ if (!isRecord14(payload) || !isRecord14(payload.response)) continue;
24204
23806
  if (typeof payload.type === "string") continue;
24205
23807
  const stop = sessionProviderStopFromAssistant(payload.response);
24206
23808
  if (stop !== void 0) return stop;
@@ -24237,7 +23839,7 @@ async function readBoundEvidenceChildKnownFailure(sessionFile) {
24237
23839
  throw sessionReadFailure(error, "failed to read discovered evidence-child session");
24238
23840
  }
24239
23841
  const header = entries.find((entry) => entry.type === "session");
24240
- if (!isRecord15(header) || header.parentSession !== sessionFile) continue;
23842
+ if (!isRecord14(header) || header.parentSession !== sessionFile) continue;
24241
23843
  const stop = extractSessionProviderStop(entries);
24242
23844
  if (stop === void 0) continue;
24243
23845
  const primary = knownFailureFromProviderStop(stop);
@@ -24269,12 +23871,12 @@ async function loadBoundAuditorVolumes(sessionFile) {
24269
23871
  return firstLine === RESUME_ENVELOPE;
24270
23872
  };
24271
23873
  const isResumeEnvelope = (msg) => {
24272
- if (!isRecord15(msg) || msg.role !== "user") return false;
23874
+ if (!isRecord14(msg) || msg.role !== "user") return false;
24273
23875
  const text = typeof msg.text === "string" ? msg.text : typeof msg.content === "string" ? msg.content : void 0;
24274
23876
  if (isResumeEnvelopeBytes(text)) return true;
24275
23877
  const content = msg.content;
24276
23878
  if (Array.isArray(content)) {
24277
- return content.some((p) => isRecord15(p) && (isResumeEnvelopeBytes(p.text) || isResumeEnvelopeBytes(p.content)));
23879
+ return content.some((p) => isRecord14(p) && (isResumeEnvelopeBytes(p.text) || isResumeEnvelopeBytes(p.content)));
24278
23880
  }
24279
23881
  return false;
24280
23882
  };
@@ -24306,7 +23908,7 @@ async function loadBoundAuditorVolumes(sessionFile) {
24306
23908
  throw sessionReadFailure(error, "failed to read discovered auditor session");
24307
23909
  }
24308
23910
  const header = entries.find((entry) => entry.type === "session");
24309
- if (!isRecord15(header)) continue;
23911
+ if (!isRecord14(header)) continue;
24310
23912
  const bindingIndexes = [];
24311
23913
  for (let i = 0; i < entries.length; i += 1) {
24312
23914
  const entry = entries[i];
@@ -24320,7 +23922,7 @@ async function loadBoundAuditorVolumes(sessionFile) {
24320
23922
  end: idx + 1 < bindingIndexes.length ? bindingIndexes[idx + 1] : entries.length
24321
23923
  })) : [{ entry: void 0, start: 0, end: entries.length }];
24322
23924
  for (const { entry: bindingEntry, start, end } of bindingPasses) {
24323
- const bindingParent = bindingEntry !== void 0 && isRecord15(bindingEntry.data) && isRecord15(bindingEntry.data.parent) ? bindingEntry.data.parent : void 0;
23925
+ const bindingParent = bindingEntry !== void 0 && isRecord14(bindingEntry.data) && isRecord14(bindingEntry.data.parent) ? bindingEntry.data.parent : void 0;
24324
23926
  const attemptEntryId = typeof bindingParent?.attemptEntryId === "string" ? bindingParent.attemptEntryId : void 0;
24325
23927
  const attemptEntryIndex = attemptEntryId === void 0 ? -1 : parentEntries.findIndex((entry) => entry.id === attemptEntryId);
24326
23928
  const boundSessionFile = typeof bindingParent?.sessionFile === "string" ? bindingParent.sessionFile : typeof header.parentSession === "string" ? header.parentSession : void 0;
@@ -24347,11 +23949,11 @@ function complianceFailureFromAuditorVolumes(volumes) {
24347
23949
  if (stop === void 0) continue;
24348
23950
  for (let i = entries.length - 1; i >= 0; i -= 1) {
24349
23951
  const entry = entries[i];
24350
- if (entry?.type !== "custom" || entry.customType !== AUDITOR_COMPLIANCE_FAILURE_ENTRY_TYPE || !isRecord15(entry.data)) continue;
24351
- const parent = isRecord15(entry.data.parent) ? entry.data.parent : void 0;
24352
- const failure = isRecord15(entry.data.failure) ? entry.data.failure : void 0;
23952
+ if (entry?.type !== "custom" || entry.customType !== AUDITOR_COMPLIANCE_FAILURE_ENTRY_TYPE || !isRecord14(entry.data)) continue;
23953
+ const parent = isRecord14(entry.data.parent) ? entry.data.parent : void 0;
23954
+ const failure = isRecord14(entry.data.failure) ? entry.data.failure : void 0;
24353
23955
  if (parent?.sessionId !== parentId || parent.sessionFile !== sessionFile || parent.attemptEntryId !== attemptEntryId || failure?.cause !== "provider" && failure?.cause !== "unrecognized") continue;
24354
- const identity = isRecord15(failure.identity) ? failure.identity : void 0;
23956
+ const identity = isRecord14(failure.identity) ? failure.identity : void 0;
24355
23957
  return {
24356
23958
  cause: failure.cause === "provider" ? "provider" : "unrecognized",
24357
23959
  ...identity === void 0 ? {} : { identity: {
@@ -24359,7 +23961,7 @@ function complianceFailureFromAuditorVolumes(volumes) {
24359
23961
  ...typeof identity.code === "string" || typeof identity.code === "number" ? { code: identity.code } : {}
24360
23962
  } },
24361
23963
  ...typeof failure.diagnostic === "string" ? { diagnostic: failure.diagnostic } : {},
24362
- ...isRecord15(failure.details) ? { details: failure.details } : {}
23964
+ ...isRecord14(failure.details) ? { details: failure.details } : {}
24363
23965
  };
24364
23966
  }
24365
23967
  }
@@ -24406,9 +24008,9 @@ function typedFailedTerminatingToolKnownFailure(entries) {
24406
24008
  if (classification.kind !== "infrastructure") continue;
24407
24009
  if (typeof message.toolCallId !== "string" || typeof message.toolName !== "string") continue;
24408
24010
  if (boundRoleToolCallForResult(attemptEntries, i, message, message.toolName) === void 0) continue;
24409
- const textPart = Array.isArray(message.content) ? message.content.find((part) => isRecord15(part) && part.type === "text" && typeof part.text === "string") : void 0;
24410
- const diagnostic = isRecord15(textPart) ? textPart.text : void 0;
24411
- const details = isRecord15(message.details) ? message.details : classification.fact;
24011
+ const textPart = Array.isArray(message.content) ? message.content.find((part) => isRecord14(part) && part.type === "text" && typeof part.text === "string") : void 0;
24012
+ const diagnostic = isRecord14(textPart) ? textPart.text : void 0;
24013
+ const details = isRecord14(message.details) ? message.details : classification.fact;
24412
24014
  return {
24413
24015
  cause: "activation",
24414
24016
  identity: { name: message.toolName, code: message.toolCallId },
@@ -24566,7 +24168,7 @@ function controlledFailureInputFromResolution(resolution) {
24566
24168
  } : {}
24567
24169
  };
24568
24170
  }
24569
- function isRecord15(value) {
24171
+ function isRecord14(value) {
24570
24172
  return typeof value === "object" && value !== null && !Array.isArray(value);
24571
24173
  }
24572
24174
  function safelyRead(object, key) {
@@ -24690,7 +24292,7 @@ function boundRoleToolCallForResult(entries, resultIndex, message, outputToolNam
24690
24292
  const candidateMessage = entries[index]?.message;
24691
24293
  if (candidateMessage?.role === "assistant" && Array.isArray(candidateMessage.content)) {
24692
24294
  for (const part of candidateMessage.content) {
24693
- if (!isRecord15(part) || part.type !== "toolCall" || part.id !== callId) {
24295
+ if (!isRecord14(part) || part.type !== "toolCall" || part.id !== callId) {
24694
24296
  continue;
24695
24297
  }
24696
24298
  if (part.name !== outputToolName) return void 0;
@@ -24762,7 +24364,7 @@ function parseNavigatorAttendanceDetails(details) {
24762
24364
  const advisoryDiagnostic = typeof details.routePlaybookReadFailure === "string" ? { advisoryDiagnostic: details.routePlaybookReadFailure } : {};
24763
24365
  if (disposition === "recommendation") {
24764
24366
  const next = details.next;
24765
- if (!isRecord15(next) || typeof next.role !== "string") {
24367
+ if (!isRecord14(next) || typeof next.role !== "string") {
24766
24368
  return {
24767
24369
  disposition: "unavailable",
24768
24370
  source: "unknown",
@@ -24770,7 +24372,7 @@ function parseNavigatorAttendanceDetails(details) {
24770
24372
  };
24771
24373
  }
24772
24374
  const reason = typeof details.reason === "string" ? details.reason : "";
24773
- const route = Array.isArray(details.route) ? details.route.filter(isRecord15).map((target) => ({
24375
+ const route = Array.isArray(details.route) ? details.route.filter(isRecord14).map((target) => ({
24774
24376
  role: String(target.role),
24775
24377
  phase: navigatorPhaseValue(target.phase)
24776
24378
  })) : void 0;
@@ -24842,7 +24444,7 @@ async function extractGateFactFromSessionDirectory(sessionDirectory, options = {
24842
24444
  }
24843
24445
  async function withOptionalGateProjection(base, sessionDirectory, gateContext = {}) {
24844
24446
  const secondaryEvidence = base.roleOutcome.kind === "failure" ? base.roleOutcome.decisiveFacts.secondaryEvidence : void 0;
24845
- if (isRecord15(secondaryEvidence) && secondaryEvidence.kind === "role_infrastructure_failure" && (secondaryEvidence.stage === "gatekeeper" || secondaryEvidence.stage === "inspector" || secondaryEvidence.stage === "notary")) return base;
24447
+ if (isRecord14(secondaryEvidence) && secondaryEvidence.kind === "role_infrastructure_failure" && (secondaryEvidence.stage === "gatekeeper" || secondaryEvidence.stage === "inspector" || secondaryEvidence.stage === "notary")) return base;
24846
24448
  const gate = await extractGateFactFromSessionDirectory(sessionDirectory, gateContext);
24847
24449
  return gate === void 0 ? base : { ...base, gate };
24848
24450
  }
@@ -24882,7 +24484,7 @@ function extractNavigatorFact(entries) {
24882
24484
  const entry = entries[i];
24883
24485
  if (entry?.type === "custom_message" && entry.customType === "ak-navigator-attendance") {
24884
24486
  const details = entry.message?.details ?? entry.details;
24885
- if (!isRecord15(details)) {
24487
+ if (!isRecord14(details)) {
24886
24488
  return {
24887
24489
  disposition: "unavailable",
24888
24490
  source: "unknown",
@@ -25280,7 +24882,7 @@ async function settleLawfulCollectorTerminalResult(admitted, authority) {
25280
24882
  const residual = boundErroredToolCandidate(entries, index, message, COLLECTOR_WAIT_TOOL);
25281
24883
  if (residual === void 0) continue;
25282
24884
  const candidate = residual.candidate;
25283
- const duration = isRecord15(candidate) ? candidate.durationMs : void 0;
24885
+ const duration = isRecord14(candidate) ? candidate.durationMs : void 0;
25284
24886
  if (Number.isSafeInteger(duration) && duration >= 1 && duration <= 9e5) {
25285
24887
  continue;
25286
24888
  }
@@ -25470,7 +25072,7 @@ async function settleLawfulSeatAcceptedTerminalResult(admitted, authority, spec,
25470
25072
  spec.toolName
25471
25073
  );
25472
25074
  if (residual !== void 0) {
25473
- const details = isRecord15(residual.candidate) ? residual.candidate : { candidate: residual.candidate };
25075
+ const details = isRecord14(residual.candidate) ? residual.candidate : { candidate: residual.candidate };
25474
25076
  return settleFailureTerminalResult(admitted, {
25475
25077
  cause: "output",
25476
25078
  diagnostic: residual.diagnostic,
@@ -25772,7 +25374,7 @@ async function settleLawfulMergerTerminalResult(admitted, authority, options) {
25772
25374
  if (message?.role !== "toolResult") continue;
25773
25375
  const residual = boundErroredToolCandidate(entries, index, message, MERGER_OUTPUT_TOOL_NAME);
25774
25376
  if (residual === void 0) continue;
25775
- const attemptId = isRecord15(residual.candidate) ? safelyRead(residual.candidate, "attemptId") : { readable: true, value: void 0 };
25377
+ const attemptId = isRecord14(residual.candidate) ? safelyRead(residual.candidate, "attemptId") : { readable: true, value: void 0 };
25776
25378
  if (!attemptId.readable || attemptId.value !== admitted.runId) continue;
25777
25379
  return {
25778
25380
  roleOutcome: buildResidualIncompleteTerminalOutcome({
@@ -26203,99 +25805,16 @@ var init_turn_request = __esm({
26203
25805
  });
26204
25806
 
26205
25807
  // src/ticket-provenance-contracts.ts
26206
- function isRecord16(value) {
26207
- return typeof value === "object" && value !== null && !Array.isArray(value);
26208
- }
26209
- function projectTicketProvenanceDiagnostic(value) {
26210
- if (!isRecord16(value)) return void 0;
26211
- if (value.recordClass !== TICKET_PROVENANCE_RECORD_CLASS_DIAGNOSTIC) {
26212
- return void 0;
26213
- }
26214
- if (typeof value.diagnosticKind !== "string" || !DIAGNOSTIC_KINDS.has(value.diagnosticKind)) {
26215
- return void 0;
26216
- }
26217
- if (typeof value.cause !== "string" || value.cause.length === 0) {
26218
- return void 0;
26219
- }
26220
- if (typeof value.recordedAt !== "string" || value.recordedAt.length === 0) {
26221
- return void 0;
26222
- }
26223
- return {
26224
- recordClass: TICKET_PROVENANCE_RECORD_CLASS_DIAGNOSTIC,
26225
- diagnosticKind: value.diagnosticKind,
26226
- cause: value.cause,
26227
- recordedAt: value.recordedAt,
26228
- ...typeof value.reason === "string" ? { reason: value.reason } : {}
26229
- };
26230
- }
26231
- function projectTicketProvenanceEntry(value) {
26232
- if (!isRecord16(value)) return void 0;
26233
- if (value.recordClass === TICKET_PROVENANCE_RECORD_CLASS_DIAGNOSTIC) {
26234
- return void 0;
26235
- }
26236
- if (!isRecord16(value.basis)) return void 0;
26237
- if (typeof value.basis.method !== "string" || !BASIS_METHODS.has(value.basis.method)) {
26238
- return void 0;
26239
- }
26240
- if (typeof value.sourceKind !== "string" || !SOURCE_KINDS.has(value.sourceKind)) {
26241
- return void 0;
26242
- }
26243
- if (!isRecord16(value.sourceRef)) return void 0;
26244
- if (typeof value.transcript !== "string" || value.transcript.length === 0) {
26245
- return void 0;
26246
- }
26247
- if (typeof value.timestamp !== "string" || value.timestamp.length === 0) {
26248
- return void 0;
26249
- }
26250
- const basis = {
26251
- method: value.basis.method,
26252
- ...Array.isArray(value.basis.anchors) ? {
26253
- anchors: value.basis.anchors.filter(
26254
- (item) => typeof item === "string"
26255
- )
26256
- } : {},
26257
- ...typeof value.basis.note === "string" ? { note: value.basis.note } : {}
26258
- };
26259
- const sourceRef = {
26260
- ...typeof value.sourceRef.sessionFile === "string" ? { sessionFile: value.sourceRef.sessionFile } : {},
26261
- ...typeof value.sourceRef.entryId === "string" || typeof value.sourceRef.entryId === "number" ? { entryId: value.sourceRef.entryId } : {},
26262
- ...typeof value.sourceRef.path === "string" ? { path: value.sourceRef.path } : {},
26263
- ...typeof value.sourceRef.url === "string" ? { url: value.sourceRef.url } : {}
26264
- };
26265
- return {
26266
- basis,
26267
- sourceKind: value.sourceKind,
26268
- sourceRef,
26269
- transcript: value.transcript,
26270
- timestamp: value.timestamp
26271
- };
26272
- }
26273
- var TICKET_PROVENANCE_KIND, TICKET_PROVENANCE_HUMAN_VIEW, TICKET_PROVENANCE_OFFERED_WATERMARK, TICKET_PROVENANCE_RECORD_CLASS_DIAGNOSTIC, SOURCE_KINDS, BASIS_METHODS, DIAGNOSTIC_KINDS;
25808
+ var TICKET_PROVENANCE_KIND, TICKET_PROVENANCE_HUMAN_VIEW;
26274
25809
  var init_ticket_provenance_contracts = __esm({
26275
25810
  "src/ticket-provenance-contracts.ts"() {
26276
25811
  "use strict";
26277
25812
  TICKET_PROVENANCE_KIND = "ticket-provenance";
26278
25813
  TICKET_PROVENANCE_HUMAN_VIEW = "\u8D77\u5C45\u5F55.md";
26279
- TICKET_PROVENANCE_OFFERED_WATERMARK = "offered-identities.jsonl";
26280
- TICKET_PROVENANCE_RECORD_CLASS_DIAGNOSTIC = "diagnostic";
26281
- SOURCE_KINDS = /* @__PURE__ */ new Set([
26282
- "cc-session",
26283
- "issue-body-comment",
26284
- "adr-decision-key",
26285
- "ticket-decree-block"
26286
- ]);
26287
- BASIS_METHODS = /* @__PURE__ */ new Set(["llm-semantic"]);
26288
- DIAGNOSTIC_KINDS = /* @__PURE__ */ new Set([
26289
- "collector-failed",
26290
- "issue-source-failed",
26291
- "quote-verify-failed"
26292
- ]);
26293
25814
  }
26294
25815
  });
26295
25816
 
26296
25817
  // src/ticket-provenance.ts
26297
- import { createHash as createHash5 } from "node:crypto";
26298
- import { appendFileSync as appendFileSync2, existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
26299
25818
  import { join as join20 } from "node:path";
26300
25819
  function ticketProvenanceSubject(ticketNumber) {
26301
25820
  if (!Number.isSafeInteger(ticketNumber) || ticketNumber < 1) {
@@ -26303,22 +25822,6 @@ function ticketProvenanceSubject(ticketNumber) {
26303
25822
  }
26304
25823
  return String(ticketNumber);
26305
25824
  }
26306
- function ticketProvenanceEntryIdentity(input) {
26307
- const ref = input.sourceRef;
26308
- const refKey = [
26309
- ref.sessionFile ?? "",
26310
- ref.entryId === void 0 ? "" : String(ref.entryId),
26311
- ref.path ?? "",
26312
- ref.url ?? ""
26313
- ].join("");
26314
- const material = [
26315
- String(input.ticketNumber),
26316
- input.sourceKind,
26317
- refKey,
26318
- input.transcript
26319
- ].join("\0");
26320
- return createHash5("sha256").update(material, "utf8").digest("hex");
26321
- }
26322
25825
  function resolveTicketProvenanceVolume(ticketNumber, cwd, home) {
26323
25826
  const path = resolveSitianRecordPath({
26324
25827
  level: "event",
@@ -26330,212 +25833,24 @@ function resolveTicketProvenanceVolume(ticketNumber, cwd, home) {
26330
25833
  return {
26331
25834
  recordFile: path.recordFile,
26332
25835
  volumeDir: path.sessionDir,
26333
- humanViewFile: join20(path.sessionDir, TICKET_PROVENANCE_HUMAN_VIEW),
26334
- offeredWatermarkFile: join20(path.sessionDir, TICKET_PROVENANCE_OFFERED_WATERMARK)
25836
+ humanViewFile: join20(path.sessionDir, TICKET_PROVENANCE_HUMAN_VIEW)
26335
25837
  };
26336
25838
  }
26337
- function readOfferedIdentities(ticketNumber, cwd, home) {
26338
- const { offeredWatermarkFile } = resolveTicketProvenanceVolume(ticketNumber, cwd, home);
26339
- if (!existsSync7(offeredWatermarkFile)) return /* @__PURE__ */ new Set();
26340
- let text;
25839
+ var init_ticket_provenance = __esm({
25840
+ "src/ticket-provenance.ts"() {
25841
+ "use strict";
25842
+ init_sitian_facade();
25843
+ init_ticket_provenance_contracts();
25844
+ }
25845
+ });
25846
+
25847
+ // src/public-cli/case-dossier-delivery.ts
25848
+ import { stat as stat2 } from "node:fs/promises";
25849
+ async function describeDossierFile(path) {
26341
25850
  try {
26342
- text = readFileSync2(offeredWatermarkFile, "utf8");
26343
- } catch (error) {
26344
- throw new TicketProvenanceWatermarkError(
26345
- "unreadable",
26346
- `ticket-provenance offered watermark unreadable (${offeredWatermarkFile})`,
26347
- { cause: error }
26348
- );
26349
- }
26350
- const seen = /* @__PURE__ */ new Set();
26351
- const lines = text.split("\n");
26352
- for (let index = 0; index < lines.length; index += 1) {
26353
- const trimmed = lines[index].trim();
26354
- if (!trimmed) continue;
26355
- let parsed;
26356
- try {
26357
- parsed = JSON.parse(trimmed);
26358
- } catch (error) {
26359
- throw new TicketProvenanceWatermarkError(
26360
- "malformed-json",
26361
- `ticket-provenance offered watermark malformed JSON at line ${index + 1} (${offeredWatermarkFile})`,
26362
- { cause: error }
26363
- );
26364
- }
26365
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed) || typeof parsed.identity !== "string" || parsed.identity.length === 0) {
26366
- throw new TicketProvenanceWatermarkError(
26367
- "bad-shape",
26368
- `ticket-provenance offered watermark bad shape at line ${index + 1} (${offeredWatermarkFile})`
26369
- );
26370
- }
26371
- seen.add(parsed.identity);
26372
- }
26373
- return seen;
26374
- }
26375
- async function readTicketProvenance(ticketNumber, cwd, home) {
26376
- const { recordFile } = resolveTicketProvenanceVolume(ticketNumber, cwd, home);
26377
- const { records: records2 } = await readSitianRecords(recordFile);
26378
- const entries = [];
26379
- const diagnostics = [];
26380
- let skipped = 0;
26381
- for (const record4 of records2) {
26382
- if (record4.kind !== TICKET_PROVENANCE_KIND) {
26383
- skipped += 1;
26384
- continue;
26385
- }
26386
- const diagnostic = projectTicketProvenanceDiagnostic(record4.payload);
26387
- if (diagnostic !== void 0) {
26388
- diagnostics.push(diagnostic);
26389
- continue;
26390
- }
26391
- const entry = projectTicketProvenanceEntry(record4.payload);
26392
- if (entry === void 0) {
26393
- skipped += 1;
26394
- continue;
26395
- }
26396
- entries.push(entry);
26397
- }
26398
- return { entries, diagnostics, records: records2, recordFile, skipped };
26399
- }
26400
- function markdownFenceFor(text) {
26401
- let longest = 0;
26402
- const runs = text.match(/`+/g);
26403
- if (runs !== null) {
26404
- for (const run of runs) {
26405
- if (run.length > longest) longest = run.length;
26406
- }
26407
- }
26408
- return "`".repeat(Math.max(3, longest + 1));
26409
- }
26410
- function renderTicketProvenanceMarkdown(input) {
26411
- const lines = [
26412
- `# \u8D77\u5C45\u5F55 \xB7 #${input.ticketNumber}`,
26413
- "",
26414
- `\u6761\u76EE\u6570\uFF1A${input.entries.length}`,
26415
- ""
26416
- ];
26417
- let index = 0;
26418
- for (const entry of input.entries) {
26419
- index += 1;
26420
- lines.push(`## ${index}. ${entry.sourceKind} \xB7 ${entry.timestamp}`);
26421
- lines.push("");
26422
- lines.push(`- basis.method: \`${entry.basis.method}\``);
26423
- if (entry.basis.anchors !== void 0 && entry.basis.anchors.length > 0) {
26424
- lines.push(`- anchors: ${entry.basis.anchors.map((a) => `\`${a}\``).join(", ")}`);
26425
- }
26426
- if (entry.basis.note !== void 0) {
26427
- lines.push(`- note: ${entry.basis.note}`);
26428
- }
26429
- const refParts = [];
26430
- if (entry.sourceRef.sessionFile !== void 0) {
26431
- refParts.push(`sessionFile=${entry.sourceRef.sessionFile}`);
26432
- }
26433
- if (entry.sourceRef.entryId !== void 0) {
26434
- refParts.push(`entryId=${String(entry.sourceRef.entryId)}`);
26435
- }
26436
- if (entry.sourceRef.path !== void 0) {
26437
- refParts.push(`path=${entry.sourceRef.path}`);
26438
- }
26439
- if (entry.sourceRef.url !== void 0) {
26440
- refParts.push(`url=${entry.sourceRef.url}`);
26441
- }
26442
- if (refParts.length > 0) {
26443
- lines.push(`- sourceRef: ${refParts.join(" \xB7 ")}`);
26444
- }
26445
- lines.push("");
26446
- const fence = markdownFenceFor(entry.transcript);
26447
- lines.push(fence);
26448
- lines.push(entry.transcript);
26449
- lines.push(fence);
26450
- lines.push("");
26451
- }
26452
- return lines.join("\n");
26453
- }
26454
- function ensureTicketProvenanceVolume(ticketNumber, cwd, home) {
26455
- const volume = resolveTicketProvenanceVolume(ticketNumber, cwd, home);
26456
- mkdirSync3(volume.volumeDir, { recursive: true });
26457
- appendFileSync2(volume.recordFile, "", "utf8");
26458
- return volume;
26459
- }
26460
- function appendTicketProvenanceDiagnostic(input) {
26461
- const subject = ticketProvenanceSubject(input.ticketNumber);
26462
- const identityParts = input.diagnostic.diagnosticKind === "quote-verify-failed" ? [
26463
- subject,
26464
- input.diagnostic.recordClass,
26465
- input.diagnostic.diagnosticKind,
26466
- input.diagnostic.cause,
26467
- input.diagnostic.reason ?? ""
26468
- ] : [
26469
- subject,
26470
- input.diagnostic.recordClass,
26471
- input.diagnostic.diagnosticKind,
26472
- input.diagnostic.recordedAt,
26473
- input.diagnostic.cause,
26474
- input.diagnostic.reason ?? ""
26475
- ];
26476
- const identity = createHash5("sha256").update(identityParts.join("\0"), "utf8").digest("hex");
26477
- return sitianReport({
26478
- level: "event",
26479
- kind: TICKET_PROVENANCE_KIND,
26480
- identity,
26481
- subject,
26482
- cwd: input.cwd,
26483
- ...input.home === void 0 ? {} : { home: input.home },
26484
- host: input.host ?? "diarist",
26485
- source: input.source ?? "diarist-diagnostic",
26486
- payload: input.diagnostic
26487
- });
26488
- }
26489
- function appendIssueSourceFailureDiagnostic(input) {
26490
- const recordedAt = input.recordedAt ?? (/* @__PURE__ */ new Date()).toISOString();
26491
- return appendTicketProvenanceDiagnostic({
26492
- ticketNumber: input.ticketNumber,
26493
- cwd: input.cwd,
26494
- ...input.home === void 0 ? {} : { home: input.home },
26495
- source: "diarist-issue-source",
26496
- diagnostic: {
26497
- recordClass: TICKET_PROVENANCE_RECORD_CLASS_DIAGNOSTIC,
26498
- diagnosticKind: "issue-source-failed",
26499
- cause: input.cause,
26500
- recordedAt,
26501
- reason: input.reason
26502
- }
26503
- });
26504
- }
26505
- function writeTicketProvenanceHumanView(input) {
26506
- const volume = ensureTicketProvenanceVolume(input.ticketNumber, input.cwd, input.home);
26507
- const md = renderTicketProvenanceMarkdown({
26508
- ticketNumber: input.ticketNumber,
26509
- entries: input.entries
26510
- });
26511
- writeFileSync2(volume.humanViewFile, md, "utf8");
26512
- return volume.humanViewFile;
26513
- }
26514
- var TicketProvenanceWatermarkError;
26515
- var init_ticket_provenance = __esm({
26516
- "src/ticket-provenance.ts"() {
26517
- "use strict";
26518
- init_sitian_facade();
26519
- init_ticket_provenance_contracts();
26520
- TicketProvenanceWatermarkError = class extends Error {
26521
- code = "ticket-provenance-watermark";
26522
- reason;
26523
- constructor(reason, message, options) {
26524
- super(message, options);
26525
- this.name = "TicketProvenanceWatermarkError";
26526
- this.reason = reason;
26527
- }
26528
- };
26529
- }
26530
- });
26531
-
26532
- // src/public-cli/case-dossier-delivery.ts
26533
- import { stat as stat2 } from "node:fs/promises";
26534
- async function describeDossierFile(path) {
26535
- try {
26536
- const stats = await stat2(path);
26537
- if (!stats.isFile()) return `\u4E0D\u53EF\u8BFB\uFF08\u975E\u666E\u901A\u6587\u4EF6\uFF09\uFF1A${path}`;
26538
- return path;
25851
+ const stats = await stat2(path);
25852
+ if (!stats.isFile()) return `\u4E0D\u53EF\u8BFB\uFF08\u975E\u666E\u901A\u6587\u4EF6\uFF09\uFF1A${path}`;
25853
+ return path;
26539
25854
  } catch (error) {
26540
25855
  const code = error.code;
26541
25856
  if (code === "ENOENT") return `\u5C1A\u672A\u751F\u6210\uFF1A${path}`;
@@ -28171,537 +27486,6 @@ var init_collector_run = __esm({
28171
27486
  }
28172
27487
  });
28173
27488
 
28174
- // src/diarist-mechanical.ts
28175
- import { createHash as createHash6 } from "node:crypto";
28176
- import { existsSync as existsSync8, readdirSync as readdirSync2, readFileSync as readFileSync3, realpathSync as realpathSync3, statSync as statSync2 } from "node:fs";
28177
- import { basename as basename7, join as join24, resolve as resolve9 } from "node:path";
28178
- import { homedir } from "node:os";
28179
- function extractCornerQuotes(text, minLength = DEFAULT_QUOTE_MIN) {
28180
- const out = [];
28181
- const re = /「([^」]+)」/g;
28182
- let match;
28183
- while ((match = re.exec(text)) !== null) {
28184
- const q = match[1].trim();
28185
- if (q.length >= minLength) out.push(q);
28186
- }
28187
- return out;
28188
- }
28189
- function filterNotifications(blocks) {
28190
- return blocks.filter((b) => !b.isNotification);
28191
- }
28192
- function blockKey(block) {
28193
- const r = block.sourceRef;
28194
- return [
28195
- block.sourceKind,
28196
- r.sessionFile ?? "",
28197
- r.entryId === void 0 ? "" : String(r.entryId),
28198
- r.path ?? "",
28199
- r.url ?? "",
28200
- createHash6("sha256").update(block.transcript, "utf8").digest("hex").slice(0, 16)
28201
- ].join("|");
28202
- }
28203
- function dedupeSourceBlocks(blocks) {
28204
- const seen = /* @__PURE__ */ new Set();
28205
- const out = [];
28206
- for (const block of blocks) {
28207
- const key = blockKey(block);
28208
- if (seen.has(key)) continue;
28209
- seen.add(key);
28210
- out.push(block);
28211
- }
28212
- return out;
28213
- }
28214
- function mechanicalSafeguardPipeline(blocks) {
28215
- return dedupeSourceBlocks(filterNotifications(blocks));
28216
- }
28217
- function encodeClaudeProjectDir(cwd) {
28218
- const abs = cwd.startsWith("/") ? cwd : `/${cwd}`;
28219
- return abs.replace(/\//g, "-");
28220
- }
28221
- function isRecord17(value) {
28222
- return typeof value === "object" && value !== null && !Array.isArray(value);
28223
- }
28224
- function messageText(message) {
28225
- if (typeof message === "string") return message;
28226
- if (!isRecord17(message)) return "";
28227
- const content = message.content;
28228
- if (typeof content === "string") return content;
28229
- if (!Array.isArray(content)) return "";
28230
- const parts = [];
28231
- for (const part of content) {
28232
- if (typeof part === "string") {
28233
- parts.push(part);
28234
- continue;
28235
- }
28236
- if (!isRecord17(part)) continue;
28237
- if (typeof part.text === "string") parts.push(part.text);
28238
- else if (typeof part.content === "string") parts.push(part.content);
28239
- }
28240
- return parts.join("\n");
28241
- }
28242
- function isNotificationRow(type, text) {
28243
- if (type === "queue-operation" || type === "system" || type === "progress") {
28244
- return true;
28245
- }
28246
- if (type === "user") {
28247
- if (text.startsWith("<command-name>") || text.startsWith("<local-command-")) {
28248
- return true;
28249
- }
28250
- if (text.startsWith("<command-message>") || text.startsWith("<command-args>")) {
28251
- return true;
28252
- }
28253
- }
28254
- return false;
28255
- }
28256
- function readCcSessionBlocks(options) {
28257
- const root = options.projectsRoot ?? join24(homedir(), ".claude", "projects");
28258
- if (!existsSync8(root)) return [];
28259
- const blocks = [];
28260
- const dirs = /* @__PURE__ */ new Set();
28261
- for (const cwd of options.cwds) {
28262
- dirs.add(join24(root, encodeClaudeProjectDir(cwd)));
28263
- }
28264
- for (const cwd of options.cwds) {
28265
- if (cwd.includes("projects")) continue;
28266
- const direct = join24(root, cwd);
28267
- if (existsSync8(direct)) dirs.add(direct);
28268
- }
28269
- for (const dir of dirs) {
28270
- if (!existsSync8(dir)) continue;
28271
- let dirStat;
28272
- try {
28273
- dirStat = statSync2(dir);
28274
- } catch (error) {
28275
- throw new DiaristSourceReadError(
28276
- "readdir-failed",
28277
- dir,
28278
- `diarist cc session dir unstatable (${dir})`,
28279
- { cause: error }
28280
- );
28281
- }
28282
- if (!dirStat.isDirectory()) continue;
28283
- let files;
28284
- try {
28285
- files = readdirSync2(dir).filter((name) => name.endsWith(".jsonl"));
28286
- } catch (error) {
28287
- throw new DiaristSourceReadError(
28288
- "readdir-failed",
28289
- dir,
28290
- `diarist cc session dir unreadable (${dir})`,
28291
- { cause: error }
28292
- );
28293
- }
28294
- for (const name of files) {
28295
- const sessionFile = join24(dir, name);
28296
- let text;
28297
- try {
28298
- text = readFileSync3(sessionFile, "utf8");
28299
- } catch (error) {
28300
- throw new DiaristSourceReadError(
28301
- "file-unreadable",
28302
- sessionFile,
28303
- `diarist cc session file unreadable (${sessionFile})`,
28304
- { cause: error }
28305
- );
28306
- }
28307
- const lines = text.split("\n");
28308
- for (let lineNo = 0; lineNo < lines.length; lineNo += 1) {
28309
- const line2 = lines[lineNo];
28310
- if (!line2.trim()) continue;
28311
- let parsed;
28312
- try {
28313
- parsed = JSON.parse(line2);
28314
- } catch (error) {
28315
- throw new DiaristSourceReadError(
28316
- "jsonl-line-unparseable",
28317
- sessionFile,
28318
- `diarist cc session JSONL line ${lineNo + 1} unparseable (${sessionFile})`,
28319
- { cause: error }
28320
- );
28321
- }
28322
- if (!isRecord17(parsed)) continue;
28323
- const type = typeof parsed.type === "string" ? parsed.type : "";
28324
- const queuedCommand = type === "attachment" && isRecord17(parsed.attachment) && parsed.attachment.type === "queued_command" && isRecord17(parsed.attachment.origin) && parsed.attachment.origin.kind === "human" && typeof parsed.attachment.prompt === "string" ? parsed.attachment.prompt : void 0;
28325
- if (type !== "user" && type !== "assistant" && queuedCommand === void 0) {
28326
- continue;
28327
- }
28328
- const transcript = queuedCommand ?? messageText(parsed.message ?? parsed);
28329
- if (transcript.trim() === "") continue;
28330
- const entryId = typeof parsed.uuid === "string" ? parsed.uuid : typeof parsed.id === "string" ? parsed.id : `${basename7(sessionFile)}:${lineNo + 1}`;
28331
- const timestamp2 = typeof parsed.timestamp === "string" ? parsed.timestamp : (/* @__PURE__ */ new Date(0)).toISOString();
28332
- const notification = isNotificationRow(type, transcript);
28333
- blocks.push({
28334
- sourceKind: "cc-session",
28335
- sourceRef: { sessionFile, entryId },
28336
- transcript,
28337
- timestamp: timestamp2,
28338
- isUserTurn: type === "user" || queuedCommand !== void 0,
28339
- isNotification: notification
28340
- });
28341
- }
28342
- }
28343
- }
28344
- return blocks;
28345
- }
28346
- function readIssueFaceBlocks(input) {
28347
- const fallbackTs = input.timestamp ?? (/* @__PURE__ */ new Date(0)).toISOString();
28348
- const blocks = [];
28349
- const body = input.face.body;
28350
- if (body.trim() !== "") {
28351
- blocks.push({
28352
- sourceKind: "issue-body-comment",
28353
- sourceRef: { url: input.face.bodyUrl, entryId: "body" },
28354
- transcript: body,
28355
- timestamp: fallbackTs,
28356
- isUserTurn: true,
28357
- isNotification: false
28358
- });
28359
- const quotes = extractCornerQuotes(body);
28360
- for (let i = 0; i < quotes.length; i += 1) {
28361
- const q = quotes[i];
28362
- blocks.push({
28363
- sourceKind: "ticket-decree-block",
28364
- sourceRef: { url: input.face.bodyUrl, entryId: `decree-${i + 1}` },
28365
- transcript: q,
28366
- timestamp: fallbackTs,
28367
- isUserTurn: true,
28368
- isNotification: false
28369
- });
28370
- }
28371
- }
28372
- for (const comment of input.face.comments) {
28373
- if (comment.body.trim() === "") continue;
28374
- blocks.push({
28375
- sourceKind: "issue-body-comment",
28376
- sourceRef: {
28377
- url: comment.htmlUrl,
28378
- entryId: comment.id
28379
- },
28380
- transcript: comment.body,
28381
- timestamp: comment.createdAt || fallbackTs,
28382
- isUserTurn: true,
28383
- isNotification: false
28384
- });
28385
- }
28386
- return blocks;
28387
- }
28388
- function readAdrDecisionKeyBlocks(input) {
28389
- const timestamp2 = input.timestamp ?? (/* @__PURE__ */ new Date(0)).toISOString();
28390
- const blocks = [];
28391
- const cwdAbs = resolve9(input.cwd);
28392
- const adrRootAbs = resolve9(cwdAbs, DIARIST_ADR_ROOT_REL);
28393
- let adrRootReal;
28394
- try {
28395
- adrRootReal = existsSync8(adrRootAbs) ? realpathSync3(adrRootAbs) : resolve9(realpathSync3(cwdAbs), DIARIST_ADR_ROOT_REL);
28396
- } catch (error) {
28397
- throw new DiaristSourceReadError(
28398
- "adr-unreadable",
28399
- cwdAbs,
28400
- `diarist ADR root is not resolvable (${adrRootAbs})`,
28401
- { cause: error }
28402
- );
28403
- }
28404
- for (const rel of input.adrPaths) {
28405
- const segments = rel.split(/[/\\]/);
28406
- if (segments[0] !== "docs" || segments[1] !== "adr" || segments.length < 3 || segments.some((part) => part === "" || part === "." || part === "..")) {
28407
- throw new DiaristSourceReadError(
28408
- "adr-escape",
28409
- resolve9(cwdAbs, rel),
28410
- `diarist referenced ADR escapes docs/adr (${rel})`
28411
- );
28412
- }
28413
- const abs = resolve9(cwdAbs, rel);
28414
- if (abs !== adrRootAbs && !pathContainedIn(adrRootAbs, abs)) {
28415
- throw new DiaristSourceReadError(
28416
- "adr-escape",
28417
- abs,
28418
- `diarist referenced ADR escapes docs/adr (${rel})`
28419
- );
28420
- }
28421
- if (!existsSync8(abs)) {
28422
- throw new DiaristSourceReadError(
28423
- "adr-missing",
28424
- abs,
28425
- `diarist referenced ADR missing (${rel})`
28426
- );
28427
- }
28428
- let realAbs;
28429
- try {
28430
- realAbs = realpathSync3(abs);
28431
- } catch (error) {
28432
- throw new DiaristSourceReadError(
28433
- "adr-unreadable",
28434
- abs,
28435
- `diarist ADR path is not resolvable (${abs})`,
28436
- { cause: error }
28437
- );
28438
- }
28439
- if (realAbs !== adrRootReal && !physicallyContainedIn(adrRootReal, realAbs)) {
28440
- throw new DiaristSourceReadError(
28441
- "adr-escape",
28442
- abs,
28443
- `diarist referenced ADR escapes docs/adr physically (${rel})`
28444
- );
28445
- }
28446
- let text;
28447
- try {
28448
- text = readFileSync3(realAbs, "utf8");
28449
- } catch (error) {
28450
- throw new DiaristSourceReadError(
28451
- "adr-unreadable",
28452
- realAbs,
28453
- `diarist ADR file unreadable (${realAbs})`,
28454
- { cause: error }
28455
- );
28456
- }
28457
- if (text.trim() === "") continue;
28458
- blocks.push({
28459
- sourceKind: "adr-decision-key",
28460
- sourceRef: { path: rel },
28461
- transcript: text,
28462
- timestamp: timestamp2,
28463
- isUserTurn: true,
28464
- isNotification: false
28465
- });
28466
- }
28467
- return blocks;
28468
- }
28469
- var DEFAULT_QUOTE_MIN, DiaristSourceReadError, DIARIST_ADR_ROOT_REL;
28470
- var init_diarist_mechanical = __esm({
28471
- "src/diarist-mechanical.ts"() {
28472
- "use strict";
28473
- init_activation_ledger_topology();
28474
- DEFAULT_QUOTE_MIN = 6;
28475
- DiaristSourceReadError = class extends Error {
28476
- code = "diarist-source-read";
28477
- reason;
28478
- sourcePath;
28479
- constructor(reason, sourcePath, message, options) {
28480
- super(message, options);
28481
- this.name = "DiaristSourceReadError";
28482
- this.reason = reason;
28483
- this.sourcePath = sourcePath;
28484
- }
28485
- };
28486
- DIARIST_ADR_ROOT_REL = "docs/adr";
28487
- }
28488
- });
28489
-
28490
- // src/diarist.ts
28491
- import { execFileSync as execFileSync3 } from "node:child_process";
28492
- function createDiaristIssueFaceFetcher(options) {
28493
- const runner = options?.runner ?? createGhApiRunner();
28494
- const transport = options?.transport ?? createGhCollectorGitHubTransport();
28495
- return async (input) => {
28496
- const projected = await projectGhIssueBody(runner, input);
28497
- let body;
28498
- if (projected.status === "available") {
28499
- body = projected.body;
28500
- } else if (projected.status === "unavailable") {
28501
- if (projected.reason === "pull-request") {
28502
- throw new DiaristIssueSourceError(
28503
- "issue-is-pull-request",
28504
- `ticket #${input.ticketNumber} resolves to a pull request, not an issue face`,
28505
- projected.cause === void 0 ? void 0 : { cause: projected.cause }
28506
- );
28507
- }
28508
- throw new DiaristIssueSourceError(
28509
- "issue-unavailable",
28510
- `issue face unavailable for ${input.owner}/${input.repo}#${input.ticketNumber}`,
28511
- projected.cause === void 0 ? void 0 : { cause: projected.cause }
28512
- );
28513
- } else if (projected.reason === "not-json") {
28514
- throw new DiaristIssueSourceError(
28515
- "issue-not-json",
28516
- `issue face payload is not JSON for ${input.owner}/${input.repo}#${input.ticketNumber}`,
28517
- projected.cause === void 0 ? void 0 : { cause: projected.cause }
28518
- );
28519
- } else if (projected.reason === "not-object") {
28520
- throw new DiaristIssueSourceError(
28521
- "issue-not-object",
28522
- `issue face payload must be a JSON object for ${input.owner}/${input.repo}#${input.ticketNumber}`
28523
- );
28524
- } else {
28525
- throw new DiaristIssueSourceError(
28526
- "issue-body-invalid",
28527
- `issue face body must be string or null for ${input.owner}/${input.repo}#${input.ticketNumber}`
28528
- );
28529
- }
28530
- let listed;
28531
- try {
28532
- listed = await transport.listIssueComments({
28533
- owner: input.owner,
28534
- repo: input.repo,
28535
- prNumber: input.ticketNumber,
28536
- ...input.signal === void 0 ? {} : { signal: input.signal }
28537
- });
28538
- } catch (error) {
28539
- throw new DiaristIssueSourceError(
28540
- "comments-failed",
28541
- `issue comments fetch failed for ${input.owner}/${input.repo}#${input.ticketNumber}`,
28542
- { cause: error }
28543
- );
28544
- }
28545
- const bodyUrl = `https://github.com/${input.owner}/${input.repo}/issues/${input.ticketNumber}`;
28546
- return {
28547
- body,
28548
- bodyUrl,
28549
- comments: listed.items.map((c) => ({
28550
- id: c.id,
28551
- body: c.body,
28552
- createdAt: c.createdAt,
28553
- htmlUrl: c.htmlUrl
28554
- }))
28555
- };
28556
- };
28557
- }
28558
- function resolveDiaristGithubOrigin(projectRoot) {
28559
- let remoteUrl;
28560
- try {
28561
- remoteUrl = execFileSync3("git", ["remote", "get-url", "origin"], {
28562
- cwd: projectRoot,
28563
- encoding: "utf8",
28564
- stdio: ["ignore", "pipe", "pipe"]
28565
- }).trim();
28566
- } catch {
28567
- return void 0;
28568
- }
28569
- if (remoteUrl.length === 0) return void 0;
28570
- return parseGitHubOriginRemote(remoteUrl);
28571
- }
28572
- async function loadDiaristIssueFace(input) {
28573
- const persistAndThrow = (error) => {
28574
- appendIssueSourceFailureDiagnostic({
28575
- ticketNumber: input.ticketNumber,
28576
- cwd: input.projectRoot,
28577
- ...input.home === void 0 ? {} : { home: input.home },
28578
- cause: error.message,
28579
- reason: error.reason
28580
- });
28581
- return error;
28582
- };
28583
- const origin = resolveDiaristGithubOrigin(input.projectRoot);
28584
- if (origin === void 0) {
28585
- throw persistAndThrow(
28586
- new DiaristIssueSourceError(
28587
- "origin-unresolved",
28588
- `bound ticket #${input.ticketNumber} issue face requires a resolvable github.com origin remote`
28589
- )
28590
- );
28591
- }
28592
- const fetcher = input.fetcher ?? createDiaristIssueFaceFetcher();
28593
- try {
28594
- return await fetcher({
28595
- owner: origin.owner,
28596
- repo: origin.repo,
28597
- ticketNumber: input.ticketNumber
28598
- });
28599
- } catch (error) {
28600
- throw persistAndThrow(
28601
- error instanceof DiaristIssueSourceError ? error : new DiaristIssueSourceError(
28602
- "issue-unavailable",
28603
- `issue face fetch failed for ${origin.owner}/${origin.repo}#${input.ticketNumber}`,
28604
- { cause: error }
28605
- )
28606
- );
28607
- }
28608
- }
28609
- async function loadSeenEntryIdentities(ticketNumber, cwd, home) {
28610
- const { recordFile } = resolveTicketProvenanceVolume(ticketNumber, cwd, home);
28611
- const { records: records2 } = await readSitianRecords(recordFile);
28612
- const seen = /* @__PURE__ */ new Set();
28613
- for (const record4 of records2) {
28614
- if (typeof record4.identity === "string" && record4.identity.length > 0) {
28615
- seen.add(record4.identity);
28616
- }
28617
- }
28618
- for (const identity of readOfferedIdentities(ticketNumber, cwd, home)) {
28619
- seen.add(identity);
28620
- }
28621
- return seen;
28622
- }
28623
- function blockEntryIdentity(ticketNumber, block) {
28624
- return ticketProvenanceEntryIdentity({
28625
- ticketNumber,
28626
- sourceKind: block.sourceKind,
28627
- sourceRef: block.sourceRef,
28628
- transcript: block.transcript
28629
- });
28630
- }
28631
- function loadSourceBlocks(input) {
28632
- const cwds = input.sessionCwds ?? [input.cwd];
28633
- const blocks = [...readCcSessionBlocks({ cwds })];
28634
- if (input.issueFace !== void 0) {
28635
- blocks.push(...readIssueFaceBlocks({ face: input.issueFace }));
28636
- const faceText = [
28637
- input.issueFace.body,
28638
- ...input.issueFace.comments.map((c) => c.body)
28639
- ].join("\n");
28640
- const adrPaths = extractReferencedAdrPaths(faceText);
28641
- if (adrPaths.length > 0) {
28642
- blocks.push(
28643
- ...readAdrDecisionKeyBlocks({
28644
- cwd: input.cwd,
28645
- adrPaths
28646
- })
28647
- );
28648
- }
28649
- }
28650
- return blocks;
28651
- }
28652
- async function prepareDiaristSourceCatalog(input) {
28653
- const known = input.ticketNumber;
28654
- if (known !== void 0) {
28655
- ensureTicketProvenanceVolume(known, input.cwd, input.home);
28656
- const volume = await readTicketProvenance(known, input.cwd, input.home);
28657
- writeTicketProvenanceHumanView({
28658
- ticketNumber: known,
28659
- cwd: input.cwd,
28660
- ...input.home === void 0 ? {} : { home: input.home },
28661
- entries: volume.entries
28662
- });
28663
- }
28664
- const rawBlocks = loadSourceBlocks(input);
28665
- const safeguarded = mechanicalSafeguardPipeline(rawBlocks);
28666
- const seen = known === void 0 ? /* @__PURE__ */ new Set() : await loadSeenEntryIdentities(known, input.cwd, input.home);
28667
- const fresh = safeguarded.filter(
28668
- (block) => known === void 0 || !seen.has(blockEntryIdentity(known, block))
28669
- );
28670
- return {
28671
- ...known === void 0 ? {} : { ticketNumber: known },
28672
- instruction: input.instruction,
28673
- runDirectory: input.runDirectory,
28674
- projectRoot: input.projectRoot,
28675
- cwd: input.cwd,
28676
- ...input.home === void 0 ? {} : { home: input.home },
28677
- candidates: fresh.map((block, candidateIndex) => ({ ...block, candidateIndex }))
28678
- };
28679
- }
28680
- function serializeDiaristSourceCatalog(catalog) {
28681
- return JSON.stringify(catalog);
28682
- }
28683
- var DiaristIssueSourceError;
28684
- var init_diarist = __esm({
28685
- "src/diarist.ts"() {
28686
- "use strict";
28687
- init_adr_path_refs();
28688
- init_collector_github();
28689
- init_diarist_mechanical();
28690
- init_reviewer_pinned_git();
28691
- init_ticket_provenance();
28692
- init_sitian_facade();
28693
- DiaristIssueSourceError = class extends Error {
28694
- code = "diarist-issue-source";
28695
- reason;
28696
- constructor(reason, message, options) {
28697
- super(message, options);
28698
- this.name = "DiaristIssueSourceError";
28699
- this.reason = reason;
28700
- }
28701
- };
28702
- }
28703
- });
28704
-
28705
27489
  // src/public-cli/diarist-run.ts
28706
27490
  var diarist_run_exports = {};
28707
27491
  __export(diarist_run_exports, {
@@ -28709,61 +27493,17 @@ __export(diarist_run_exports, {
28709
27493
  runPublicDiarist: () => runPublicDiarist,
28710
27494
  runPublicDiaristResume: () => runPublicDiaristResume
28711
27495
  });
28712
- import { existsSync as existsSync9 } from "node:fs";
28713
- import { writeFile as writeFile7 } from "node:fs/promises";
28714
- import { join as join25 } from "node:path";
28715
- function withDiaristCatalogPath(prompt, sourcesPath) {
28716
- if (sourcesPath === void 0 || sourcesPath.trim() === "") return prompt;
28717
- return `${prompt}
28718
-
28719
- \u5DF2\u51BB\u7ED3\u6765\u6E90\u6587\u4EF6\uFF08\u8DEF\u5F84\uFF09\uFF1A
28720
- - ${sourcesPath}`;
28721
- }
28722
- function buildDiaristTurnRequest(admitted, options, sourcesPath) {
28723
- const continuation = sourcesPath === void 0 ? options.continuation : {
28724
- ...options.continuation,
28725
- prompt: withDiaristCatalogPath(options.continuation.prompt, sourcesPath)
28726
- };
27496
+ function buildDiaristTurnRequest(admitted, options) {
28727
27497
  return projectRoleTurnRequest(
28728
27498
  admitted,
28729
- {
28730
- activation: {
28731
- role: "diarist",
28732
- ...sourcesPath === void 0 ? {} : { sourcesPath }
28733
- }
28734
- },
28735
- { ...options, continuation }
27499
+ { activation: { role: "diarist" } },
27500
+ options
28736
27501
  );
28737
27502
  }
28738
- async function freezeDiaristSourceCatalog(admitted, env) {
28739
- const path = join25(admitted.runDirectory, DIARIST_SOURCE_CATALOG_FILE);
28740
- if (existsSync9(path)) {
28741
- const identity = await readRoleRunIdentity(admitted.runDirectory);
28742
- if (identity !== void 0 && identity.state !== "terminal") return path;
28743
- }
28744
- const issueFace = admitted.ticketNumber === void 0 ? void 0 : await loadDiaristIssueFace({
28745
- ticketNumber: admitted.ticketNumber,
28746
- projectRoot: admitted.projectRoot,
28747
- home: env.home
28748
- });
28749
- const catalog = await prepareDiaristSourceCatalog({
28750
- ...admitted.ticketNumber === void 0 ? {} : { ticketNumber: admitted.ticketNumber },
28751
- instruction: admitted.instruction,
28752
- runDirectory: admitted.runDirectory,
28753
- projectRoot: admitted.projectRoot,
28754
- cwd: admitted.projectRoot,
28755
- home: env.home,
28756
- ...issueFace === void 0 ? {} : { issueFace },
28757
- sessionCwds: [admitted.projectRoot, env.cwd]
28758
- });
28759
- await writeFile7(path, serializeDiaristSourceCatalog(catalog), "utf8");
28760
- return path;
28761
- }
28762
- function diaristAdapters(options) {
27503
+ function diaristAdapters() {
28763
27504
  return {
28764
27505
  trySettle: (admitted, authority, scope) => trySettleDiaristTerminalResult(admitted, authority, scope),
28765
- shouldPresentSettled: () => true,
28766
- ...options?.beforeDispatch === void 0 ? {} : { beforeDispatch: options.beforeDispatch }
27506
+ shouldPresentSettled: () => true
28767
27507
  };
28768
27508
  }
28769
27509
  async function runPublicDiarist(argv, env, io, parseDiaristArgv2) {
@@ -28849,15 +27589,7 @@ async function runPublicDiarist(argv, env, io, parseDiaristArgv2) {
28849
27589
  env,
28850
27590
  io,
28851
27591
  request: turnRequest,
28852
- adapters: diaristAdapters({
28853
- beforeDispatch: async (admittedSeat) => {
28854
- const sourcesPath = await freezeDiaristSourceCatalog(admittedSeat, env);
28855
- Object.assign(
28856
- turnRequest,
28857
- buildDiaristTurnRequest(admittedSeat, turnProjection, sourcesPath)
28858
- );
28859
- }
28860
- }),
27592
+ adapters: diaristAdapters(),
28861
27593
  ...env.engine === void 0 ? {} : { effectiveEngine: env.engine }
28862
27594
  }).then(async (result2) => {
28863
27595
  if (admitted.ticketNumber === void 0 && result2.admitted !== void 0) {
@@ -28887,7 +27619,6 @@ async function runPublicDiaristResume(request, env, io) {
28887
27619
  admitted.runDirectory,
28888
27620
  effective.summons
28889
27621
  );
28890
- const sourcesPath = await freezeDiaristSourceCatalog(admitted, env);
28891
27622
  return buildDiaristTurnRequest(
28892
27623
  admitted,
28893
27624
  resumeTurnRequestProjectionOptions(
@@ -28895,19 +27626,16 @@ async function runPublicDiaristResume(request, env, io) {
28895
27626
  effective,
28896
27627
  env,
28897
27628
  summonsPrepared
28898
- ),
28899
- sourcesPath
27629
+ )
28900
27630
  );
28901
27631
  },
28902
27632
  adapters: diaristAdapters(),
28903
27633
  ...env.engine === void 0 ? {} : { effectiveEngine: env.engine }
28904
27634
  });
28905
27635
  }
28906
- var DIARIST_SOURCE_CATALOG_FILE;
28907
27636
  var init_diarist_run = __esm({
28908
27637
  "src/public-cli/diarist-run.ts"() {
28909
27638
  "use strict";
28910
- init_diarist();
28911
27639
  init_engine_material();
28912
27640
  init_cli_errors();
28913
27641
  init_invocation();
@@ -28916,7 +27644,6 @@ var init_diarist_run = __esm({
28916
27644
  init_seat_ticket_binding();
28917
27645
  init_settlement();
28918
27646
  init_turn_request();
28919
- DIARIST_SOURCE_CATALOG_FILE = "diarist-sources.json";
28920
27647
  }
28921
27648
  });
28922
27649
 
@@ -28999,7 +27726,7 @@ async function runCountersignCourtDiaristStation(admitted, env, io) {
28999
27726
  instruction: `\u6574\u7406 #${admitted.ticketNumber} \u7684\u672C\u6848\u4F9D\u636E\u3002`,
29000
27727
  projectRoot: admitted.projectRoot,
29001
27728
  failureLabel: `ticket #${admitted.ticketNumber}`,
29002
- // Refresh holds a typed key — hand it off so freeze loads issue face.
27729
+ // Refresh holds a typed key — hand it off so identity is bound before turn.
29003
27730
  boundTicketNumber: admitted.ticketNumber
29004
27731
  },
29005
27732
  env,
@@ -30041,8 +28768,8 @@ var init_judge_run = __esm({
30041
28768
  });
30042
28769
 
30043
28770
  // src/public-cli/merger-run.ts
30044
- import { mkdir as mkdir5, writeFile as writeFile8 } from "node:fs/promises";
30045
- import { join as join26, resolve as resolve10 } from "node:path";
28771
+ import { mkdir as mkdir5, writeFile as writeFile7 } from "node:fs/promises";
28772
+ import { join as join24, resolve as resolve9 } from "node:path";
30046
28773
  function mergerMethods(packageRoot2) {
30047
28774
  return [
30048
28775
  {
@@ -30084,7 +28811,7 @@ async function loadMergerMethodMaterial(packageRoot2) {
30084
28811
  );
30085
28812
  }
30086
28813
  async function admitMergerShellForActivationFailure(options) {
30087
- const projectRoot = resolve10(options.project ?? options.cwd);
28814
+ const projectRoot = resolve9(options.project ?? options.cwd);
30088
28815
  const runId = (options.createRunId ?? uuidv7)();
30089
28816
  const {
30090
28817
  principal,
@@ -30108,9 +28835,9 @@ async function admitMergerShellForActivationFailure(options) {
30108
28835
  expectedConflictPaths: [],
30109
28836
  resolutionScope: []
30110
28837
  };
30111
- const admittedRequestPath = join26(runDirectory, "admitted-request.json");
30112
- const mergerInputPath = join26(runDirectory, "merger-input.json");
30113
- await writeFile8(
28838
+ const admittedRequestPath = join24(runDirectory, "admitted-request.json");
28839
+ const mergerInputPath = join24(runDirectory, "merger-input.json");
28840
+ await writeFile7(
30114
28841
  admittedRequestPath,
30115
28842
  `${JSON.stringify(
30116
28843
  {
@@ -30513,13 +29240,13 @@ var init_reviewer_run = __esm({
30513
29240
  });
30514
29241
 
30515
29242
  // src/analyst-book-key.ts
30516
- import { statSync as statSync3 } from "node:fs";
29243
+ import { statSync as statSync2 } from "node:fs";
30517
29244
  import { isAbsolute as isAbsolute8 } from "node:path";
30518
29245
  function resolveAnalystBookKey(projectRoot) {
30519
29246
  const identity = physicalPathIdentity(projectRoot);
30520
29247
  let stats;
30521
29248
  try {
30522
- stats = statSync3(identity);
29249
+ stats = statSync2(identity);
30523
29250
  } catch (error) {
30524
29251
  const code = errnoCode(error);
30525
29252
  if (code === "ENOENT" || code === "ENOTDIR") return `root:${identity}`;
@@ -30548,13 +29275,13 @@ var init_analyst_book_key = __esm({
30548
29275
 
30549
29276
  // src/atomic-write.ts
30550
29277
  import { randomUUID as randomUUID6 } from "node:crypto";
30551
- import { rename, rm, writeFile as writeFile9 } from "node:fs/promises";
30552
- import { dirname as dirname12, join as join27 } from "node:path";
29278
+ import { rename, rm, writeFile as writeFile8 } from "node:fs/promises";
29279
+ import { dirname as dirname12, join as join25 } from "node:path";
30553
29280
  async function writeFileAtomically(destination, contents) {
30554
29281
  const parent = dirname12(destination);
30555
- const temporary = join27(parent, `.atomic-write-${randomUUID6()}.tmp`);
29282
+ const temporary = join25(parent, `.atomic-write-${randomUUID6()}.tmp`);
30556
29283
  try {
30557
- await writeFile9(temporary, contents);
29284
+ await writeFile8(temporary, contents);
30558
29285
  await rename(temporary, destination);
30559
29286
  } catch (error) {
30560
29287
  await rm(temporary, { force: true }).catch(() => void 0);
@@ -30569,16 +29296,16 @@ var init_atomic_write = __esm({
30569
29296
 
30570
29297
  // src/analyst-index.ts
30571
29298
  import { open as open3, readFile as readFile17, unlink as unlink4 } from "node:fs/promises";
30572
- import { dirname as dirname13, join as join28 } from "node:path";
29299
+ import { dirname as dirname13, join as join26 } from "node:path";
30573
29300
  function sleep(ms) {
30574
- return new Promise((resolve12) => {
30575
- setTimeout(resolve12, ms);
29301
+ return new Promise((resolve11) => {
29302
+ setTimeout(resolve11, ms);
30576
29303
  });
30577
29304
  }
30578
29305
  async function withAnalystLibraryIndexLock(ledgerHome, fn) {
30579
29306
  const indexPath = analystLibraryIndexPath(ledgerHome);
30580
29307
  ensureRealDirectoryTree(ledgerHome, dirname13(indexPath));
30581
- const lockPath = join28(dirname13(indexPath), LIBRARY_INDEX_LOCK_NAME);
29308
+ const lockPath = join26(dirname13(indexPath), LIBRARY_INDEX_LOCK_NAME);
30582
29309
  assertLedgerFileInsideHome(lockPath, ledgerHome);
30583
29310
  const startedAt = Date.now();
30584
29311
  while (true) {
@@ -30605,7 +29332,7 @@ async function withAnalystLibraryIndexLock(ledgerHome, fn) {
30605
29332
  }
30606
29333
  }
30607
29334
  function analystLibraryIndexPath(ledgerHome) {
30608
- return join28(ledgerHome, "analyst", "library-index.json");
29335
+ return join26(ledgerHome, "analyst", "library-index.json");
30609
29336
  }
30610
29337
  function rowFromIssueMetricsPage(page) {
30611
29338
  return {
@@ -30901,22 +29628,22 @@ var init_analyst_cohort = __esm({
30901
29628
 
30902
29629
  // src/analyst-ledger.ts
30903
29630
  import { readdir as readdir7, readFile as readFile18 } from "node:fs/promises";
30904
- import { join as join29 } from "node:path";
29631
+ import { join as join27 } from "node:path";
30905
29632
  function isMissingPathError5(error) {
30906
29633
  return error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
30907
29634
  }
30908
29635
  function errorText3(error) {
30909
29636
  return error instanceof Error ? error.message : String(error);
30910
29637
  }
30911
- function isRecord18(value) {
29638
+ function isRecord15(value) {
30912
29639
  return typeof value === "object" && value !== null && !Array.isArray(value);
30913
29640
  }
30914
29641
  async function readExistingRunLifecycleState(runDirectory) {
30915
29642
  try {
30916
29643
  const raw = JSON.parse(
30917
- await readFile18(join29(runDirectory, "run-state.json"), "utf8")
29644
+ await readFile18(join27(runDirectory, "run-state.json"), "utf8")
30918
29645
  );
30919
- if (!isRecord18(raw) || typeof raw.state !== "string") return void 0;
29646
+ if (!isRecord15(raw) || typeof raw.state !== "string") return void 0;
30920
29647
  return raw.state;
30921
29648
  } catch {
30922
29649
  return void 0;
@@ -30946,13 +29673,13 @@ async function listLedgerBookNames(booksRoot) {
30946
29673
  async function readInvocationScopeFields(runDirectory) {
30947
29674
  let raw;
30948
29675
  try {
30949
- raw = await readFile18(join29(runDirectory, "invocation.json"), "utf8");
29676
+ raw = await readFile18(join27(runDirectory, "invocation.json"), "utf8");
30950
29677
  } catch (error) {
30951
29678
  if (isMissingPathError5(error)) return void 0;
30952
29679
  throw error;
30953
29680
  }
30954
29681
  const parsed = JSON.parse(raw);
30955
- if (!isRecord18(parsed)) return void 0;
29682
+ if (!isRecord15(parsed)) return void 0;
30956
29683
  if (typeof parsed.projectRoot !== "string" || parsed.projectRoot.trim() === "") {
30957
29684
  return void 0;
30958
29685
  }
@@ -30978,15 +29705,15 @@ function decideIssueScope(input) {
30978
29705
  }
30979
29706
  async function resolveSessionFile(runDirectory) {
30980
29707
  try {
30981
- const raw = await readFile18(join29(runDirectory, "invocation.json"), "utf8");
29708
+ const raw = await readFile18(join27(runDirectory, "invocation.json"), "utf8");
30982
29709
  const parsed = JSON.parse(raw);
30983
- if (isRecord18(parsed) && typeof parsed.sessionFile === "string" && parsed.sessionFile.trim() !== "") {
29710
+ if (isRecord15(parsed) && typeof parsed.sessionFile === "string" && parsed.sessionFile.trim() !== "") {
30984
29711
  return parsed.sessionFile;
30985
29712
  }
30986
29713
  } catch (error) {
30987
29714
  if (!isMissingPathError5(error)) throw error;
30988
29715
  }
30989
- return join29(runDirectory, "session", "session.jsonl");
29716
+ return join27(runDirectory, "session", "session.jsonl");
30990
29717
  }
30991
29718
  function attributeSessionRowsForRun(input) {
30992
29719
  if (pathContainedIn(input.runDirectory, input.sessionFile)) {
@@ -31158,9 +29885,9 @@ async function classifyScopedRun(input) {
31158
29885
  }
31159
29886
  let gateCycles;
31160
29887
  try {
31161
- const parentSessionFile = join29(input.runDirectory, "session", "session.jsonl");
29888
+ const parentSessionFile = join27(input.runDirectory, "session", "session.jsonl");
31162
29889
  gateCycles = await readAnalystGateCyclesFromAuditorRoles(
31163
- join29(input.runDirectory, "session", "auditor-roles"),
29890
+ join27(input.runDirectory, "session", "auditor-roles"),
31164
29891
  { parentSessionFile }
31165
29892
  );
31166
29893
  } catch (error) {
@@ -31193,7 +29920,7 @@ async function classifyScopedRun(input) {
31193
29920
  async function scanAnalystIssueRuns(input) {
31194
29921
  const ledgerHome = resolveActivationLedgerHome(input.home);
31195
29922
  const scopeTicketNumber = input.ticketNumber;
31196
- const booksRoot = join29(ledgerHome, "books");
29923
+ const booksRoot = join27(ledgerHome, "books");
31197
29924
  let wholeBook = false;
31198
29925
  let scopeRootIdentity;
31199
29926
  let bookNames;
@@ -31225,7 +29952,7 @@ async function scanAnalystIssueRuns(input) {
31225
29952
  const unreadable = [];
31226
29953
  const scopeConflicts = [];
31227
29954
  for (const book of bookNames) {
31228
- const runsDir = join29(booksRoot, book, "runs");
29955
+ const runsDir = join27(booksRoot, book, "runs");
31229
29956
  let runNames;
31230
29957
  try {
31231
29958
  const entries = await readdir7(runsDir, { withFileTypes: true });
@@ -31237,7 +29964,7 @@ async function scanAnalystIssueRuns(input) {
31237
29964
  for (const runName of runNames) {
31238
29965
  const parsed = parseRunDirectoryName2(runName);
31239
29966
  if (parsed === void 0) continue;
31240
- const runDirectory = join29(runsDir, runName);
29967
+ const runDirectory = join27(runsDir, runName);
31241
29968
  let scopeFields;
31242
29969
  try {
31243
29970
  scopeFields = await readInvocationScopeFields(runDirectory);
@@ -31285,7 +30012,7 @@ var init_analyst_ledger = __esm({
31285
30012
  });
31286
30013
 
31287
30014
  // src/analyst-metric-families/acceptance-success-rework.ts
31288
- function isRecord19(value) {
30015
+ function isRecord16(value) {
31289
30016
  return typeof value === "object" && value !== null && !Array.isArray(value);
31290
30017
  }
31291
30018
  function wallMsFromSpan(span) {
@@ -31294,21 +30021,21 @@ function wallMsFromSpan(span) {
31294
30021
  function findCollectorGroups(body) {
31295
30022
  if (Array.isArray(body.groups)) return body.groups;
31296
30023
  const receipt = body.receipt;
31297
- if (isRecord19(receipt) && Array.isArray(receipt.groups)) return receipt.groups;
30024
+ if (isRecord16(receipt) && Array.isArray(receipt.groups)) return receipt.groups;
31298
30025
  const outcome = body.outcome;
31299
- if (isRecord19(outcome)) {
30026
+ if (isRecord16(outcome)) {
31300
30027
  const facts = outcome.decisiveFacts;
31301
- if (isRecord19(facts) && Array.isArray(facts.groups)) return facts.groups;
30028
+ if (isRecord16(facts) && Array.isArray(facts.groups)) return facts.groups;
31302
30029
  }
31303
30030
  return void 0;
31304
30031
  }
31305
30032
  function extractStatus(body) {
31306
30033
  const outcome = body.outcome;
31307
- if (isRecord19(outcome) && typeof outcome.status === "string" && outcome.status.trim() !== "") {
30034
+ if (isRecord16(outcome) && typeof outcome.status === "string" && outcome.status.trim() !== "") {
31308
30035
  return outcome.status;
31309
30036
  }
31310
30037
  const receipt = body.receipt;
31311
- if (isRecord19(receipt) && typeof receipt.status === "string" && receipt.status.trim() !== "") {
30038
+ if (isRecord16(receipt) && typeof receipt.status === "string" && receipt.status.trim() !== "") {
31312
30039
  return receipt.status;
31313
30040
  }
31314
30041
  if (typeof body.status === "string" && body.status.trim() !== "") {
@@ -31933,21 +30660,21 @@ var init_leg_wall_clock = __esm({
31933
30660
  });
31934
30661
 
31935
30662
  // src/analyst-metric-families/round-timeline.ts
31936
- function isRecord20(value) {
30663
+ function isRecord17(value) {
31937
30664
  return typeof value === "object" && value !== null && !Array.isArray(value);
31938
30665
  }
31939
30666
  function wallMsFromSpan2(startedAt, endedAt) {
31940
30667
  return Date.parse(endedAt) - Date.parse(startedAt);
31941
30668
  }
31942
30669
  function readOutcomeStatus(body) {
31943
- if (!isRecord20(body.outcome)) return void 0;
30670
+ if (!isRecord17(body.outcome)) return void 0;
31944
30671
  const status = body.outcome.status;
31945
30672
  if (typeof status !== "string" || status.trim() === "") return void 0;
31946
30673
  return status;
31947
30674
  }
31948
30675
  function readClassCount(body) {
31949
- if (!isRecord20(body.outcome)) return void 0;
31950
- if (!isRecord20(body.outcome.decisiveFacts)) return void 0;
30676
+ if (!isRecord17(body.outcome)) return void 0;
30677
+ if (!isRecord17(body.outcome.decisiveFacts)) return void 0;
31951
30678
  const classCount = body.outcome.decisiveFacts.classCount;
31952
30679
  if (typeof classCount !== "number" || !Number.isFinite(classCount)) {
31953
30680
  return void 0;
@@ -32090,8 +30817,8 @@ var init_analyst_metric_family = __esm({
32090
30817
  });
32091
30818
 
32092
30819
  // src/analyst-page.ts
32093
- import { createHash as createHash7 } from "node:crypto";
32094
- import { dirname as dirname14, join as join30 } from "node:path";
30820
+ import { createHash as createHash5 } from "node:crypto";
30821
+ import { dirname as dirname14, join as join28 } from "node:path";
32095
30822
  function analystIssuePageKey(address) {
32096
30823
  const parts = ["book", address.bookKey];
32097
30824
  if (address.issueNumber !== void 0) {
@@ -32099,10 +30826,10 @@ function analystIssuePageKey(address) {
32099
30826
  } else if (address.scopeRootIdentity !== void 0) {
32100
30827
  parts.push("root", physicalPathIdentity(address.scopeRootIdentity));
32101
30828
  }
32102
- return createHash7("sha256").update(parts.join("\0")).digest("hex").slice(0, 32);
30829
+ return createHash5("sha256").update(parts.join("\0")).digest("hex").slice(0, 32);
32103
30830
  }
32104
30831
  function analystIssuePagePath(ledgerHome, address) {
32105
- return join30(ledgerHome, "analyst", "issues", `${analystIssuePageKey(address)}.json`);
30832
+ return join28(ledgerHome, "analyst", "issues", `${analystIssuePageKey(address)}.json`);
32106
30833
  }
32107
30834
  function analystIssuePageAddressFromPage(page) {
32108
30835
  return {
@@ -32463,7 +31190,7 @@ var init_analyst_entry = __esm({
32463
31190
 
32464
31191
  // src/public-cli/analyst-run.ts
32465
31192
  import { readFile as readFile20 } from "node:fs/promises";
32466
- import { isAbsolute as isAbsolute9, resolve as resolve11 } from "node:path";
31193
+ import { isAbsolute as isAbsolute9, resolve as resolve10 } from "node:path";
32467
31194
  function resolveAnalystIssueBookKeyFromCwd(cwd = process.cwd()) {
32468
31195
  try {
32469
31196
  return resolveBookKeyFromGit(cwd);
@@ -32512,7 +31239,7 @@ async function buildAnalystSweepModeInputFromAttachmentPaths(attachmentPaths) {
32512
31239
  );
32513
31240
  }
32514
31241
  const sourcePath = attachmentPaths[0];
32515
- const absolute = isAbsolute9(sourcePath) ? sourcePath : resolve11(sourcePath);
31242
+ const absolute = isAbsolute9(sourcePath) ? sourcePath : resolve10(sourcePath);
32516
31243
  let bytes;
32517
31244
  try {
32518
31245
  bytes = await readFile20(absolute);
@@ -32635,7 +31362,7 @@ __export(cli_exports, {
32635
31362
  runAkRole: () => runAkRole
32636
31363
  });
32637
31364
  import { realpath as realpath6 } from "node:fs/promises";
32638
- import { join as join31 } from "node:path";
31365
+ import { join as join29 } from "node:path";
32639
31366
  function takePublicGlobalFlag(argv, index, options) {
32640
31367
  const tokens = argv.slice(index);
32641
31368
  const taken = options.takeDashed(tokens);
@@ -32767,7 +31494,7 @@ function resolveHome(env) {
32767
31494
  return env.home ?? packageMachineHome();
32768
31495
  }
32769
31496
  function resolveAgentDir(env, home) {
32770
- return env.agentDir ?? process.env.PI_CODING_AGENT_DIR ?? join31(home, ".pi", "agent");
31497
+ return env.agentDir ?? process.env.PI_CODING_AGENT_DIR ?? join29(home, ".pi", "agent");
32771
31498
  }
32772
31499
  function parseThinking(value) {
32773
31500
  return value;
@@ -32972,6 +31699,7 @@ function renderHelp() {
32972
31699
  "Persistent config: ak-role config set <seat> <provider/model[:thinking]> | unset <gatekeeper|inspector|notary>",
32973
31700
  "Persistent engine (callable roles): ak-role config set-engine <seat> <name> | unset-engine <seat>",
32974
31701
  "Persistent host (callable roles): ak-role config set-host <seat> <name> | unset-host <seat>",
31702
+ "Provider host alias: ak-role config set-provider-alias <provider> <host> <alias> | unset-provider-alias <provider> <host>",
32975
31703
  "Host resolution: --host \u2192 persistent seat host \u2192 pi (resume uses the same order; #617)",
32976
31704
  "Effective seats: ak-role roles"
32977
31705
  );
@@ -33071,6 +31799,15 @@ function renderConfig(config) {
33071
31799
  }
33072
31800
  }
33073
31801
  lines.push(`autoResumeLimit ${config.autoResumeLimit ?? AUTO_RESUME_LIMIT}`);
31802
+ const aliases = config.providerAliases;
31803
+ if (aliases !== void 0) {
31804
+ for (const provider of Object.keys(aliases).sort()) {
31805
+ const byHost = aliases[provider];
31806
+ for (const host of Object.keys(byHost).sort()) {
31807
+ lines.push(`providerAlias ${provider} ${host} ${byHost[host]}`);
31808
+ }
31809
+ }
31810
+ }
33074
31811
  return `${lines.join("\n")}
33075
31812
  `;
33076
31813
  }
@@ -33220,6 +31957,44 @@ async function runConfigCommand(args, home, packageRoot2, io) {
33220
31957
  io.stdout(renderConfig(config));
33221
31958
  return 0;
33222
31959
  }
31960
+ if (args[0] === "set-provider-alias") {
31961
+ if (args.length !== 4) {
31962
+ throw new CliUsageError(
31963
+ "usage: ak-role config set-provider-alias <provider> <host> <alias>"
31964
+ );
31965
+ }
31966
+ let config = await loadAndValidateConfig(home, packageRoot2);
31967
+ try {
31968
+ config = setProviderHostAlias(config, args[1], args[2], args[3]);
31969
+ } catch (error) {
31970
+ throw new CliUsageError(
31971
+ error instanceof Error ? error.message : String(error),
31972
+ { cause: error }
31973
+ );
31974
+ }
31975
+ await savePublicCliConfig(config, home);
31976
+ io.stdout(renderConfig(config));
31977
+ return 0;
31978
+ }
31979
+ if (args[0] === "unset-provider-alias") {
31980
+ if (args.length !== 3) {
31981
+ throw new CliUsageError(
31982
+ "usage: ak-role config unset-provider-alias <provider> <host>"
31983
+ );
31984
+ }
31985
+ let config = await loadAndValidateConfig(home, packageRoot2);
31986
+ try {
31987
+ config = unsetProviderHostAlias(config, args[1], args[2]);
31988
+ } catch (error) {
31989
+ throw new CliUsageError(
31990
+ error instanceof Error ? error.message : String(error),
31991
+ { cause: error }
31992
+ );
31993
+ }
31994
+ await savePublicCliConfig(config, home);
31995
+ io.stdout(renderConfig(config));
31996
+ return 0;
31997
+ }
33223
31998
  throw new CliUsageError(`unknown config subcommand: ${args[0]}`);
33224
31999
  }
33225
32000
  async function runAkRole(argv, env) {
@@ -33722,8 +32497,8 @@ var init_cli = __esm({
33722
32497
  });
33723
32498
 
33724
32499
  // src/public-cli/main.ts
33725
- import { existsSync as existsSync10 } from "node:fs";
33726
- import { dirname as dirname15, join as join32 } from "node:path";
32500
+ import { existsSync as existsSync7 } from "node:fs";
32501
+ import { dirname as dirname15, join as join30 } from "node:path";
33727
32502
  import { fileURLToPath as fileURLToPath2 } from "node:url";
33728
32503
 
33729
32504
  // src/public-cli/host-pi-runtime.ts
@@ -33812,8 +32587,8 @@ function linkPackage(packageRoot2, name, targetDir) {
33812
32587
  // src/public-cli/main.ts
33813
32588
  var here = dirname15(fileURLToPath2(import.meta.url));
33814
32589
  function resolvePackageRoot(binDir) {
33815
- const canonical = join32(binDir, "..", "..");
33816
- if (existsSync10(join32(canonical, "package.json"))) {
32590
+ const canonical = join30(binDir, "..", "..");
32591
+ if (existsSync7(join30(canonical, "package.json"))) {
33817
32592
  return canonical;
33818
32593
  }
33819
32594
  return binDir;