@akagilnc/pi-workflow-roles 0.1.5368 → 0.1.5375

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 (165) hide show
  1. package/dist/acp-host/production-host.js +719 -776
  2. package/dist/activation-ledger-git.js +2 -2
  3. package/dist/activation-ledger-topology.js +1 -7
  4. package/dist/analyst-entry.js +4 -8
  5. package/dist/analyst-gate-cycles-read.js +3 -11
  6. package/dist/analyst-index.js +3 -9
  7. package/dist/analyst-ledger.js +1 -11
  8. package/dist/analyst-metric-families/acceptance-success-rework.js +1 -3
  9. package/dist/analyst-metric-families/round-timeline.js +1 -3
  10. package/dist/analyst-page.js +2 -2
  11. package/dist/archivist-record-topology.js +2 -2
  12. package/dist/audit-escalation.js +2 -1
  13. package/dist/auditor-soul.js +2 -1
  14. package/dist/collector-config.js +6 -8
  15. package/dist/compliance-transport.js +2 -1
  16. package/dist/countersign-contracts.js +2 -1
  17. package/dist/diarist-contracts.js +3 -2
  18. package/dist/doctor-contracts.js +1 -3
  19. package/dist/doctor-evidence.js +7 -8
  20. package/dist/dossier-resolution.js +1 -3
  21. package/dist/engine-detour-usage.js +1 -3
  22. package/dist/gatekeeper-role.js +2 -9
  23. package/dist/gleaner-left-contracts.js +2 -1
  24. package/dist/headless-host/description.js +14 -17
  25. package/dist/headless-host/production-host.js +721 -780
  26. package/dist/host-session-record.js +3 -2
  27. package/dist/inspector-contracts.js +2 -1
  28. package/dist/ledger-session-read.js +1 -3
  29. package/dist/merger-contracts.js +9 -9
  30. package/dist/migrate-book-topology.js +348 -314
  31. package/dist/navigator-attendance.js +9 -11
  32. package/dist/navigator-invocation-identity.js +3 -2
  33. package/dist/navigator-public-session.js +3 -5
  34. package/dist/navigator-session-contracts.js +8 -10
  35. package/dist/navigator-work-base.js +5 -8
  36. package/dist/notary-contracts.js +3 -5
  37. package/dist/package-contracts/auditor-output.js +1 -3
  38. package/dist/package-contracts/fixer-packet.js +3 -6
  39. package/dist/package-contracts/gatekeeper-output.js +1 -3
  40. package/dist/package-contracts/navigator-output.js +8 -8
  41. package/dist/package-contracts/terminating-infrastructure.js +5 -9
  42. package/dist/package-contracts/terminating-tools.js +4 -3
  43. package/dist/public-cli/analyst-run.js +3 -2
  44. package/dist/public-cli/auto-resume.js +3 -8
  45. package/dist/public-cli/cli.js +9 -8
  46. package/dist/public-cli/config.js +8 -11
  47. package/dist/public-cli/countersign-run.js +1 -3
  48. package/dist/public-cli/host-providers.js +7 -14
  49. package/dist/public-cli/instruction-seat-run.js +4 -3
  50. package/dist/public-cli/invocation.js +9 -8
  51. package/dist/public-cli/main.js +1531 -1567
  52. package/dist/public-cli/post-admission.js +4 -3
  53. package/dist/public-cli/run-lifecycle.js +14 -26
  54. package/dist/public-cli/settlement.js +10 -26
  55. package/dist/public-role-summons.js +3 -2
  56. package/dist/receipt-delivery-policy.js +1 -3
  57. package/dist/role-run-placement.js +3 -5
  58. package/dist/role-run-relocation.js +12 -19
  59. package/dist/run-terminal-artifacts.js +1 -11
  60. package/dist/run-ticket-number.js +2 -4
  61. package/dist/session-assistant-usage.js +2 -1
  62. package/dist/session-dialogue.js +1 -14
  63. package/dist/sitian-reader.js +2 -4
  64. package/dist/submission-correctable-error.js +2 -1
  65. package/dist/submission-errors.js +2 -1
  66. package/dist/submission-gate.js +2 -1
  67. package/dist/submission-ledger.js +4 -5
  68. package/dist/ticket-provenance-contracts.js +1 -3
  69. package/dist/ticket-provenance.js +2 -1
  70. package/dist/typed-provider-http.js +4 -7
  71. package/dist/unknown-value.js +28 -0
  72. package/dist/user-dialogue-stdin.js +2 -1
  73. package/package.json +1 -1
  74. package/src/acp-host/role-turn-host.ts +4 -2
  75. package/src/activation-ledger-git.ts +3 -2
  76. package/src/activation-ledger-topology.ts +4 -12
  77. package/src/analyst-entry.ts +3 -11
  78. package/src/analyst-gate-cycles-read.ts +3 -15
  79. package/src/analyst-index.ts +3 -13
  80. package/src/analyst-ledger.ts +2 -16
  81. package/src/analyst-metric-families/acceptance-success-rework.ts +2 -4
  82. package/src/analyst-metric-families/round-timeline.ts +2 -4
  83. package/src/analyst-page.ts +2 -2
  84. package/src/archivist-record-topology.ts +2 -2
  85. package/src/audit-escalation.ts +2 -1
  86. package/src/auditor-soul.ts +3 -1
  87. package/src/book-topology-migration-placement.ts +5 -16
  88. package/src/book-topology-migrators-t11.ts +16 -15
  89. package/src/book-topology-mixed-volume-migrators.ts +3 -6
  90. package/src/book-topology-record-class-migrators.ts +7 -10
  91. package/src/book-topology-runs-migrator.ts +4 -3
  92. package/src/collector-config.ts +7 -9
  93. package/src/compliance-transport.ts +2 -1
  94. package/src/countersign-contracts.ts +2 -1
  95. package/src/diarist-contracts.ts +3 -2
  96. package/src/doctor-contracts.ts +3 -1
  97. package/src/doctor-evidence.ts +8 -7
  98. package/src/doctor-role.ts +4 -2
  99. package/src/dossier-resolution.ts +2 -4
  100. package/src/engine-detour-tool.ts +0 -2
  101. package/src/engine-detour-usage.ts +2 -4
  102. package/src/external-host-turn-loop.ts +3 -1
  103. package/src/factory-board.ts +1 -8
  104. package/src/gatekeeper-role.ts +2 -10
  105. package/src/gleaner-left-contracts.ts +3 -1
  106. package/src/headless-host/description.ts +15 -18
  107. package/src/headless-host/role-turn-host.ts +10 -9
  108. package/src/host-session-record.ts +4 -2
  109. package/src/inspector-contracts.ts +2 -1
  110. package/src/ledger-session-read.ts +2 -5
  111. package/src/merger-contracts.ts +10 -9
  112. package/src/navigator-attendance.ts +10 -12
  113. package/src/navigator-invocation-identity.ts +3 -2
  114. package/src/navigator-public-session.ts +4 -6
  115. package/src/navigator-session-contracts.ts +8 -11
  116. package/src/navigator-work-base.ts +5 -8
  117. package/src/navigator-work-context.ts +2 -1
  118. package/src/notary-contracts.ts +4 -6
  119. package/src/oauth-keepalive.ts +5 -18
  120. package/src/package-contracts/auditor-output.ts +2 -4
  121. package/src/package-contracts/fixer-packet.ts +4 -6
  122. package/src/package-contracts/gatekeeper-output.ts +2 -4
  123. package/src/package-contracts/judge-output.ts +0 -1
  124. package/src/package-contracts/navigator-output.ts +8 -8
  125. package/src/package-contracts/terminating-infrastructure.ts +6 -20
  126. package/src/package-contracts/terminating-tools.ts +8 -12
  127. package/src/pi/adapter.ts +0 -1
  128. package/src/pi/role-turn-host.ts +0 -1
  129. package/src/public-cli/analyst-run.ts +4 -2
  130. package/src/public-cli/auto-resume.ts +4 -11
  131. package/src/public-cli/cli.ts +10 -10
  132. package/src/public-cli/config.ts +8 -27
  133. package/src/public-cli/countersign-run.ts +2 -4
  134. package/src/public-cli/host-providers.ts +10 -27
  135. package/src/public-cli/instruction-seat-run.ts +5 -3
  136. package/src/public-cli/invocation.ts +11 -10
  137. package/src/public-cli/post-admission.ts +5 -3
  138. package/src/public-cli/run-lifecycle.ts +20 -41
  139. package/src/public-cli/settlement.ts +11 -33
  140. package/src/public-role-summons.ts +4 -3
  141. package/src/receipt-delivery-policy.ts +1 -4
  142. package/src/reviewer-role.ts +0 -1
  143. package/src/role-envelope.ts +5 -3
  144. package/src/role-run-placement.ts +4 -10
  145. package/src/role-run-relocation.ts +13 -23
  146. package/src/role-runtime.ts +9 -15
  147. package/src/run-terminal-artifacts.ts +2 -16
  148. package/src/run-ticket-number.ts +4 -10
  149. package/src/session-assistant-usage.ts +3 -1
  150. package/src/session-dialogue.ts +1 -4
  151. package/src/session-identity.ts +0 -1
  152. package/src/sitian-reader.ts +2 -4
  153. package/src/submission-correctable-error.ts +3 -1
  154. package/src/submission-errors.ts +2 -1
  155. package/src/submission-gate.ts +3 -1
  156. package/src/submission-ledger.ts +5 -6
  157. package/src/ticket-provenance-contracts.ts +1 -4
  158. package/src/ticket-provenance.ts +3 -1
  159. package/src/ticket-snapshot.ts +2 -4
  160. package/src/ticket-trajectory.ts +1 -8
  161. package/src/typed-provider-http.ts +5 -15
  162. package/src/unknown-value.ts +34 -0
  163. package/src/user-dialogue-stdin.ts +3 -1
  164. package/src/worker-role.ts +2 -5
  165. package/src/worker-submission-gates.ts +5 -7
