harnery 0.34.0 → 0.35.0

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 (212) hide show
  1. package/dist/commander.d.ts.map +1 -1
  2. package/dist/commander.js +2 -0
  3. package/dist/commands/agents.d.ts +15 -4
  4. package/dist/commands/agents.d.ts.map +1 -1
  5. package/dist/commands/agents.js +91 -162
  6. package/dist/commands/browse.d.ts.map +1 -1
  7. package/dist/commands/browse.js +26 -2
  8. package/dist/commands/decision.d.ts.map +1 -1
  9. package/dist/commands/decision.js +2 -2
  10. package/dist/commands/events.d.ts.map +1 -1
  11. package/dist/commands/events.js +18 -1
  12. package/dist/commands/presence.d.ts.map +1 -1
  13. package/dist/commands/presence.js +2 -2
  14. package/dist/commands/semantic.d.ts +4 -0
  15. package/dist/commands/semantic.d.ts.map +1 -0
  16. package/dist/commands/semantic.js +147 -0
  17. package/dist/commands/web.d.ts.map +1 -1
  18. package/dist/commands/web.js +17 -0
  19. package/dist/core/agents/canonical-emit.d.ts +3 -0
  20. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  21. package/dist/core/agents/canonical-emit.js +12 -0
  22. package/dist/core/agents/claim-path.d.ts +11 -0
  23. package/dist/core/agents/claim-path.d.ts.map +1 -0
  24. package/dist/core/agents/claim-path.js +22 -0
  25. package/dist/core/agents/coord-client.d.ts +29 -3
  26. package/dist/core/agents/coord-client.d.ts.map +1 -1
  27. package/dist/core/agents/coord-client.js +88 -9
  28. package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
  29. package/dist/core/agents/live-authority-v3.js +1 -3
  30. package/dist/core/agents/live-lifecycle-v3.js +3 -3
  31. package/dist/core/agents/live-observation-v3.d.ts.map +1 -1
  32. package/dist/core/agents/live-observation-v3.js +2 -2
  33. package/dist/core/agents/render/prompt-context.js +12 -10
  34. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  35. package/dist/core/agents/rules/stop-hook.js +23 -11
  36. package/dist/core/agents/session-name-display.d.ts +2 -1
  37. package/dist/core/agents/session-name-display.d.ts.map +1 -1
  38. package/dist/core/agents/session-name-display.js +10 -3
  39. package/dist/core/agents/state/heartbeat-reader.d.ts +46 -0
  40. package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -0
  41. package/dist/core/agents/state/heartbeat-reader.js +25 -0
  42. package/dist/core/agents/state/heartbeat-writer.d.ts +3 -48
  43. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  44. package/dist/core/agents/state/heartbeat-writer.js +16 -34
  45. package/dist/core/agents/state/live-coordination-view.d.ts +1 -1
  46. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
  47. package/dist/core/agents/state/live-coordination-view.js +25 -1
  48. package/dist/core/agents/state/names.d.ts +9 -1
  49. package/dist/core/agents/state/names.d.ts.map +1 -1
  50. package/dist/core/agents/state/names.js +190 -182
  51. package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
  52. package/dist/core/agents/state/stale-sweep.js +23 -5
  53. package/dist/core/artifacts/constants.d.ts +5 -0
  54. package/dist/core/artifacts/constants.d.ts.map +1 -0
  55. package/dist/core/artifacts/constants.js +4 -0
  56. package/dist/core/artifacts/index.d.ts +3 -3
  57. package/dist/core/artifacts/index.d.ts.map +1 -1
  58. package/dist/core/artifacts/index.js +50 -7
  59. package/dist/core/events/v3/base-contract.d.ts +795 -0
  60. package/dist/core/events/v3/base-contract.d.ts.map +1 -1
  61. package/dist/core/events/v3/base-contract.js +33 -0
  62. package/dist/core/events/v3/capabilities.d.ts +11 -0
  63. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  64. package/dist/core/events/v3/capabilities.js +23 -0
  65. package/dist/core/events/v3/generated.d.ts +1 -1
  66. package/dist/core/events/v3/generated.js +1 -1
  67. package/dist/core/events/v3/index.d.ts +4 -3
  68. package/dist/core/events/v3/index.d.ts.map +1 -1
  69. package/dist/core/events/v3/index.js +4 -3
  70. package/dist/core/events/v3/latency.d.ts +31 -1
  71. package/dist/core/events/v3/latency.d.ts.map +1 -1
  72. package/dist/core/events/v3/latency.js +127 -3
  73. package/dist/core/events/v3/live-routing.d.ts +30 -0
  74. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  75. package/dist/core/events/v3/live-routing.js +109 -1
  76. package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
  77. package/dist/core/events/v3/producers/command-recorder.js +10 -1
  78. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
  79. package/dist/core/events/v3/producers/coordination-recorder.js +14 -3
  80. package/dist/core/events/v3/producers/hook-base.d.ts +17 -1
  81. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  82. package/dist/core/events/v3/producers/hook-base.js +82 -1
  83. package/dist/core/events/v3/producers/intake.d.ts +6 -0
  84. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  85. package/dist/core/events/v3/producers/intake.js +11 -0
  86. package/dist/core/events/v3/producers/recorder.d.ts +62 -0
  87. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  88. package/dist/core/events/v3/producers/recorder.js +654 -18
  89. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +51 -0
  90. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -0
  91. package/dist/core/events/v3/runtime-telemetry-capabilities.js +54 -0
  92. package/dist/core/events/v3/turn-telemetry.d.ts +9 -0
  93. package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
  94. package/dist/core/hooks/adapter/parse.d.ts +3 -0
  95. package/dist/core/hooks/adapter/parse.d.ts.map +1 -1
  96. package/dist/core/hooks/adapter/parse.js +14 -0
  97. package/dist/core/hooks/adapter/runtime-telemetry.d.ts +119 -0
  98. package/dist/core/hooks/adapter/runtime-telemetry.d.ts.map +1 -0
  99. package/dist/core/hooks/adapter/runtime-telemetry.js +568 -0
  100. package/dist/core/hooks/cli.js +114 -38
  101. package/dist/core/hooks/remediation-cap.d.ts +34 -0
  102. package/dist/core/hooks/remediation-cap.d.ts.map +1 -0
  103. package/dist/core/hooks/remediation-cap.js +71 -0
  104. package/dist/core/hooks/resolve/transcript.d.ts +25 -9
  105. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  106. package/dist/core/hooks/resolve/transcript.js +35 -17
  107. package/dist/core/semantic/adapters.d.ts +34 -0
  108. package/dist/core/semantic/adapters.d.ts.map +1 -0
  109. package/dist/core/semantic/adapters.js +222 -0
  110. package/dist/core/semantic/contract.d.ts +588 -0
  111. package/dist/core/semantic/contract.d.ts.map +1 -0
  112. package/dist/core/semantic/contract.js +230 -0
  113. package/dist/core/semantic/evidence.d.ts +11 -0
  114. package/dist/core/semantic/evidence.d.ts.map +1 -0
  115. package/dist/core/semantic/evidence.js +262 -0
  116. package/dist/core/semantic/index.d.ts +10 -0
  117. package/dist/core/semantic/index.d.ts.map +1 -0
  118. package/dist/core/semantic/index.js +9 -0
  119. package/dist/core/semantic/once.d.ts +33 -0
  120. package/dist/core/semantic/once.d.ts.map +1 -0
  121. package/dist/core/semantic/once.js +293 -0
  122. package/dist/core/semantic/prompt.d.ts +12 -0
  123. package/dist/core/semantic/prompt.d.ts.map +1 -0
  124. package/dist/core/semantic/prompt.js +70 -0
  125. package/dist/core/semantic/scheduler.d.ts +16 -0
  126. package/dist/core/semantic/scheduler.d.ts.map +1 -0
  127. package/dist/core/semantic/scheduler.js +67 -0
  128. package/dist/core/semantic/service-status.d.ts +31 -0
  129. package/dist/core/semantic/service-status.d.ts.map +1 -0
  130. package/dist/core/semantic/service-status.js +84 -0
  131. package/dist/core/semantic/service.d.ts +51 -0
  132. package/dist/core/semantic/service.d.ts.map +1 -0
  133. package/dist/core/semantic/service.js +470 -0
  134. package/dist/core/semantic/storage.d.ts +71 -0
  135. package/dist/core/semantic/storage.d.ts.map +1 -0
  136. package/dist/core/semantic/storage.js +179 -0
  137. package/dist/core/semantic/validate.d.ts +16 -0
  138. package/dist/core/semantic/validate.d.ts.map +1 -0
  139. package/dist/core/semantic/validate.js +174 -0
  140. package/dist/lib/browser/client.d.ts +11 -0
  141. package/dist/lib/browser/client.d.ts.map +1 -1
  142. package/dist/lib/browser/client.js +13 -0
  143. package/dist/lib/browser/index.d.ts +1 -0
  144. package/dist/lib/browser/index.d.ts.map +1 -1
  145. package/dist/lib/browser/standalone-html.d.ts +25 -0
  146. package/dist/lib/browser/standalone-html.d.ts.map +1 -0
  147. package/dist/lib/browser/standalone-html.js +284 -0
  148. package/dist/lib/instructions/apply.d.ts.map +1 -1
  149. package/dist/lib/instructions/apply.js +1 -0
  150. package/dist/lib/instructions/templates.d.ts +2 -0
  151. package/dist/lib/instructions/templates.d.ts.map +1 -1
  152. package/dist/lib/instructions/templates.js +144 -4
  153. package/package.json +6 -1
  154. package/schemas/event-v3.schema.json +2758 -478
  155. package/src/commander.ts +2 -0
  156. package/src/commands/agents.ts +104 -152
  157. package/src/commands/browse.ts +25 -2
  158. package/src/commands/decision.ts +8 -2
  159. package/src/commands/events.ts +21 -1
  160. package/src/commands/presence.ts +7 -2
  161. package/src/commands/semantic.ts +179 -0
  162. package/src/commands/web.ts +15 -0
  163. package/src/core/agents/canonical-emit.ts +15 -0
  164. package/src/core/agents/claim-path.ts +23 -0
  165. package/src/core/agents/coord-client.ts +92 -8
  166. package/src/core/agents/live-authority-v3.ts +1 -4
  167. package/src/core/agents/live-lifecycle-v3.ts +8 -3
  168. package/src/core/agents/live-observation-v3.ts +7 -2
  169. package/src/core/agents/render/prompt-context.ts +13 -10
  170. package/src/core/agents/rules/stop-hook.ts +24 -11
  171. package/src/core/agents/session-name-display.ts +11 -3
  172. package/src/core/agents/state/heartbeat-reader.ts +69 -0
  173. package/src/core/agents/state/heartbeat-writer.ts +20 -84
  174. package/src/core/agents/state/live-coordination-view.ts +26 -1
  175. package/src/core/agents/state/names.ts +190 -182
  176. package/src/core/agents/state/stale-sweep.ts +25 -5
  177. package/src/core/artifacts/constants.ts +4 -0
  178. package/src/core/artifacts/index.ts +49 -7
  179. package/src/core/events/v3/base-contract.ts +39 -0
  180. package/src/core/events/v3/capabilities.ts +34 -0
  181. package/src/core/events/v3/generated.ts +1 -1
  182. package/src/core/events/v3/index.ts +21 -0
  183. package/src/core/events/v3/latency.ts +213 -2
  184. package/src/core/events/v3/live-routing.ts +120 -1
  185. package/src/core/events/v3/producers/command-recorder.ts +10 -1
  186. package/src/core/events/v3/producers/coordination-recorder.ts +17 -5
  187. package/src/core/events/v3/producers/hook-base.ts +115 -1
  188. package/src/core/events/v3/producers/intake.ts +18 -0
  189. package/src/core/events/v3/producers/recorder.ts +856 -21
  190. package/src/core/events/v3/runtime-telemetry-capabilities.ts +137 -0
  191. package/src/core/events/v3/turn-telemetry.ts +10 -0
  192. package/src/core/hooks/adapter/parse.ts +16 -0
  193. package/src/core/hooks/adapter/runtime-telemetry.ts +805 -0
  194. package/src/core/hooks/cli.ts +126 -41
  195. package/src/core/hooks/remediation-cap.ts +77 -0
  196. package/src/core/hooks/resolve/transcript.ts +49 -17
  197. package/src/core/semantic/adapters.ts +293 -0
  198. package/src/core/semantic/contract.ts +298 -0
  199. package/src/core/semantic/evidence.ts +336 -0
  200. package/src/core/semantic/index.ts +127 -0
  201. package/src/core/semantic/once.ts +410 -0
  202. package/src/core/semantic/prompt.ts +84 -0
  203. package/src/core/semantic/scheduler.ts +107 -0
  204. package/src/core/semantic/service-status.ts +118 -0
  205. package/src/core/semantic/service.ts +580 -0
  206. package/src/core/semantic/storage.ts +286 -0
  207. package/src/core/semantic/validate.ts +212 -0
  208. package/src/lib/browser/client.ts +21 -0
  209. package/src/lib/browser/index.ts +4 -0
  210. package/src/lib/browser/standalone-html.ts +312 -0
  211. package/src/lib/instructions/apply.ts +1 -0
  212. package/src/lib/instructions/templates.ts +149 -4
