@akagilnc/pi-workflow-roles 0.1.3565 → 0.1.3621

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 (142) hide show
  1. package/README.md +4 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/acp-host/production-host.js +18477 -8099
  4. package/dist/analyst-gate-cycles-read.js +387 -0
  5. package/dist/archivist-record-entry.js +22 -1
  6. package/dist/audit-escalation.js +6 -0
  7. package/dist/auditor-soul.js +74 -0
  8. package/dist/collector-config.js +86 -0
  9. package/dist/collector-evidence.js +316 -0
  10. package/dist/collector-github.js +527 -0
  11. package/dist/collector-ledger.js +853 -0
  12. package/dist/collector-tool-schemas.js +33 -0
  13. package/dist/compliance-transport.js +104 -52
  14. package/dist/diarist-contracts.js +72 -0
  15. package/dist/diarist-mechanical.js +411 -0
  16. package/dist/diarist-ticket-resolution.js +177 -0
  17. package/dist/diarist.js +311 -0
  18. package/dist/doctor-auditor.js +25 -0
  19. package/dist/doctor-contracts.js +2 -0
  20. package/dist/doctor-evidence.js +142 -0
  21. package/dist/gatekeeper-role.js +104 -81
  22. package/dist/host-transition-prior-native.js +78 -0
  23. package/dist/institutional-resolution.js +1 -95
  24. package/dist/judge-auditor.js +26 -0
  25. package/dist/ledger-session-read.js +227 -0
  26. package/dist/merger-git-state.js +78 -0
  27. package/dist/navigator-attendance.js +15 -7
  28. package/dist/navigator-public-session.js +170 -0
  29. package/dist/navigator-session-contracts.js +36 -40
  30. package/dist/notary-source-run.js +122 -0
  31. package/dist/package-contracts/auditor-output.js +66 -0
  32. package/dist/package-contracts/evidence-child-output.js +34 -0
  33. package/dist/package-contracts/judge-output.js +2 -0
  34. package/dist/package-contracts/terminating-tools.js +44 -3
  35. package/dist/package-resources/method-skill.js +254 -0
  36. package/dist/packaged-role-registry.js +56 -0
  37. package/dist/pi/durable-principal.js +61 -0
  38. package/dist/pi/in-process-session.js +25 -6
  39. package/dist/pi/known-failure.js +52 -0
  40. package/dist/pi/role-turn-host.js +430 -0
  41. package/dist/public-cli/auto-resume.js +414 -0
  42. package/dist/public-cli/cli-errors.js +8 -0
  43. package/dist/public-cli/cli-io.js +1 -0
  44. package/dist/public-cli/command-renderer.js +5 -0
  45. package/dist/public-cli/doctor-run.js +84 -0
  46. package/dist/public-cli/inspector-run.js +136 -0
  47. package/dist/public-cli/instruction-seat-run.js +256 -0
  48. package/dist/public-cli/invocation.js +2225 -0
  49. package/dist/public-cli/judge-run.js +118 -0
  50. package/dist/public-cli/load-production-acp-host.js +40 -0
  51. package/dist/public-cli/main.js +1511 -1124
  52. package/dist/public-cli/notary-run.js +161 -0
  53. package/dist/public-cli/option-definitions.js +1192 -0
  54. package/dist/public-cli/post-admission.js +667 -0
  55. package/dist/public-cli/public-run-credentials.js +49 -0
  56. package/dist/public-cli/registry.js +8 -2
  57. package/dist/public-cli/reviewer-dispatch-rejection.js +77 -0
  58. package/dist/public-cli/run-lifecycle.js +1344 -0
  59. package/dist/public-cli/seat-ticket-binding.js +113 -0
  60. package/dist/public-cli/settlement.js +3441 -0
  61. package/dist/public-cli/terminal.js +135 -0
  62. package/dist/public-cli/turn-request.js +25 -0
  63. package/dist/public-role-summons.js +301 -0
  64. package/dist/receipt-delivery-policy.js +10 -0
  65. package/dist/reviewer-child-executor.js +80 -8
  66. package/dist/reviewer-execution-ledger.js +2 -1
  67. package/dist/run-terminal-artifacts.js +195 -0
  68. package/dist/run-ticket-number.js +40 -0
  69. package/dist/session-assistant-usage.js +107 -0
  70. package/dist/shape-unreadable-failure.js +34 -0
  71. package/dist/submission-errors.js +3 -0
  72. package/dist/submission-ledger.js +388 -0
  73. package/dist/ticket-provenance-contracts.js +115 -0
  74. package/dist/ticket-provenance.js +340 -0
  75. package/extensions/role-runtime.ts +8 -0
  76. package/package.json +1 -1
  77. package/resources/diarist-collect.md +6 -10
  78. package/scripts/build-package.mjs +2 -1
  79. package/souls/diarist.md +9 -0
  80. package/souls/doctor-auditor.md +1 -0
  81. package/souls/evidence-child.md +1 -0
  82. package/src/acp-host/production-host.ts +4 -0
  83. package/src/acp-host/role-envelope.ts +4 -3
  84. package/src/acp-host/role-turn-host.ts +9 -1
  85. package/src/analyst-gate-cycles-read.ts +37 -2
  86. package/src/archivist-record-entry.ts +45 -1
  87. package/src/audit-escalation.ts +17 -0
  88. package/src/auditor-role.ts +22 -0
  89. package/src/auditor-soul.ts +42 -0
  90. package/src/compliance-transport.ts +177 -66
  91. package/src/diarist-contracts.ts +88 -0
  92. package/src/diarist-role.ts +60 -0
  93. package/src/diarist.ts +253 -179
  94. package/src/doctor-auditor.ts +10 -14
  95. package/src/doctor-contracts.ts +1 -0
  96. package/src/doctor-role.ts +2 -2
  97. package/src/evidence-child-role.ts +22 -0
  98. package/src/gatekeeper-pass-envelope.ts +109 -0
  99. package/src/gatekeeper-role.ts +145 -104
  100. package/src/host-contracts.ts +15 -2
  101. package/src/institutional-resolution.ts +8 -163
  102. package/src/judge-auditor.ts +10 -15
  103. package/src/judge-role.ts +8 -0
  104. package/src/navigator-attendance.ts +25 -9
  105. package/src/navigator-public-session.ts +217 -0
  106. package/src/navigator-session-contracts.ts +61 -54
  107. package/src/notary-source-run.ts +3 -1
  108. package/src/package-contracts/auditor-output.ts +82 -0
  109. package/src/package-contracts/evidence-child-output.ts +51 -0
  110. package/src/package-contracts/judge-output.ts +1 -0
  111. package/src/package-contracts/reviewer-output.ts +2 -2
  112. package/src/package-contracts/terminating-tools.ts +53 -3
  113. package/src/packaged-role-registry.ts +63 -0
  114. package/src/pi/adapter.ts +2 -1
  115. package/src/pi/in-process-session.ts +38 -12
  116. package/src/pi/role-turn-host.ts +42 -0
  117. package/src/public-cli/cli.ts +43 -6
  118. package/src/public-cli/countersign-run.ts +9 -129
  119. package/src/public-cli/diarist-run.ts +312 -0
  120. package/src/public-cli/instruction-seat-run.ts +289 -50
  121. package/src/public-cli/invocation.ts +87 -25
  122. package/src/public-cli/option-definitions.ts +79 -0
  123. package/src/public-cli/post-admission.ts +9 -3
  124. package/src/public-cli/registry.ts +7 -1
  125. package/src/public-cli/run-lifecycle.ts +53 -6
  126. package/src/public-cli/settlement.ts +170 -7
  127. package/src/public-cli/terminal.ts +4 -1
  128. package/src/public-role-summons.ts +431 -0
  129. package/src/receipt-delivery-policy.ts +10 -0
  130. package/src/reviewer-agent.ts +1 -1
  131. package/src/reviewer-child-executor.ts +114 -12
  132. package/src/reviewer-execution-ledger.ts +3 -2
  133. package/src/role-runtime.ts +275 -23
  134. package/src/session-assistant-usage.ts +119 -0
  135. package/src/session-opening-materials.ts +1 -1
  136. package/src/shape-unreadable-failure.ts +49 -0
  137. package/src/submission-errors.ts +3 -0
  138. package/src/ticket-provenance-contracts.ts +1 -0
  139. package/src/ticket-provenance.ts +0 -23
  140. package/dist/evidence-child-executor.js +0 -829
  141. package/src/diarist-llm-collector.ts +0 -324
  142. package/src/evidence-child-executor.ts +0 -1140
