@intentrax/sdk 1.0.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.
@@ -0,0 +1,2412 @@
1
+ #!/usr/bin/env node
2
+ import { createHash } from "node:crypto";
3
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
+ import { dirname, isAbsolute, join, relative, resolve } from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+ import { buildAgentGatewayAdmissionEnvelope } from "../index.js";
7
+
8
+ const VERSION = "1.0.0";
9
+ const ADMISSION_SCHEMA_VERSION = "intentrax.runtime.agent_admission_request/1.0";
10
+ const INIT_SCHEMA_VERSION = "intentrax.onboarding.agent_adapter_init/1.0";
11
+ const ACTION_RECEIPT_SCHEMA_VERSION = "intentrax.onboarding.agent_adapter_action_receipt/1.0";
12
+ const HOST_WIRING_GUIDE_SCHEMA_VERSION = "intentrax.onboarding.agent_adapter_host_wiring_guide/1.0";
13
+ const LOCAL_INIT_CHECK_SCHEMA_VERSION = "intentrax.sdk.agent_adapter_init_offline_check/1.0";
14
+ const LOCAL_INIT_CHECK_VERIFIER_VERSION = "intentrax-typescript-cli-init-offline-checker/1.0";
15
+ const LOCAL_PROOF_VERIFICATION_SCHEMA_VERSION = "intentrax.sdk.local_proof_verification_report/1.0";
16
+ const LOCAL_PROOF_VERIFIER_VERSION = "intentrax-typescript-cli-local-proof-verifier/1.0";
17
+ const LOCAL_PDF_RECEIPT_VERIFICATION_SCHEMA_VERSION = "intentrax.sdk.local_pdf_receipt_verification_report/1.0";
18
+ const LOCAL_PDF_RECEIPT_VERIFIER_VERSION = "intentrax-typescript-cli-local-pdf-receipt-verifier/1.0";
19
+ const ENDPOINT = "/v1/agent/admissions";
20
+ const DOMAIN = "INTENTRAX_AGENT_ADAPTER_INIT_V1";
21
+ const ACTION_RECEIPT_DOMAIN = "INTENTRAX_AGENT_ADAPTER_ACTION_RECEIPT_V1";
22
+ const HOST_WIRING_GUIDE_DOMAIN = "INTENTRAX_AGENT_ADAPTER_HOST_WIRING_GUIDE_V1";
23
+ const LOCAL_INIT_CHECK_DOMAIN = "INTENTRAX_AGENT_ADAPTER_INIT_OFFLINE_CHECK_V1";
24
+ const LOCAL_PROOF_VERIFY_DOMAIN = "INTENTRAX_LOCAL_PROOF_VERIFY_V1";
25
+ const LOCAL_PDF_RECEIPT_VERIFY_DOMAIN = "INTENTRAX_LOCAL_PDF_RECEIPT_VERIFY_V1";
26
+ const TENANT_HEADER = "X-Intentrax-Tenant-ID";
27
+ const API_KEY_HEADER = "X-Intentrax-Api-Key";
28
+ const IDEMPOTENCY_HEADER = "X-Intentrax-Idempotency-Key";
29
+ const MVP_ADAPTERS = Object.freeze(["claude-code", "cursor", "mcp", "langchain", "langgraph", "vercel-ai-sdk"]);
30
+ const ADAPTER_ALIASES = Object.freeze({ "generic-mcp": "mcp" });
31
+ const OAP_COMPATIBILITY_BOUNDARY = "EXCLUDED_FROM_MVP";
32
+ const OAP_EXCLUSION_MARKERS = Object.freeze(["OAP", "Open Agent Passport", "Open Agent Protocol"]);
33
+ const OAP_EXCLUSION_PATTERN = /\bOAP\b|Open Agent Passport|Open Agent Protocol/i;
34
+ const INIT_CHECK_REQUIRED_FILES = Object.freeze([
35
+ ".intentrax/agent-adapter.json",
36
+ ".intentrax/sample-admission-request.json",
37
+ ".intentrax/action-receipt.json",
38
+ ".intentrax/submit_sample.curl",
39
+ ]);
40
+ const SECRET_FIXTURE_MARKERS = Object.freeze([
41
+ "intentrax-check-init-secret-token",
42
+ "intentrax-check-init-secret-api-key",
43
+ "intentrax-check-init-secret-password",
44
+ "intentrax-check-init-secret-private-key",
45
+ "intentrax-check-init-secret-cookie",
46
+ ]);
47
+ const REQUIRED_GATEWAY_REFS = [
48
+ "sha256:46f136e995bf1921533652a0721e8ea47816d250aee0da951258bec5645754af",
49
+ "sha256:4c6a9a6ce776170fa968682c51efafdd39301390f94176b2029e22594917ee1f",
50
+ "sha256:8a6d71f9e60ab0ef32de1eb63d049adb3820104c30489a5c42e7acaeeb222ce1",
51
+ "sha256:8c63d17014da7fd015b77c10fb702bcf005f0ed1dee1516991747e230c3dbfc0",
52
+ "sha256:b4c6a6ab375273436e38f7b5fb58b1c270a453297a184c019c4cabab3007e698",
53
+ "sha256:b9d82729f18f8720ee4d8575192966b9aec2320b25a8e79c6e2862c005053787",
54
+ ];
55
+ const SAMPLE_ACTION_BY_SURFACE = {
56
+ A2A_DELEGATION: "HAND_OFF_PROOF",
57
+ DIRECT_TOOL_CALL: "GET_PROOF",
58
+ MCP_TOOL_CALL: "GET_PROOF",
59
+ SDK_AGENT_CALL: "SUBMIT_INTENT",
60
+ };
61
+
62
+ const ADAPTERS = {
63
+ "claude-code": {
64
+ display_name: "Claude Code Agent",
65
+ matrix_adapter_id: "CLAUDE_CODE_AGENT",
66
+ normalized_surface_id: "MCP_TOOL_CALL",
67
+ normalized_adapter_id: "GENERIC_MCP_PROOF_ADAPTER",
68
+ hook_surface: "pre_tool_use",
69
+ hook_file_name: "claude-code-pre-tool-use.mjs",
70
+ hook_entrypoint: "beforeClaudeCodeToolUse",
71
+ hook_label: "Claude Code pre-tool-use hook",
72
+ native_template_id: "claude_code_pre_tool_use_v1",
73
+ native_event_kind: "CLAUDE_CODE_PRE_TOOL_USE",
74
+ native_normalizer: "normalizeClaudeCodePreToolUse",
75
+ quickstart_ref: "examples/adapters/claude-code.md",
76
+ },
77
+ cursor: {
78
+ display_name: "Cursor Agent",
79
+ matrix_adapter_id: "CURSOR_AGENT",
80
+ normalized_surface_id: "MCP_TOOL_CALL",
81
+ normalized_adapter_id: "GENERIC_MCP_PROOF_ADAPTER",
82
+ hook_surface: "before_shell_execution",
83
+ hook_file_name: "cursor-before-shell-execution.mjs",
84
+ hook_entrypoint: "beforeCursorShellExecution",
85
+ hook_label: "Cursor before-shell-execution hook",
86
+ native_template_id: "cursor_before_shell_execution_v1",
87
+ native_event_kind: "CURSOR_BEFORE_SHELL_EXECUTION",
88
+ native_normalizer: "normalizeCursorShellExecution",
89
+ quickstart_ref: "examples/adapters/cursor.md",
90
+ },
91
+ mcp: {
92
+ display_name: "Generic MCP",
93
+ matrix_adapter_id: "GENERIC_MCP",
94
+ normalized_surface_id: "MCP_TOOL_CALL",
95
+ normalized_adapter_id: "GENERIC_MCP_PROOF_ADAPTER",
96
+ hook_surface: "mcp_tool_call",
97
+ hook_file_name: "mcp-tool-call-admission.mjs",
98
+ hook_entrypoint: "beforeMCPToolCall",
99
+ hook_label: "generic MCP tool-call hook",
100
+ native_template_id: "mcp_tool_call_v1",
101
+ native_event_kind: "MCP_TOOL_CALL",
102
+ native_normalizer: "normalizeMCPToolCall",
103
+ quickstart_ref: "examples/adapters/mcp.md",
104
+ },
105
+ langchain: {
106
+ display_name: "LangChain Agent",
107
+ matrix_adapter_id: "LANGCHAIN_AGENT",
108
+ normalized_surface_id: "SDK_AGENT_CALL",
109
+ normalized_adapter_id: "SDK_AGENT_PROOF_ADAPTER",
110
+ hook_surface: "callback_or_tool_wrapper",
111
+ hook_file_name: "langchain-callback-wrapper.mjs",
112
+ hook_entrypoint: "withIntentraxLangChainCallback",
113
+ hook_label: "LangChain callback or tool wrapper",
114
+ native_template_id: "langchain_callback_wrapper_v1",
115
+ native_event_kind: "LANGCHAIN_CALLBACK_OR_TOOL",
116
+ native_normalizer: "normalizeLangChainCallback",
117
+ quickstart_ref: "examples/adapters/langchain.md",
118
+ },
119
+ langgraph: {
120
+ display_name: "LangGraph Agent",
121
+ matrix_adapter_id: "LANGGRAPH_AGENT",
122
+ normalized_surface_id: "SDK_AGENT_CALL",
123
+ normalized_adapter_id: "SDK_AGENT_PROOF_ADAPTER",
124
+ hook_surface: "graph_node_middleware",
125
+ hook_file_name: "langgraph-node-middleware.mjs",
126
+ hook_entrypoint: "withIntentraxLangGraphNode",
127
+ hook_label: "LangGraph node middleware",
128
+ native_template_id: "langgraph_node_middleware_v1",
129
+ native_event_kind: "LANGGRAPH_NODE_MIDDLEWARE",
130
+ native_normalizer: "normalizeLangGraphNode",
131
+ quickstart_ref: "examples/adapters/langgraph.md",
132
+ },
133
+ "vercel-ai-sdk": {
134
+ display_name: "Vercel AI SDK Agent",
135
+ matrix_adapter_id: "VERCEL_AI_SDK_AGENT",
136
+ normalized_surface_id: "SDK_AGENT_CALL",
137
+ normalized_adapter_id: "SDK_AGENT_PROOF_ADAPTER",
138
+ hook_surface: "typescript_route_wrapper",
139
+ hook_file_name: "vercel-ai-sdk-route-wrapper.mjs",
140
+ hook_entrypoint: "withIntentraxVercelAIRoute",
141
+ hook_label: "Vercel AI SDK route wrapper",
142
+ native_template_id: "vercel_ai_sdk_route_wrapper_v1",
143
+ native_event_kind: "VERCEL_AI_SDK_ROUTE_WRAPPER",
144
+ native_normalizer: "normalizeVercelAIRoute",
145
+ quickstart_ref: "examples/adapters/vercel-ai-sdk.md",
146
+ },
147
+ "custom-agent": {
148
+ display_name: "Custom Agent",
149
+ matrix_adapter_id: "CUSTOM_AGENT",
150
+ normalized_surface_id: "DIRECT_TOOL_CALL",
151
+ normalized_adapter_id: "DIRECT_TOOL_PROOF_ADAPTER",
152
+ hook_surface: "direct_http_or_sdk",
153
+ hook_file_name: "custom-agent-admission-hook.mjs",
154
+ hook_entrypoint: "withIntentraxCustomAgentAdmission",
155
+ hook_label: "custom agent admission hook",
156
+ quickstart_ref: "integrations/agent-adapters/custom-agent.md",
157
+ },
158
+ crewai: {
159
+ display_name: "CrewAI Agent",
160
+ matrix_adapter_id: "CREWAI_AGENT",
161
+ normalized_surface_id: "SDK_AGENT_CALL",
162
+ normalized_adapter_id: "SDK_AGENT_PROOF_ADAPTER",
163
+ hook_surface: "crew_step_wrapper",
164
+ hook_file_name: "crewai-step-wrapper.mjs",
165
+ hook_entrypoint: "withIntentraxCrewAIStep",
166
+ hook_label: "CrewAI step wrapper",
167
+ quickstart_ref: "integrations/agent-adapters/crewai-agent.md",
168
+ },
169
+ autogen: {
170
+ display_name: "AutoGen Agent",
171
+ matrix_adapter_id: "AUTOGEN_AGENT",
172
+ normalized_surface_id: "A2A_DELEGATION",
173
+ normalized_adapter_id: "GENERIC_A2A_PROOF_ADAPTER",
174
+ hook_surface: "multi_agent_a2a_wrapper",
175
+ hook_file_name: "autogen-a2a-wrapper.mjs",
176
+ hook_entrypoint: "withIntentraxAutoGenA2AWrapper",
177
+ hook_label: "AutoGen A2A wrapper",
178
+ quickstart_ref: "integrations/agent-adapters/autogen-agent.md",
179
+ },
180
+ openclaw: {
181
+ display_name: "OpenClaw Agent",
182
+ matrix_adapter_id: "OPENCLAW_AGENT",
183
+ normalized_surface_id: "SDK_AGENT_CALL",
184
+ normalized_adapter_id: "SDK_AGENT_PROOF_ADAPTER",
185
+ hook_surface: "generic_agent_wrapper",
186
+ hook_file_name: "openclaw-agent-wrapper.mjs",
187
+ hook_entrypoint: "withIntentraxOpenClawAgent",
188
+ hook_label: "OpenClaw agent wrapper",
189
+ quickstart_ref: "integrations/agent-adapters/openclaw-agent.md",
190
+ },
191
+ n8n: {
192
+ display_name: "n8n",
193
+ matrix_adapter_id: "N8N",
194
+ normalized_surface_id: "DIRECT_TOOL_CALL",
195
+ normalized_adapter_id: "DIRECT_TOOL_PROOF_ADAPTER",
196
+ hook_surface: "http_request_node",
197
+ hook_file_name: "n8n-http-request-node.mjs",
198
+ hook_entrypoint: "withIntentraxN8NRequestNode",
199
+ hook_label: "n8n HTTP request node wrapper",
200
+ quickstart_ref: "integrations/agent-adapters/n8n.md",
201
+ },
202
+ deepflow: {
203
+ display_name: "DeepFlow Agent",
204
+ matrix_adapter_id: "DEEPFLOW_AGENT",
205
+ normalized_surface_id: "SDK_AGENT_CALL",
206
+ normalized_adapter_id: "SDK_AGENT_PROOF_ADAPTER",
207
+ hook_surface: "workflow_step_wrapper",
208
+ hook_file_name: "deepflow-step-wrapper.mjs",
209
+ hook_entrypoint: "withIntentraxDeepFlowStep",
210
+ hook_label: "DeepFlow workflow step wrapper",
211
+ quickstart_ref: "integrations/agent-adapters/deepflow-agent.md",
212
+ },
213
+ };
214
+
215
+ async function main(argv) {
216
+ const [command, subject, ...rest] = argv;
217
+ if (!command || command === "--help" || command === "-h") {
218
+ printHelp();
219
+ return 0;
220
+ }
221
+ if (command === "--version" || command === "-v") {
222
+ console.log(VERSION);
223
+ return 0;
224
+ }
225
+ if (command === "check-init") {
226
+ const options = parseCheckInitOptions([subject, ...rest].filter((value) => value !== undefined));
227
+ const output = await checkInitCommand(options);
228
+ if (options.json) {
229
+ console.log(JSON.stringify(output, null, 2));
230
+ } else if (output.status === "PASS") {
231
+ console.log(`Intentrax init verification PASS: adapter=${output.adapter_name} hook=${output.hook_starter.file_path} offline=true`);
232
+ } else {
233
+ console.error(`Intentrax init verification FAIL: ${output.errors.map((error) => error.field).join(", ")}`);
234
+ }
235
+ return output.status === "PASS" ? 0 : 2;
236
+ }
237
+ if (command === "verify-proof") {
238
+ const options = parseVerifyProofOptions(rest);
239
+ const output = verifyProofExportCommand(subject, options);
240
+ if (options.json) {
241
+ console.log(JSON.stringify(output, null, 2));
242
+ return 0;
243
+ }
244
+ console.log(`Intentrax proof export verification PASS: proof=${output.registry_entry_id} report=${output.report_path} hash=${output.report_hash}`);
245
+ return 0;
246
+ }
247
+ if (command === "verify-pdf-receipt") {
248
+ const options = parseVerifyPDFReceiptOptions(rest);
249
+ const output = verifyPDFReceiptCommand(subject, options);
250
+ if (options.json) {
251
+ console.log(JSON.stringify(output, null, 2));
252
+ return 0;
253
+ }
254
+ console.log(`Intentrax PDF receipt verification PASS: pdf=${output.pdf_path} report=${output.report_path} hash=${output.pdf_hash}`);
255
+ return 0;
256
+ }
257
+ if (command !== "init") {
258
+ fail(`unknown command: ${command}`);
259
+ }
260
+ const adapterName = resolveAdapterName(subject || "");
261
+ const adapter = ADAPTERS[adapterName];
262
+ if (!adapter) {
263
+ fail(`unknown adapter: ${subject || "<missing>"}`);
264
+ }
265
+ const options = parseOptions(rest);
266
+ const output = buildInitOutput(adapterName, adapter, options);
267
+ if (options.dryRun || options.json) {
268
+ console.log(JSON.stringify(output, null, 2));
269
+ return 0;
270
+ }
271
+ const targetDir = resolve(options.outputDir || process.cwd(), ".intentrax");
272
+ const writePlan = buildInitWritePlan(output, options);
273
+ assertNoUnsafeInitOverwrite(writePlan, options);
274
+ mkdirSync(targetDir, { recursive: true });
275
+ mkdirSync(join(targetDir, "hooks"), { recursive: true });
276
+ mkdirSync(join(targetDir, "wiring"), { recursive: true });
277
+ for (const file of writePlan) {
278
+ writeFileSync(file.path, file.content, { mode: 0o600 });
279
+ }
280
+ console.log(`Intentrax adapter initialized: ${adapterName}`);
281
+ console.log(`Config: ${join(targetDir, "agent-adapter.json")}`);
282
+ console.log(`Sample admission: ${join(targetDir, "sample-admission-request.json")}`);
283
+ console.log(`Action receipt: ${join(targetDir, "action-receipt.json")}`);
284
+ console.log(`Submit sample: ${join(resolve(options.outputDir || process.cwd()), output.submit_sample.file_path)}`);
285
+ console.log(`Hook starter: ${join(resolve(options.outputDir || process.cwd()), output.hook_starter.file_path)}`);
286
+ console.log(`Host wiring guide: ${join(resolve(options.outputDir || process.cwd()), output.host_wiring_guide.file_path)}`);
287
+ console.log(`Endpoint: ${output.normalized_contract.endpoint}`);
288
+ console.log(`Next: set INTENTRAX_API_KEY, then run from ${output.submit_sample.working_directory}:`);
289
+ console.log(output.submit_sample.curl);
290
+ return 0;
291
+ }
292
+
293
+ function parseOptions(args) {
294
+ const options = {
295
+ dryRun: false,
296
+ force: false,
297
+ json: false,
298
+ outputDir: "",
299
+ baseUrl: "http://127.0.0.1:8080",
300
+ tenantId: "tenant-local-dev",
301
+ };
302
+ for (let index = 0; index < args.length; index += 1) {
303
+ const arg = args[index];
304
+ if (arg === "--dry-run") {
305
+ options.dryRun = true;
306
+ } else if (arg === "--force") {
307
+ options.force = true;
308
+ } else if (arg === "--json") {
309
+ options.json = true;
310
+ } else if (arg === "--output-dir") {
311
+ options.outputDir = requireValue(args, ++index, arg);
312
+ } else if (arg === "--base-url") {
313
+ options.baseUrl = requireValue(args, ++index, arg);
314
+ } else if (arg === "--tenant-id") {
315
+ options.tenantId = requireValue(args, ++index, arg);
316
+ } else {
317
+ fail(`unknown option: ${arg}`);
318
+ }
319
+ }
320
+ return options;
321
+ }
322
+
323
+ function resolveAdapterName(adapterName) {
324
+ return ADAPTER_ALIASES[adapterName] || adapterName;
325
+ }
326
+
327
+ function buildInitWritePlan(output, options) {
328
+ const root = resolve(options.outputDir || process.cwd());
329
+ return Object.freeze([
330
+ initFile(root, ".intentrax/agent-adapter.json", JSON.stringify(output.config, null, 2) + "\n"),
331
+ initFile(root, ".intentrax/sample-admission-request.json", JSON.stringify(output.sample_admission_request, null, 2) + "\n"),
332
+ initFile(root, ".intentrax/action-receipt.json", JSON.stringify(output.action_receipt, null, 2) + "\n"),
333
+ initFile(root, output.submit_sample.file_path, output.submit_sample.curl + "\n"),
334
+ initFile(root, output.hook_starter.file_path, output.hook_starter.source + "\n"),
335
+ initFile(root, output.host_wiring_guide.file_path, output.host_wiring_guide.source + "\n"),
336
+ ]);
337
+ }
338
+
339
+ function initFile(root, filePath, content) {
340
+ return Object.freeze({
341
+ file_path: filePath,
342
+ path: join(root, filePath),
343
+ content,
344
+ });
345
+ }
346
+
347
+ function assertNoUnsafeInitOverwrite(writePlan, options) {
348
+ if (options.force) return;
349
+ const conflicts = [];
350
+ for (const file of writePlan) {
351
+ if (!existsSync(file.path)) continue;
352
+ const existing = readFileSync(file.path, "utf8");
353
+ if (existing !== file.content) {
354
+ conflicts.push(file.file_path);
355
+ }
356
+ }
357
+ if (conflicts.length > 0) {
358
+ fail(`refusing to overwrite existing Intentrax init file(s): ${conflicts.join(", ")}. Re-run with --force after reviewing local changes.`);
359
+ }
360
+ }
361
+
362
+ function parseCheckInitOptions(args) {
363
+ const options = {
364
+ json: false,
365
+ outputDir: "",
366
+ };
367
+ for (let index = 0; index < args.length; index += 1) {
368
+ const arg = args[index];
369
+ if (arg === "--json") {
370
+ options.json = true;
371
+ } else if (arg === "--output-dir") {
372
+ options.outputDir = requireValue(args, ++index, arg);
373
+ } else {
374
+ fail(`unknown option: ${arg}`);
375
+ }
376
+ }
377
+ if (!options.outputDir) {
378
+ fail("check-init requires --output-dir");
379
+ }
380
+ return options;
381
+ }
382
+
383
+ async function checkInitCommand(options) {
384
+ const root = resolve(options.outputDir);
385
+ const errors = [];
386
+ const files = {};
387
+ const fileSources = {};
388
+
389
+ for (const filePath of INIT_CHECK_REQUIRED_FILES) {
390
+ fileSources[filePath] = readInitCheckFile(root, filePath, files, errors);
391
+ }
392
+
393
+ const config = parseInitCheckJSON(fileSources[".intentrax/agent-adapter.json"], ".intentrax/agent-adapter.json", errors);
394
+ const sampleAdmission = parseInitCheckJSON(fileSources[".intentrax/sample-admission-request.json"], ".intentrax/sample-admission-request.json", errors);
395
+ const actionReceipt = parseInitCheckJSON(fileSources[".intentrax/action-receipt.json"], ".intentrax/action-receipt.json", errors);
396
+ const submitSampleSource = fileSources[".intentrax/submit_sample.curl"] ?? "";
397
+
398
+ validateInitCheckConfig(config, errors);
399
+ validateInitCheckActionReceipt(actionReceipt, config, errors);
400
+ validateInitCheckAdmission(sampleAdmission, config, actionReceipt, errors);
401
+ validateInitCheckSubmitSample(submitSampleSource, config, actionReceipt, sampleAdmission, errors);
402
+ validateInitCheckOAPBoundary(fileSources, errors);
403
+
404
+ const hookBinding = findHookBinding(config, actionReceipt, errors);
405
+ let hookSource = "";
406
+ let hostWiringGuideSourceText = "";
407
+ let hookInvocation = {
408
+ invoked: false,
409
+ entrypoint_found: false,
410
+ submitted: false,
411
+ network_attempted: false,
412
+ secret_leakage_detected: false,
413
+ result_payload_hash: "",
414
+ };
415
+ if (hookBinding.file_path) {
416
+ hookSource = readInitCheckFile(root, hookBinding.file_path, files, errors);
417
+ const hookErrorsBeforeSourceValidation = errors.length;
418
+ validateInitCheckHookSource(hookSource, hookBinding, errors);
419
+ const hookSourceValidationFailed = errors.length > hookErrorsBeforeSourceValidation;
420
+ if (!hookSourceValidationFailed) {
421
+ hookInvocation = await invokeInitCheckHook(root, hookBinding, errors);
422
+ }
423
+ }
424
+ const hostWiringBinding = findHostWiringBinding(config, actionReceipt, hookBinding, errors);
425
+ if (hostWiringBinding.file_path) {
426
+ hostWiringGuideSourceText = readInitCheckFile(root, hostWiringBinding.file_path, files, errors);
427
+ validateInitCheckHostWiringGuideSource(hostWiringGuideSourceText, hostWiringBinding, hookBinding, errors);
428
+ }
429
+
430
+ const adapterName = readString(actionReceipt, ["adapter_profile", "adapter_name"]) ||
431
+ readString(config, ["adapter_profile", "adapter_name"]);
432
+ const admissionEnvelope = isRecord(sampleAdmission) ? buildAgentGatewayAdmissionEnvelope(sampleAdmission) : { status: "FAIL" };
433
+ const status = errors.length === 0 ? "PASS" : "FAIL";
434
+ const sortedErrors = errors.map((error) => Object.freeze(error)).sort((a, b) => canonicalJson(a).localeCompare(canonicalJson(b)));
435
+ const boundaries = {
436
+ offline_verifier_used: true,
437
+ runtime_server_not_required: true,
438
+ network_not_required: true,
439
+ intentrax_api_key_not_required: true,
440
+ generated_hook_invoked_no_submit: hookInvocation.invoked && hookInvocation.submitted === false,
441
+ generated_hook_network_not_attempted: hookInvocation.network_attempted === false,
442
+ secret_bearing_fixture_redacted: hookInvocation.secret_leakage_detected === false,
443
+ no_secret_material_written: readBoolean(config, ["boundary_assertions", "no_secret_material_written"]) === true &&
444
+ readBoolean(actionReceipt, ["boundary_assertions", "no_secret_material_written"]) === true,
445
+ aevn_aep_remains_authoritative: readBoolean(config, ["boundary_assertions", "aevn_aep_remains_authoritative"]) === true &&
446
+ readBoolean(actionReceipt, ["boundary_assertions", "canonical_aep_remains_authoritative"]) === true,
447
+ action_receipt_non_authoritative: readBoolean(actionReceipt, ["authoritative"]) === false,
448
+ production_authorization_unchanged: readBoolean(actionReceipt, ["production_authorization_unchanged"]) === true,
449
+ oap_compatibility: OAP_COMPATIBILITY_BOUNDARY,
450
+ };
451
+ const withoutHash = {
452
+ schema_version: LOCAL_INIT_CHECK_SCHEMA_VERSION,
453
+ verifier_version: LOCAL_INIT_CHECK_VERIFIER_VERSION,
454
+ status,
455
+ offline: true,
456
+ output_dir: root,
457
+ adapter_name: adapterName,
458
+ mvp_adapter: MVP_ADAPTERS.includes(adapterName),
459
+ normalized_contract: {
460
+ endpoint: ENDPOINT,
461
+ method: "POST",
462
+ tenant_header: TENANT_HEADER,
463
+ api_key_header: API_KEY_HEADER,
464
+ idempotency_header: IDEMPOTENCY_HEADER,
465
+ },
466
+ files,
467
+ admission_fixture: {
468
+ file_path: ".intentrax/sample-admission-request.json",
469
+ status: admissionEnvelope.status,
470
+ request_hash: admissionEnvelope.output?.request_hash ?? "",
471
+ idempotency_key_hash: isRecord(sampleAdmission) ? sampleAdmission.idempotency_key_hash ?? "" : "",
472
+ request_payload_hash: isRecord(sampleAdmission) ? sampleAdmission.request_payload_hash ?? "" : "",
473
+ },
474
+ action_receipt: {
475
+ file_path: ".intentrax/action-receipt.json",
476
+ receipt_hash: isRecord(actionReceipt) ? actionReceipt.receipt_hash ?? "" : "",
477
+ authoritative: isRecord(actionReceipt) ? actionReceipt.authoritative === true : false,
478
+ },
479
+ hook_starter: {
480
+ file_path: hookBinding.file_path,
481
+ entrypoint: hookBinding.entrypoint,
482
+ source_hash: hookSource ? hashGeneratedHookSource(hookSource) : "",
483
+ expected_source_hash: hookBinding.source_hash,
484
+ invoked: hookInvocation.invoked,
485
+ entrypoint_found: hookInvocation.entrypoint_found,
486
+ submitted: hookInvocation.submitted,
487
+ network_attempted: hookInvocation.network_attempted,
488
+ secret_leakage_detected: hookInvocation.secret_leakage_detected,
489
+ result_payload_hash: hookInvocation.result_payload_hash,
490
+ },
491
+ host_wiring_guide: {
492
+ file_path: hostWiringBinding.file_path,
493
+ host_runtime: hostWiringBinding.host_runtime,
494
+ hook_file_path: hostWiringBinding.hook_file_path,
495
+ hook_entrypoint: hostWiringBinding.hook_entrypoint,
496
+ guide_hash: hostWiringGuideSourceText ? hashGeneratedHostWiringSource(hostWiringGuideSourceText) : "",
497
+ expected_guide_hash: hostWiringBinding.guide_hash,
498
+ present: hostWiringBinding.file_path ? files[hostWiringBinding.file_path]?.present === true : false,
499
+ },
500
+ boundaries,
501
+ errors: sortedErrors,
502
+ report_hash: "",
503
+ };
504
+ return Object.freeze({
505
+ ...withoutHash,
506
+ report_hash: sha256Hex(LOCAL_INIT_CHECK_DOMAIN + canonicalJson(withoutHash)),
507
+ });
508
+ }
509
+
510
+ function readInitCheckFile(root, filePath, files, errors) {
511
+ const resolved = resolveInitCheckPath(root, filePath, errors);
512
+ files[filePath] = {
513
+ present: false,
514
+ sha256: "",
515
+ byte_length: 0,
516
+ };
517
+ if (!resolved) return "";
518
+ if (!existsSync(resolved)) {
519
+ pushCheckError(errors, "missing_file", filePath, "Expected init file is missing.");
520
+ return "";
521
+ }
522
+ const source = readFileSync(resolved, "utf8");
523
+ files[filePath] = {
524
+ present: true,
525
+ sha256: sha256Hex(source),
526
+ byte_length: Buffer.byteLength(source, "utf8"),
527
+ };
528
+ return source;
529
+ }
530
+
531
+ function resolveInitCheckPath(root, filePath, errors) {
532
+ if (!isSafeInitCheckRelativePath(filePath)) {
533
+ pushCheckError(errors, "unsafe_path", filePath, "Configured init file path escapes the output directory.");
534
+ return "";
535
+ }
536
+ const resolved = resolve(root, filePath);
537
+ const rel = relative(root, resolved);
538
+ if (rel.startsWith("..") || isAbsolute(rel)) {
539
+ pushCheckError(errors, "unsafe_path", filePath, "Configured init file path escapes the output directory.");
540
+ return "";
541
+ }
542
+ return resolved;
543
+ }
544
+
545
+ function isSafeInitCheckRelativePath(filePath) {
546
+ return typeof filePath === "string" &&
547
+ filePath.length > 0 &&
548
+ filePath.trim() === filePath &&
549
+ !isAbsolute(filePath) &&
550
+ !/^[A-Za-z]:[\\/]/.test(filePath) &&
551
+ !filePath.includes("\u0000") &&
552
+ !filePath.split(/[\\/]+/).includes("..") &&
553
+ filePath.startsWith(".intentrax/");
554
+ }
555
+
556
+ function parseInitCheckJSON(source, filePath, errors) {
557
+ if (!source) return null;
558
+ try {
559
+ return JSON.parse(source);
560
+ } catch (error) {
561
+ pushCheckError(errors, "invalid_json", filePath, `Invalid JSON: ${stableErrorMessage(error)}`);
562
+ return null;
563
+ }
564
+ }
565
+
566
+ function validateInitCheckConfig(config, errors) {
567
+ if (!isRecord(config)) {
568
+ pushCheckError(errors, "invalid_json_shape", ".intentrax/agent-adapter.json", "Agent adapter config must be a JSON object.");
569
+ return;
570
+ }
571
+ if (config.schema_version !== INIT_SCHEMA_VERSION) {
572
+ pushCheckError(errors, "schema_version", "config.schema_version", "Unexpected agent adapter config schema version.");
573
+ }
574
+ const adapterName = readString(config, ["adapter_profile", "adapter_name"]);
575
+ const adapter = ADAPTERS[adapterName];
576
+ if (!adapter) {
577
+ pushCheckError(errors, "adapter_profile", "config.adapter_profile.adapter_name", "Unknown Intentrax adapter profile.");
578
+ } else {
579
+ assertCheckEqual(errors, config.adapter_profile.display_name, adapter.display_name, "config.adapter_profile.display_name");
580
+ assertCheckEqual(errors, config.adapter_profile.matrix_adapter_id, adapter.matrix_adapter_id, "config.adapter_profile.matrix_adapter_id");
581
+ assertCheckEqual(errors, config.adapter_profile.hook_surface, adapter.hook_surface, "config.adapter_profile.hook_surface");
582
+ assertCheckEqual(errors, config.adapter_profile.native_hook_starter?.file_path, `.intentrax/hooks/${adapter.hook_file_name}`, "config.adapter_profile.native_hook_starter.file_path");
583
+ assertCheckEqual(errors, config.adapter_profile.native_hook_starter?.entrypoint, adapter.hook_entrypoint, "config.adapter_profile.native_hook_starter.entrypoint");
584
+ assertCheckEqual(errors, config.adapter_profile.native_hook_starter?.native_template_id, adapter.native_template_id ?? "generic_admission_hook_v1", "config.adapter_profile.native_hook_starter.native_template_id");
585
+ assertCheckEqual(errors, config.adapter_profile.native_hook_starter?.native_event_kind, adapter.native_event_kind ?? "GENERIC_AGENT_EVENT", "config.adapter_profile.native_hook_starter.native_event_kind");
586
+ assertCheckEqual(errors, config.adapter_profile.host_wiring_guide?.file_path, `.intentrax/wiring/${adapterName}-host-wiring.md`, "config.adapter_profile.host_wiring_guide.file_path");
587
+ assertCheckEqual(errors, config.adapter_profile.host_wiring_guide?.host_runtime, adapter.display_name, "config.adapter_profile.host_wiring_guide.host_runtime");
588
+ assertCheckEqual(errors, config.adapter_profile.host_wiring_guide?.hook_file_path, `.intentrax/hooks/${adapter.hook_file_name}`, "config.adapter_profile.host_wiring_guide.hook_file_path");
589
+ assertCheckEqual(errors, config.adapter_profile.host_wiring_guide?.hook_entrypoint, adapter.hook_entrypoint, "config.adapter_profile.host_wiring_guide.hook_entrypoint");
590
+ assertCheckEqual(errors, config.adapter_profile.host_wiring_guide?.setup_level, "HOST_BINDING_GUIDE", "config.adapter_profile.host_wiring_guide.setup_level");
591
+ assertCheckEqual(errors, config.adapter_profile.host_wiring_guide?.authoritative, false, "config.adapter_profile.host_wiring_guide.authoritative");
592
+ assertCheckEqual(errors, config.adapter_profile.host_wiring_guide?.secret_material_written, false, "config.adapter_profile.host_wiring_guide.secret_material_written");
593
+ }
594
+ assertCheckEqual(errors, config.normalized_contract?.endpoint, ENDPOINT, "config.normalized_contract.endpoint");
595
+ assertCheckEqual(errors, config.normalized_contract?.method, "POST", "config.normalized_contract.method");
596
+ assertCheckEqual(errors, config.normalized_contract?.tenant_header, TENANT_HEADER, "config.normalized_contract.tenant_header");
597
+ assertCheckEqual(errors, config.normalized_contract?.api_key_header, API_KEY_HEADER, "config.normalized_contract.api_key_header");
598
+ assertCheckEqual(errors, config.normalized_contract?.idempotency_header, IDEMPOTENCY_HEADER, "config.normalized_contract.idempotency_header");
599
+ assertCheckEqual(errors, config.boundary_assertions?.no_secret_material_written, true, "config.boundary_assertions.no_secret_material_written");
600
+ assertCheckEqual(errors, config.boundary_assertions?.no_tool_execution_inside_admission, true, "config.boundary_assertions.no_tool_execution_inside_admission");
601
+ assertCheckEqual(errors, config.boundary_assertions?.aevn_aep_remains_authoritative, true, "config.boundary_assertions.aevn_aep_remains_authoritative");
602
+ assertCheckEqual(errors, config.boundary_assertions?.oap_compatibility, OAP_COMPATIBILITY_BOUNDARY, "config.boundary_assertions.oap_compatibility");
603
+ assertCheckEqual(errors, config.sample_submission?.api_key_env, "INTENTRAX_API_KEY", "config.sample_submission.api_key_env");
604
+ }
605
+
606
+ function validateInitCheckActionReceipt(actionReceipt, config, errors) {
607
+ if (!isRecord(actionReceipt)) {
608
+ pushCheckError(errors, "invalid_json_shape", ".intentrax/action-receipt.json", "Action receipt must be a JSON object.");
609
+ return;
610
+ }
611
+ if (actionReceipt.schema_version !== ACTION_RECEIPT_SCHEMA_VERSION) {
612
+ pushCheckError(errors, "schema_version", "action_receipt.schema_version", "Unexpected action receipt schema version.");
613
+ }
614
+ assertCheckEqual(errors, actionReceipt.receipt_type, "AGENT_ADAPTER_INIT_SAMPLE_ACTION_RECEIPT", "action_receipt.receipt_type");
615
+ assertCheckEqual(errors, actionReceipt.file_path, ".intentrax/action-receipt.json", "action_receipt.file_path");
616
+ assertCheckEqual(errors, actionReceipt.authoritative, false, "action_receipt.authoritative");
617
+ assertCheckEqual(errors, actionReceipt.canonical_aep_authoritative, true, "action_receipt.canonical_aep_authoritative");
618
+ assertCheckEqual(errors, actionReceipt.production_authorization_unchanged, true, "action_receipt.production_authorization_unchanged");
619
+ assertCheckEqual(errors, actionReceipt.boundary_assertions?.canonical_aep_remains_authoritative, true, "action_receipt.boundary_assertions.canonical_aep_remains_authoritative");
620
+ assertCheckEqual(errors, actionReceipt.boundary_assertions?.oap_compatibility, OAP_COMPATIBILITY_BOUNDARY, "action_receipt.boundary_assertions.oap_compatibility");
621
+ assertCheckEqual(errors, actionReceipt.boundary_assertions?.action_receipt_does_not_replace_aep, true, "action_receipt.boundary_assertions.action_receipt_does_not_replace_aep");
622
+ assertCheckEqual(errors, actionReceipt.boundary_assertions?.production_authorization_unchanged, true, "action_receipt.boundary_assertions.production_authorization_unchanged");
623
+ assertCheckEqual(errors, actionReceipt.evidence_links?.runtime_admission_endpoint, ENDPOINT, "action_receipt.evidence_links.runtime_admission_endpoint");
624
+ assertCheckEqual(errors, actionReceipt.evidence_links?.proof_verification_endpoint, "/v1/proofs/verify", "action_receipt.evidence_links.proof_verification_endpoint");
625
+ assertCheckEqual(errors, actionReceipt.evidence_links?.proof_export_endpoint_template, "/v1/proofs/{proof_id}/export?format=json|aep-json|pdf", "action_receipt.evidence_links.proof_export_endpoint_template");
626
+ assertCheckEqual(errors, actionReceipt.evidence_links?.verifier_handoff_endpoint_template, "/v1/evidence/dry-run/{receipt_id}/verifier-handoff", "action_receipt.evidence_links.verifier_handoff_endpoint_template");
627
+ assertCheckEqual(errors, actionReceipt.evidence_links?.aevn_authoritative, true, "action_receipt.evidence_links.aevn_authoritative");
628
+ assertCheckEqual(errors, actionReceipt.evidence_links?.aep_authoritative, true, "action_receipt.evidence_links.aep_authoritative");
629
+ if (isRecord(config)) {
630
+ assertCheckEqual(errors, actionReceipt.receipt_hash, config.action_receipt?.receipt_hash, "config.action_receipt.receipt_hash");
631
+ assertCheckEqual(errors, actionReceipt.adapter_profile?.adapter_name, config.adapter_profile?.adapter_name, "action_receipt.adapter_profile.adapter_name");
632
+ assertCheckEqual(errors, actionReceipt.hook_starter_binding?.file_path, config.adapter_profile?.native_hook_starter?.file_path, "action_receipt.hook_starter_binding.file_path");
633
+ assertCheckEqual(errors, actionReceipt.hook_starter_binding?.entrypoint, config.adapter_profile?.native_hook_starter?.entrypoint, "action_receipt.hook_starter_binding.entrypoint");
634
+ assertCheckEqual(errors, actionReceipt.host_wiring_guide_binding?.file_path, config.adapter_profile?.host_wiring_guide?.file_path, "action_receipt.host_wiring_guide_binding.file_path");
635
+ assertCheckEqual(errors, actionReceipt.host_wiring_guide_binding?.guide_hash, config.adapter_profile?.host_wiring_guide?.guide_hash, "action_receipt.host_wiring_guide_binding.guide_hash");
636
+ assertCheckEqual(errors, actionReceipt.host_wiring_guide_binding?.hook_file_path, config.adapter_profile?.native_hook_starter?.file_path, "action_receipt.host_wiring_guide_binding.hook_file_path");
637
+ assertCheckEqual(errors, actionReceipt.host_wiring_guide_binding?.hook_entrypoint, config.adapter_profile?.native_hook_starter?.entrypoint, "action_receipt.host_wiring_guide_binding.hook_entrypoint");
638
+ }
639
+ const receiptHash = actionReceipt.receipt_hash;
640
+ if (!isSHA256(receiptHash)) {
641
+ pushCheckError(errors, "receipt_hash", "action_receipt.receipt_hash", "Action receipt hash must be a SHA-256 hex string.");
642
+ } else {
643
+ const { receipt_hash: _receiptHash, ...withoutHash } = actionReceipt;
644
+ const expectedReceiptHash = sha256Hex(ACTION_RECEIPT_DOMAIN + canonicalJson(withoutHash));
645
+ if (receiptHash !== expectedReceiptHash) {
646
+ pushCheckError(errors, "receipt_hash_mismatch", "action_receipt.receipt_hash", "Action receipt hash does not match the on-disk receipt body.");
647
+ }
648
+ }
649
+ }
650
+
651
+ function validateInitCheckAdmission(sampleAdmission, config, actionReceipt, errors) {
652
+ if (!isRecord(sampleAdmission)) {
653
+ pushCheckError(errors, "invalid_json_shape", ".intentrax/sample-admission-request.json", "Sample admission request must be a JSON object.");
654
+ return;
655
+ }
656
+ const envelope = buildAgentGatewayAdmissionEnvelope(sampleAdmission);
657
+ if (envelope.status !== "PASS") {
658
+ pushCheckError(errors, "agent_gateway_admission_shape", ".intentrax/sample-admission-request.json", `Malformed Agent Gateway admission fixture: ${envelope.error.invalid_fields.join(",")}.`);
659
+ }
660
+ const adapterName = readString(actionReceipt, ["adapter_profile", "adapter_name"]) ||
661
+ readString(config, ["adapter_profile", "adapter_name"]);
662
+ const adapter = ADAPTERS[adapterName];
663
+ if (!adapter) return;
664
+ const expectedAction = SAMPLE_ACTION_BY_SURFACE[adapter.normalized_surface_id];
665
+ assertCheckEqual(errors, sampleAdmission.surface_id, adapter.normalized_surface_id, "sample_admission_request.surface_id");
666
+ assertCheckEqual(errors, sampleAdmission.adapter_id, adapter.normalized_adapter_id, "sample_admission_request.adapter_id");
667
+ assertCheckEqual(errors, sampleAdmission.action, expectedAction, "sample_admission_request.action");
668
+ if (!sameJSON(sampleAdmission.evidence_refs, REQUIRED_GATEWAY_REFS)) {
669
+ pushCheckError(errors, "gateway_refs", "sample_admission_request.evidence_refs", "Sample evidence refs differ from the locked private-alpha Agent Gateway refs.");
670
+ }
671
+ if (!sameJSON(sampleAdmission.proof_refs, REQUIRED_GATEWAY_REFS)) {
672
+ pushCheckError(errors, "gateway_refs", "sample_admission_request.proof_refs", "Sample proof refs differ from the locked private-alpha Agent Gateway refs.");
673
+ }
674
+ const expectedPayload = {
675
+ adapter: adapterName,
676
+ action: expectedAction,
677
+ hook_surface: adapter.hook_surface,
678
+ tenant_id: sampleAdmission.tenant_id,
679
+ };
680
+ const expectedPayloadHash = sha256Hex(canonicalJson(expectedPayload));
681
+ assertCheckEqual(errors, sampleAdmission.request_payload_hash, expectedPayloadHash, "sample_admission_request.request_payload_hash");
682
+ assertCheckEqual(errors, sampleAdmission.protocol_payload_ref, `sha256:${expectedPayloadHash}`, "sample_admission_request.protocol_payload_ref");
683
+ assertCheckEqual(errors, sampleAdmission.idempotency_key_hash, sha256Hex("INTENTRAX_AGENT_INIT_IDEMPOTENCY_V1" + expectedPayloadHash), "sample_admission_request.idempotency_key_hash");
684
+ if (isRecord(actionReceipt)) {
685
+ assertCheckEqual(errors, sampleAdmission.tenant_id, actionReceipt.sample_admission_binding?.tenant_id, "action_receipt.sample_admission_binding.tenant_id");
686
+ assertCheckEqual(errors, sampleAdmission.request_payload_hash, actionReceipt.sample_admission_binding?.request_payload_hash, "action_receipt.sample_admission_binding.request_payload_hash");
687
+ assertCheckEqual(errors, sampleAdmission.protocol_payload_ref, actionReceipt.sample_admission_binding?.protocol_payload_ref, "action_receipt.sample_admission_binding.protocol_payload_ref");
688
+ assertCheckEqual(errors, sampleAdmission.idempotency_key_hash, actionReceipt.sample_admission_binding?.idempotency_key_hash, "action_receipt.sample_admission_binding.idempotency_key_hash");
689
+ assertCheckEqual(errors, sampleAdmission.evidence_refs.length, actionReceipt.sample_admission_binding?.evidence_ref_count, "action_receipt.sample_admission_binding.evidence_ref_count");
690
+ assertCheckEqual(errors, sampleAdmission.proof_refs.length, actionReceipt.sample_admission_binding?.proof_ref_count, "action_receipt.sample_admission_binding.proof_ref_count");
691
+ }
692
+ if (isRecord(config)) {
693
+ assertCheckEqual(errors, sampleAdmission.action, config.runtime_gate_fixture?.sample_action, "config.runtime_gate_fixture.sample_action");
694
+ assertCheckEqual(errors, sampleAdmission.idempotency_key_hash, config.sample_submission?.idempotency_key_hash, "config.sample_submission.idempotency_key_hash");
695
+ }
696
+ }
697
+
698
+ function validateInitCheckSubmitSample(submitSampleSource, config, actionReceipt, sampleAdmission, errors) {
699
+ if (!submitSampleSource) return;
700
+ if (isRecord(config)) {
701
+ assertCheckEqual(errors, submitSampleSource, `${config.sample_submission?.curl ?? ""}\n`, ".intentrax/submit_sample.curl");
702
+ assertCheckEqual(errors, config.sample_submission?.file_path, ".intentrax/submit_sample.curl", "config.sample_submission.file_path");
703
+ assertCheckEqual(errors, config.sample_submission?.body_file, ".intentrax/sample-admission-request.json", "config.sample_submission.body_file");
704
+ }
705
+ if (isRecord(actionReceipt)) {
706
+ assertCheckEqual(errors, actionReceipt.submit_sample_binding?.file_path, ".intentrax/submit_sample.curl", "action_receipt.submit_sample_binding.file_path");
707
+ assertCheckEqual(errors, actionReceipt.submit_sample_binding?.body_file, ".intentrax/sample-admission-request.json", "action_receipt.submit_sample_binding.body_file");
708
+ assertCheckEqual(errors, actionReceipt.submit_sample_binding?.api_key_env, "INTENTRAX_API_KEY", "action_receipt.submit_sample_binding.api_key_env");
709
+ }
710
+ if (isRecord(sampleAdmission)) {
711
+ assertCheckEqual(errors, actionReceipt?.submit_sample_binding?.idempotency_key_hash, sampleAdmission.idempotency_key_hash, "action_receipt.submit_sample_binding.idempotency_key_hash");
712
+ if (!submitSampleSource.includes(`${IDEMPOTENCY_HEADER}: ${sampleAdmission.idempotency_key_hash}`)) {
713
+ pushCheckError(errors, "submit_sample", ".intentrax/submit_sample.curl", "Submit sample does not bind the sample idempotency hash.");
714
+ }
715
+ }
716
+ if (!submitSampleSource.includes("$INTENTRAX_API_KEY")) {
717
+ pushCheckError(errors, "submit_sample", ".intentrax/submit_sample.curl", "Submit sample must reference INTENTRAX_API_KEY rather than writing a secret.");
718
+ }
719
+ if (/fixture-api-key|test-api-key|begin private|seed_hex|current_seed_hex/i.test(submitSampleSource)) {
720
+ pushCheckError(errors, "secret_material", ".intentrax/submit_sample.curl", "Submit sample contains forbidden test or private material markers.");
721
+ }
722
+ }
723
+
724
+ function validateInitCheckOAPBoundary(fileSources, errors) {
725
+ for (const [filePath, source] of Object.entries(fileSources)) {
726
+ if (containsOAPCompatibilityMarkerInArtifact(filePath, source)) {
727
+ pushCheckError(errors, "oap_excluded", filePath, oapExcludedMessage());
728
+ }
729
+ }
730
+ }
731
+
732
+ function findHookBinding(config, actionReceipt, errors) {
733
+ const configHook = readString(config, ["adapter_profile", "native_hook_starter", "file_path"]);
734
+ const receiptHook = readString(actionReceipt, ["hook_starter_binding", "file_path"]);
735
+ const configEntrypoint = readString(config, ["adapter_profile", "native_hook_starter", "entrypoint"]);
736
+ const receiptEntrypoint = readString(actionReceipt, ["hook_starter_binding", "entrypoint"]);
737
+ const sourceHash = readString(actionReceipt, ["hook_starter_binding", "source_hash"]);
738
+ if (!configHook) {
739
+ pushCheckError(errors, "hook_binding", "config.adapter_profile.native_hook_starter.file_path", "Config does not identify a generated hook starter.");
740
+ }
741
+ if (!receiptHook) {
742
+ pushCheckError(errors, "hook_binding", "action_receipt.hook_starter_binding.file_path", "Action receipt does not identify a generated hook starter.");
743
+ }
744
+ if (configHook && receiptHook && configHook !== receiptHook) {
745
+ pushCheckError(errors, "hook_binding", "action_receipt.hook_starter_binding.file_path", "Config and action receipt hook file paths differ.");
746
+ }
747
+ if (configEntrypoint && receiptEntrypoint && configEntrypoint !== receiptEntrypoint) {
748
+ pushCheckError(errors, "hook_binding", "action_receipt.hook_starter_binding.entrypoint", "Config and action receipt hook entrypoints differ.");
749
+ }
750
+ if (sourceHash && !isSHA256(sourceHash)) {
751
+ pushCheckError(errors, "hook_binding", "action_receipt.hook_starter_binding.source_hash", "Hook source hash must be a SHA-256 hex string.");
752
+ }
753
+ return {
754
+ file_path: configHook || receiptHook || "",
755
+ entrypoint: configEntrypoint || receiptEntrypoint || "",
756
+ source_hash: sourceHash || "",
757
+ };
758
+ }
759
+
760
+ function findHostWiringBinding(config, actionReceipt, hookBinding, errors) {
761
+ const configGuide = readString(config, ["adapter_profile", "host_wiring_guide", "file_path"]);
762
+ const receiptGuide = readString(actionReceipt, ["host_wiring_guide_binding", "file_path"]);
763
+ const configHash = readString(config, ["adapter_profile", "host_wiring_guide", "guide_hash"]);
764
+ const receiptHash = readString(actionReceipt, ["host_wiring_guide_binding", "guide_hash"]);
765
+ const configHookPath = readString(config, ["adapter_profile", "host_wiring_guide", "hook_file_path"]);
766
+ const receiptHookPath = readString(actionReceipt, ["host_wiring_guide_binding", "hook_file_path"]);
767
+ const configEntrypoint = readString(config, ["adapter_profile", "host_wiring_guide", "hook_entrypoint"]);
768
+ const receiptEntrypoint = readString(actionReceipt, ["host_wiring_guide_binding", "hook_entrypoint"]);
769
+ if (!configGuide) {
770
+ pushCheckError(errors, "host_wiring_guide_binding", "config.adapter_profile.host_wiring_guide.file_path", "Config does not identify a generated host wiring guide.");
771
+ }
772
+ if (!receiptGuide) {
773
+ pushCheckError(errors, "host_wiring_guide_binding", "action_receipt.host_wiring_guide_binding.file_path", "Action receipt does not identify a generated host wiring guide.");
774
+ }
775
+ if (configGuide && receiptGuide && configGuide !== receiptGuide) {
776
+ pushCheckError(errors, "host_wiring_guide_binding", "action_receipt.host_wiring_guide_binding.file_path", "Config and action receipt host wiring guide paths differ.");
777
+ }
778
+ if (configHash && receiptHash && configHash !== receiptHash) {
779
+ pushCheckError(errors, "host_wiring_guide_binding", "action_receipt.host_wiring_guide_binding.guide_hash", "Config and action receipt host wiring guide hashes differ.");
780
+ }
781
+ if (receiptHash && !isSHA256(receiptHash)) {
782
+ pushCheckError(errors, "host_wiring_guide_binding", "action_receipt.host_wiring_guide_binding.guide_hash", "Host wiring guide hash must be a SHA-256 hex string.");
783
+ }
784
+ if (configHookPath && hookBinding.file_path && configHookPath !== hookBinding.file_path) {
785
+ pushCheckError(errors, "host_wiring_guide_binding", "config.adapter_profile.host_wiring_guide.hook_file_path", "Host wiring guide is not bound to the generated hook starter.");
786
+ }
787
+ if (receiptHookPath && hookBinding.file_path && receiptHookPath !== hookBinding.file_path) {
788
+ pushCheckError(errors, "host_wiring_guide_binding", "action_receipt.host_wiring_guide_binding.hook_file_path", "Action receipt host wiring guide is not bound to the generated hook starter.");
789
+ }
790
+ if (configEntrypoint && hookBinding.entrypoint && configEntrypoint !== hookBinding.entrypoint) {
791
+ pushCheckError(errors, "host_wiring_guide_binding", "config.adapter_profile.host_wiring_guide.hook_entrypoint", "Host wiring guide entrypoint does not match the generated hook starter.");
792
+ }
793
+ if (receiptEntrypoint && hookBinding.entrypoint && receiptEntrypoint !== hookBinding.entrypoint) {
794
+ pushCheckError(errors, "host_wiring_guide_binding", "action_receipt.host_wiring_guide_binding.hook_entrypoint", "Action receipt host wiring guide entrypoint does not match the generated hook starter.");
795
+ }
796
+ return {
797
+ file_path: configGuide || receiptGuide || "",
798
+ host_runtime: readString(config, ["adapter_profile", "host_wiring_guide", "host_runtime"]) ||
799
+ readString(actionReceipt, ["host_wiring_guide_binding", "host_runtime"]),
800
+ hook_file_path: configHookPath || receiptHookPath || "",
801
+ hook_entrypoint: configEntrypoint || receiptEntrypoint || "",
802
+ guide_hash: receiptHash || configHash || "",
803
+ };
804
+ }
805
+
806
+ function validateInitCheckHookSource(hookSource, hookBinding, errors) {
807
+ if (!hookSource) return;
808
+ const actualHash = hashGeneratedHookSource(hookSource);
809
+ if (hookBinding.source_hash && actualHash !== hookBinding.source_hash) {
810
+ pushCheckError(errors, "hook_source_hash_mismatch", "action_receipt.hook_starter_binding.source_hash", "Generated hook source hash does not match the action receipt binding.");
811
+ }
812
+ if (!hookBinding.entrypoint) {
813
+ pushCheckError(errors, "hook_binding", "action_receipt.hook_starter_binding.entrypoint", "Generated hook entrypoint is missing.");
814
+ } else if (!hookSource.includes(`function ${hookBinding.entrypoint}`)) {
815
+ pushCheckError(errors, "hook_entrypoint", hookBinding.file_path, "Generated hook source does not contain the configured entrypoint.");
816
+ }
817
+ if (containsOAPCompatibilityMarker(hookSource)) {
818
+ pushCheckError(errors, "oap_excluded", hookBinding.file_path, oapExcludedMessage());
819
+ }
820
+ }
821
+
822
+ function validateInitCheckHostWiringGuideSource(source, hostWiringBinding, hookBinding, errors) {
823
+ if (!source) return;
824
+ const actualHash = hashGeneratedHostWiringSource(source);
825
+ if (hostWiringBinding.guide_hash && actualHash !== hostWiringBinding.guide_hash) {
826
+ pushCheckError(errors, "host_wiring_guide_hash_mismatch", "action_receipt.host_wiring_guide_binding.guide_hash", "Generated host wiring guide hash does not match the action receipt binding.");
827
+ }
828
+ if (hookBinding.file_path && !source.includes(`\`${hookBinding.file_path}\``)) {
829
+ pushCheckError(errors, "host_wiring_guide_binding", hostWiringBinding.file_path, "Host wiring guide does not reference the generated hook starter path.");
830
+ }
831
+ if (hookBinding.entrypoint && !source.includes(hookBinding.entrypoint)) {
832
+ pushCheckError(errors, "host_wiring_guide_binding", hostWiringBinding.file_path, "Host wiring guide does not reference the generated hook entrypoint.");
833
+ }
834
+ if (!source.includes(ENDPOINT) || !source.includes(TENANT_HEADER) || !source.includes(API_KEY_HEADER) || !source.includes(IDEMPOTENCY_HEADER)) {
835
+ pushCheckError(errors, "host_wiring_guide_binding", hostWiringBinding.file_path, "Host wiring guide does not include the locked runtime admission binding.");
836
+ }
837
+ if (!source.includes("npx @intentrax/sdk check-init --output-dir .")) {
838
+ pushCheckError(errors, "host_wiring_guide_binding", hostWiringBinding.file_path, "Host wiring guide does not include the offline check-init command.");
839
+ }
840
+ if (containsOAPCompatibilityMarker(source)) {
841
+ pushCheckError(errors, "oap_excluded", hostWiringBinding.file_path, oapExcludedMessage());
842
+ }
843
+ if (/fixture-api-key|test-api-key|begin private|seed_hex|current_seed_hex|must-not-appear/i.test(source)) {
844
+ pushCheckError(errors, "secret_material", hostWiringBinding.file_path, "Host wiring guide contains forbidden test or private material markers.");
845
+ }
846
+ }
847
+
848
+ function containsOAPCompatibilityMarker(source) {
849
+ return OAP_EXCLUSION_PATTERN.test(source ?? "");
850
+ }
851
+
852
+ function containsOAPCompatibilityMarkerInArtifact(filePath, source) {
853
+ if (!source) return false;
854
+ if (!filePath.endsWith(".json")) {
855
+ return containsOAPCompatibilityMarker(source);
856
+ }
857
+ try {
858
+ const parsed = JSON.parse(source);
859
+ return containsOAPCompatibilityMarkerInJSONValue(parsed, []);
860
+ } catch {
861
+ return containsOAPCompatibilityMarker(source);
862
+ }
863
+ }
864
+
865
+ function containsOAPCompatibilityMarkerInJSONValue(value, path) {
866
+ if (typeof value === "string") {
867
+ return !isOAPMarkerExemptJSONPath(path) && containsOAPCompatibilityMarker(value);
868
+ }
869
+ if (Array.isArray(value)) {
870
+ return value.some((item, index) => containsOAPCompatibilityMarkerInJSONValue(item, path.concat(String(index))));
871
+ }
872
+ if (isRecord(value)) {
873
+ return Object.entries(value).some(([key, nested]) => containsOAPCompatibilityMarkerInJSONValue(nested, path.concat(key)));
874
+ }
875
+ return false;
876
+ }
877
+
878
+ function isOAPMarkerExemptJSONPath(path) {
879
+ const field = path[path.length - 1] ?? "";
880
+ return field === "working_directory";
881
+ }
882
+
883
+ function oapExcludedMessage() {
884
+ return `OAP compatibility is excluded from this MVP verifier. Excluded markers: ${OAP_EXCLUSION_MARKERS.join(", ")}.`;
885
+ }
886
+
887
+ async function invokeInitCheckHook(root, hookBinding, errors) {
888
+ const result = {
889
+ invoked: false,
890
+ entrypoint_found: false,
891
+ submitted: false,
892
+ network_attempted: false,
893
+ secret_leakage_detected: false,
894
+ result_payload_hash: "",
895
+ };
896
+ const resolvedHookPath = resolveInitCheckPath(root, hookBinding.file_path, errors);
897
+ if (!resolvedHookPath || !existsSync(resolvedHookPath) || !hookBinding.entrypoint) {
898
+ return result;
899
+ }
900
+ const hadAPIKey = Object.prototype.hasOwnProperty.call(process.env, "INTENTRAX_API_KEY");
901
+ const previousAPIKey = process.env.INTENTRAX_API_KEY;
902
+ const previousFetch = globalThis.fetch;
903
+ const networkBlocker = async () => {
904
+ result.network_attempted = true;
905
+ throw new Error("Intentrax check-init blocked network access during offline hook invocation.");
906
+ };
907
+ try {
908
+ delete process.env.INTENTRAX_API_KEY;
909
+ globalThis.fetch = networkBlocker;
910
+ const hookModule = await import(pathToFileURL(resolvedHookPath).href);
911
+ const entrypoint = hookModule[hookBinding.entrypoint];
912
+ result.entrypoint_found = typeof entrypoint === "function";
913
+ if (!result.entrypoint_found) {
914
+ pushCheckError(errors, "hook_entrypoint", hookBinding.entrypoint, "Generated hook module does not export the configured entrypoint.");
915
+ return result;
916
+ }
917
+ const hookResult = await entrypoint(buildSecretBearingHookFixture(), {
918
+ submit: false,
919
+ fetchImpl: networkBlocker,
920
+ });
921
+ result.invoked = true;
922
+ result.submitted = hookResult?.submitted === true;
923
+ result.result_payload_hash = isRecord(hookResult?.admission_request) ? hookResult.admission_request.request_payload_hash ?? "" : "";
924
+ const serialized = JSON.stringify(hookResult);
925
+ result.secret_leakage_detected = SECRET_FIXTURE_MARKERS.some((marker) => serialized.includes(marker));
926
+ if (result.submitted) {
927
+ pushCheckError(errors, "hook_offline_mode", hookBinding.entrypoint, "Generated hook submitted during offline check-init invocation.");
928
+ }
929
+ if (result.network_attempted) {
930
+ pushCheckError(errors, "hook_network", hookBinding.entrypoint, "Generated hook attempted network access during offline check-init invocation.");
931
+ }
932
+ if (result.secret_leakage_detected) {
933
+ pushCheckError(errors, "hook_secret_leakage", hookBinding.entrypoint, "Generated hook result leaked a secret-bearing fixture value.");
934
+ }
935
+ assertCheckEqual(errors, hookResult?.mutation_performed, false, "hook_result.mutation_performed");
936
+ assertCheckEqual(errors, hookResult?.tool_execution_performed, false, "hook_result.tool_execution_performed");
937
+ assertCheckEqual(errors, hookResult?.proof_generation_performed, false, "hook_result.proof_generation_performed");
938
+ assertCheckEqual(errors, hookResult?.policy_re_evaluation_performed, false, "hook_result.policy_re_evaluation_performed");
939
+ } catch (error) {
940
+ pushCheckError(errors, "hook_invocation", hookBinding.entrypoint, `Generated hook failed offline invocation: ${stableErrorMessage(error)}`);
941
+ } finally {
942
+ if (hadAPIKey) {
943
+ process.env.INTENTRAX_API_KEY = previousAPIKey;
944
+ } else {
945
+ delete process.env.INTENTRAX_API_KEY;
946
+ }
947
+ globalThis.fetch = previousFetch;
948
+ }
949
+ return result;
950
+ }
951
+
952
+ function buildSecretBearingHookFixture() {
953
+ const [token, apiKey, password, privateKey, cookie] = SECRET_FIXTURE_MARKERS;
954
+ return Object.freeze({
955
+ tool_name: "intentrax.check_init.fixture",
956
+ toolName: "intentrax.check_init.fixture",
957
+ name: "intentrax.check_init.fixture",
958
+ command: "echo should-not-run",
959
+ input: {
960
+ visible: "ok",
961
+ token,
962
+ api_key: apiKey,
963
+ password,
964
+ nested: {
965
+ private_key: privateKey,
966
+ },
967
+ },
968
+ arguments: {
969
+ visible: "ok",
970
+ authorization: `Bearer ${token}`,
971
+ },
972
+ headers: {
973
+ Authorization: `Bearer ${token}`,
974
+ Cookie: `session=${cookie}`,
975
+ },
976
+ apiKey,
977
+ session: cookie,
978
+ metadata: {
979
+ credential: password,
980
+ trace_id: "check-init-trace",
981
+ },
982
+ });
983
+ }
984
+
985
+ function hashGeneratedHookSource(source) {
986
+ return sha256Hex(source.endsWith("\n") ? source.slice(0, -1) : source);
987
+ }
988
+
989
+ function hashGeneratedHostWiringSource(source) {
990
+ return sha256Hex(HOST_WIRING_GUIDE_DOMAIN + (source.endsWith("\n") ? source.slice(0, -1) : source));
991
+ }
992
+
993
+ function assertCheckEqual(errors, actual, expected, field) {
994
+ if (!sameJSON(actual, expected)) {
995
+ pushCheckError(errors, "binding_mismatch", field, `Expected ${field} to match generated init binding.`);
996
+ }
997
+ }
998
+
999
+ function sameJSON(a, b) {
1000
+ if (a === undefined || b === undefined) return a === b;
1001
+ return canonicalJson(a) === canonicalJson(b);
1002
+ }
1003
+
1004
+ function readString(value, path) {
1005
+ const out = readPath(value, path);
1006
+ return typeof out === "string" ? out : "";
1007
+ }
1008
+
1009
+ function readBoolean(value, path) {
1010
+ const out = readPath(value, path);
1011
+ return typeof out === "boolean" ? out : undefined;
1012
+ }
1013
+
1014
+ function readPath(value, path) {
1015
+ let out = value;
1016
+ for (const key of path) {
1017
+ if (!isRecord(out)) return undefined;
1018
+ out = out[key];
1019
+ }
1020
+ return out;
1021
+ }
1022
+
1023
+ function pushCheckError(errors, code, field, message) {
1024
+ errors.push({
1025
+ code,
1026
+ field,
1027
+ message,
1028
+ });
1029
+ }
1030
+
1031
+ function stableErrorMessage(error) {
1032
+ return error && typeof error.message === "string" ? error.message : String(error);
1033
+ }
1034
+
1035
+ function parseVerifyProofOptions(args) {
1036
+ const options = {
1037
+ json: false,
1038
+ reportOut: ".intentrax/offline-proof-verification.report.json",
1039
+ };
1040
+ for (let index = 0; index < args.length; index += 1) {
1041
+ const arg = args[index];
1042
+ if (arg === "--json") {
1043
+ options.json = true;
1044
+ } else if (arg === "--report-out") {
1045
+ options.reportOut = requireValue(args, ++index, arg);
1046
+ } else {
1047
+ fail(`unknown option: ${arg}`);
1048
+ }
1049
+ }
1050
+ return options;
1051
+ }
1052
+
1053
+ function parseVerifyPDFReceiptOptions(args) {
1054
+ const options = {
1055
+ json: false,
1056
+ pdfHash: "",
1057
+ reportOut: ".intentrax/pdf-receipt-verification.report.json",
1058
+ };
1059
+ for (let index = 0; index < args.length; index += 1) {
1060
+ const arg = args[index];
1061
+ if (arg === "--json") {
1062
+ options.json = true;
1063
+ } else if (arg === "--pdf-hash") {
1064
+ options.pdfHash = requireValue(args, ++index, arg);
1065
+ } else if (arg === "--report-out") {
1066
+ options.reportOut = requireValue(args, ++index, arg);
1067
+ } else {
1068
+ fail(`unknown option: ${arg}`);
1069
+ }
1070
+ }
1071
+ return options;
1072
+ }
1073
+
1074
+ function verifyProofExportCommand(proofExportPath, options) {
1075
+ if (!proofExportPath) {
1076
+ fail("verify-proof requires a proof export JSON path");
1077
+ }
1078
+ const resolvedProofExportPath = resolve(proofExportPath);
1079
+ const source = readFileSync(resolvedProofExportPath, "utf8");
1080
+ if (containsForbiddenPrivateMarker(source)) {
1081
+ fail("proof export contains private material marker");
1082
+ }
1083
+ const proofExport = parseSingleJSON(source, "proof export");
1084
+ const report = buildLocalProofVerificationReport(proofExport, resolvedProofExportPath, resolve(options.reportOut));
1085
+ const reportData = JSON.stringify(report, null, 2) + "\n";
1086
+ mkdirSync(dirname(resolve(options.reportOut)), { recursive: true });
1087
+ writeFileSync(resolve(options.reportOut), reportData, { mode: 0o600 });
1088
+ return report;
1089
+ }
1090
+
1091
+ function verifyPDFReceiptCommand(pdfPath, options) {
1092
+ if (!pdfPath) {
1093
+ fail("verify-pdf-receipt requires a PDF receipt path");
1094
+ }
1095
+ if (!options.pdfHash) {
1096
+ fail("verify-pdf-receipt requires --pdf-hash");
1097
+ }
1098
+ const resolvedPDFPath = resolve(pdfPath);
1099
+ const resolvedReportPath = resolve(options.reportOut);
1100
+ const bytes = readFileSync(resolvedPDFPath);
1101
+ const report = buildLocalPDFReceiptVerificationReport(bytes, resolvedPDFPath, resolvedReportPath, options.pdfHash);
1102
+ const reportData = JSON.stringify(report, null, 2) + "\n";
1103
+ mkdirSync(dirname(resolvedReportPath), { recursive: true });
1104
+ writeFileSync(resolvedReportPath, reportData, { mode: 0o600 });
1105
+ return report;
1106
+ }
1107
+
1108
+ function buildLocalPDFReceiptVerificationReport(bytes, pdfPath, reportPath, expectedPDFHash) {
1109
+ const expectedHash = normalizeSHA256Hex(expectedPDFHash, "pdf_hash");
1110
+ const actualHash = sha256HexBytes(bytes);
1111
+ const pdfHeaderPresent = bytes.length >= 5 && bytes.subarray(0, 5).toString("ascii") === "%PDF-";
1112
+ const invalid = [];
1113
+ if (!pdfHeaderPresent) invalid.push("pdf_header");
1114
+ if (actualHash !== expectedHash) invalid.push("pdf_hash");
1115
+ if (invalid.length > 0) {
1116
+ fail(`pdf receipt verification failed closed: ${invalid.join(",")}`);
1117
+ }
1118
+ const withoutHash = {
1119
+ schema_version: LOCAL_PDF_RECEIPT_VERIFICATION_SCHEMA_VERSION,
1120
+ verifier_version: LOCAL_PDF_RECEIPT_VERIFIER_VERSION,
1121
+ status: "PASS",
1122
+ offline: true,
1123
+ pdf_path: pdfPath,
1124
+ report_path: reportPath,
1125
+ pdf_hash: actualHash,
1126
+ expected_pdf_hash: expectedHash,
1127
+ byte_length: bytes.length,
1128
+ hash_algorithm: "SHA-256",
1129
+ pdf_header_present: true,
1130
+ pdf_receipt_non_authoritative: true,
1131
+ canonical_json_authoritative: true,
1132
+ production_authorization_unchanged: true,
1133
+ boundary_assertions: {
1134
+ offline_verifier_used: true,
1135
+ runtime_server_not_required: true,
1136
+ network_not_required: true,
1137
+ private_key_material_absent: true,
1138
+ pdf_hash_recomputed: true,
1139
+ pdf_hash_matches_response_header: true,
1140
+ pdf_receipt_non_authoritative: true,
1141
+ canonical_json_authoritative: true,
1142
+ production_authorization_unchanged: true,
1143
+ },
1144
+ report_hash: "",
1145
+ };
1146
+ return Object.freeze({
1147
+ ...withoutHash,
1148
+ report_hash: sha256Hex(LOCAL_PDF_RECEIPT_VERIFY_DOMAIN + canonicalJson(withoutHash)),
1149
+ });
1150
+ }
1151
+
1152
+ function buildLocalProofVerificationReport(proofExport, proofExportPath, reportPath) {
1153
+ const invalid = validateProofLookupExport(proofExport);
1154
+ if (invalid.length > 0) {
1155
+ fail(`proof export verification failed closed: ${invalid.join(",")}`);
1156
+ }
1157
+ const record = proofExport.proof_record;
1158
+ const bundle = record.verification_bundle;
1159
+ const withoutHash = {
1160
+ schema_version: LOCAL_PROOF_VERIFICATION_SCHEMA_VERSION,
1161
+ verifier_version: LOCAL_PROOF_VERIFIER_VERSION,
1162
+ status: "PASS",
1163
+ offline: true,
1164
+ proof_export_path: proofExportPath,
1165
+ report_path: reportPath,
1166
+ tenant_id: record.tenant_id,
1167
+ registry_entry_id: record.registry_entry_id,
1168
+ aep_hash: record.aep_hash,
1169
+ proof_record_hash: record.record_hash,
1170
+ proof_lookup_hash: proofExport.result_hash,
1171
+ verification_bundle_hash: bundle.bundle_hash,
1172
+ hash_algorithm: "SHA-256",
1173
+ boundary_assertions: {
1174
+ offline_verifier_used: true,
1175
+ runtime_server_not_required: true,
1176
+ network_not_required: true,
1177
+ private_key_material_absent: true,
1178
+ proof_lookup_hash_recomputed: true,
1179
+ proof_record_hash_recomputed: true,
1180
+ registry_bundle_hash_recomputed: true,
1181
+ canonical_json_authoritative: true,
1182
+ pdf_receipt_non_authoritative: true,
1183
+ },
1184
+ report_hash: "",
1185
+ };
1186
+ return Object.freeze({
1187
+ ...withoutHash,
1188
+ report_hash: sha256Hex(LOCAL_PROOF_VERIFY_DOMAIN + canonicalJson(withoutHash)),
1189
+ });
1190
+ }
1191
+
1192
+ function validateProofLookupExport(lookup) {
1193
+ const invalid = [];
1194
+ if (!isRecord(lookup)) return ["proof_export"];
1195
+ const query = lookup.query;
1196
+ const record = lookup.proof_record;
1197
+ const bundle = isRecord(record) ? record.verification_bundle : undefined;
1198
+ if (lookup.schema_version !== "intentrax.registry.proof_lookup/1.0") invalid.push("schema_version");
1199
+ if (lookup.store_mode !== "POSTGRESQL_APPEND_ONLY") invalid.push("store_mode");
1200
+ if (lookup.hash_algorithm !== "SHA-256") invalid.push("hash_algorithm");
1201
+ if (!isRecord(query)) invalid.push("query");
1202
+ if (!isRecord(record)) invalid.push("proof_record");
1203
+ if (!isRecord(bundle)) invalid.push("verification_bundle");
1204
+ if (invalid.length > 0) return sortedUnique(invalid);
1205
+
1206
+ if (!stableNonEmpty(query.tenant_id) || query.tenant_id !== record.tenant_id) invalid.push("query.tenant_id");
1207
+ if (!stableNonEmpty(query.registry_entry_id) && !isSHA256(query.aep_hash)) invalid.push("query");
1208
+ if (stableNonEmpty(query.registry_entry_id) && query.registry_entry_id !== record.registry_entry_id) invalid.push("query.registry_entry_id");
1209
+ if (stableNonEmpty(query.aep_hash) && query.aep_hash !== record.aep_hash) invalid.push("query.aep_hash");
1210
+ if (record.schema_version !== "intentrax.registry.persistence_foundation/1.0") invalid.push("proof_record.schema_version");
1211
+ if (record.record_type !== "REGISTRY_BACKED_PROOF") invalid.push("proof_record.record_type");
1212
+ if (record.store_mode !== "POSTGRESQL_APPEND_ONLY") invalid.push("proof_record.store_mode");
1213
+ if (record.hash_algorithm !== "SHA-256") invalid.push("proof_record.hash_algorithm");
1214
+ if (record.append_only !== true) invalid.push("proof_record.append_only");
1215
+ if (record.trust_status !== "VALID") invalid.push("proof_record.trust_status");
1216
+ for (const field of ["tenant_id", "registry_entry_id", "execution_id", "canonical_aep_json", "lookup_ref"]) {
1217
+ if (!stableNonEmpty(record[field])) invalid.push(`proof_record.${field}`);
1218
+ }
1219
+ for (const field of ["aep_hash", "admission_hash", "registry_entry_hash", "registry_output_hash", "signature_hash", "verification_hash", "replay_hash", "audit_hash", "record_hash"]) {
1220
+ if (!isSHA256(record[field])) invalid.push(`proof_record.${field}`);
1221
+ }
1222
+ if (!isRecord(record.registry_entry)) invalid.push("proof_record.registry_entry");
1223
+ if (isRecord(record.registry_entry)) {
1224
+ if (record.registry_entry.registry_entry_id !== record.registry_entry_id) invalid.push("registry_entry.registry_entry_id");
1225
+ if (record.registry_entry.execution_id !== record.execution_id) invalid.push("registry_entry.execution_id");
1226
+ if (record.registry_entry.tenant_id !== record.tenant_id) invalid.push("registry_entry.tenant_id");
1227
+ if (record.registry_entry.aep_hash !== record.aep_hash) invalid.push("registry_entry.aep_hash");
1228
+ if (record.registry_entry.canonical_aep_json !== record.canonical_aep_json) invalid.push("registry_entry.canonical_aep_json");
1229
+ if (record.registry_entry.trust_status !== record.trust_status) invalid.push("registry_entry.trust_status");
1230
+ }
1231
+ if (record.lookup_ref !== `intentrax://registry/proofs/${record.tenant_id}/${record.aep_hash}`) invalid.push("proof_record.lookup_ref");
1232
+
1233
+ if (bundle.schema_version !== "intentrax.registry.proof_verification_bundle/1.0") invalid.push("verification_bundle.schema_version");
1234
+ if (bundle.hash_algorithm !== "SHA-256") invalid.push("verification_bundle.hash_algorithm");
1235
+ if (!isSHA256(bundle.bundle_hash)) invalid.push("verification_bundle.bundle_hash");
1236
+ if (!isRecord(bundle.registry_output)) invalid.push("verification_bundle.registry_output");
1237
+ if (isRecord(bundle.registry_output)) {
1238
+ if (bundle.registry_output.registry_entry_id !== record.registry_entry_id) invalid.push("verification_bundle.registry_output.registry_entry_id");
1239
+ if (bundle.registry_output.execution_id !== record.execution_id) invalid.push("verification_bundle.registry_output.execution_id");
1240
+ if (bundle.registry_output.aep_hash !== record.aep_hash) invalid.push("verification_bundle.registry_output.aep_hash");
1241
+ if (bundle.registry_output.canonical_aep_json !== record.canonical_aep_json) invalid.push("verification_bundle.registry_output.canonical_aep_json");
1242
+ if (bundle.registry_output.trust_status !== record.trust_status) invalid.push("verification_bundle.registry_output.trust_status");
1243
+ }
1244
+ if (!Array.isArray(bundle.key_references) || bundle.key_references.length === 0) invalid.push("verification_bundle.key_references");
1245
+ if (Array.isArray(bundle.key_references)) {
1246
+ for (const [index, key] of bundle.key_references.entries()) {
1247
+ if (!isRecord(key) || !stableNonEmpty(key.public_key_material) || stableNonEmpty(key.key_material)) {
1248
+ invalid.push(`verification_bundle.key_references.${index}`);
1249
+ }
1250
+ if (isRecord(key) && String(key.public_key_material || "").toLowerCase().includes("private")) {
1251
+ invalid.push(`verification_bundle.key_references.${index}.public_key_material`);
1252
+ }
1253
+ }
1254
+ }
1255
+ if (isSHA256(bundle.bundle_hash) && bundle.bundle_hash !== hashWithBlankField(bundle, "bundle_hash")) invalid.push("verification_bundle.bundle_hash");
1256
+ if (isSHA256(record.record_hash) && record.record_hash !== hashWithBlankField(record, "record_hash")) invalid.push("proof_record.record_hash");
1257
+ if (isSHA256(lookup.result_hash) && lookup.result_hash !== hashWithBlankField(lookup, "result_hash")) invalid.push("result_hash");
1258
+ if (!isSHA256(lookup.result_hash)) invalid.push("result_hash");
1259
+ return sortedUnique(invalid);
1260
+ }
1261
+
1262
+ function hashWithBlankField(value, field) {
1263
+ return sha256Hex(JSON.stringify(goPersistenceOrder({ ...value, [field]: "" })));
1264
+ }
1265
+
1266
+ function goPersistenceOrder(value) {
1267
+ if (!isRecord(value)) {
1268
+ if (Array.isArray(value)) return value.map(goPersistenceOrder);
1269
+ return value;
1270
+ }
1271
+ if (value.schema_version === "intentrax.registry.proof_lookup/1.0") {
1272
+ return ordered(value, ["schema_version", "store_mode", "query", "proof_record", "result_hash", "hash_algorithm"]);
1273
+ }
1274
+ if (stableNonEmpty(value.tenant_id) && (stableNonEmpty(value.registry_entry_id) || stableNonEmpty(value.aep_hash)) && Object.keys(value).every((key) => ["tenant_id", "registry_entry_id", "aep_hash"].includes(key))) {
1275
+ return ordered(value, ["tenant_id", "registry_entry_id", "aep_hash"]);
1276
+ }
1277
+ if (value.schema_version === "intentrax.registry.persistence_foundation/1.0") {
1278
+ return ordered(value, [
1279
+ "schema_version",
1280
+ "record_type",
1281
+ "store_mode",
1282
+ "migration_id",
1283
+ "tenant_id",
1284
+ "registry_entry_id",
1285
+ "execution_id",
1286
+ "aep_hash",
1287
+ "canonical_aep_json",
1288
+ "admission_hash",
1289
+ "registry_entry_hash",
1290
+ "registry_output_hash",
1291
+ "signature_hash",
1292
+ "verification_hash",
1293
+ "replay_hash",
1294
+ "audit_hash",
1295
+ "trust_status",
1296
+ "lookup_ref",
1297
+ "append_only",
1298
+ "registry_entry",
1299
+ "verification_bundle",
1300
+ "record_hash",
1301
+ "hash_algorithm",
1302
+ ]);
1303
+ }
1304
+ if (value.schema_version === "intentrax.registry.proof_verification_bundle/1.0") {
1305
+ return ordered(value, ["schema_version", "registry_output", "payload", "key_binding", "key_references", "bundle_hash", "hash_algorithm"]);
1306
+ }
1307
+ if (value.schema_version === "intentrax.registry.entry/1.0") {
1308
+ return ordered(value, [
1309
+ "schema_version",
1310
+ "registry_entry_id",
1311
+ "execution_id",
1312
+ "tenant_id",
1313
+ "aep_hash",
1314
+ "canonical_aep_json",
1315
+ "policy_id",
1316
+ "signer_id",
1317
+ "signature_hash",
1318
+ "verification_hash",
1319
+ "trust_trace_hash",
1320
+ "trust_integrity_lock",
1321
+ "trust_status",
1322
+ "record_version",
1323
+ "index_keys",
1324
+ "integrity",
1325
+ ]);
1326
+ }
1327
+ if (value.schema_version === "intentrax.trust.key_binding_set/1.0" || (isRecord(value.signer_identity) && isRecord(value.quorum) && Array.isArray(value.keys))) {
1328
+ return ordered(value, ["schema_version", "signer_identity", "quorum", "keys", "integrity"]);
1329
+ }
1330
+ if (value.schema_version === "intentrax.trust.signature_payload_result/1.0" || (isRecord(value.payload) && stableNonEmpty(value.canonical_payload_json))) {
1331
+ return ordered(value, ["schema_version", "payload", "canonical_payload_json", "payload_hash", "payload_byte_length", "integrity"]);
1332
+ }
1333
+ if (value.schema_version === "intentrax.trust.signature_bundle/1.0" || (Array.isArray(value.signatures) && stableNonEmpty(value.payload_hash))) {
1334
+ return ordered(value, ["schema_version", "signatures", "payload_hash", "required_signatures", "total_signers", "integrity"]);
1335
+ }
1336
+ if (stableNonEmpty(value.payload_version) && stableNonEmpty(value.canonical_aep_json) && stableNonEmpty(value.aep_hash)) {
1337
+ return ordered(value, ["payload_version", "canonical_aep_json", "aep_hash"]);
1338
+ }
1339
+ if (stableNonEmpty(value.principal_id) && stableNonEmpty(value.principal_type) && stableNonEmpty(value.identity_binding_ref)) {
1340
+ return ordered(value, ["principal_id", "principal_type", "identity_binding_ref"]);
1341
+ }
1342
+ if (Number.isInteger(value.required_signatures) && Number.isInteger(value.total_signers) && Object.keys(value).every((key) => ["required_signatures", "total_signers"].includes(key))) {
1343
+ return ordered(value, ["required_signatures", "total_signers"]);
1344
+ }
1345
+ if (stableNonEmpty(value.key_id) && stableNonEmpty(value.signature_hex)) {
1346
+ return ordered(value, ["key_id", "key_version", "algorithm", "signature_hex", "payload_hash", "public_key_hash", "key_binding_hash"]);
1347
+ }
1348
+ if (stableNonEmpty(value.key_id) && stableNonEmpty(value.key_version) && stableNonEmpty(value.key_binding_hash)) {
1349
+ return ordered(value, ["key_id", "key_version", "key_status", "algorithm", "principal_id", "public_key_hash", "key_material_hash", "key_binding_hash"]);
1350
+ }
1351
+ if (stableNonEmpty(value.key_id) && stableNonEmpty(value.key_version) && stableNonEmpty(value.public_key_material)) {
1352
+ return ordered(value, ["key_id", "key_version", "key_material", "public_key_material", "deterministic_key_handle", "key_status", "algorithm", "principal_id"]);
1353
+ }
1354
+ if (stableNonEmpty(value.execution_id) && stableNonEmpty(value.aep_hash) && stableNonEmpty(value.canonical_aep_json) && isRecord(value.signature) && isRecord(value.verification_result)) {
1355
+ return ordered(value, [
1356
+ "execution_id",
1357
+ "aep_hash",
1358
+ "canonical_aep_json",
1359
+ "signature",
1360
+ "trust_status",
1361
+ "registry_entry_id",
1362
+ "index_keys",
1363
+ "verification_result",
1364
+ "replay_result",
1365
+ "projection_views",
1366
+ "audit_result",
1367
+ "registry_trace",
1368
+ "integrity_lock",
1369
+ ]);
1370
+ }
1371
+ if (value.schema_version === "intentrax.registry.stored_verification/1.0" || stableNonEmpty(value.verification_status)) {
1372
+ return ordered(value, [
1373
+ "schema_version",
1374
+ "verification_status",
1375
+ "aep_integrity_valid",
1376
+ "signature_verification_valid",
1377
+ "trust_status_reconfirmed",
1378
+ "recomputed_aep_hash",
1379
+ "verification_hash",
1380
+ "integrity",
1381
+ ]);
1382
+ }
1383
+ if (value.schema_version === "intentrax.registry.replay/1.0" || stableNonEmpty(value.replay_status)) {
1384
+ return ordered(value, ["schema_version", "replay_status", "original_aep_hash", "replay_aep_hash", "output_match", "replay_consistent", "replay_result_hash", "integrity"]);
1385
+ }
1386
+ if (value.schema_version === "intentrax.registry.projection/1.0" || Array.isArray(value.rows)) {
1387
+ return ordered(value, ["schema_version", "status", "rows", "result_count", "projection_hash", "integrity"]);
1388
+ }
1389
+ if (value.schema_version === "intentrax.registry.observability/1.0" || Array.isArray(value.trace_refs)) {
1390
+ return ordered(value, ["schema_version", "status", "trace_refs", "report_hash", "integrity"]);
1391
+ }
1392
+ if (value.schema_version === "intentrax.registry.audit/1.0" || stableNonEmpty(value.audit_status)) {
1393
+ return ordered(value, ["schema_version", "audit_status", "checked_artifacts", "anomalies", "registry_output_ready", "audit_hash", "integrity"]);
1394
+ }
1395
+ if (stableNonEmpty(value.registry_entry_id) && stableNonEmpty(value.policy_id) && stableNonEmpty(value.signer_id) && stableNonEmpty(value.trust_status)) {
1396
+ return ordered(value, ["registry_entry_id", "execution_id", "aep_hash", "policy_id", "signer_id", "trust_status", "tenant_id"]);
1397
+ }
1398
+ if (stableNonEmpty(value.execution_id) && stableNonEmpty(value.policy_id) && stableNonEmpty(value.signer_id) && stableNonEmpty(value.trust_status)) {
1399
+ return ordered(value, ["execution_id", "aep_hash", "policy_id", "signer_id", "trust_status", "tenant_id"]);
1400
+ }
1401
+ if (stableNonEmpty(value.component) && stableNonEmpty(value.artifact_hash)) {
1402
+ return ordered(value, ["component", "artifact_hash"]);
1403
+ }
1404
+ if (stableNonEmpty(value.hash_algorithm) && Object.keys(value).some((key) => ["input_hash", "output_hash", "trace_hash"].includes(key))) {
1405
+ return ordered(value, ["input_hash", "output_hash", "trace_hash", "hash_algorithm"]);
1406
+ }
1407
+ return ordered(value, Object.keys(value).sort());
1408
+ }
1409
+
1410
+ function ordered(value, fieldOrder) {
1411
+ const out = {};
1412
+ const seen = new Set();
1413
+ for (const field of fieldOrder) {
1414
+ if (Object.prototype.hasOwnProperty.call(value, field)) {
1415
+ out[field] = goPersistenceOrder(value[field]);
1416
+ seen.add(field);
1417
+ }
1418
+ }
1419
+ for (const field of Object.keys(value).filter((key) => !seen.has(key)).sort()) {
1420
+ out[field] = goPersistenceOrder(value[field]);
1421
+ }
1422
+ return out;
1423
+ }
1424
+
1425
+ function parseSingleJSON(source, label) {
1426
+ try {
1427
+ return JSON.parse(source);
1428
+ } catch (error) {
1429
+ fail(`${label} is not valid JSON: ${error.message}`);
1430
+ }
1431
+ }
1432
+
1433
+ function containsForbiddenPrivateMarker(value) {
1434
+ return /seed_hex|current_seed_hex|private[_ -]?key|privatekey|private_material|begin private/i.test(value);
1435
+ }
1436
+
1437
+ function isRecord(value) {
1438
+ return value !== null && typeof value === "object" && !Array.isArray(value);
1439
+ }
1440
+
1441
+ function stableNonEmpty(value) {
1442
+ return typeof value === "string" && value.length > 0 && value.trim() === value;
1443
+ }
1444
+
1445
+ function isSHA256(value) {
1446
+ return typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
1447
+ }
1448
+
1449
+ function sortedUnique(values) {
1450
+ return [...new Set(values.filter(Boolean))].sort();
1451
+ }
1452
+
1453
+ function buildInitOutput(adapterName, adapter, options) {
1454
+ const sampleAction = SAMPLE_ACTION_BY_SURFACE[adapter.normalized_surface_id];
1455
+ const payload = {
1456
+ adapter: adapterName,
1457
+ action: sampleAction,
1458
+ hook_surface: adapter.hook_surface,
1459
+ tenant_id: options.tenantId,
1460
+ };
1461
+ const payloadHash = sha256Hex(canonicalJson(payload));
1462
+ const idempotencyKeyHash = sha256Hex("INTENTRAX_AGENT_INIT_IDEMPOTENCY_V1" + payloadHash);
1463
+ const sampleAdmissionRequest = {
1464
+ schema_version: ADMISSION_SCHEMA_VERSION,
1465
+ tenant_id: options.tenantId,
1466
+ surface_id: adapter.normalized_surface_id,
1467
+ action: payload.action,
1468
+ adapter_id: adapter.normalized_adapter_id,
1469
+ evidence_refs: REQUIRED_GATEWAY_REFS,
1470
+ proof_refs: REQUIRED_GATEWAY_REFS,
1471
+ request_payload_hash: payloadHash,
1472
+ protocol_payload_ref: `sha256:${payloadHash}`,
1473
+ idempotency_key_hash: idempotencyKeyHash,
1474
+ };
1475
+ const submitSample = buildSubmitSample(sampleAdmissionRequest, options);
1476
+ const hookStarter = buildHookStarter(adapterName, adapter, sampleAdmissionRequest);
1477
+ const hostWiringGuide = buildHostWiringGuide(adapterName, adapter, hookStarter, submitSample);
1478
+ const actionReceipt = buildActionReceipt(adapterName, adapter, sampleAdmissionRequest, hookStarter, hostWiringGuide, submitSample);
1479
+ const config = {
1480
+ schema_version: INIT_SCHEMA_VERSION,
1481
+ cli_version: VERSION,
1482
+ adapter_profile: {
1483
+ adapter_name: adapterName,
1484
+ display_name: adapter.display_name,
1485
+ matrix_adapter_id: adapter.matrix_adapter_id,
1486
+ hook_surface: adapter.hook_surface,
1487
+ hook_label: adapter.hook_label,
1488
+ quickstart_ref: adapter.quickstart_ref,
1489
+ native_hook_starter: {
1490
+ file_path: hookStarter.file_path,
1491
+ module_format: "ESM",
1492
+ entrypoint: hookStarter.entrypoint,
1493
+ native_template_id: hookStarter.native_template_id,
1494
+ native_event_kind: hookStarter.native_event_kind,
1495
+ adapter_surface: adapter.normalized_surface_id,
1496
+ adapter_id: adapter.normalized_adapter_id,
1497
+ runtime_submission_required: true,
1498
+ secret_material_written: false,
1499
+ },
1500
+ host_wiring_guide: {
1501
+ file_path: hostWiringGuide.file_path,
1502
+ guide_hash: hostWiringGuide.guide_hash,
1503
+ host_runtime: hostWiringGuide.host_runtime,
1504
+ hook_file_path: hookStarter.file_path,
1505
+ hook_entrypoint: hookStarter.entrypoint,
1506
+ adapter_surface: adapter.normalized_surface_id,
1507
+ adapter_id: adapter.normalized_adapter_id,
1508
+ setup_level: "HOST_BINDING_GUIDE",
1509
+ authoritative: false,
1510
+ secret_material_written: false,
1511
+ },
1512
+ },
1513
+ normalized_contract: {
1514
+ base_url: options.baseUrl,
1515
+ endpoint: ENDPOINT,
1516
+ method: "POST",
1517
+ tenant_header: TENANT_HEADER,
1518
+ api_key_header: API_KEY_HEADER,
1519
+ idempotency_header: IDEMPOTENCY_HEADER,
1520
+ content_type: "application/json",
1521
+ },
1522
+ runtime_gate_fixture: {
1523
+ sample_action: sampleAction,
1524
+ required_gateway_ref_count: REQUIRED_GATEWAY_REFS.length,
1525
+ sample_is_contract_admissible: true,
1526
+ proof_generation_owner: "intentrax_runtime",
1527
+ },
1528
+ action_receipt: {
1529
+ file_path: actionReceipt.file_path,
1530
+ receipt_id: actionReceipt.receipt_id,
1531
+ receipt_hash: actionReceipt.receipt_hash,
1532
+ authoritative: false,
1533
+ canonical_aep_authoritative: true,
1534
+ production_authorization_unchanged: true,
1535
+ },
1536
+ boundary_assertions: {
1537
+ no_secret_material_written: true,
1538
+ no_tool_execution_inside_admission: true,
1539
+ no_payload_mutation: true,
1540
+ no_policy_re_evaluation: true,
1541
+ no_private_key_material_required: true,
1542
+ intentrax_owns_proof_generation: true,
1543
+ aevn_aep_remains_authoritative: true,
1544
+ oap_compatibility: OAP_COMPATIBILITY_BOUNDARY,
1545
+ },
1546
+ sample_submission: {
1547
+ method: submitSample.method,
1548
+ url: submitSample.url,
1549
+ file_path: submitSample.file_path,
1550
+ body_file: submitSample.body_file,
1551
+ working_directory: submitSample.working_directory,
1552
+ curl: submitSample.curl,
1553
+ required_headers: [
1554
+ "content-type",
1555
+ TENANT_HEADER,
1556
+ API_KEY_HEADER,
1557
+ IDEMPOTENCY_HEADER,
1558
+ ],
1559
+ api_key_env: "INTENTRAX_API_KEY",
1560
+ idempotency_key_hash: sampleAdmissionRequest.idempotency_key_hash,
1561
+ },
1562
+ next_steps: [
1563
+ "Review .intentrax/sample-admission-request.json.",
1564
+ "Review .intentrax/action-receipt.json as a developer summary only.",
1565
+ `Wire ${hookStarter.file_path} into your ${adapter.hook_label}.`,
1566
+ `Open ${hostWiringGuide.file_path} for the host wiring steps and local check command.`,
1567
+ "Set X-Intentrax-Api-Key from your secret manager at runtime.",
1568
+ "Run .intentrax/submit_sample.curl after confirming the target runtime uses the locked private-alpha Agent Gateway bundle.",
1569
+ ],
1570
+ };
1571
+ return {
1572
+ schema_version: "intentrax.onboarding.agent_adapter_init_result/1.0",
1573
+ status: "READY",
1574
+ config,
1575
+ normalized_contract: config.normalized_contract,
1576
+ sample_admission_request: sampleAdmissionRequest,
1577
+ action_receipt: actionReceipt,
1578
+ hook_starter: hookStarter,
1579
+ host_wiring_guide: hostWiringGuide,
1580
+ submit_sample: submitSample,
1581
+ init_hash: sha256Hex(DOMAIN + canonicalJson({ action_receipt: actionReceipt, config, hook_starter: hookStarter, host_wiring_guide: hostWiringGuide, sample_admission_request: sampleAdmissionRequest })),
1582
+ };
1583
+ }
1584
+
1585
+ function buildActionReceipt(adapterName, adapter, sampleAdmissionRequest, hookStarter, hostWiringGuide, submitSample) {
1586
+ const withoutHash = {
1587
+ schema_version: ACTION_RECEIPT_SCHEMA_VERSION,
1588
+ receipt_id: `intentrax-init-${adapterName}-${sampleAdmissionRequest.request_payload_hash.slice(0, 12)}`,
1589
+ receipt_type: "AGENT_ADAPTER_INIT_SAMPLE_ACTION_RECEIPT",
1590
+ file_path: ".intentrax/action-receipt.json",
1591
+ authoritative: false,
1592
+ canonical_aep_authoritative: true,
1593
+ production_authorization_unchanged: true,
1594
+ adapter_profile: {
1595
+ adapter_name: adapterName,
1596
+ display_name: adapter.display_name,
1597
+ matrix_adapter_id: adapter.matrix_adapter_id,
1598
+ hook_surface: adapter.hook_surface,
1599
+ native_template_id: hookStarter.native_template_id,
1600
+ native_event_kind: hookStarter.native_event_kind,
1601
+ normalized_surface_id: sampleAdmissionRequest.surface_id,
1602
+ normalized_adapter_id: sampleAdmissionRequest.adapter_id,
1603
+ action: sampleAdmissionRequest.action,
1604
+ },
1605
+ sample_admission_binding: {
1606
+ file_path: ".intentrax/sample-admission-request.json",
1607
+ tenant_id: sampleAdmissionRequest.tenant_id,
1608
+ request_payload_hash: sampleAdmissionRequest.request_payload_hash,
1609
+ protocol_payload_ref: sampleAdmissionRequest.protocol_payload_ref,
1610
+ idempotency_key_hash: sampleAdmissionRequest.idempotency_key_hash,
1611
+ evidence_ref_count: sampleAdmissionRequest.evidence_refs.length,
1612
+ proof_ref_count: sampleAdmissionRequest.proof_refs.length,
1613
+ },
1614
+ hook_starter_binding: {
1615
+ file_path: hookStarter.file_path,
1616
+ entrypoint: hookStarter.entrypoint,
1617
+ source_hash: hookStarter.source_hash,
1618
+ },
1619
+ host_wiring_guide_binding: {
1620
+ file_path: hostWiringGuide.file_path,
1621
+ host_runtime: hostWiringGuide.host_runtime,
1622
+ hook_file_path: hookStarter.file_path,
1623
+ hook_entrypoint: hookStarter.entrypoint,
1624
+ guide_hash: hostWiringGuide.guide_hash,
1625
+ authoritative: false,
1626
+ },
1627
+ submit_sample_binding: {
1628
+ file_path: submitSample.file_path,
1629
+ method: submitSample.method,
1630
+ url: submitSample.url,
1631
+ body_file: submitSample.body_file,
1632
+ idempotency_key_hash: sampleAdmissionRequest.idempotency_key_hash,
1633
+ api_key_env: "INTENTRAX_API_KEY",
1634
+ },
1635
+ evidence_links: {
1636
+ runtime_admission_endpoint: ENDPOINT,
1637
+ proof_verification_endpoint: "/v1/proofs/verify",
1638
+ proof_export_endpoint_template: "/v1/proofs/{proof_id}/export?format=json|aep-json|pdf",
1639
+ verifier_handoff_endpoint_template: "/v1/evidence/dry-run/{receipt_id}/verifier-handoff",
1640
+ aevn_authoritative: true,
1641
+ aep_authoritative: true,
1642
+ aep_export_link_state: "AVAILABLE_AFTER_RUNTIME_ADMISSION",
1643
+ registry_reference_link_state: "AVAILABLE_AFTER_RUNTIME_ADMISSION",
1644
+ },
1645
+ boundary_assertions: {
1646
+ developer_summary_only: true,
1647
+ non_authoritative_developer_summary: true,
1648
+ canonical_aep_remains_authoritative: true,
1649
+ action_receipt_does_not_replace_aep: true,
1650
+ no_secret_material_written: true,
1651
+ no_tool_execution_inside_admission: true,
1652
+ no_payload_mutation: true,
1653
+ no_policy_re_evaluation: true,
1654
+ no_proof_generation_inside_adapter: true,
1655
+ no_registry_write_performed: true,
1656
+ production_authorization_unchanged: true,
1657
+ oap_compatibility: OAP_COMPATIBILITY_BOUNDARY,
1658
+ },
1659
+ hash_algorithm: "SHA-256",
1660
+ };
1661
+ return Object.freeze({
1662
+ ...withoutHash,
1663
+ receipt_hash: sha256Hex(ACTION_RECEIPT_DOMAIN + canonicalJson(withoutHash)),
1664
+ });
1665
+ }
1666
+
1667
+ function buildHostWiringGuide(adapterName, adapter, hookStarter, submitSample) {
1668
+ const filePath = `.intentrax/wiring/${adapterName}-host-wiring.md`;
1669
+ const source = hostWiringGuideSource(adapterName, adapter, hookStarter, submitSample);
1670
+ return Object.freeze({
1671
+ schema_version: HOST_WIRING_GUIDE_SCHEMA_VERSION,
1672
+ file_path: filePath,
1673
+ adapter_name: adapterName,
1674
+ host_runtime: adapter.display_name,
1675
+ hook_surface: adapter.hook_surface,
1676
+ hook_label: adapter.hook_label,
1677
+ hook_file_path: hookStarter.file_path,
1678
+ hook_entrypoint: hookStarter.entrypoint,
1679
+ endpoint: ENDPOINT,
1680
+ tenant_header: TENANT_HEADER,
1681
+ api_key_header: API_KEY_HEADER,
1682
+ idempotency_header: IDEMPOTENCY_HEADER,
1683
+ submit_sample_file_path: submitSample.file_path,
1684
+ guide_hash: hashGeneratedHostWiringSource(source),
1685
+ source,
1686
+ boundary_assertions: {
1687
+ authoritative: false,
1688
+ no_secret_material_written: true,
1689
+ no_tool_execution_inside_admission: true,
1690
+ no_payload_mutation: true,
1691
+ no_policy_re_evaluation: true,
1692
+ no_proof_generation_inside_adapter: true,
1693
+ no_registry_write_performed: true,
1694
+ intentrax_runtime_remains_proof_owner: true,
1695
+ aevn_aep_remains_authoritative: true,
1696
+ },
1697
+ });
1698
+ }
1699
+
1700
+ function hostWiringGuideSource(adapterName, adapter, hookStarter, submitSample) {
1701
+ const hostSnippet = hostWiringSnippet(adapterName, adapter, hookStarter);
1702
+ return [
1703
+ `# Intentrax ${adapter.display_name} Host Wiring`,
1704
+ "",
1705
+ `Generated by \`intentrax init ${adapterName}\`. This guide is a local developer wiring aid and is not canonical evidence.`,
1706
+ "",
1707
+ "## Generated Files",
1708
+ "",
1709
+ `- Hook starter: \`${hookStarter.file_path}\``,
1710
+ `- Hook entrypoint: \`${hookStarter.entrypoint}\``,
1711
+ "- Sample admission request: `.intentrax/sample-admission-request.json`",
1712
+ "- Action receipt: `.intentrax/action-receipt.json`",
1713
+ `- Submit sample: \`${submitSample.file_path}\``,
1714
+ "",
1715
+ "## Runtime Values",
1716
+ "",
1717
+ `- Endpoint: \`${ENDPOINT}\``,
1718
+ `- Tenant header: \`${TENANT_HEADER}\``,
1719
+ `- API key header: \`${API_KEY_HEADER}\` from \`INTENTRAX_API_KEY\``,
1720
+ `- Idempotency header: \`${IDEMPOTENCY_HEADER}\` from the generated admission request`,
1721
+ "",
1722
+ "Set runtime values outside the repo, for example:",
1723
+ "",
1724
+ "```bash",
1725
+ "export INTENTRAX_BASE_URL=\"http://127.0.0.1:8080\"",
1726
+ "export INTENTRAX_API_KEY=\"...\"",
1727
+ "```",
1728
+ "",
1729
+ "## Host Binding",
1730
+ "",
1731
+ hostSnippet,
1732
+ "",
1733
+ "## Local Verification",
1734
+ "",
1735
+ "Run the offline verifier after wiring the host entrypoint:",
1736
+ "",
1737
+ "```bash",
1738
+ "npx @intentrax/sdk check-init --output-dir .",
1739
+ "```",
1740
+ "",
1741
+ "The verifier reads the generated files, imports the hook starter without submitting to the network, checks the hook and wiring hashes, and confirms no tenant credential is required.",
1742
+ "",
1743
+ "## Boundaries",
1744
+ "",
1745
+ "- The adapter submits an admission request only when the host invokes the hook with `submit: true`.",
1746
+ "- Intentrax admission does not execute the tool.",
1747
+ "- The adapter does not mutate prompts, tool arguments, policy results, proof payloads, or registry entries.",
1748
+ "- The adapter does not generate AEP truth or access signing material.",
1749
+ "- The generated Action Receipt is a developer summary only; runtime AEVN/AEP evidence and verifier output remain authoritative.",
1750
+ ].join("\n");
1751
+ }
1752
+
1753
+ function hostWiringSnippet(adapterName, adapter, hookStarter) {
1754
+ const importName = hookStarter.entrypoint;
1755
+ const importPath = `./${hookStarter.file_path}`;
1756
+ const handlerName = hostWiringHandlerName(adapterName);
1757
+ const eventLabel = hostWiringEventLabel(adapterName, adapter);
1758
+ return [
1759
+ `Import the generated module from your ${adapter.hook_label} and call it before the host allows the native action to continue:`,
1760
+ "",
1761
+ "```js",
1762
+ `import { ${importName} } from "${importPath}";`,
1763
+ "",
1764
+ `export async function ${handlerName}(${eventLabel}) {`,
1765
+ ` const result = await ${importName}(${eventLabel}, { submit: true });`,
1766
+ " if (result.admission_response?.admission_allowed === false) {",
1767
+ " throw new Error(\"Intentrax admission denied before host execution.\");",
1768
+ " }",
1769
+ " return result;",
1770
+ "}",
1771
+ "```",
1772
+ "",
1773
+ hostWiringAdapterNote(adapterName, adapter),
1774
+ ].join("\n");
1775
+ }
1776
+
1777
+ function hostWiringHandlerName(adapterName) {
1778
+ switch (adapterName) {
1779
+ case "claude-code":
1780
+ return "intentraxClaudeCodePreToolUse";
1781
+ case "cursor":
1782
+ return "intentraxCursorBeforeShellExecution";
1783
+ case "mcp":
1784
+ return "intentraxMCPBeforeToolCall";
1785
+ case "langchain":
1786
+ return "intentraxLangChainToolStart";
1787
+ case "langgraph":
1788
+ return "intentraxLangGraphNodeTransition";
1789
+ case "vercel-ai-sdk":
1790
+ return "intentraxVercelAIRouteAdmission";
1791
+ default:
1792
+ return `intentrax${toPascalCase(adapterName)}Admission`;
1793
+ }
1794
+ }
1795
+
1796
+ function hostWiringEventLabel(adapterName, adapter) {
1797
+ switch (adapterName) {
1798
+ case "claude-code":
1799
+ return "preToolUseEvent";
1800
+ case "cursor":
1801
+ return "shellExecutionEvent";
1802
+ case "mcp":
1803
+ return "toolCallEvent";
1804
+ case "langchain":
1805
+ return "toolStartEvent";
1806
+ case "langgraph":
1807
+ return "nodeTransitionEvent";
1808
+ case "vercel-ai-sdk":
1809
+ return "routeEvent";
1810
+ default:
1811
+ return `${adapter.hook_surface.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "adapter"}Event`;
1812
+ }
1813
+ }
1814
+
1815
+ function hostWiringAdapterNote(adapterName, adapter) {
1816
+ switch (adapterName) {
1817
+ case "claude-code":
1818
+ return "Use the wrapper from the host's pre-tool-use hook path so the admission decision is evaluated before any tool call proceeds.";
1819
+ case "cursor":
1820
+ return "Use the wrapper from the IDE or shell-execution hook path before command execution or tool invocation continues.";
1821
+ case "mcp":
1822
+ return "Use the wrapper around the MCP `tools/call` boundary before forwarding the call to the upstream tool handler.";
1823
+ case "langchain":
1824
+ return "Use the wrapper from a callback or tool wrapper before the LangChain tool body runs, then attach the returned admission metadata to the run context.";
1825
+ case "langgraph":
1826
+ return "Use the wrapper from node middleware before the node transition commits, then attach the returned admission metadata to checkpoint state.";
1827
+ case "vercel-ai-sdk":
1828
+ return "Use the wrapper inside the route handler before model or tool-side effects proceed, then attach the returned admission metadata to route-scoped evidence.";
1829
+ default:
1830
+ return `Use the wrapper at the ${adapter.hook_label} boundary before native side effects proceed.`;
1831
+ }
1832
+ }
1833
+
1834
+ function toPascalCase(value) {
1835
+ return String(value)
1836
+ .split(/[^A-Za-z0-9]+/)
1837
+ .filter(Boolean)
1838
+ .map((part) => part.slice(0, 1).toUpperCase() + part.slice(1))
1839
+ .join("");
1840
+ }
1841
+
1842
+ function buildHookStarter(adapterName, adapter, sampleAdmissionRequest) {
1843
+ const filePath = `.intentrax/hooks/${adapter.hook_file_name}`;
1844
+ const source = hookSource(adapterName, adapter);
1845
+ return {
1846
+ schema_version: "intentrax.onboarding.agent_adapter_native_hook_starter/1.0",
1847
+ file_path: filePath,
1848
+ adapter_name: adapterName,
1849
+ hook_surface: adapter.hook_surface,
1850
+ hook_label: adapter.hook_label,
1851
+ entrypoint: adapter.hook_entrypoint,
1852
+ native_template_id: adapter.native_template_id ?? "generic_admission_hook_v1",
1853
+ native_event_kind: adapter.native_event_kind ?? "GENERIC_AGENT_EVENT",
1854
+ endpoint: ENDPOINT,
1855
+ tenant_id: sampleAdmissionRequest.tenant_id,
1856
+ surface_id: sampleAdmissionRequest.surface_id,
1857
+ adapter_id: sampleAdmissionRequest.adapter_id,
1858
+ action: sampleAdmissionRequest.action,
1859
+ source_hash: sha256Hex(source),
1860
+ source,
1861
+ boundary_assertions: {
1862
+ no_secret_material_written: true,
1863
+ no_tool_execution_inside_admission: true,
1864
+ no_payload_mutation: true,
1865
+ no_policy_re_evaluation: true,
1866
+ no_proof_generation_inside_adapter: true,
1867
+ no_private_key_material_required: true,
1868
+ intentrax_runtime_remains_proof_owner: true,
1869
+ aevn_aep_remains_authoritative: true,
1870
+ },
1871
+ };
1872
+ }
1873
+
1874
+ function hookSource(adapterName, adapter) {
1875
+ const contract = nativeExportContract(adapter);
1876
+ const metadataExport = contract?.metadata_export ?? "intentraxHookMetadata";
1877
+ return `import { createHash } from "node:crypto";
1878
+ import { readFile } from "node:fs/promises";
1879
+
1880
+ const SAMPLE_ADMISSION_REQUEST_URL = new URL("../sample-admission-request.json", import.meta.url);
1881
+ const ENDPOINT = "${ENDPOINT}";
1882
+ const TENANT_HEADER = "${TENANT_HEADER}";
1883
+ const API_KEY_HEADER = "${API_KEY_HEADER}";
1884
+ const IDEMPOTENCY_HEADER = "${IDEMPOTENCY_HEADER}";
1885
+
1886
+ const hookMetadata = Object.freeze({
1887
+ schema_version: "intentrax.onboarding.agent_adapter_native_hook_starter/1.0",
1888
+ adapter_name: "${adapterName}",
1889
+ display_name: "${adapter.display_name}",
1890
+ hook_surface: "${adapter.hook_surface}",
1891
+ native_template_id: "${adapter.native_template_id ?? "generic_admission_hook_v1"}",
1892
+ native_event_kind: "${adapter.native_event_kind ?? "GENERIC_AGENT_EVENT"}",
1893
+ surface_id: "${adapter.normalized_surface_id}",
1894
+ adapter_id: "${adapter.normalized_adapter_id}",
1895
+ action: "${SAMPLE_ACTION_BY_SURFACE[adapter.normalized_surface_id]}",
1896
+ endpoint: ENDPOINT,
1897
+ boundary_assertions: Object.freeze({
1898
+ no_secret_material_written: true,
1899
+ no_tool_execution_inside_admission: true,
1900
+ no_payload_mutation: true,
1901
+ no_policy_re_evaluation: true,
1902
+ no_proof_generation_inside_adapter: true,
1903
+ intentrax_runtime_remains_proof_owner: true,
1904
+ aevn_aep_remains_authoritative: true,
1905
+ }),
1906
+ });
1907
+
1908
+ export const ${metadataExport} = hookMetadata;
1909
+
1910
+ ${adapter.native_normalizer ? nativeAdapterExportsSource(adapter, contract) : genericAdapterExportsSource(adapter)}
1911
+
1912
+ async function buildNativeHookResult(event = {}, options = {}) {
1913
+ const admission_request = await buildNativeAdmissionForHook(event);
1914
+ const submit = options.submit === true;
1915
+ const admission_response = submit ? await submitNativeAdmission(admission_request, options) : null;
1916
+ return Object.freeze({
1917
+ schema_version: "intentrax.onboarding.agent_adapter_native_hook_result/1.0",
1918
+ adapter_name: hookMetadata.adapter_name,
1919
+ hook_surface: hookMetadata.hook_surface,
1920
+ admission_request,
1921
+ admission_response,
1922
+ original_event_ref: stableNativeHookEventRef(event),
1923
+ submitted: submit,
1924
+ mutation_performed: false,
1925
+ tool_execution_performed: false,
1926
+ proof_generation_performed: false,
1927
+ policy_re_evaluation_performed: false,
1928
+ });
1929
+ }
1930
+
1931
+ async function buildNativeAdmissionForHook(event = {}) {
1932
+ const sample = JSON.parse(await readFile(SAMPLE_ADMISSION_REQUEST_URL, "utf8"));
1933
+ const requestPayloadHash = sha256Hex(canonicalJson({
1934
+ adapter_name: hookMetadata.adapter_name,
1935
+ hook_surface: hookMetadata.hook_surface,
1936
+ original_event_ref: stableNativeHookEventRef(event),
1937
+ }));
1938
+ return Object.freeze({
1939
+ ...sample,
1940
+ request_payload_hash: requestPayloadHash,
1941
+ protocol_payload_ref: \`sha256:\${requestPayloadHash}\`,
1942
+ idempotency_key_hash: sha256Hex("INTENTRAX_AGENT_HOOK_IDEMPOTENCY_V1" + requestPayloadHash),
1943
+ });
1944
+ }
1945
+
1946
+ async function submitNativeAdmission(request, options = {}) {
1947
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch;
1948
+ if (typeof fetchImpl !== "function") {
1949
+ throw new Error("Intentrax hook submission requires fetch or options.fetchImpl.");
1950
+ }
1951
+ const env = runtimeEnv();
1952
+ const apiKey = requiredRuntimeValue(options.apiKey ?? env.INTENTRAX_API_KEY, "INTENTRAX_API_KEY");
1953
+ const baseUrl = String(options.baseUrl ?? env.INTENTRAX_BASE_URL ?? "http://127.0.0.1:8080").replace(/\\/+$/, "");
1954
+ const response = await fetchImpl(baseUrl + ENDPOINT, {
1955
+ method: "POST",
1956
+ headers: {
1957
+ "content-type": "application/json",
1958
+ [TENANT_HEADER]: request.tenant_id,
1959
+ [API_KEY_HEADER]: apiKey,
1960
+ [IDEMPOTENCY_HEADER]: request.idempotency_key_hash,
1961
+ },
1962
+ body: canonicalJson(request),
1963
+ });
1964
+ const text = await response.text();
1965
+ const body = text ? JSON.parse(text) : {};
1966
+ const admissionAllowed = response.ok && body.admission_status === "ADMITTED";
1967
+ const result = Object.freeze({
1968
+ status_code: response.status,
1969
+ ok: response.ok,
1970
+ admission_allowed: admissionAllowed,
1971
+ fail_closed: !admissionAllowed,
1972
+ response_hash: sha256Hex(text),
1973
+ body,
1974
+ });
1975
+ if (!admissionAllowed) {
1976
+ const status = body.admission_status ?? "UNKNOWN";
1977
+ throw new Error(\`Intentrax admission failed closed: http_status=\${response.status} admission_status=\${status}\`);
1978
+ }
1979
+ return result;
1980
+ }
1981
+
1982
+ function stableNativeHookEventRef(event) {
1983
+ return "sha256:" + sha256Hex(canonicalJson({
1984
+ event_type: typeof event,
1985
+ event: sanitizeEvent(event),
1986
+ }));
1987
+ }
1988
+
1989
+ function hashedHookPart(value) {
1990
+ return "sha256:" + sha256Hex(canonicalJson(sanitizeEvent(value ?? {})));
1991
+ }
1992
+
1993
+ function stableText(value, fallback = "") {
1994
+ return typeof value === "string" && value.trim() === value && value.length > 0 ? value : fallback;
1995
+ }
1996
+
1997
+ function firstStableText(values, fallback) {
1998
+ for (const value of values) {
1999
+ const out = stableText(value);
2000
+ if (out) return out;
2001
+ }
2002
+ return fallback;
2003
+ }
2004
+
2005
+ function sanitizedKeys(value) {
2006
+ const sanitized = sanitizeEvent(value);
2007
+ return sanitized !== null && typeof sanitized === "object" && !Array.isArray(sanitized) ? Object.keys(sanitized).sort() : [];
2008
+ }
2009
+
2010
+ function sanitizeEvent(value) {
2011
+ if (value === null || typeof value === "string" || typeof value === "boolean") return value;
2012
+ if (typeof value === "number" && Number.isFinite(value) && Number.isInteger(value)) return value;
2013
+ if (typeof value === "number") return String(value);
2014
+ if (Array.isArray(value)) return value.map(sanitizeEvent);
2015
+ if (typeof value === "object") {
2016
+ const out = {};
2017
+ for (const key of Object.keys(value).sort()) {
2018
+ if (isSensitiveKey(key)) continue;
2019
+ out[key] = sanitizeEvent(value[key]);
2020
+ }
2021
+ return out;
2022
+ }
2023
+ return String(value);
2024
+ }
2025
+
2026
+ function isSensitiveKey(key) {
2027
+ return /secret|token|api[_-]?key|password|private[_-]?key|authorization|cookie|credential|session|bearer|client[_-]?key/i.test(key);
2028
+ }
2029
+
2030
+ function canonicalJson(value) {
2031
+ if (value === null) return "null";
2032
+ if (Array.isArray(value)) return \`[\${value.map(canonicalJson).join(",")}]\`;
2033
+ if (typeof value === "string") return JSON.stringify(value);
2034
+ if (typeof value === "boolean") return value ? "true" : "false";
2035
+ if (typeof value === "number" && Number.isInteger(value) && Number.isFinite(value)) return String(value);
2036
+ if (typeof value === "object") {
2037
+ return \`{\${Object.keys(value).sort().map((key) => \`\${JSON.stringify(key)}:\${canonicalJson(value[key])}\`).join(",")}}\`;
2038
+ }
2039
+ throw new Error("canonical_json: unsupported value");
2040
+ }
2041
+
2042
+ function sha256Hex(value) {
2043
+ return createHash("sha256").update(value, "utf8").digest("hex");
2044
+ }
2045
+
2046
+ function requiredRuntimeValue(value, name) {
2047
+ if (typeof value !== "string" || value.trim() === "") {
2048
+ throw new Error(\`\${name} must be provided at runtime and is never written by intentrax init.\`);
2049
+ }
2050
+ return value;
2051
+ }
2052
+
2053
+ function runtimeEnv() {
2054
+ if (typeof process !== "object" || process === null || typeof process.env !== "object" || process.env === null) {
2055
+ return {};
2056
+ }
2057
+ return process.env;
2058
+ }
2059
+ `;
2060
+ }
2061
+
2062
+ function genericAdapterExportsSource(adapter) {
2063
+ return `export async function ${adapter.hook_entrypoint}(event = {}, options = {}) {
2064
+ return buildIntentraxHookResult(event, options);
2065
+ }
2066
+
2067
+ export async function buildIntentraxHookResult(event = {}, options = {}) {
2068
+ return buildNativeHookResult(event, options);
2069
+ }
2070
+
2071
+ export async function buildIntentraxAdmissionForHook(event = {}) {
2072
+ return buildNativeAdmissionForHook(event);
2073
+ }
2074
+
2075
+ export async function submitIntentraxAdmission(request, options = {}) {
2076
+ return submitNativeAdmission(request, options);
2077
+ }`;
2078
+ }
2079
+
2080
+ function nativeExportContract(adapter) {
2081
+ switch (adapter.native_normalizer) {
2082
+ case "normalizeClaudeCodePreToolUse":
2083
+ return {
2084
+ metadata_export: "intentraxClaudeCodeHookMetadata",
2085
+ result_export: "buildClaudeCodePreToolUseResult",
2086
+ admission_export: "buildClaudeCodePreToolUseAdmission",
2087
+ extract_export: "extractClaudeCodePreToolUseIntent",
2088
+ stable_ref_export: "stableClaudeCodePreToolUseEventRef",
2089
+ submit_export: "submitClaudeCodeAdmission",
2090
+ };
2091
+ case "normalizeCursorShellExecution":
2092
+ return {
2093
+ metadata_export: "intentraxCursorHookMetadata",
2094
+ result_export: "buildCursorShellExecutionResult",
2095
+ admission_export: "buildCursorShellExecutionAdmission",
2096
+ extract_export: "extractCursorShellExecutionIntent",
2097
+ stable_ref_export: "stableCursorShellExecutionEventRef",
2098
+ submit_export: "submitCursorAdmission",
2099
+ };
2100
+ case "normalizeMCPToolCall":
2101
+ return {
2102
+ metadata_export: "intentraxMCPHookMetadata",
2103
+ result_export: "buildMCPToolCallResult",
2104
+ admission_export: "buildMCPToolCallAdmission",
2105
+ extract_export: "extractMCPToolCallIntent",
2106
+ stable_ref_export: "stableMCPToolCallEventRef",
2107
+ submit_export: "submitMCPAdmission",
2108
+ };
2109
+ case "normalizeLangChainCallback":
2110
+ return {
2111
+ metadata_export: "intentraxLangChainHookMetadata",
2112
+ result_export: "buildLangChainToolStartResult",
2113
+ admission_export: "buildLangChainToolStartAdmission",
2114
+ extract_export: "extractLangChainToolStartIntent",
2115
+ stable_ref_export: "stableLangChainRunRef",
2116
+ submit_export: "submitLangChainAdmission",
2117
+ evidence_export: "buildLangChainIntentraxRunMetadata",
2118
+ evidence_kind: "LANGCHAIN_INTENTRAX_RUN_METADATA",
2119
+ };
2120
+ case "normalizeLangGraphNode":
2121
+ return {
2122
+ metadata_export: "intentraxLangGraphHookMetadata",
2123
+ result_export: "buildLangGraphNodeTransitionResult",
2124
+ admission_export: "buildLangGraphNodeTransitionAdmission",
2125
+ extract_export: "extractLangGraphNodeTransitionIntent",
2126
+ stable_ref_export: "stableLangGraphCheckpointRef",
2127
+ submit_export: "submitLangGraphAdmission",
2128
+ evidence_export: "buildLangGraphIntentraxStateEvidence",
2129
+ evidence_kind: "LANGGRAPH_INTENTRAX_STATE_EVIDENCE",
2130
+ };
2131
+ case "normalizeVercelAIRoute":
2132
+ return {
2133
+ metadata_export: "intentraxVercelAISDKHookMetadata",
2134
+ result_export: "buildVercelAIRouteResult",
2135
+ admission_export: "buildVercelAIRouteAdmission",
2136
+ extract_export: "extractVercelAIToolCallIntent",
2137
+ stable_ref_export: "stableVercelAIRouteRef",
2138
+ submit_export: "submitVercelAIAdmission",
2139
+ evidence_export: "buildVercelAIIntentraxResponseMetadata",
2140
+ evidence_kind: "VERCEL_AI_INTENTRAX_RESPONSE_METADATA",
2141
+ };
2142
+ default:
2143
+ return null;
2144
+ }
2145
+ }
2146
+
2147
+ function nativeAdapterExportsSource(adapter, contract) {
2148
+ return `export async function ${adapter.hook_entrypoint}(event = {}, options = {}) {
2149
+ return ${contract.result_export}(event, options);
2150
+ }
2151
+
2152
+ export async function ${contract.result_export}(event = {}, options = {}) {
2153
+ return buildNativeHookResult(${contract.extract_export}(event), options);
2154
+ }
2155
+
2156
+ export async function ${contract.admission_export}(event = {}) {
2157
+ return buildNativeAdmissionForHook(${contract.extract_export}(event));
2158
+ }
2159
+
2160
+ ${nativeNormalizerSource(adapter.native_normalizer, contract.extract_export)}
2161
+
2162
+ export function ${contract.stable_ref_export}(event = {}) {
2163
+ return stableNativeHookEventRef(${contract.extract_export}(event));
2164
+ }
2165
+
2166
+ export async function ${contract.submit_export}(request, options = {}) {
2167
+ return submitNativeAdmission(request, options);
2168
+ }
2169
+
2170
+ ${contract.evidence_export ? nativeEvidenceSource(contract) : ""}`;
2171
+ }
2172
+
2173
+ function nativeEvidenceSource(contract) {
2174
+ return `export function ${contract.evidence_export}(event = {}) {
2175
+ const intent = ${contract.extract_export}(event);
2176
+ return Object.freeze({
2177
+ schema_version: "intentrax.onboarding.agent_adapter_native_evidence/1.0",
2178
+ evidence_kind: "${contract.evidence_kind}",
2179
+ adapter_name: hookMetadata.adapter_name,
2180
+ hook_surface: hookMetadata.hook_surface,
2181
+ event_ref: ${contract.stable_ref_export}(event),
2182
+ intent,
2183
+ });
2184
+ }`;
2185
+ }
2186
+
2187
+ function nativeNormalizerSource(normalizer, exportName) {
2188
+ switch (normalizer) {
2189
+ case "normalizeClaudeCodePreToolUse":
2190
+ return `export function ${exportName}(event = {}) {
2191
+ return Object.freeze({
2192
+ adapter_event_kind: hookMetadata.native_event_kind,
2193
+ adapter_name: hookMetadata.adapter_name,
2194
+ hook_surface: hookMetadata.hook_surface,
2195
+ admission_timing: "BEFORE_CLAUDE_CODE_TOOL_USE",
2196
+ tool_name: firstStableText([event.tool_name, event.toolName, event.name], "unknown_claude_code_tool"),
2197
+ tool_input_keys: sanitizedKeys(event.tool_input ?? event.input ?? event.arguments ?? {}),
2198
+ tool_input_ref: hashedHookPart(event.tool_input ?? event.input ?? event.arguments ?? {}),
2199
+ permission_prompt_ref: hashedHookPart(event.permission_prompt ?? event.prompt ?? {}),
2200
+ raw_event_ref: stableNativeHookEventRef(event),
2201
+ });
2202
+ }`;
2203
+ case "normalizeCursorShellExecution":
2204
+ return `export function ${exportName}(event = {}) {
2205
+ return Object.freeze({
2206
+ adapter_event_kind: hookMetadata.native_event_kind,
2207
+ adapter_name: hookMetadata.adapter_name,
2208
+ hook_surface: hookMetadata.hook_surface,
2209
+ admission_timing: "BEFORE_CURSOR_SHELL_EXECUTION",
2210
+ shell: firstStableText([event.shell, event.shell_name, event.terminal], "cursor_shell"),
2211
+ command_ref: hashedHookPart(event.command ?? event.shell_command ?? event.args ?? {}),
2212
+ workspace_ref: hashedHookPart({ cwd: event.cwd, workspace: event.workspace, workspace_id: event.workspace_id }),
2213
+ raw_event_ref: stableNativeHookEventRef(event),
2214
+ });
2215
+ }`;
2216
+ case "normalizeMCPToolCall":
2217
+ return `export function ${exportName}(event = {}) {
2218
+ return Object.freeze({
2219
+ adapter_event_kind: hookMetadata.native_event_kind,
2220
+ adapter_name: hookMetadata.adapter_name,
2221
+ hook_surface: hookMetadata.hook_surface,
2222
+ admission_timing: "BEFORE_MCP_TOOL_CALL",
2223
+ server_name: firstStableText([event.server_name, event.serverName, event.server?.name], "unknown_mcp_server"),
2224
+ tool_name: firstStableText([event.tool_name, event.toolName, event.name], "unknown_mcp_tool"),
2225
+ argument_keys: sanitizedKeys(event.arguments ?? event.args ?? event.input ?? {}),
2226
+ argument_ref: hashedHookPart(event.arguments ?? event.args ?? event.input ?? {}),
2227
+ raw_event_ref: stableNativeHookEventRef(event),
2228
+ });
2229
+ }`;
2230
+ case "normalizeLangChainCallback":
2231
+ return `export function ${exportName}(event = {}) {
2232
+ return Object.freeze({
2233
+ adapter_event_kind: hookMetadata.native_event_kind,
2234
+ adapter_name: hookMetadata.adapter_name,
2235
+ hook_surface: hookMetadata.hook_surface,
2236
+ admission_timing: "BEFORE_LANGCHAIN_TOOL_OR_CHAIN",
2237
+ run_type: firstStableText([event.run_type, event.type, event.serialized?.name], "langchain_callback"),
2238
+ tool_name: firstStableText([event.tool_name, event.name, event.serialized?.id], "unknown_langchain_tool"),
2239
+ input_ref: hashedHookPart(event.input ?? event.inputs ?? event.arguments ?? {}),
2240
+ metadata_ref: hashedHookPart(event.metadata ?? event.tags ?? {}),
2241
+ raw_event_ref: stableNativeHookEventRef(event),
2242
+ });
2243
+ }`;
2244
+ case "normalizeLangGraphNode":
2245
+ return `export function ${exportName}(event = {}) {
2246
+ return Object.freeze({
2247
+ adapter_event_kind: hookMetadata.native_event_kind,
2248
+ adapter_name: hookMetadata.adapter_name,
2249
+ hook_surface: hookMetadata.hook_surface,
2250
+ admission_timing: "BEFORE_LANGGRAPH_NODE",
2251
+ graph_name: firstStableText([event.graph_name, event.graphName, event.graph?.name], "langgraph_graph"),
2252
+ node_name: firstStableText([event.node_name, event.nodeName, event.name], "unknown_langgraph_node"),
2253
+ state_ref: hashedHookPart(event.state ?? event.input ?? event.messages ?? {}),
2254
+ config_ref: hashedHookPart(event.config ?? event.runtime ?? {}),
2255
+ raw_event_ref: stableNativeHookEventRef(event),
2256
+ });
2257
+ }`;
2258
+ case "normalizeVercelAIRoute":
2259
+ return `export function ${exportName}(event = {}) {
2260
+ return Object.freeze({
2261
+ adapter_event_kind: hookMetadata.native_event_kind,
2262
+ adapter_name: hookMetadata.adapter_name,
2263
+ hook_surface: hookMetadata.hook_surface,
2264
+ admission_timing: "BEFORE_VERCEL_AI_SDK_GENERATION",
2265
+ route_ref: hashedHookPart({ method: event.method, path: event.path, url: event.url }),
2266
+ model_ref: hashedHookPart(event.model ?? event.provider ?? {}),
2267
+ prompt_ref: hashedHookPart(event.prompt ?? event.messages ?? event.body ?? {}),
2268
+ raw_event_ref: stableNativeHookEventRef(event),
2269
+ });
2270
+ }`;
2271
+ default:
2272
+ throw new Error(`unknown native normalizer: ${normalizer}`);
2273
+ }
2274
+ }
2275
+
2276
+ function buildSubmitSample(sampleAdmissionRequest, options) {
2277
+ const baseUrl = options.baseUrl.replace(/\/+$/, "");
2278
+ const url = baseUrl + ENDPOINT;
2279
+ const workingDirectory = options.outputDir ? resolve(options.outputDir) : ".";
2280
+ const bodyFile = ".intentrax/sample-admission-request.json";
2281
+ const filePath = ".intentrax/submit_sample.curl";
2282
+ const headers = {
2283
+ "content-type": "application/json",
2284
+ [TENANT_HEADER]: sampleAdmissionRequest.tenant_id,
2285
+ [API_KEY_HEADER]: "$INTENTRAX_API_KEY",
2286
+ [IDEMPOTENCY_HEADER]: sampleAdmissionRequest.idempotency_key_hash,
2287
+ };
2288
+ return {
2289
+ schema_version: "intentrax.onboarding.agent_adapter_submit_sample/1.0",
2290
+ method: "POST",
2291
+ url,
2292
+ headers,
2293
+ file_path: filePath,
2294
+ body_file: bodyFile,
2295
+ working_directory: workingDirectory,
2296
+ curl: buildCurl(url, headers, bodyFile),
2297
+ };
2298
+ }
2299
+
2300
+ function buildCurl(url, headers, bodyFile) {
2301
+ return [
2302
+ "curl -sS",
2303
+ quote(url),
2304
+ "-H",
2305
+ quote(`content-type: ${headers["content-type"]}`),
2306
+ "-H",
2307
+ quote(`${TENANT_HEADER}: ${headers[TENANT_HEADER]}`),
2308
+ "-H",
2309
+ quote(`${API_KEY_HEADER}: ${headers[API_KEY_HEADER]}`),
2310
+ "-H",
2311
+ quote(`${IDEMPOTENCY_HEADER}: ${headers[IDEMPOTENCY_HEADER]}`),
2312
+ "--data-binary",
2313
+ quote(`@${bodyFile}`),
2314
+ ].join(" ");
2315
+ }
2316
+
2317
+ function quote(value) {
2318
+ return JSON.stringify(value);
2319
+ }
2320
+
2321
+ function canonicalJson(value) {
2322
+ if (value === null) return "null";
2323
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
2324
+ if (typeof value === "string") return JSON.stringify(value);
2325
+ if (typeof value === "boolean") return value ? "true" : "false";
2326
+ if (typeof value === "number" && Number.isInteger(value) && Number.isFinite(value)) return String(value);
2327
+ if (typeof value === "object") {
2328
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(",")}}`;
2329
+ }
2330
+ throw new Error("canonical_json: unsupported value");
2331
+ }
2332
+
2333
+ function sha256Hex(value) {
2334
+ return createHash("sha256").update(value, "utf8").digest("hex");
2335
+ }
2336
+
2337
+ function sha256HexBytes(value) {
2338
+ return createHash("sha256").update(value).digest("hex");
2339
+ }
2340
+
2341
+ function normalizeSHA256Hex(value, field) {
2342
+ const normalized = String(value || "").trim().toLowerCase().replace(/^sha256:/, "");
2343
+ if (!/^[a-f0-9]{64}$/.test(normalized)) {
2344
+ fail(`${field}: malformed SHA-256 hex`);
2345
+ }
2346
+ return normalized;
2347
+ }
2348
+
2349
+ function requireValue(args, index, option) {
2350
+ const value = args[index];
2351
+ if (!value) {
2352
+ fail(`${option} requires a value`);
2353
+ }
2354
+ return value;
2355
+ }
2356
+
2357
+ function fail(message) {
2358
+ console.error(`intentrax: ${message}`);
2359
+ printHelp();
2360
+ process.exit(2);
2361
+ }
2362
+
2363
+ function printHelp() {
2364
+ console.log(`Intentrax CLI ${VERSION}
2365
+
2366
+ Usage:
2367
+ intentrax init <adapter> [--dry-run] [--force] [--json] [--output-dir <dir>] [--base-url <url>] [--tenant-id <tenant>]
2368
+ intentrax check-init --output-dir <dir> [--json]
2369
+ intentrax verify-proof <proof-export.json> [--json] [--report-out <file>]
2370
+ intentrax verify-pdf-receipt <receipt.pdf> --pdf-hash <X-Intentrax-PDF-Hash> [--json] [--report-out <file>]
2371
+
2372
+ Adapters:
2373
+ ${Object.keys(ADAPTERS).join(", ")}
2374
+
2375
+ Aliases:
2376
+ generic-mcp -> mcp
2377
+
2378
+ Init verification:
2379
+ check-init verifies an initialized .intentrax adapter directory offline,
2380
+ recomputes hook and action receipt bindings, validates the generated Agent
2381
+ Gateway admission fixture, and invokes the generated hook without
2382
+ INTENTRAX_API_KEY or network submission.
2383
+
2384
+ Proof export verification:
2385
+ verify-proof reads an exported registry-backed proof lookup JSON package,
2386
+ recomputes its proof lookup, proof record, and verification bundle hashes,
2387
+ rejects private key material markers, and writes a deterministic offline
2388
+ report. Runtime access, network access, and private keys are not required.
2389
+ The JSON export is authoritative; PDF receipts are human-readable companions.
2390
+
2391
+ PDF receipt verification:
2392
+ verify-pdf-receipt reads downloaded PDF receipt bytes, checks the PDF header,
2393
+ recomputes SHA-256, and compares it with the X-Intentrax-PDF-Hash response
2394
+ header. This validates the companion PDF bytes only; the canonical JSON proof
2395
+ export and AEP evidence remain authoritative.
2396
+
2397
+ Examples:
2398
+ intentrax init claude-code --dry-run
2399
+ intentrax init cursor --output-dir .
2400
+ intentrax init cursor --output-dir . --force
2401
+ intentrax init mcp --json
2402
+ intentrax init generic-mcp --dry-run
2403
+ intentrax init langchain
2404
+ intentrax init langgraph
2405
+ intentrax init vercel-ai-sdk
2406
+ intentrax check-init --output-dir . --json
2407
+ intentrax verify-proof .intentrax-runtime/pilot-local-sovereign/local-sovereign-proof-export.json --report-out .intentrax/offline-proof-verification.report.json
2408
+ intentrax verify-pdf-receipt .intentrax/proof-001-aep-receipt.pdf --pdf-hash <X-Intentrax-PDF-Hash>
2409
+ `);
2410
+ }
2411
+
2412
+ process.exitCode = await main(process.argv.slice(2));