@@ -0,0 +1,293 @@
1
+ import { execFile } from "node:child_process";
2
+ import { mkdtempSync, readFileSync, rmSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { promisify } from "node:util";
6
+ import type { TSchema } from "@sinclair/typebox";
7
+ import { whichBin } from "../../lib/headless/index.ts";
8
+ import {
9
+ type SemanticConfiguredModel,
10
+ type SemanticHarness,
11
+ SemanticModelReplyV2Schema,
12
+ } from "./contract.ts";
13
+ import type { SemanticReaderResolution } from "./storage.ts";
14
+
15
+ const execFileAsync = promisify(execFile);
16
+ const MAX_OUTPUT_BYTES = 512 * 1024;
17
+ const DEFAULT_TIMEOUT_MS = 90_000;
18
+
19
+ export interface SemanticReaderRoute {
20
+ harness: SemanticHarness;
21
+ binary: string;
22
+ configured_model: SemanticConfiguredModel;
23
+ invocation_model_id: string;
24
+ }
25
+
26
+ export interface SemanticAdapterSuccess {
27
+ ok: true;
28
+ text: string;
29
+ resolved_model_id: string;
30
+ model_attestation: "verified" | "requested-only";
31
+ duration_ms: number;
32
+ output_bytes: number;
33
+ }
34
+
35
+ export interface SemanticAdapterFailure {
36
+ ok: false;
37
+ reason_code:
38
+ | "harness_unavailable"
39
+ | "authentication_unavailable"
40
+ | "model_unavailable"
41
+ | "model_mismatch";
42
+ resolved_model_id?: string;
43
+ model_attestation?: "verified" | "requested-only";
44
+ duration_ms: number;
45
+ }
46
+
47
+ export type SemanticAdapterResult = SemanticAdapterSuccess | SemanticAdapterFailure;
48
+
49
+ export interface SemanticAdapter {
50
+ readonly route: SemanticReaderRoute;
51
+ discover(now?: () => Date): SemanticReaderResolution;
52
+ invoke(
53
+ prompt: string,
54
+ timeoutMs?: number,
55
+ responseSchema?: TSchema,
56
+ ): Promise<SemanticAdapterResult>;
57
+ }
58
+
59
+ export const SEMANTIC_READER_ROUTES: Record<SemanticHarness, SemanticReaderRoute> = {
60
+ "claude-code": {
61
+ harness: "claude-code",
62
+ binary: "claude",
63
+ configured_model: "haiku-4.5",
64
+ invocation_model_id: "claude-haiku-4-5-20251001",
65
+ },
66
+ codex: {
67
+ harness: "codex",
68
+ binary: "codex",
69
+ configured_model: "gpt-5.6-luna",
70
+ invocation_model_id: "gpt-5.6-luna",
71
+ },
72
+ cursor: {
73
+ harness: "cursor",
74
+ binary: "cursor-agent",
75
+ configured_model: "composer-2.5",
76
+ invocation_model_id: "composer-2.5",
77
+ },
78
+ };
79
+
80
+ export function createSemanticAdapters(): Record<SemanticHarness, SemanticAdapter> {
81
+ return {
82
+ "claude-code": createAdapter(SEMANTIC_READER_ROUTES["claude-code"]),
83
+ codex: createAdapter(SEMANTIC_READER_ROUTES.codex),
84
+ cursor: createAdapter(SEMANTIC_READER_ROUTES.cursor),
85
+ };
86
+ }
87
+
88
+ export function discoverSemanticReaders(
89
+ adapters: Record<SemanticHarness, SemanticAdapter> = createSemanticAdapters(),
90
+ ): Record<SemanticHarness, SemanticReaderResolution> {
91
+ return {
92
+ "claude-code": adapters["claude-code"].discover(),
93
+ codex: adapters.codex.discover(),
94
+ cursor: adapters.cursor.discover(),
95
+ };
96
+ }
97
+
98
+ function createAdapter(route: SemanticReaderRoute): SemanticAdapter {
99
+ return {
100
+ route,
101
+ discover(now = () => new Date()) {
102
+ const installed = whichBin(route.binary) !== undefined;
103
+ return {
104
+ harness: route.harness,
105
+ configured_model: route.configured_model,
106
+ ...(installed
107
+ ? {
108
+ resolved_model_id: route.invocation_model_id,
109
+ model_attestation: "requested-only" as const,
110
+ available: true,
111
+ }
112
+ : { available: false, reason_code: "harness_unavailable" as const }),
113
+ discovered_at: now().toISOString(),
114
+ };
115
+ },
116
+ async invoke(
117
+ prompt,
118
+ timeoutMs = DEFAULT_TIMEOUT_MS,
119
+ responseSchema = SemanticModelReplyV2Schema,
120
+ ) {
121
+ if (!whichBin(route.binary)) {
122
+ return { ok: false, reason_code: "harness_unavailable", duration_ms: 0 };
123
+ }
124
+ return await invokeRoute(route, prompt, timeoutMs, responseSchema);
125
+ },
126
+ };
127
+ }
128
+
129
+ async function invokeRoute(
130
+ route: SemanticReaderRoute,
131
+ prompt: string,
132
+ timeoutMs: number,
133
+ responseSchema: TSchema,
134
+ ): Promise<SemanticAdapterResult> {
135
+ const dir = mkdtempSync(join(tmpdir(), "harnery-semantic-"));
136
+ const started = Date.now();
137
+ try {
138
+ const invocation = buildInvocation(route, prompt, dir, responseSchema);
139
+ const pending = execFileAsync(route.binary, invocation.args, {
140
+ cwd: dir,
141
+ env: semanticChildEnv(),
142
+ timeout: timeoutMs,
143
+ maxBuffer: MAX_OUTPUT_BYTES,
144
+ });
145
+ pending.child.stdin?.end();
146
+ const { stdout } = await pending;
147
+ const raw = invocation.outputFile ? readFileSync(invocation.outputFile, "utf8") : stdout;
148
+ const parsed = parseHarnessOutput(route.harness, raw);
149
+ if (!parsed.text.trim()) throw new Error("empty semantic response");
150
+ if (parsed.executedModelId && parsed.executedModelId !== route.invocation_model_id) {
151
+ return {
152
+ ok: false,
153
+ reason_code: "model_mismatch",
154
+ resolved_model_id: parsed.executedModelId,
155
+ model_attestation: "verified",
156
+ duration_ms: Date.now() - started,
157
+ };
158
+ }
159
+ return {
160
+ ok: true,
161
+ text: parsed.text,
162
+ resolved_model_id: parsed.executedModelId ?? route.invocation_model_id,
163
+ model_attestation: parsed.executedModelId ? "verified" : "requested-only",
164
+ duration_ms: Date.now() - started,
165
+ output_bytes: Buffer.byteLength(parsed.text),
166
+ };
167
+ } catch (error) {
168
+ return {
169
+ ok: false,
170
+ reason_code: classifyFailure(error),
171
+ resolved_model_id: route.invocation_model_id,
172
+ model_attestation: "requested-only",
173
+ duration_ms: Date.now() - started,
174
+ };
175
+ } finally {
176
+ rmSync(dir, { recursive: true, force: true });
177
+ }
178
+ }
179
+
180
+ function buildInvocation(
181
+ route: SemanticReaderRoute,
182
+ prompt: string,
183
+ dir: string,
184
+ responseSchema: TSchema,
185
+ ): { args: string[]; outputFile?: string } {
186
+ if (route.harness === "claude-code") {
187
+ return {
188
+ args: [
189
+ "-p",
190
+ prompt,
191
+ "--output-format",
192
+ "json",
193
+ "--json-schema",
194
+ JSON.stringify(responseSchema),
195
+ "--model",
196
+ route.invocation_model_id,
197
+ "--effort",
198
+ "low",
199
+ "--max-turns",
200
+ "1",
201
+ "--tools",
202
+ "",
203
+ "--strict-mcp-config",
204
+ "--mcp-config",
205
+ '{"mcpServers":{}}',
206
+ "--safe-mode",
207
+ "--no-session-persistence",
208
+ ],
209
+ };
210
+ }
211
+ if (route.harness === "codex") {
212
+ const outputFile = join(dir, "last-message.json");
213
+ return {
214
+ outputFile,
215
+ args: [
216
+ "exec",
217
+ "--model",
218
+ route.invocation_model_id,
219
+ "--sandbox",
220
+ "read-only",
221
+ "--skip-git-repo-check",
222
+ "--ephemeral",
223
+ "--ignore-user-config",
224
+ "--ignore-rules",
225
+ "--output-last-message",
226
+ outputFile,
227
+ "--cd",
228
+ dir,
229
+ prompt,
230
+ ],
231
+ };
232
+ }
233
+ return {
234
+ args: [
235
+ "-p",
236
+ prompt,
237
+ "--output-format",
238
+ "json",
239
+ "--mode",
240
+ "ask",
241
+ "--sandbox",
242
+ "enabled",
243
+ "--trust",
244
+ "--model",
245
+ route.invocation_model_id,
246
+ ],
247
+ };
248
+ }
249
+
250
+ function parseHarnessOutput(
251
+ harness: SemanticHarness,
252
+ raw: string,
253
+ ): { text: string; executedModelId?: string } {
254
+ if (harness === "codex") return { text: raw };
255
+ try {
256
+ const envelope = JSON.parse(raw) as {
257
+ is_error?: boolean;
258
+ result?: unknown;
259
+ model?: unknown;
260
+ };
261
+ if (envelope.is_error) throw new Error("harness returned an error envelope");
262
+ return {
263
+ text: typeof envelope.result === "string" ? envelope.result : "",
264
+ ...(typeof envelope.model === "string" ? { executedModelId: envelope.model } : {}),
265
+ };
266
+ } catch (error) {
267
+ if (error instanceof SyntaxError) return { text: raw };
268
+ throw error;
269
+ }
270
+ }
271
+
272
+ function semanticChildEnv(): NodeJS.ProcessEnv {
273
+ const env = { ...process.env };
274
+ for (const key of Object.keys(env)) {
275
+ if (key.startsWith("HARNERY_") || key === "CODEX_THREAD_ID" || key === "CLAUDECODE") {
276
+ delete env[key];
277
+ }
278
+ }
279
+ return env;
280
+ }
281
+
282
+ function classifyFailure(error: unknown): SemanticAdapterFailure["reason_code"] {
283
+ const value = error as NodeJS.ErrnoException;
284
+ if (value.code === "ENOENT") return "harness_unavailable";
285
+ const message = value.message ?? String(error);
286
+ if (/auth|login|credential|unauthorized|forbidden/i.test(message)) {
287
+ return "authentication_unavailable";
288
+ }
289
+ if (/model.*(?:not found|unknown|unavailable|unsupported)|invalid.*model/i.test(message)) {
290
+ return "model_unavailable";
291
+ }
292
+ return "model_unavailable";
293
+ }
@@ -0,0 +1,298 @@
1
+ import { type Static, type TProperties, type TSchema, Type } from "@sinclair/typebox";
2
+
3
+ export const SEMANTIC_EVIDENCE_SCHEMA_VERSION = 1 as const;
4
+ export const SEMANTIC_READ_MODEL_SCHEMA_VERSION = 2 as const;
5
+ export const SEMANTIC_EVIDENCE_CONTRACT_VERSION = 1 as const;
6
+ export const SEMANTIC_PROMPT_CONTRACT_VERSION = 3 as const;
7
+
8
+ const StrictObject = <T extends TProperties>(properties: T) =>
9
+ Type.Object(properties, { additionalProperties: false });
10
+ const Timestamp = Type.String({
11
+ pattern: "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$",
12
+ });
13
+ const Sha256 = Type.String({ pattern: "^sha256:[a-f0-9]{64}$" });
14
+ const SafeToken = Type.String({ pattern: "^[a-zA-Z0-9][a-zA-Z0-9._:+-]{0,127}$" });
15
+ const uuidV7Pattern = "[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}";
16
+ const EventId = Type.String({ pattern: `^evt_${uuidV7Pattern}$` });
17
+ const GenerationId = Type.String({ pattern: `^gen_${uuidV7Pattern}$` });
18
+ const InstanceId = Type.String({ pattern: "^inst_[a-zA-Z0-9._-]{1,128}$" });
19
+
20
+ export const SEMANTIC_HARNESSES = ["claude-code", "codex", "cursor"] as const;
21
+ export const SEMANTIC_CONFIGURED_MODELS = ["haiku-4.5", "gpt-5.6-luna", "composer-2.5"] as const;
22
+ export const SEMANTIC_PHASES = [
23
+ "orienting",
24
+ "researching",
25
+ "planning",
26
+ "implementing",
27
+ "verifying",
28
+ "coordinating",
29
+ "waiting",
30
+ "recovering",
31
+ "wrapping-up",
32
+ "unknown",
33
+ ] as const;
34
+ /**
35
+ * Model-synthesized presentation cues. Authoritative operational expressions
36
+ * such as blocked, waiting, alert, recovering, compacting, observing, strained,
37
+ * and conducting remain deterministic Codec projections and are excluded.
38
+ */
39
+ export const SEMANTIC_EXPRESSION_CUES = [
40
+ "focused",
41
+ "curious",
42
+ "deliberating",
43
+ "investigating",
44
+ "building",
45
+ "coordinating",
46
+ "planning",
47
+ "verifying",
48
+ "weighing",
49
+ "wrapping-up",
50
+ ] as const;
51
+ export const SEMANTIC_TAGS = [
52
+ "research",
53
+ "planning",
54
+ "implementation",
55
+ "verification",
56
+ "coordination",
57
+ "waiting",
58
+ "recovery",
59
+ "delivery",
60
+ "documentation",
61
+ "infrastructure",
62
+ ] as const;
63
+ export const SEMANTIC_EVIDENCE_KINDS = [
64
+ "task",
65
+ "lifecycle",
66
+ "intent",
67
+ "operation",
68
+ "wait",
69
+ "progress",
70
+ "artifact",
71
+ "action",
72
+ "terminal",
73
+ "error",
74
+ "recovery",
75
+ "claim-conflict",
76
+ ] as const;
77
+
78
+ export type SemanticHarness = (typeof SEMANTIC_HARNESSES)[number];
79
+ export type SemanticConfiguredModel = (typeof SEMANTIC_CONFIGURED_MODELS)[number];
80
+ export type SemanticPhase = (typeof SEMANTIC_PHASES)[number];
81
+ export type SemanticExpressionCue = (typeof SEMANTIC_EXPRESSION_CUES)[number];
82
+ export type SemanticTag = (typeof SEMANTIC_TAGS)[number];
83
+ export type SemanticEvidenceKind = (typeof SEMANTIC_EVIDENCE_KINDS)[number];
84
+ export type SemanticBasis =
85
+ | "direct-fact"
86
+ | "deterministic-projection"
87
+ | "model-synthesis"
88
+ | "prediction";
89
+ export type SemanticConfidence = "high" | "medium" | "low";
90
+
91
+ const HarnessSchema = Type.Union(SEMANTIC_HARNESSES.map((value) => Type.Literal(value)));
92
+ const ConfiguredModelSchema = Type.Union(
93
+ SEMANTIC_CONFIGURED_MODELS.map((value) => Type.Literal(value)),
94
+ );
95
+ const PhaseSchema = Type.Union(SEMANTIC_PHASES.map((value) => Type.Literal(value)));
96
+ const ExpressionCueSchema = Type.Union(
97
+ SEMANTIC_EXPRESSION_CUES.map((value) => Type.Literal(value)),
98
+ );
99
+ const TagSchema = Type.Union(SEMANTIC_TAGS.map((value) => Type.Literal(value)));
100
+ const EvidenceKindSchema = Type.Union(SEMANTIC_EVIDENCE_KINDS.map((value) => Type.Literal(value)));
101
+ const ConfidenceSchema = Type.Union([
102
+ Type.Literal("high"),
103
+ Type.Literal("medium"),
104
+ Type.Literal("low"),
105
+ ]);
106
+
107
+ function SemanticFieldSchema<T extends TSchema>(
108
+ value: T,
109
+ options: {
110
+ allowEmptyCitations?: boolean;
111
+ kind?: "synthesis" | "prediction" | "expression";
112
+ } = {},
113
+ ) {
114
+ const kind = options.kind ?? "synthesis";
115
+ return StrictObject({
116
+ value,
117
+ basis: Type.Literal(kind === "prediction" ? "prediction" : "model-synthesis"),
118
+ confidence:
119
+ kind === "prediction"
120
+ ? Type.Literal("low")
121
+ : kind === "expression"
122
+ ? Type.Union([Type.Literal("medium"), Type.Literal("low")])
123
+ : ConfidenceSchema,
124
+ evidence_event_ids: Type.Array(EventId, {
125
+ minItems: options.allowEmptyCitations ? 0 : 1,
126
+ maxItems: 16,
127
+ uniqueItems: true,
128
+ }),
129
+ });
130
+ }
131
+
132
+ export const SemanticEvidenceObservationV1Schema = StrictObject({
133
+ kind: EvidenceKindSchema,
134
+ event_id: EventId,
135
+ observed_at: Timestamp,
136
+ label: Type.Optional(Type.String({ minLength: 1, maxLength: 120 })),
137
+ outcome: Type.Optional(SafeToken),
138
+ error_class: Type.Optional(SafeToken),
139
+ });
140
+
141
+ export const SemanticEvidenceV1Schema = StrictObject({
142
+ schema_version: Type.Literal(SEMANTIC_EVIDENCE_SCHEMA_VERSION),
143
+ evidence_contract_version: Type.Literal(SEMANTIC_EVIDENCE_CONTRACT_VERSION),
144
+ instance_id: InstanceId,
145
+ generation_id: GenerationId,
146
+ source_harness: HarnessSchema,
147
+ source: StrictObject({
148
+ ledger_genesis_id: Type.String({ pattern: "^gex_[a-zA-Z0-9._-]{1,128}$" }),
149
+ observed_through_event_id: EventId,
150
+ observed_through_ts: Timestamp,
151
+ }),
152
+ task: Type.Optional(
153
+ StrictObject({ value: Type.String({ minLength: 1, maxLength: 200 }), event_id: EventId }),
154
+ ),
155
+ lifecycle: Type.Optional(StrictObject({ state: SafeToken, event_id: EventId })),
156
+ intent: Type.Optional(StrictObject({ kind: SafeToken, event_id: EventId })),
157
+ operation: Type.Optional(
158
+ StrictObject({
159
+ category: SafeToken,
160
+ label: Type.String({ minLength: 1, maxLength: 80 }),
161
+ event_id: EventId,
162
+ }),
163
+ ),
164
+ waits: Type.Array(StrictObject({ kind: SafeToken, event_id: EventId, started_at: Timestamp }), {
165
+ maxItems: 8,
166
+ }),
167
+ recent: Type.Array(SemanticEvidenceObservationV1Schema, { maxItems: 8 }),
168
+ attention: Type.Optional(SemanticEvidenceObservationV1Schema),
169
+ relationships: Type.Optional(
170
+ StrictObject({
171
+ parent_generation_id: Type.Optional(GenerationId),
172
+ dependency_ids: Type.Array(SafeToken, { maxItems: 16, uniqueItems: true }),
173
+ }),
174
+ ),
175
+ evidence_event_ids: Type.Array(EventId, { minItems: 1, maxItems: 64, uniqueItems: true }),
176
+ evidence_digest: Sha256,
177
+ });
178
+
179
+ export const SemanticMeaningV2Schema = StrictObject({
180
+ headline: SemanticFieldSchema(Type.String({ minLength: 1, maxLength: 60 })),
181
+ summary: SemanticFieldSchema(Type.String({ minLength: 1, maxLength: 240 })),
182
+ phase: SemanticFieldSchema(PhaseSchema),
183
+ expression_cue: Type.Optional(SemanticFieldSchema(ExpressionCueSchema, { kind: "expression" })),
184
+ purpose: Type.Optional(SemanticFieldSchema(Type.String({ minLength: 1, maxLength: 180 }))),
185
+ recent_result: Type.Optional(SemanticFieldSchema(Type.String({ minLength: 1, maxLength: 180 }))),
186
+ attention: Type.Optional(SemanticFieldSchema(Type.String({ minLength: 1, maxLength: 180 }))),
187
+ next_step: Type.Optional(
188
+ SemanticFieldSchema(Type.String({ minLength: 1, maxLength: 180 }), {
189
+ kind: "prediction",
190
+ }),
191
+ ),
192
+ tags: Type.Optional(
193
+ SemanticFieldSchema(Type.Array(TagSchema, { maxItems: 8, uniqueItems: true }), {
194
+ allowEmptyCitations: true,
195
+ }),
196
+ ),
197
+ });
198
+
199
+ export const SemanticModelReplyV2Schema = StrictObject({
200
+ schema_version: Type.Literal(SEMANTIC_READ_MODEL_SCHEMA_VERSION),
201
+ generation_id: GenerationId,
202
+ evidence_digest: Sha256,
203
+ meaning: SemanticMeaningV2Schema,
204
+ });
205
+
206
+ /** Native structured-output schema bound to one evidence request. */
207
+ export function semanticModelReplyV2SchemaFor(expected: {
208
+ generation_id: string;
209
+ evidence_digest: string;
210
+ }) {
211
+ return StrictObject({
212
+ schema_version: Type.Literal(SEMANTIC_READ_MODEL_SCHEMA_VERSION),
213
+ generation_id: Type.Literal(expected.generation_id),
214
+ evidence_digest: Type.Literal(expected.evidence_digest),
215
+ meaning: SemanticMeaningV2Schema,
216
+ });
217
+ }
218
+
219
+ const ReaderCommon = {
220
+ harness: HarnessSchema,
221
+ configured_model: ConfiguredModelSchema,
222
+ prompt_contract_version: Type.Literal(SEMANTIC_PROMPT_CONTRACT_VERSION),
223
+ };
224
+ const UnresolvedReaderSchema = StrictObject(ReaderCommon);
225
+ const ResolvedReaderSchema = StrictObject({
226
+ ...ReaderCommon,
227
+ resolved_model_id: Type.String({ minLength: 1, maxLength: 160 }),
228
+ model_attestation: Type.Union([Type.Literal("verified"), Type.Literal("requested-only")]),
229
+ });
230
+ const ReaderSchema = Type.Union([UnresolvedReaderSchema, ResolvedReaderSchema]);
231
+
232
+ const ReadModelBase = {
233
+ schema_version: Type.Literal(SEMANTIC_READ_MODEL_SCHEMA_VERSION),
234
+ instance_id: InstanceId,
235
+ generation_id: GenerationId,
236
+ source: StrictObject({
237
+ ledger_genesis_id: Type.String({ pattern: "^gex_[a-zA-Z0-9._-]{1,128}$" }),
238
+ evidence_digest: Sha256,
239
+ observed_through_event_id: EventId,
240
+ observed_through_ts: Timestamp,
241
+ }),
242
+ generated_at: Timestamp,
243
+ };
244
+
245
+ export const SemanticAcceptedReadModelV2Schema = StrictObject({
246
+ ...ReadModelBase,
247
+ reader_outcome: Type.Literal("accepted"),
248
+ reader: ResolvedReaderSchema,
249
+ meaning: SemanticMeaningV2Schema,
250
+ });
251
+
252
+ export const SemanticUnavailableReadModelV2Schema = StrictObject({
253
+ ...ReadModelBase,
254
+ reader_outcome: Type.Literal("unavailable"),
255
+ reader: ReaderSchema,
256
+ receipt: StrictObject({
257
+ reason_code: Type.Union([
258
+ Type.Literal("harness_unavailable"),
259
+ Type.Literal("authentication_unavailable"),
260
+ Type.Literal("model_unavailable"),
261
+ Type.Literal("model_mismatch"),
262
+ ]),
263
+ }),
264
+ });
265
+
266
+ export const SemanticInvalidReadModelV2Schema = StrictObject({
267
+ ...ReadModelBase,
268
+ reader_outcome: Type.Literal("invalid"),
269
+ reader: ResolvedReaderSchema,
270
+ receipt: StrictObject({ reason_code: Type.Literal("invalid_output") }),
271
+ });
272
+
273
+ export const SemanticDeferredReadModelV2Schema = StrictObject({
274
+ ...ReadModelBase,
275
+ reader_outcome: Type.Literal("deferred"),
276
+ reader: ReaderSchema,
277
+ receipt: StrictObject({ reason_code: Type.Literal("rate_cap"), eligible_after: Timestamp }),
278
+ });
279
+
280
+ export const SemanticAgentReadModelV2Schema = Type.Union([
281
+ SemanticAcceptedReadModelV2Schema,
282
+ SemanticUnavailableReadModelV2Schema,
283
+ SemanticInvalidReadModelV2Schema,
284
+ SemanticDeferredReadModelV2Schema,
285
+ ]);
286
+
287
+ export type SemanticEvidenceObservationV1 = Static<typeof SemanticEvidenceObservationV1Schema>;
288
+ export type SemanticEvidenceV1 = Static<typeof SemanticEvidenceV1Schema>;
289
+ export type SemanticField<T> = {
290
+ value: T;
291
+ basis: SemanticBasis;
292
+ confidence: SemanticConfidence;
293
+ evidence_event_ids: string[];
294
+ };
295
+ export type SemanticMeaningV2 = Static<typeof SemanticMeaningV2Schema>;
296
+ export type SemanticModelReplyV2 = Static<typeof SemanticModelReplyV2Schema>;
297
+ export type SemanticAcceptedReadModelV2 = Static<typeof SemanticAcceptedReadModelV2Schema>;
298
+ export type SemanticAgentReadModelV2 = Static<typeof SemanticAgentReadModelV2Schema>;