@@ -0,0 +1,78 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { exactUtf8 } from "./exact-utf8.js";
4
+ import { isFullGitObjectId } from "./git-object-id.js";
5
+ const execFileAsync = promisify(execFile);
6
+ async function git(cwd, args) {
7
+ const { stdout } = await execFileAsync("git", args, { cwd, encoding: "buffer", maxBuffer: 16 * 1024 * 1024 });
8
+ return new Uint8Array(stdout);
9
+ }
10
+ function line(bytes, label) {
11
+ const value = exactUtf8(bytes, label).trim();
12
+ if (!value)
13
+ throw new Error(`${label} is empty`);
14
+ return value;
15
+ }
16
+ function nulPaths(bytes, label) {
17
+ const raw = exactUtf8(bytes, label);
18
+ if (raw.length > 0 && !raw.endsWith("\0"))
19
+ throw new Error(`${label} is not NUL terminated`);
20
+ return raw.split("\0").filter(Boolean).sort((a, b) => Buffer.compare(Buffer.from(a), Buffer.from(b)));
21
+ }
22
+ async function unmerged(cwd) {
23
+ const raw = exactUtf8(await git(cwd, ["ls-files", "-u", "-z"]), "Git unmerged index");
24
+ const paths = new Set();
25
+ for (const row of raw.split("\0")) {
26
+ if (!row)
27
+ continue;
28
+ const tab = row.indexOf("\t");
29
+ if (tab < 0 || tab === row.length - 1)
30
+ throw new Error("Git returned a malformed unmerged index row");
31
+ paths.add(row.slice(tab + 1));
32
+ }
33
+ return [...paths].sort((a, b) => Buffer.compare(Buffer.from(a), Buffer.from(b)));
34
+ }
35
+ export function createProductionMergerGitState(repositoryRoot = process.cwd()) {
36
+ return {
37
+ async activeMerge() {
38
+ const targetObjectId = line(await git(repositoryRoot, ["rev-parse", "--verify", "HEAD"]), "Git HEAD");
39
+ let mergeHeadRaw;
40
+ try {
41
+ mergeHeadRaw = await git(repositoryRoot, ["rev-parse", "--verify", "MERGE_HEAD"]);
42
+ }
43
+ catch {
44
+ throw new Error("Assigned repository does not have one ordinary in-progress merge");
45
+ }
46
+ const mergeHeads = exactUtf8(mergeHeadRaw, "Git MERGE_HEAD").trim().split(/\r?\n/).filter(Boolean);
47
+ if (mergeHeads.length !== 1 || !isFullGitObjectId(targetObjectId) || !isFullGitObjectId(mergeHeads[0]) || targetObjectId.length !== mergeHeads[0].length)
48
+ throw new Error("Assigned repository does not have one ordinary in-progress merge");
49
+ let automaticMergeTreeRaw;
50
+ try {
51
+ automaticMergeTreeRaw = await git(repositoryRoot, ["rev-parse", "--verify", "AUTO_MERGE^{tree}"]);
52
+ }
53
+ catch {
54
+ throw new Error("Git automatic merge tree identity is unavailable or invalid");
55
+ }
56
+ const automaticMergeTreeId = line(automaticMergeTreeRaw, "Git automatic merge tree");
57
+ if (!isFullGitObjectId(automaticMergeTreeId) || automaticMergeTreeId.length !== targetObjectId.length)
58
+ throw new Error("Git automatic merge tree identity is unavailable or invalid");
59
+ return { targetObjectId, sourceObjectId: mergeHeads[0], unmergedPaths: await unmerged(repositoryRoot), automaticMergeTreeId };
60
+ },
61
+ async completedMerge(mergeCommitId, automaticMergeTreeId) {
62
+ if (!isFullGitObjectId(mergeCommitId) || !isFullGitObjectId(automaticMergeTreeId) || mergeCommitId.length !== automaticMergeTreeId.length)
63
+ throw new Error("Merger completion object ID is invalid");
64
+ const identity = exactUtf8(await git(repositoryRoot, ["show", "-s", "--format=%H%x00%P", mergeCommitId]), "Git merge commit").trimEnd().split("\0");
65
+ if (identity.length !== 2 || identity[0] !== mergeCommitId)
66
+ throw new Error("Git merge completion identity drifted");
67
+ const parentObjectIds = identity[1].split(" ").filter(Boolean);
68
+ const currentHead = line(await git(repositoryRoot, ["rev-parse", "--verify", "HEAD"]), "Git HEAD");
69
+ const status = await git(repositoryRoot, ["status", "--porcelain=v1", "-z", "--untracked-files=all"]);
70
+ const frozenTree = line(await git(repositoryRoot, ["rev-parse", "--verify", `${automaticMergeTreeId}^{tree}`]), "Git frozen automatic merge tree");
71
+ if (frozenTree !== automaticMergeTreeId)
72
+ throw new Error("Git frozen automatic merge tree identity drifted");
73
+ const mergeTree = line(await git(repositoryRoot, ["rev-parse", "--verify", `${mergeCommitId}^{tree}`]), "Git completed merge tree");
74
+ const resolutionChangedPaths = nulPaths(await git(repositoryRoot, ["diff-tree", "--no-commit-id", "--name-only", "-r", "-z", "--no-renames", automaticMergeTreeId, mergeTree]), "Git resolution path delta");
75
+ return { mergeCommitId: currentHead, parentObjectIds, unmergedPaths: await unmerged(repositoryRoot), worktreeClean: status.byteLength === 0 && currentHead === mergeCommitId, resolutionChangedPaths };
76
+ },
77
+ };
78
+ }
@@ -13,7 +13,7 @@ import {
13
13
  activationBookDirectory,
14
14
  resolveActivationLedgerHome
15
15
  } from "./activation-ledger-topology.js";