@@ -1,4 +1,3 @@
1
- import { createHash } from "node:crypto";
2
1
  import { mkdir, readFile, writeFile } from "node:fs/promises";
3
2
  import { homedir } from "node:os";
4
3
  import { dirname, join, resolve } from "node:path";
@@ -35,6 +34,8 @@ import { issueRoot, subjectPath } from "./work-subject-identity.js";
35
34
  import { createReceiptDeliveryPolicy, NO_RECEIPT_LIFECYCLE_ENTRY_TYPE } from "./receipt-delivery-policy.js";
36
35
  import { navigatorProseFromUnknown } from "./package-contracts/navigator-output.js";
37
36
  import { persistNavigatorWorkBase } from "./navigator-work-base.js";
37
+ import { sha256Hex } from "./sha256.js";
38
+ import { isRecord } from "./unknown-value.js";
38
39
  const NAVIGATOR_EVENT_TYPE = "ak-navigator-attendance";
39
40
  function resolveNavigatorAuthorityMaterial(roleInput, fileAuthority) {
40
41
  if (roleInput !== void 0 && roleInput.trim() !== "") return roleInput;
@@ -53,27 +54,24 @@ const unavailableKeys = /* @__PURE__ */ new Set(["context", "session", "model",
53
54
  function unavailableKey(value) {
54
55
  return typeof value === "string" && unavailableKeys.has(value) ? value : void 0;
55
56
  }
56
- function exactRecord(value) {
57
- return typeof value === "object" && value !== null && !Array.isArray(value);
58
- }
59
57
  function rejectedPrepareReason(entries, start) {
60
58
  const recent = entries.slice(start);
61
59
  const prepareCalls = /* @__PURE__ */ new Set();
62
60
  for (const entry of recent) {
63
- if (!exactRecord(entry) || entry.type !== "message" || !exactRecord(entry.message) || entry.message.role !== "assistant" || !Array.isArray(entry.message.content)) continue;
61
+ if (!isRecord(entry) || entry.type !== "message" || !isRecord(entry.message) || entry.message.role !== "assistant" || !Array.isArray(entry.message.content)) continue;
64
62
  for (const part of entry.message.content) {
65
- if (exactRecord(part) && part.type === "toolCall" && part.name === NAVIGATOR_PREPARE_TOOL_NAME && typeof part.id === "string") prepareCalls.add(part.id);
63
+ if (isRecord(part) && part.type === "toolCall" && part.name === NAVIGATOR_PREPARE_TOOL_NAME && typeof part.id === "string") prepareCalls.add(part.id);
66
64
  }
67
65
  }
68
66
  let reason;
69
67
  for (const entry of recent) {
70
- if (!exactRecord(entry) || entry.type !== "message" || !exactRecord(entry.message) || entry.message.role !== "toolResult" || entry.message.isError !== true) continue;
68
+ if (!isRecord(entry) || entry.type !== "message" || !isRecord(entry.message) || entry.message.role !== "toolResult" || entry.message.isError !== true) continue;
71
69
  const callId = entry.message.toolCallId;
72
70
  if (entry.message.toolName !== NAVIGATOR_PREPARE_TOOL_NAME || typeof callId !== "string" || !prepareCalls.has(callId)) {
73
71
  return void 0;
74
72
  }
75
73
  const content = entry.message.content;
76
- const text = Array.isArray(content) ? content.flatMap((part) => exactRecord(part) && typeof part.text === "string" ? [part.text] : []).join("") : typeof content === "string" ? content : "";
74
+ const text = Array.isArray(content) ? content.flatMap((part) => isRecord(part) && typeof part.text === "string" ? [part.text] : []).join("") : typeof content === "string" ? content : "";
77
75
  if (text.trim() !== "") reason = text.trim();
78
76
  }
79
77
  return reason;
@@ -86,7 +84,7 @@ function navigatorSubjectKey(subjectRoot, subject, provenance = "role_input") {
86
84
  if (provenance === "placeholder") return subjectRoot;
87
85
  const normalized = subject.trim().replace(/\s+/g, " ");
88
86
  if (normalized === "") return subjectRoot;
89
- return `${subjectRoot}#${createHash("sha256").update(normalized).digest("hex").slice(0, 32)}`;
87
+ return `${subjectRoot}#${sha256Hex(normalized).slice(0, 32)}`;
90
88
  }
91
89
  function navigatorSubjectKeyForInput(subjectRoot, reference, cwd = process.cwd()) {
92
90
  if (issueRoot(subjectRoot) !== void 0 || !subjectRoot.includes("/.ak/work/")) return subjectRoot;
@@ -308,10 +306,10 @@ function createNavigatorAttendance(options) {
308
306
  return void 0;
309
307
  }
310
308
  const nativeFailure = [...activeSession.entries()].reverse().find((entry) => {
311
- if (!exactRecord(entry) || entry.type !== "message" || !exactRecord(entry.message)) return false;
309
+ if (!isRecord(entry) || entry.type !== "message" || !isRecord(entry.message)) return false;
312
310
  return entry.message.role === "assistant" && typeof entry.message.errorMessage === "string" && entry.message.errorMessage.trim() !== "";
313
311
  });
314
- const nativeMessage = exactRecord(nativeFailure) && exactRecord(nativeFailure.message) ? nativeFailure.message : void 0;
312
+ const nativeMessage = isRecord(nativeFailure) && isRecord(nativeFailure.message) ? nativeFailure.message : void 0;
315
313
  const errorMessage = nativeMessage !== void 0 && typeof nativeMessage.errorMessage === "string" ? nativeMessage.errorMessage : "Navigator did not submit direction advice";
316
314
  const providerFailure = activeSession.providerFailure?.();
317
315
  const source = providerFailure?.source ?? "unknown";
@@ -1,5 +1,6 @@
1
1
  import { LEGACY_REVIEW_OUTPUT_ROLES, PACKAGED_ROLE_REGISTRY } from "./packaged-role-registry.js";
2
2
  import { isUuidV7, uuidv7 } from "./uuidv7.js";
3
+ import { isRecord } from "./unknown-value.js";
3
4
  import { workSubjectKeysEqual } from "./work-subject-identity.js";
4
5
  const NAVIGATOR_INVOCATION_ENTRY = "ak-navigator-invocation";
5
6
  const NAVIGATOR_ROUTE_PLAYBOOK_FAILURE_ENTRY = "ak-navigator-route-playbook-failure";
@@ -34,7 +35,7 @@ function extractInfrastructureFailureEvidence(error) {
34
35
  return evidence;
35
36
  }
36
37
  function hasNavigatorInfrastructureFailureBase(value) {
37
- if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
38
+ if (!isRecord(value)) return false;
38
39
  const record = value;
39
40
  for (const key of NAVIGATOR_INFRASTRUCTURE_FAILURE_KEYS) {
40
41
  if (!Object.hasOwn(record, key)) return false;
@@ -56,7 +57,7 @@ function invocationPhaseFromUnknown(value) {
56
57
  return void 0;
57
58
  }
58
59
  function parseInvocationMarkerIdentity(data) {
59
- if (data === null || typeof data !== "object" || Array.isArray(data)) return void 0;
60
+ if (!isRecord(data)) return void 0;
60
61
  const record = data;
61
62
  const invocationId = record.invocationId;
62
63
  if (typeof invocationId !== "string") return void 0;
@@ -15,6 +15,7 @@ import {
15
15
  attachWorkContextPointer,
16
16
  navigatorWorkContextFile
17
17
  } from "./navigator-work-base.js";
18
+ import { isRecord } from "./unknown-value.js";
18
19
  async function resolveNavigatorLedgerHome(context) {
19
20
  const { tryHomeFromAkRolesPath } = await import("./activation-ledger-topology.js");
20
21
  const runDirectory = runDirectoryFromHostContext(context);
@@ -30,9 +31,6 @@ async function resolveNavigatorLedgerHome(context) {
30
31
  return void 0;
31
32
  }
32
33
  const NAVIGATOR_HOST_RUN_POINTER_ENTRY = "ak-navigator-host-run";
33
- function exactRecord(value) {
34
- return typeof value === "object" && value !== null && !Array.isArray(value);
35
- }
36
34
  function runIdFromNavigatorDirectory(runDirectory) {
37
35
  const entry = basename(runDirectory);
38
36
  const suffix = "@navigator";
@@ -43,10 +41,10 @@ function runIdFromNavigatorDirectory(runDirectory) {
43
41
  function readNavigatorHostRunPointer(entries) {
44
42
  for (let index = entries.length - 1; index >= 0; index -= 1) {
45
43
  const entry = entries[index];
46
- if (!exactRecord(entry)) continue;
44
+ if (!isRecord(entry)) continue;
47
45
  if (entry.type === "custom" && entry.customType === NAVIGATOR_HOST_RUN_POINTER_ENTRY) {
48
46
  const data = entry.data;
49
- if (exactRecord(data) && typeof data.runId === "string" && data.runId.trim() !== "") {
47
+ if (isRecord(data) && typeof data.runId === "string" && data.runId.trim() !== "") {
50
48
  return data.runId.trim();
51
49
  }
52
50
  }
@@ -3,6 +3,7 @@ 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 { isRecord, errorText, isEnoent } from "./unknown-value.js";
6
7
  const NAVIGATOR_PREPARE_TOOL_NAME = "ak_navigator_prepare";
7
8
  const NAVIGATOR_UNAVAILABLE_KEYS = /* @__PURE__ */ new Set([
8
9
  "context",
@@ -30,12 +31,9 @@ class NavigatorUnavailableError extends Error {
30
31
  }
31
32
  }
32
33
  function navigatorUnavailableError(source, error, cause = source) {
33
- const message = error instanceof Error ? error.message : String(error);
34
+ const message = errorText(error);
34
35
  return error instanceof NavigatorUnavailableError ? error : new NavigatorUnavailableError(source, message, cause, error);
35
36
  }
36
- function exactRecord(value) {
37
- return typeof value === "object" && value !== null && !Array.isArray(value);
38
- }
39
37
  function navigatorProviderFailureFromStatus(status) {
40
38
  if (status === 401 || status === 403) return { source: "auth", cause: "auth" };
41
39
  if (status === 429) return { source: "quota", cause: "quota" };
@@ -57,7 +55,7 @@ function navigatorProviderFailureFromError(error) {
57
55
  if (cursor instanceof NavigatorUnavailableError) {
58
56
  return { source: cursor.unavailableSource, cause: cursor.unavailableCause };
59
57
  }
60
- if (!exactRecord(cursor)) {
58
+ if (!isRecord(cursor)) {
61
59
  cursor = cursor instanceof Error ? cursor.cause : void 0;
62
60
  continue;
63
61
  }
@@ -75,13 +73,13 @@ function navigatorProviderFailureFromError(error) {
75
73
  function navigatorProviderFailureFromDiagnostics(diagnostics) {
76
74
  if (!Array.isArray(diagnostics)) return void 0;
77
75
  for (const diagnostic of diagnostics) {
78
- if (!exactRecord(diagnostic)) continue;
76
+ if (!isRecord(diagnostic)) continue;
79
77
  if (diagnostic.type === "provider_transport_failure") return { source: "transport", cause: "transport" };
80
- if (exactRecord(diagnostic.error)) {
78
+ if (isRecord(diagnostic.error)) {
81
79
  const fromCode = navigatorProviderFailureFromCode(diagnostic.error.code);
82
80
  if (fromCode !== void 0) return fromCode;
83
81
  }
84
- if (exactRecord(diagnostic.details)) {
82
+ if (isRecord(diagnostic.details)) {
85
83
  const status = typeof diagnostic.details.status === "number" ? diagnostic.details.status : typeof diagnostic.details.statusCode === "number" ? diagnostic.details.statusCode : void 0;
86
84
  const fromStatus = navigatorProviderFailureFromStatus(status);
87
85
  if (fromStatus !== void 0) return fromStatus;
@@ -142,12 +140,12 @@ function navigatorModelSettingPath() {
142
140
  async function readNavigatorModelSetting(path = navigatorModelSettingPath()) {
143
141
  try {
144
142
  const raw = JSON.parse(await readFile(path, "utf8"));
145
- if (!exactRecord(raw) || typeof raw.model !== "string" || raw.model.trim() === "") {
143
+ if (!isRecord(raw) || typeof raw.model !== "string" || raw.model.trim() === "") {
146
144
  throw new Error("Navigator model setting is malformed");
147
145
  }
148
146
  return raw.model;
149
147
  } catch (error) {
150
- if (error instanceof Error && "code" in error && error.code === "ENOENT") {
148
+ if (isEnoent(error)) {
151
149
  throw new Error("Navigator model setting is missing");
152
150
  }
153
151
  throw error;
@@ -2,6 +2,7 @@ import { existsSync, realpathSync } from "node:fs";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import { basename, dirname, join, resolve } from "node:path";
4
4
  import { writeFileAtomically } from "./atomic-write.js";
5
+ import { isEnoent, isRecord } from "./unknown-value.js";
5
6
  const NAVIGATOR_WORK_CONTEXT_BASENAME = "work-context.json";
6
7
  function navigatorWorkContextFile(sessionDir) {
7
8
  return join(sessionDir, NAVIGATOR_WORK_CONTEXT_BASENAME);
@@ -32,9 +33,7 @@ async function persistNavigatorWorkBase(sessionDir, body) {
32
33
  const current = await readFile(path, "utf8");
33
34
  if (current === next) return path;
34
35
  } catch (error) {
35
- if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) {
36
- throw error;
37
- }
36
+ if (!isEnoent(error)) throw error;
38
37
  }
39
38
  await writeFileAtomically(path, next);
40
39
  return path;
@@ -46,9 +45,7 @@ async function readNavigatorWorkBase(path) {
46
45
  try {
47
46
  text = await readFile(canonical, "utf8");
48
47
  } catch (error) {
49
- if (error instanceof Error && "code" in error && error.code === "ENOENT") {
50
- return void 0;
51
- }
48
+ if (isEnoent(error)) return void 0;
52
49
  throw error;
53
50
  }
54
51
  let parsed;
@@ -57,7 +54,7 @@ async function readNavigatorWorkBase(path) {
57
54
  } catch {
58
55
  return void 0;
59
56
  }
60
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return void 0;
57
+ if (!isRecord(parsed)) return void 0;
61
58
  const record = parsed;
62
59
  if (typeof record.subject !== "string" || typeof record.authority !== "string") return void 0;
63
60
  if (record.authority.trim() === "") return void 0;
@@ -68,7 +65,7 @@ function jsonObjectFromPrompt(prompt) {
68
65
  if (!head.startsWith("{")) return void 0;
69
66
  try {
70
67
  const parsed = JSON.parse(head);
71
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return void 0;
68
+ if (!isRecord(parsed)) return void 0;
72
69
  return parsed;
73
70
  } catch {
74
71
  return void 0;
@@ -1,4 +1,5 @@
1
1
  import { REVIEW_SUBMISSION_OUTPUT_TOOL_NAME, reviewSubmissionSchema } from "./review-submission.js";
2
+ import { isRecord } from "./unknown-value.js";
2
3
  const NOTARY_OUTPUT_TOOL_NAME = REVIEW_SUBMISSION_OUTPUT_TOOL_NAME;
3
4
  const NOTARY_SOURCE_RUN_FLAG = {
4
5
  name: "ak-notary-source-run",
@@ -15,11 +16,8 @@ const NOTARY_TICKET_FLAG = {
15
16
  }
16
17
  };
17
18
  const notaryOutputSchema = reviewSubmissionSchema;
18
- function isRecord(value) {
19
- return typeof value === "object" && value !== null && !Array.isArray(value);
20
- }
21
19
  function projectLawfulNotaryOutput(value) {
22
- return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
20
+ return isRecord(value) ? value : void 0;
23
21
  }
24
22
  function retainNotarySubmission(value) {
25
23
  if (value === void 0) return { missing: "arguments" };
@@ -30,7 +28,7 @@ function retainNotarySubmission(value) {
30
28
  }
31
29
  }
32
30
  function validateRecordedNotaryOutput(value) {
33
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
31
+ if (!isRecord(value)) {
34
32
  throw new Error("Notary output is not an object");
35
33
  }
36
34
  return value;
@@ -3,11 +3,9 @@
3
3
  * Lawful explicit releases: converged | continue | escalate.
4
4
  */
5
5
  import { REVIEW_SUBMISSION_OUTPUT_TOOL_NAME, reviewSubmissionSchema } from "../review-submission.js";
6
+ import { isRecord } from "../unknown-value.js";
6
7
  export const AUDITOR_OUTPUT_TOOL_NAME = REVIEW_SUBMISSION_OUTPUT_TOOL_NAME;
7
8
  export const auditorOutputSchema = reviewSubmissionSchema;
8
- function isRecord(value) {
9
- return typeof value === "object" && value !== null && !Array.isArray(value);
10
- }
11
9
  /** #836: no field drop — original object is the receipt. */
12
10
  export function projectLawfulAuditorOutput(value) {
13
11
  return isRecord(value) ? value : undefined;
@@ -1,10 +1,11 @@
1
1
  import { Type } from "typebox";
2
2
  import { Value } from "typebox/value";
3
+ import { isRecord } from "../unknown-value.js";
3
4
  const FIXER_PREREQUISITE_ID_PATTERN = "^[A-Za-z0-9][A-Za-z0-9._-]*$";
4
5
  const fixerPrerequisiteSchema = Type.Object({
5
6
  id: Type.String({ pattern: FIXER_PREREQUISITE_ID_PATTERN }),
6
7
  requirement: Type.String({ pattern: "\\S" })
7
- }, { additionalProperties: false });
8
+ });
8
9
  const fixerPrerequisitesSchema = Type.Array(fixerPrerequisiteSchema);
9
10
  function causeMessage(cause) {
10
11
  if (cause instanceof Error) return cause.message;
@@ -32,13 +33,9 @@ function fail(cause) {
32
33
  function parseFailure(value) {
33
34
  if (!Array.isArray(value)) fail(new Error("Fixer prerequisites must be a JSON array"));
34
35
  for (const entry of value) {
35
- if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
36
+ if (!isRecord(entry)) {
36
37
  fail(new Error("Fixer prerequisite entry must be an object with id and requirement fields"));
37
38
  }
38
- const keys = Object.keys(entry);
39
- if (keys.length !== 2 || !keys.includes("id") || !keys.includes("requirement")) {
40
- fail(new Error("Fixer prerequisite entry fields must be exactly id and requirement"));
41
- }
42
39
  if (typeof entry.id !== "string" || !new RegExp(FIXER_PREREQUISITE_ID_PATTERN).test(entry.id)) {
43
40
  fail(new Error(`Fixer prerequisite id violates pattern ${FIXER_PREREQUISITE_ID_PATTERN}`));
44
41
  }
@@ -1,6 +1,7 @@
1
1
  import { Type } from "typebox";
2
2
  import { openToolObject } from "../open-tool-schema.js";
3
3
  import { withTerminatingOutputDeclarations } from "./terminating-infrastructure.js";
4
+ import { isRecord } from "../unknown-value.js";
4
5
  const GATEKEEPER_OUTPUT_TOOL_NAME = "ak_gatekeeper_output";
5
6
  const gatekeeperDecisionSchema = openToolObject(
6
7
  Type.Object({
@@ -18,9 +19,6 @@ const gatekeeperDecisionSchema = openToolObject(
18
19
  const gatekeeperOutputSchema = withTerminatingOutputDeclarations(
19
20
  gatekeeperDecisionSchema
20
21
  );
21
- function isRecord(value) {
22
- return typeof value === "object" && value !== null && !Array.isArray(value);
23
- }
24
22
  function asStringArray(value) {
25
23
  if (!Array.isArray(value)) return [];
26
24
  return value.filter((item) => typeof item === "string");
@@ -1,4 +1,5 @@
1
1
  import { Type } from "typebox";
2
+ import { isRecord } from "../unknown-value.js";
2
3
  import { openToolObject } from "../open-tool-schema.js";
3
4
  import { withTerminatingOutputDeclarations } from "./terminating-infrastructure.js";
4
5
  const NAVIGATOR_OUTPUT_TOOL_NAME = "ak_navigator_output";
@@ -14,18 +15,17 @@ const navigatorOutputSchema = withTerminatingOutputDeclarations(
14
15
  function projectLawfulNavigatorOutput(value) {
15
16
  if (value === void 0 || value === null) return void 0;
16
17
  if (typeof value === "string") return { prose: value };
17
- if (typeof value === "object" && !Array.isArray(value)) {
18
- const record = value;
19
- if (typeof record.prose === "string") return { prose: record.prose };
20
- if (record.prose !== void 0 && record.prose !== null) {
21
- return { prose: typeof record.prose === "string" ? record.prose : String(record.prose) };
18
+ if (isRecord(value)) {
19
+ if (typeof value.prose === "string") return { prose: value.prose };
20
+ if (value.prose !== void 0 && value.prose !== null) {
21
+ return { prose: typeof value.prose === "string" ? value.prose : String(value.prose) };
22
22
  }
23
- const keys = Object.keys(record);
23
+ const keys = Object.keys(value);
24
24
  if (keys.length === 0) return { prose: "" };
25
25
  try {
26
- return { prose: JSON.stringify(record) };
26
+ return { prose: JSON.stringify(value) };
27
27
  } catch {
28
- return { prose: String(record) };
28
+ return { prose: String(value) };
29
29
  }
30
30
  }
31
31
  return { prose: String(value) };
@@ -1,4 +1,5 @@
1
1
  import { Type } from "typebox";
2
+ import { isRecord } from "../unknown-value.js";
2
3
  const INFRASTRUCTURE_FAILURE_DECLARATION_KEY = "infrastructureFailure";
3
4
  const INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY = "diagnostic";
4
5
  const infrastructureFailureNested = Type.Object(
@@ -37,15 +38,10 @@ function withTerminatingOutputDeclarations(schema) {
37
38
  return object;
38
39
  }
39
40
  function isInfrastructureFailureDeclaration(parameters) {
40
- if (parameters === null || typeof parameters !== "object" || Array.isArray(parameters)) {
41
- return false;
42
- }
43
- const record = parameters;
44
- if (!Object.hasOwn(record, INFRASTRUCTURE_FAILURE_DECLARATION_KEY)) return false;
45
- const declaration = record[INFRASTRUCTURE_FAILURE_DECLARATION_KEY];
46
- if (declaration === null || typeof declaration !== "object" || Array.isArray(declaration)) {
47
- return false;
48
- }
41
+ if (!isRecord(parameters)) return false;
42
+ if (!Object.hasOwn(parameters, INFRASTRUCTURE_FAILURE_DECLARATION_KEY)) return false;
43
+ const declaration = parameters[INFRASTRUCTURE_FAILURE_DECLARATION_KEY];
44
+ if (!isRecord(declaration)) return false;
49
45
  const diagnostic = declaration[INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY];
50
46
  return typeof diagnostic === "string" && diagnostic.trim().length > 0;
51
47
  }
@@ -19,6 +19,7 @@ import { INSPECTOR_OUTPUT_TOOL_NAME, validateRecordedInspectorOutput } from "../
19
19
  import { DIARIST_OUTPUT_TOOL_NAME, validateRecordedDiaristOutput } from "../diarist-contracts.js";
20
20
  import { SECRETARIAT_OUTPUT_TOOL_NAME } from "../secretariat-contracts.js";
21
21
  import { CODER_OUTPUT_TOOL_NAME, FIXER_OUTPUT_TOOL_NAME, validateAcceptedWorkerDetails, } from "./worker-output.js";
22
+ import { isRecord } from "../unknown-value.js";
22
23
  export { CODER_OUTPUT_TOOL_NAME, COLLECTOR_OUTPUT_TOOL, FIXER_OUTPUT_TOOL_NAME, JUDGE_OUTPUT_TOOL_NAME, REVIEWER_OUTPUT_TOOL_NAME, MERGER_OUTPUT_TOOL_NAME, validateReviewerIntent, validateAcceptedWorkerDetails, validateDoctorSubmissionShape, validateRecordedDoctorOutput, validateMergerOutput, validateRecordedNotaryOutput, validateRecordedCountersignOutput, validateRecordedGleanerLeftOutput, validateRecordedInspectorOutput, validateRecordedGatekeeperOutput, validateRecordedNavigatorOutput, validateRecordedAuditorOutput, validateRecordedDiaristOutput, };
23
24
  export const TERMINATING_TOOL_NAMES = [...new Set([
24
25
  ...PACKAGED_ROLE_REGISTRY.map((entry) => entry.outputTool),
@@ -39,7 +40,7 @@ export class AcceptedDetailsContractError extends CorrectableSubmissionError {
39
40
  * Callers that need a typed view may still cast; code must not bounce on status.
40
41
  */
41
42
  export function validateAcceptedDetails(_toolName, details) {
42
- if (details !== null && typeof details === "object" && !Array.isArray(details)) {
43
+ if (isRecord(details)) {
43
44
  return details;
44
45
  }
45
46
  // Non-object payload still records as empty object rather than rejecting.
@@ -85,8 +86,8 @@ export function deepEqual(a, b) {
85
86
  return false;
86
87
  return a.every((item, index) => deepEqual(item, b[index]));
87
88
  }
88
- if (typeof a === "object") {
89
- if (typeof b !== "object" || b === null || Array.isArray(b))
89
+ if (isRecord(a)) {
90
+ if (!isRecord(b))
90
91
  return false;
91
92
  const aKeys = Object.keys(a).sort();
92
93
  const bKeys = Object.keys(b).sort();
@@ -20,6 +20,7 @@ import { exactUtf8 } from "../exact-utf8.js";
20
20
  import { readOrComputeAnalystIssuePage, runAnalyst, analystSweepModeInputSchema, AnalystIssueComputeError, } from "../analyst-entry.js";
21
21
  import { CliUsageError } from "./cli-errors.js";
22
22
  import { presentControlledFailure, presentStructuralRejection } from "./settlement.js";
23
+ import { errorText } from "../unknown-value.js";
23
24
  /**
24
25
  * Resolve the issue-query book from cwd git common-dir (same owner as record layer).
25
26
  * Non-git cwd fails loud — bare / --ticket both require a book identity.
@@ -63,7 +64,7 @@ export async function buildAnalystIssueModeInputFromPublicArgv(parsed, _ledgerHo
63
64
  }
64
65
  /**
65
66
  * Attachment JSON → library AnalystSweepModeInput via the sole schema (#337).
66
- * No parallel hand shape; rejects missing/extra/wrong-type fields only.
67
+ * No parallel hand shape; rejects missing or wrong-type fields only.
67
68
  */
68
69
  export function parseAnalystSweepModeInputFromJsonValue(value) {
69
70
  if (!Value.Check(analystSweepModeInputSchema, value)) {
@@ -94,7 +95,7 @@ export async function buildAnalystSweepModeInputFromAttachmentPaths(attachmentPa
94
95
  text = exactUtf8(bytes, "analyst sweep attachment");
95
96
  }
96
97
  catch (error) {
97
- const detail = error instanceof Error ? error.message : String(error);
98
+ const detail = errorText(error);
98
99
  throw new CliUsageError(detail, { cause: error });
99
100
  }
100
101
  let parsed;
@@ -22,6 +22,7 @@ import { processCancelSignalName } from "./process-cancel.js";
22
22
  import { isLawfulTypedTerminalOutcome, formatTerminalResult } from "./terminal.js";
23
23
  import { attachRecordedSubmissions, presentFailureTerminal, resolveControlledFailureResumeObservation, } from "./settlement.js";
24
24
  import { serializeThrownValue } from "../serialize-thrown-value.js";
25
+ import { errorText, isEnoent } from "../unknown-value.js";
25
26
  const dummyIo = { stdout: () => { }, stderr: () => { } };
26
27
  /**
27
28
  * Persist run-state after a host-turn result, outside the retried dispatch try.
@@ -83,7 +84,7 @@ async function finalizeExceptionRunBestEffort(runDirectory, io) {
83
84
  export class TurnDispatchedFailure extends Error {
84
85
  name = "TurnDispatchedFailure";
85
86
  constructor(cause) {
86
- super(`settlement failed after the host turn genuinely started: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
87
+ super(`settlement failed after the host turn genuinely started: ${errorText(cause)}`, { cause });
87
88
  }
88
89
  }
89
90
  /** Session custom-entry type carrying the pointer to one dispatch error file. */
@@ -111,7 +112,7 @@ export async function ensureRealArtifactsDirectory(runDirectory) {
111
112
  }
112
113
  }
113
114
  catch (error) {
114
- if (!isMissingPathError(error))
115
+ if (!isEnoent(error))
115
116
  throw error;
116
117
  await mkdir(artifactsDir, { recursive: true });
117
118
  const created = await lstat(artifactsDir);
@@ -121,12 +122,6 @@ export async function ensureRealArtifactsDirectory(runDirectory) {
121
122
  }
122
123
  return artifactsDir;
123
124
  }
124
- /** ENOENT identity shared with settlement.ts's hardened audit-artifact path. */
125
- function isMissingPathError(error) {
126
- return (error instanceof Error &&
127
- "code" in error &&
128
- error.code === "ENOENT");
129
- }
130
125
  /** Cycle- and bigint-safe JSON replacer so serialization itself cannot drop data. */
131
126
  function jsonSafeReplacer() {
132
127
  const seen = new WeakSet();
@@ -25,6 +25,7 @@ import { runPublicAnalyst } from "./analyst-run.js";
25
25
  import { AUTO_RESUME_LIMIT, peekRoleRunRole, } from "./run-lifecycle.js";
26
26
  import { INTERNAL_ROLE_ENTRYPOINT_RELATIVE, PUBLIC_CALLABLE_ROLES, isPublicCallableRole, isPublicCliSupportCommand, isPublicConfigurableSeat, listHelpCapabilities, } from "./registry.js";
27
27
  import { formatCliDiagnostic, formatErrorCauseDetail, presentStructuralRejection, } from "./settlement.js";
28
+ import { errorText } from "../unknown-value.js";
28
29
  export { buildExplicitInternalActivationArgs, resolveInternalRoleEntrypoint, } from "../pi/role-turn-host.js";
29
30
  export { CliUsageError } from "./cli-errors.js";
30
31
  /**
@@ -305,7 +306,7 @@ function requireLegalEngineModel(model) {
305
306
  return assertLegalEngineModel(model);
306
307
  }
307
308
  catch (error) {
308
- throw new CliUsageError(error instanceof Error ? error.message : String(error), { cause: error });
309
+ throw new CliUsageError(errorText(error), { cause: error });
309
310
  }
310
311
  }
311
312
  function requireLegalEngineName(name) {
@@ -313,7 +314,7 @@ function requireLegalEngineName(name) {
313
314
  return assertLegalEngineName(name);
314
315
  }
315
316
  catch (error) {
316
- throw new CliUsageError(error instanceof Error ? error.message : String(error), { cause: error });
317
+ throw new CliUsageError(errorText(error), { cause: error });
317
318
  }
318
319
  }
319
320
  /** Callable seats own persistent call axes (checked against the callable predicate). */
@@ -328,7 +329,7 @@ function loadAndValidateConfig(home, packageRoot) {
328
329
  validatePublicCliConfigAxes(config, packageRoot);
329
330
  }
330
331
  catch (error) {
331
- throw new CliUsageError(error instanceof Error ? error.message : String(error), { cause: error });
332
+ throw new CliUsageError(errorText(error), { cause: error });
332
333
  }
333
334
  return config;
334
335
  });
@@ -590,7 +591,7 @@ async function runConfigCommand(args, home, packageRoot, io) {
590
591
  config = setPersistentSeatHost(config, seat, unset ? undefined : args[2]);
591
592
  }
592
593
  catch (error) {
593
- throw new CliUsageError(error instanceof Error ? error.message : String(error), { cause: error });
594
+ throw new CliUsageError(errorText(error), { cause: error });
594
595
  }
595
596
  await savePublicCliConfig(config, home);
596
597
  io.stdout(renderConfig(config, home));
@@ -612,7 +613,7 @@ async function runConfigCommand(args, home, packageRoot, io) {
612
613
  config = setPersistentSeatEngine(config, seat, name, engineModel);
613
614
  }
614
615
  catch (error) {
615
- throw new CliUsageError(error instanceof Error ? error.message : String(error), { cause: error });
616
+ throw new CliUsageError(errorText(error), { cause: error });
616
617
  }
617
618
  await savePublicCliConfig(config, home);
618
619
  io.stdout(renderConfig(config, home));
@@ -629,7 +630,7 @@ async function runConfigCommand(args, home, packageRoot, io) {
629
630
  config = setPersistentSeatEngine(config, seat, undefined);
630
631
  }
631
632
  catch (error) {
632
- throw new CliUsageError(error instanceof Error ? error.message : String(error), { cause: error });
633
+ throw new CliUsageError(errorText(error), { cause: error });
633
634
  }
634
635
  await savePublicCliConfig(config, home);
635
636
  io.stdout(renderConfig(config, home));
@@ -648,7 +649,7 @@ async function runConfigCommand(args, home, packageRoot, io) {
648
649
  config = setPersistentSeatEngineModel(config, seat, model);
649
650
  }
650
651
  catch (error) {
651
- throw new CliUsageError(error instanceof Error ? error.message : String(error), { cause: error });
652
+ throw new CliUsageError(errorText(error), { cause: error });
652
653
  }
653
654
  await savePublicCliConfig(config, home);
654
655
  io.stdout(renderConfig(config, home));
@@ -665,7 +666,7 @@ async function runConfigCommand(args, home, packageRoot, io) {
665
666
  config = setPersistentSeatEngineModel(config, seat, undefined);
666
667
  }
667
668
  catch (error) {
668
- throw new CliUsageError(error instanceof Error ? error.message : String(error), { cause: error });
669
+ throw new CliUsageError(errorText(error), { cause: error });
669
670
  }
670
671
  await savePublicCliConfig(config, home);
671
672
  io.stdout(renderConfig(config, home));
@@ -19,6 +19,7 @@ import {
19
19
  isPublicConfigurableSeat,
20
20
  seatModelOnly
21
21
  } from "./registry.js";
22
+ import { isEnoent, isRecord } from "../unknown-value.js";
22
23
  const GATE_OFFICER_SEATS = PUBLIC_ROLE_RECORDS.flatMap(
23
24
  (record) => "provinceConfig" in record && record.provinceConfig === true ? [record.role] : []
24
25
  );
@@ -37,9 +38,7 @@ async function loadPublicCliConfig(home) {
37
38
  const raw = await readFile(path, "utf8");
38
39
  return parsePublicCliConfig(JSON.parse(raw));
39
40
  } catch (error) {
40
- if (error instanceof Error && "code" in error && error.code === "ENOENT") {
41
- return { seats: {} };
42
- }
41
+ if (isEnoent(error)) return { seats: {} };
43
42
  throw error;
44
43
  }
45
44
  }
@@ -260,7 +259,7 @@ function serializePublicCliConfig(config) {
260
259
  };
261
260
  }
262
261
  function parsePublicCliConfig(value) {
263
- if (value === null || typeof value !== "object" || Array.isArray(value)) {
262
+ if (!isRecord(value)) {
264
263
  throw new Error("public CLI config must be an object");
265
264
  }
266
265
  const record = value;
@@ -270,7 +269,7 @@ function parsePublicCliConfig(value) {
270
269
  }
271
270
  const unknownSeats = {};
272
271
  if (record.unknownSeats !== void 0) {
273
- if (record.unknownSeats === null || typeof record.unknownSeats !== "object" || Array.isArray(record.unknownSeats)) {
272
+ if (!isRecord(record.unknownSeats)) {
274
273
  throw new Error("public CLI config.unknownSeats must be an object");
275
274
  }
276
275
  Object.assign(unknownSeats, record.unknownSeats);
@@ -283,7 +282,7 @@ function parsePublicCliConfig(value) {
283
282
  if (record.seats === void 0) {
284
283
  return withOpaque({});
285
284
  }
286
- if (record.seats === null || typeof record.seats !== "object" || Array.isArray(record.seats)) {
285
+ if (!isRecord(record.seats)) {
287
286
  throw new Error("public CLI config.seats must be an object");
288
287
  }
289
288
  const seats = {};
@@ -299,7 +298,7 @@ function parsePublicCliConfig(value) {
299
298
  return withOpaque(seats);
300
299
  }
301
300
  function parseSeatModelConfig(value, seat) {
302
- if (value === null || typeof value !== "object" || Array.isArray(value)) {
301
+ if (!isRecord(value)) {
303
302
  throw new Error(`config seat ${seat} must be an object`);
304
303
  }
305
304
  const raw = value;
@@ -481,7 +480,7 @@ function listRolesForDisplay(config, credentials, invocation) {
481
480
  return effectiveSeatConfigurations(config, credentials, invocation);
482
481
  }
483
482
  function credentialProvidersFromAuthData(data) {
484
- if (data === null || typeof data !== "object" || Array.isArray(data)) {
483
+ if (!isRecord(data)) {
485
484
  return { "openai-codex": false, xai: false };
486
485
  }
487
486
  const record = data;
@@ -498,9 +497,7 @@ async function loadCredentialProviders(agentDir) {
498
497
  const raw = await readFile(join(agentDir, "auth.json"), "utf8");
499
498
  return credentialProvidersFromAuthData(JSON.parse(raw));
500
499
  } catch (error) {
501
- if (error instanceof Error && "code" in error && error.code === "ENOENT") {
502
- return { "openai-codex": false, xai: false };
503
- }
500
+ if (isEnoent(error)) return { "openai-codex": false, xai: false };
504
501
  throw error;
505
502
  }
506
503
  }
@@ -1,7 +1,5 @@
1
1
  import { readableGateItem } from "../readable-gate-item.js";
2
- function isRecord(value) {
3
- return typeof value === "object" && value !== null && !Array.isArray(value);
4
- }
2
+ import { isRecord } from "../unknown-value.js";
5
3
  function isEscalatePayload(payload) {
6
4
  if (!isRecord(payload))
7
5
  return false;