16
- import { createNativeNavigatorSessionFactory } from "./evidence-child-executor.js";
16
+ import { createNativeNavigatorSessionFactory } from "./navigator-public-session.js";
17
17
  import {
18
18
  NAVIGATOR_DEFAULT_MODEL,
19
19
  NAVIGATOR_PREPARE_TOOL_NAME,
@@ -340,11 +340,7 @@ function createNavigatorAttendance(options) {
340
340
  routePlaybookSettlement = routePlaybookPromise.then(() => void 0);
341
341
  const modelPromise = (async () => {
342
342
  try {
343
- const resolved = await resolveNavigatorSeatSelection(
344
- options.context,
345
- options.modelSettingPath,
346
- options.modelSettingPath ?? navigatorModelSettingPath()
347
- );
343
+ const resolved = await resolveNavigatorSeatSelection(options.context);
348
344
  return resolved.configuredLabel;
349
345
  } catch (error) {
350
346
  if (error instanceof NavigatorUnavailableError) throw error;
@@ -489,6 +485,11 @@ ${helpContext}
489
485
  return;
490
486
  }
491
487
  if (promptFailure !== void 0) throw promptFailure;
488
+ const sessionNoReceipt = activeSession.noReceipt?.();
489
+ if (sessionNoReceipt !== void 0) {
490
+ delivery.recordNestedNoReceipt(sessionNoReceipt);
491
+ return;
492
+ }
492
493
  if (deliveryRequest && output === void 0) delivery.recordDeliveryRequest();
493
494
  };
494
495
  await promptAllowingRejectedPrepare(request, false);
@@ -578,6 +579,7 @@ ${helpContext}
578
579
  }
579
580
  };
580
581
  async function settleOnce(settlement) {
582
+ if (disposed) return;
581
583
  const invocationId = activeInvocationId ?? invocationPrincipal;
582
584
  let report;
583
585
  if (settlement.kind === "human_decision" || settlement.kind === "role_infrastructure_failure") {
@@ -626,8 +628,10 @@ ${helpContext}
626
628
  session?.appendEntry(SETTLEMENT_ENTRY, { invocationId, subjectKey, role: settlement.role, phase: settlement.phase, kind: settlement.kind, ...settlement.status === void 0 ? {} : { status: settlement.status } });
627
629
  let selected = selectNavigatorCandidate(prepared, settlement);
628
630
  if (selected?.candidate.next !== void 0 && !selected.matchedToSettlement) {
631
+ if (disposed) return;
629
632
  prepareBoundSettlement = settlement;
630
633
  prepared = await prepare();
634
+ if (disposed) return;
631
635
  selected = selectNavigatorCandidate(prepared, settlement);
632
636
  }
633
637
  const selectedCandidate = selected?.candidate;
@@ -676,8 +680,12 @@ ${helpContext}
676
680
  ...report.routePlaybookReadFailure === void 0 ? {} : { routePlaybookReadFailure: report.routePlaybookReadFailure },
677
681
  ...report.arrivalMessage === void 0 ? {} : { arrivalMessage: report.arrivalMessage }
678
682
  };
679
- if (!disposed) {
683
+ if (disposed) return;
684
+ try {
680
685
  await options.onEvent(event, report);
686
+ } catch (error) {
687
+ if (disposed) return;
688
+ throw error;
681
689
  }
682
690
  preparation = void 0;
683
691
  sessionReady = void 0;
@@ -0,0 +1,170 @@
1
+ import { sitianReport } from "./sitian-facade.js";
2
+ import {
3
+ NavigatorUnavailableError,
4
+ navigatorProviderFailureFromDiagnostics,
5
+ navigatorProviderFailureFromError,
6
+ navigatorProviderFailureFromStatus,
7
+ navigatorUnavailableError,
8
+ parseNavigatorModelSetting,
9
+ resolveNavigatorSeatSelection
10
+ } from "./navigator-session-contracts.js";
11
+ function providerFailureFromPublicTerminal(outcome) {
12
+ const facts = outcome.decisiveFacts;
13
+ const secondary = typeof facts.secondaryEvidence === "object" && facts.secondaryEvidence !== null ? facts.secondaryEvidence : void 0;
14
+ const httpStatus = typeof secondary?.httpStatus === "number" ? secondary.httpStatus : typeof facts.httpStatus === "number" ? facts.httpStatus : typeof facts.errorCode === "number" ? facts.errorCode : void 0;
15
+ const fromStatus = navigatorProviderFailureFromStatus(httpStatus);
16
+ if (fromStatus !== void 0) return fromStatus;
17
+ const diagnostics = secondary?.diagnostics ?? facts.diagnostics;
18
+ const fromDiagnostics = navigatorProviderFailureFromDiagnostics(diagnostics);
19
+ if (fromDiagnostics !== void 0) return fromDiagnostics;
20
+ const fromCode = navigatorProviderFailureFromError({
21
+ code: secondary?.code ?? facts.errorCode
22
+ });
23
+ if (fromCode !== void 0) return fromCode;
24
+ if (outcome.cause === "provider") return { source: "transport", cause: "transport" };
25
+ return { source: "session", cause: "session" };
26
+ }
27
+ function createNativeNavigatorSessionFactory() {
28
+ return async ({ context, subject, tool }) => {
29
+ const resolved = await resolveNavigatorSeatSelection(context);
30
+ let thinkingLevel = resolved.thinkingLevel;
31
+ const { createRecordSession } = await import("./archivist-record-entry.js");
32
+ const sessionManager = createRecordSession({
33
+ cwd: context.cwd,
34
+ kind: "navigator",
35
+ subject,
36
+ parent: context.sessionManager
37
+ });
38
+ let providerFailure;
39
+ let noReceipt;
40
+ let disposed = false;
41
+ let inFlightPrompt;
42
+ const resolveHome = async () => {
43
+ const parentFile = context.sessionManager?.getSessionFile?.();
44
+ if (typeof parentFile === "string" && parentFile.trim() !== "") {
45
+ try {
46
+ const { tryHomeFromAkRolesPath, homeFromRunDirectory } = await import("./activation-ledger-topology.js");
47
+ const fromParent = tryHomeFromAkRolesPath(parentFile);
48
+ if (fromParent !== void 0 && fromParent.length > 0) return fromParent;
49
+ const runDir = parentFile.replace(/\/session\/session\.jsonl$/, "");
50
+ if (runDir !== parentFile) {
51
+ try {
52
+ return homeFromRunDirectory(runDir);
53
+ } catch {
54
+ }
55
+ }
56
+ } catch {
57
+ }
58
+ }
59
+ const envHome = process.env.HOME;
60
+ return typeof envHome === "string" && envHome.trim() !== "" ? envHome : void 0;
61
+ };
62
+ return {
63
+ prompt: async (text) => {
64
+ if (disposed) {
65
+ throw navigatorUnavailableError("session", new Error("Navigator attendance was disposed"));
66
+ }
67
+ providerFailure = void 0;
68
+ noReceipt = void 0;
69
+ const run = (async () => {
70
+ try {
71
+ const { summonPublicRole } = await import("./public-role-summons.js");
72
+ const home = await resolveHome();
73
+ const summoned = await summonPublicRole({
74
+ role: "navigator",
75
+ argv: [text],
76
+ cwd: context.cwd,
77
+ ...home === void 0 ? {} : { home }
78
+ });
79
+ const outcome = summoned.terminal?.roleOutcome;
80
+ if (outcome === void 0) {
81
+ const detail = summoned.stderr?.trim() || `exit ${summoned.exitCode}`;
82
+ providerFailure = { source: "transport", cause: "transport" };
83
+ throw navigatorUnavailableError(
84
+ "transport",
85
+ new Error(`Navigator public summon produced no terminal (${detail})`)
86
+ );
87
+ }
88
+ if (outcome.kind === "failure") {
89
+ providerFailure = providerFailureFromPublicTerminal(outcome);
90
+ throw navigatorUnavailableError(
91
+ providerFailure.source,
92
+ new Error(outcome.diagnostic),
93
+ providerFailure.cause
94
+ );
95
+ }
96
+ if (outcome.kind === "no_receipt") {
97
+ noReceipt = outcome;
98
+ return;
99
+ }
100
+ if (outcome.kind !== "accepted") {
101
+ providerFailure = { source: "session", cause: "session" };
102
+ throw navigatorUnavailableError(
103
+ "session",
104
+ new Error("Navigator public summon returned unusable terminal")
105
+ );
106
+ }
107
+ const candidates = outcome.decisiveFacts.candidates;
108
+ if (!Array.isArray(candidates)) {
109
+ return;
110
+ }
111
+ await tool.execute(
112
+ "navigator-public-prepare",
113
+ { candidates },
114
+ void 0,
115
+ void 0,
116
+ context
117
+ );
118
+ } catch (error) {
119
+ if (error instanceof NavigatorUnavailableError) throw error;
120
+ const fact = navigatorProviderFailureFromError(error);
121
+ providerFailure = fact ?? { source: "transport", cause: "transport" };
122
+ throw navigatorUnavailableError(providerFailure.source, error, providerFailure.cause);
123
+ }
124
+ })();
125
+ inFlightPrompt = run;
126
+ try {
127
+ await run;
128
+ } finally {
129
+ if (inFlightPrompt === run) inFlightPrompt = void 0;
130
+ }
131
+ },
132
+ providerFailure: () => providerFailure,
133
+ noReceipt: () => noReceipt,
134
+ appendEntry: (customType, data) => {
135
+ sessionManager.appendCustomEntry(customType, data);
136
+ try {
137
+ sitianReport({
138
+ level: "event",
139
+ kind: "attendance",
140
+ cwd: context.cwd,
141
+ sessionParent: sessionManager.getSessionFile(),
142
+ payload: { customType, data },
143
+ source: "navigator-public-session"
144
+ });
145
+ } catch {
146
+ }
147
+ },
148
+ entries: () => sessionManager.getEntries(),
149
+ setModel: async (next, nextThinking) => {
150
+ let nextParsed;
151
+ try {
152
+ nextParsed = parseNavigatorModelSetting(next);
153
+ } catch (error) {
154
+ throw navigatorUnavailableError("model", error);
155
+ }
156
+ thinkingLevel = nextThinking ?? nextParsed.thinkingLevel;
157
+ },
158
+ getThinkingLevel: () => thinkingLevel,
159
+ recordPointer: () => sessionManager.getSessionDir(),
160
+ dispose: async () => {
161
+ disposed = true;
162
+ const pending = inFlightPrompt;
163
+ if (pending !== void 0) await pending.catch(() => void 0);
164
+ }
165
+ };
166
+ };
167
+ }
168
+ export {
169
+ createNativeNavigatorSessionFactory
170
+ };
@@ -3,11 +3,6 @@ import { homedir } from "node:os";
3
3
  import { dirname, join } from "node:path";
4
4
  import { Type } from "typebox";
5
5
  import { Value } from "typebox/value";
6
- import { auditorRunDirectory } from "./auditor-dossier-tool.js";
7
- import {
8
- InstitutionalResolutionError,
9
- readInstitutionalSeatSelection
10
- } from "./institutional-resolution.js";
11
6
  const NAVIGATOR_PREPARE_TOOL_NAME = "ak_navigator_prepare";
12
7
  const NAVIGATOR_DEFAULT_MODEL = "openai-codex/gpt-5.6-luna:max";
13
8
  const NAVIGATOR_UNAVAILABLE_KEYS = /* @__PURE__ */ new Set([
@@ -159,50 +154,51 @@ function parseNavigatorModelSetting(value) {
159
154
  const suffix = colon < 0 ? void 0 : modelWithThinking.slice(colon + 1);
160
155
  const model = colon < 0 ? modelWithThinking : modelWithThinking.slice(0, colon);
161
156
  if (model === "") throw new Error("Navigator model setting must include a model");
162
- return suffix === void 0 ? { provider, model } : { provider, model, thinkingLevel: suffix };
157
+ if (suffix !== void 0 && suffix.trim() === "") {
158
+ throw new Error("Navigator model setting thinking suffix must be non-blank");
159
+ }
160
+ return {
161
+ provider,
162
+ model,
163
+ ...suffix === void 0 ? {} : { thinkingLevel: suffix }
164
+ };
163
165
  }
164
- async function resolveNavigatorSeatSelection(context, modelSettingPath, defaultModelSettingPath) {
165
- const runDirectory = auditorRunDirectory(context);
166
- if (runDirectory !== void 0) {
167
- try {
168
- const selection = await readInstitutionalSeatSelection(runDirectory, "navigator");
166
+ async function resolveNavigatorSeatSelection(context) {
167
+ try {
168
+ const { loadPublicCliConfig } = await import("./public-cli/config.js");
169
+ const { seatModelOnly } = await import("./public-cli/registry.js");
170
+ const { packageMachineHome } = await import("./activation-ledger-topology.js");
171
+ const homeCandidate = context.home;
172
+ const envHome = process.env.HOME;
173
+ const home = typeof homeCandidate === "string" ? homeCandidate : typeof envHome === "string" && envHome.trim() !== "" ? envHome : packageMachineHome();
174
+ const config = await loadPublicCliConfig(home);
175
+ const modelOnly = seatModelOnly(config.seats.navigator);
176
+ if (modelOnly === void 0) {
177
+ const parsed = parseNavigatorModelSetting(NAVIGATOR_DEFAULT_MODEL);
169
178
  return {
170
179
  selection: {
171
- provider: selection.provider,
172
- model: selection.model,
173
- ...selection.thinking === void 0 ? {} : { thinking: selection.thinking }
180
+ provider: parsed.provider,
181
+ model: parsed.model,
182
+ ...parsed.thinkingLevel === void 0 ? {} : { thinking: parsed.thinkingLevel }
174
183
  },
175
- configuredLabel: selection.thinking === void 0 ? `${selection.provider}/${selection.model}` : `${selection.provider}/${selection.model}:${selection.thinking}`,
176
- ...selection.thinking === void 0 ? {} : { thinkingLevel: selection.thinking }
184
+ configuredLabel: NAVIGATOR_DEFAULT_MODEL,
185
+ ...parsed.thinkingLevel === void 0 ? {} : { thinkingLevel: parsed.thinkingLevel }
177
186
  };
178
- } catch (error) {
179
- if (error instanceof InstitutionalResolutionError && (error.reason === "missing-page" || error.reason === "missing-seat")) {
180
- } else {
181
- throw error instanceof NavigatorUnavailableError ? error : navigatorUnavailableError("model", error);
182
- }
183
187
  }
184
- }
185
- let configured;
186
- try {
187
- configured = await readNavigatorModelSetting(modelSettingPath ?? defaultModelSettingPath);
188
+ const thinkingRaw = modelOnly.thinking;
189
+ const configuredLabel = thinkingRaw === void 0 ? `${modelOnly.provider}/${modelOnly.model}` : `${modelOnly.provider}/${modelOnly.model}:${thinkingRaw}`;
190
+ return {
191
+ selection: {
192
+ provider: modelOnly.provider,
193
+ model: modelOnly.model,
194
+ ...thinkingRaw === void 0 ? {} : { thinking: thinkingRaw }
195
+ },
196
+ configuredLabel,
197
+ ...thinkingRaw === void 0 ? {} : { thinkingLevel: thinkingRaw }
198
+ };
188
199
  } catch (error) {
189
200
  throw navigatorUnavailableError("model", error);
190
201
  }
191
- let parsed;
192
- try {
193
- parsed = parseNavigatorModelSetting(configured);
194
- } catch (error) {
195
- throw navigatorUnavailableError("model", error);
196
- }
197
- return {
198
- selection: {
199
- provider: parsed.provider,
200
- model: parsed.model,
201
- ...parsed.thinkingLevel === void 0 ? {} : { thinking: parsed.thinkingLevel }
202
- },
203
- configuredLabel: configured,
204
- ...parsed.thinkingLevel === void 0 ? {} : { thinkingLevel: parsed.thinkingLevel }
205
- };
206
202
  }
207
203
  export {
208
204
  NAVIGATOR_DEFAULT_MODEL,
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Resolve and validate the public Notary source-run locator.
3
+ * Only machine-ledger retained runs are authoritative: no project-tree projection,
4
+ * no attachment substitute. Caller supplies a run/case pointer; Notary self-fetches.
5
+ */
6
+ import { dirname, isAbsolute, join, resolve, basename } from "node:path";
7
+ import { lstat, realpath } from "node:fs/promises";
8
+ import { resolveBookKeyFromGit } from "./activation-ledger-git.js";
9
+ import { activationBookDirectory, physicalPathIdentity, resolveActivationLedgerHome, } from "./activation-ledger-topology.js";
10
+ import { readRoleRunIdentity } from "./public-cli/run-lifecycle.js";
11
+ // Run directory leaf: <runId>@<role>. Production uses uuidv7 runIds; offline tracers
12
+ // may use deterministic non-uuid leaves. Role token stays identifier-shaped.
13
+ const RUN_DIR_NAME = /^([A-Za-z0-9][A-Za-z0-9._-]*)@([A-Za-z][A-Za-z0-9_-]*)$/;
14
+ export class NotarySourceRunError extends Error {
15
+ constructor(message, options) {
16
+ super(message, options);
17
+ this.name = "NotarySourceRunError";
18
+ }
19
+ }
20
+ function parseRunDirectoryName(name) {
21
+ const match = RUN_DIR_NAME.exec(name);
22
+ if (match === null)
23
+ return undefined;
24
+ return { runId: match[1], role: match[2] };
25
+ }
26
+ async function requireRunDirectory(candidate, display) {
27
+ let real;
28
+ try {
29
+ real = await realpath(candidate);
30
+ }
31
+ catch (error) {
32
+ throw new NotarySourceRunError(`notary --source-run is not a readable run directory: ${display}`, { cause: error });
33
+ }
34
+ let stat;
35
+ try {
36
+ stat = await lstat(real);
37
+ }
38
+ catch (error) {
39
+ throw new NotarySourceRunError(`notary --source-run is not a readable run directory: ${display}`, { cause: error });
40
+ }
41
+ if (!stat.isDirectory()) {
42
+ throw new NotarySourceRunError(`notary --source-run must be a run directory: ${display}`);
43
+ }
44
+ const identity = parseRunDirectoryName(basename(real));
45
+ if (identity === undefined) {
46
+ throw new NotarySourceRunError(`notary --source-run must be named <runId>@<role>: ${basename(real)}`);
47
+ }
48
+ return real;
49
+ }
50
+ /**
51
+ * Resolve `--source-run` to a machine-ledger retained run directory and typed identity.
52
+ * Accepts:
53
+ * - bare `<runId>@<role>` under the project's book runs home
54
+ * - absolute/relative path that realpath's to that same book runs slot
55
+ *
56
+ * Rejects project-tree projections and any path outside the project's ledger book runs.
57
+ * Retained `run-state.json` must match basename identity and book binding.
58
+ */
59
+ export async function resolveNotarySourceRunLocator(options) {
60
+ const raw = options.sourceRun.trim();
61
+ if (raw === "") {
62
+ throw new NotarySourceRunError("notary --source-run requires a run locator");
63
+ }
64
+ const ledgerHome = resolveActivationLedgerHome(options.home);
65
+ const bookKey = resolveBookKeyFromGit(options.projectRoot);
66
+ const bookRunsRoot = join(activationBookDirectory(ledgerHome, bookKey), "runs");
67
+ let candidate;
68
+ const bare = parseRunDirectoryName(raw);
69
+ if (bare !== undefined && !raw.includes("/") && !raw.includes("\\")) {
70
+ candidate = join(bookRunsRoot, `${bare.runId}@${bare.role}`);
71
+ }
72
+ else {
73
+ candidate = isAbsolute(raw) ? raw : resolve(options.projectRoot, raw);
74
+ }
75
+ const real = await requireRunDirectory(candidate, raw);
76
+ const identity = parseRunDirectoryName(basename(real));
77
+ const runsRootIdentity = physicalPathIdentity(bookRunsRoot);
78
+ const parentIdentity = physicalPathIdentity(dirname(real));
79
+ if (parentIdentity !== runsRootIdentity) {
80
+ throw new NotarySourceRunError("notary --source-run must resolve to a retained run under the project machine-ledger book");
81
+ }
82
+ // Authoritative retained record only — legal role/state via shared reader (DRY #14).
83
+ // Identity envelope only: principal payload is not interpreted here.
84
+ const runState = await readRoleRunIdentity(real);
85
+ if (runState === undefined) {
86
+ throw new NotarySourceRunError("notary --source-run lacks retained run-state identity");
87
+ }
88
+ if (runState.runId !== identity.runId || runState.role !== identity.role) {
89
+ throw new NotarySourceRunError("notary --source-run retained identity does not match directory name");
90
+ }
91
+ if (runState.bookKey !== bookKey) {
92
+ throw new NotarySourceRunError("notary --source-run retained book binding does not match project case");
93
+ }
94
+ if (physicalPathIdentity(runState.runDirectory) !== physicalPathIdentity(real)) {
95
+ throw new NotarySourceRunError("notary --source-run retained runDirectory does not match locator path");
96
+ }
97
+ return {
98
+ runDirectory: real,
99
+ runId: identity.runId,
100
+ role: identity.role,
101
+ };
102
+ }
103
+ /** Internal activation loader: path is the admitted absolute source run directory. */
104
+ export async function loadNotarySourceRunLocator(path) {
105
+ const real = await requireRunDirectory(path, path);
106
+ const identity = parseRunDirectoryName(basename(real));
107
+ const runState = await readRoleRunIdentity(real);
108
+ if (runState === undefined) {
109
+ throw new NotarySourceRunError("notary source-run lacks retained run-state identity");
110
+ }
111
+ if (runState.runId !== identity.runId || runState.role !== identity.role) {
112
+ throw new NotarySourceRunError("notary source-run retained identity does not match directory name");
113
+ }
114
+ if (physicalPathIdentity(runState.runDirectory) !== physicalPathIdentity(real)) {
115
+ throw new NotarySourceRunError("notary source-run retained runDirectory does not match locator path");
116
+ }
117
+ return {
118
+ runDirectory: real,
119
+ runId: identity.runId,
120
+ role: identity.role,
121
+ };
122
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Public Auditor (审刑院) terminating receipt contracts (#675).
3
+ * Lawful explicit releases: pass | revise | escalate.
4
+ */
5
+ import { Type } from "typebox";
6
+ import { openToolObject } from "../open-tool-schema.js";
7
+ import { withInfrastructureFailureDeclaration } from "./terminating-infrastructure.js";
8
+ export const AUDITOR_OUTPUT_TOOL_NAME = "ak_auditor_output";
9
+ export const AUDITOR_ACCEPTED_TEXT = "审刑院回执已接受";
10
+ export const auditorOutputSchema = withInfrastructureFailureDeclaration(openToolObject(Type.Object({
11
+ status: Type.Unknown({
12
+ description: "pass | revise | escalate — 形状指引,非 schema 闸",
13
+ }),
14
+ violations: Type.Optional(Type.Unknown({
15
+ description: "status 为 revise 时的违规条目",
16
+ })),
17
+ conflicts: Type.Optional(Type.Unknown({
18
+ description: "status 为 escalate 时的冲突",
19
+ })),
20
+ decisionGate: Type.Optional(Type.Unknown({
21
+ description: "status 为 escalate 时的决策闸",
22
+ })),
23
+ })));
24
+ function isRecord(value) {
25
+ return typeof value === "object" && value !== null && !Array.isArray(value);
26
+ }
27
+ export function projectLawfulAuditorOutput(value) {
28
+ if (!isRecord(value))
29
+ return undefined;
30
+ if (value.status === "pass")
31
+ return { status: "pass" };
32
+ if (value.status === "revise") {
33
+ return {
34
+ status: "revise",
35
+ ...(Object.hasOwn(value, "violations") ? { violations: value.violations } : {}),
36
+ };
37
+ }
38
+ if (value.status === "escalate") {
39
+ return {
40
+ status: "escalate",
41
+ ...(Object.hasOwn(value, "conflicts") ? { conflicts: value.conflicts } : {}),
42
+ ...(Object.hasOwn(value, "decisionGate") ? { decisionGate: value.decisionGate } : {}),
43
+ };
44
+ }
45
+ return undefined;
46
+ }
47
+ export function validateRecordedAuditorOutput(value) {
48
+ const projected = projectLawfulAuditorOutput(value);
49
+ if (projected === undefined) {
50
+ throw new Error("Auditor output has no recognized execution discriminator");
51
+ }
52
+ return projected;
53
+ }
54
+ export function auditorDecisiveFacts(output) {
55
+ const facts = { status: output.status };
56
+ if (output.status === "revise" && output.violations !== undefined) {
57
+ facts.violations = output.violations;
58
+ }
59
+ if (output.status === "escalate") {
60
+ if (output.conflicts !== undefined)
61
+ facts.conflicts = output.conflicts;
62
+ if (output.decisionGate !== undefined)
63
+ facts.decisionGate = output.decisionGate;
64
+ }
65
+ return facts;
66
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Public Evidence-Child terminating receipt contracts (#675).
3
+ * One report body; shape is not an admission gate (ADR 0055).
4
+ */
5
+ import { Type } from "typebox";
6
+ import { openToolObject } from "../open-tool-schema.js";
7
+ import { withInfrastructureFailureDeclaration } from "./terminating-infrastructure.js";
8
+ export const EVIDENCE_CHILD_OUTPUT_TOOL_NAME = "ak_evidence_child_output";
9
+ export const EVIDENCE_CHILD_ACCEPTED_TEXT = "取证回执已接受";
10
+ export const evidenceChildOutputSchema = withInfrastructureFailureDeclaration(openToolObject(Type.Object({
11
+ report: Type.Unknown({
12
+ description: "取证报告正文 — 形状指引,非 schema 闸",
13
+ }),
14
+ })));
15
+ function isRecord(value) {
16
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17
+ }
18
+ export function projectLawfulEvidenceChildOutput(value) {
19
+ // No field-presence gate (ADR 0055 / CLAUDE.md §0 / #675). Retain delivered bytes:
20
+ // report key when present, otherwise the whole object as the report body.
21
+ if (!isRecord(value))
22
+ return undefined;
23
+ return { report: Object.hasOwn(value, "report") ? value.report : value };
24
+ }
25
+ export function validateRecordedEvidenceChildOutput(value) {
26
+ const projected = projectLawfulEvidenceChildOutput(value);
27
+ if (projected === undefined) {
28
+ throw new Error("Evidence-child output is not an object");
29
+ }
30
+ return projected;
31
+ }
32
+ export function evidenceChildDecisiveFacts(output) {
33
+ return { report: output.report };
34
+ }
@@ -1,6 +1,7 @@
1
1
  const JUDGE_OUTPUT_TOOL_NAME = "ak_judge_output";
2
2
  const JUDGE_ACCEPTED_TEXT = "\u5927\u7406\u5BFA\u56DE\u6267\u5DF2\u63A5\u53D7";
3
3
  const JUDGE_ACCEPTED_AUDIT_NO_RECEIPT_TEXT = "\u5927\u7406\u5BFA\u56DE\u6267\u5DF2\u63A5\u53D7\uFF1B\u5BA1\u8BA1\u65E0\u56DE\u6267";
4
+ const JUDGE_ACCEPTED_AUDIT_UNREADABLE_TEXT = "\u5927\u7406\u5BFA\u56DE\u6267\u5DF2\u63A5\u53D7\uFF1B\u5BA1\u8BA1\u5F62\u72B6\u4E0D\u53EF\u8BFB";
4
5
  function validateAcceptedJudgeDetails(verdict) {
5
6
  if (verdict === null || typeof verdict !== "object" || Array.isArray(verdict)) throw new Error("Judge verdict has no execution discriminator");
6
7
  let judgeStatus;
@@ -19,6 +20,7 @@ function validateAcceptedJudgeDetails(verdict) {
19
20
  }
20
21
  export {
21
22
  JUDGE_ACCEPTED_AUDIT_NO_RECEIPT_TEXT,
23
+ JUDGE_ACCEPTED_AUDIT_UNREADABLE_TEXT,
22
24
  JUDGE_ACCEPTED_TEXT,
23
25
  JUDGE_OUTPUT_TOOL_NAME,
24
26
  validateAcceptedJudgeDetails