@fusionkit/protocol 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/api.d.ts +106 -0
  2. package/dist/api.js +6 -0
  3. package/dist/chain.d.ts +14 -0
  4. package/dist/chain.js +49 -0
  5. package/dist/constants.d.ts +25 -0
  6. package/dist/constants.js +36 -0
  7. package/dist/contract.d.ts +6 -0
  8. package/dist/contract.js +32 -0
  9. package/dist/execution.d.ts +67 -0
  10. package/dist/execution.js +27 -0
  11. package/dist/generated/model-fusion-openapi.d.ts +44 -0
  12. package/dist/generated/model-fusion-openapi.js +23 -0
  13. package/dist/hash.d.ts +10 -0
  14. package/dist/hash.js +31 -0
  15. package/dist/index.d.ts +42 -0
  16. package/dist/index.js +30 -0
  17. package/dist/jcs.d.ts +14 -0
  18. package/dist/jcs.js +49 -0
  19. package/dist/keys.d.ts +14 -0
  20. package/dist/keys.js +36 -0
  21. package/dist/model-fusion.d.ts +167 -0
  22. package/dist/model-fusion.js +596 -0
  23. package/dist/receipt-story.d.ts +27 -0
  24. package/dist/receipt-story.js +127 -0
  25. package/dist/receipt.d.ts +20 -0
  26. package/dist/receipt.js +162 -0
  27. package/dist/test/model-fusion.test.d.ts +1 -0
  28. package/dist/test/model-fusion.test.js +213 -0
  29. package/dist/test/protocol.test.d.ts +1 -0
  30. package/dist/test/protocol.test.js +240 -0
  31. package/dist/test/tool-executor.test.d.ts +1 -0
  32. package/dist/test/tool-executor.test.js +86 -0
  33. package/dist/test/trace.test.d.ts +1 -0
  34. package/dist/test/trace.test.js +75 -0
  35. package/dist/tool-executor.d.ts +58 -0
  36. package/dist/tool-executor.js +80 -0
  37. package/dist/trace.d.ts +119 -0
  38. package/dist/trace.js +248 -0
  39. package/dist/types.d.ts +375 -0
  40. package/dist/types.js +14 -0
  41. package/dist/validators.d.ts +7 -0
  42. package/dist/validators.js +32 -0
  43. package/dist/vocabulary.d.ts +12 -0
  44. package/dist/vocabulary.js +79 -0
  45. package/package.json +27 -0
package/dist/api.d.ts ADDED
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Wire-level API contracts shared by the plane (server), SDK (client),
3
+ * runner, handoff SDK, CLI, and control panel. These are data contracts,
4
+ * not behavior: the plane implements them, everything else consumes them.
5
+ */
6
+ import type { ActorRef, ChainedEvent, ContinuationRef, DisclosureMode, RunContract, RunStatus, SecretClaim, SessionIsolation } from "./types.js";
7
+ import type { ExecutionSpec } from "./execution.js";
8
+ /** A run request as accepted by `POST /v1/runs`. */
9
+ export type RunRequest = {
10
+ runId: string;
11
+ requestedBy: ActorRef;
12
+ agentKind: string;
13
+ agentVersion?: string;
14
+ prompt: string;
15
+ pool: string;
16
+ secretNames: string[];
17
+ workspace: RunContract["workspace"];
18
+ network: RunContract["network"];
19
+ budget: RunContract["budget"];
20
+ disclosure: DisclosureMode;
21
+ /** Durable machine intent. Defaults from agent/prompt for legacy callers. */
22
+ execution?: ExecutionSpec;
23
+ /** Requested session isolation. Defaults to "process". */
24
+ isolation?: SessionIsolation;
25
+ /** Present when the run continues prior work from a handoff envelope. */
26
+ continuation?: ContinuationRef;
27
+ };
28
+ export type RunRequestInput = Omit<RunRequest, "runId">;
29
+ /** Outcome of policy evaluation at contract time. */
30
+ export type PolicyDecision = {
31
+ decision: "allow" | "ask";
32
+ reason: string;
33
+ consentRequirements: string[];
34
+ };
35
+ /** `dryRun` output: the full disclosure report, with nothing moved. */
36
+ export type DisclosureReport = {
37
+ dryRun: true;
38
+ agent: {
39
+ kind: string;
40
+ version?: string;
41
+ };
42
+ pool: string;
43
+ workspace: {
44
+ baseRef: string;
45
+ bundleHash: string;
46
+ dirtyDiffHash?: string;
47
+ untrackedPaths: string[];
48
+ deniedPaths: string[];
49
+ };
50
+ secrets: SecretClaim[];
51
+ network: {
52
+ defaultDeny: boolean;
53
+ allowHosts: string[];
54
+ };
55
+ budget: {
56
+ maxSpendUsd?: number;
57
+ maxDurationMin?: number;
58
+ };
59
+ disclosure: string;
60
+ execution?: ExecutionSpec;
61
+ isolation?: SessionIsolation;
62
+ continuation?: ContinuationRef;
63
+ policyDecision: PolicyDecision;
64
+ };
65
+ /** What a runner receives when it claims a contract. */
66
+ export type ClaimResult = {
67
+ runId: string;
68
+ contract: RunContract;
69
+ claimToken: string;
70
+ events: ChainedEvent[];
71
+ secrets: {
72
+ name: string;
73
+ value: string;
74
+ }[];
75
+ };
76
+ /** Detailed view of a single run, as returned by `GET /v1/runs/:id`. */
77
+ export type RunView = {
78
+ runId: string;
79
+ status: RunStatus;
80
+ createdAt: string;
81
+ updatedAt: string;
82
+ consentRequirements: string[];
83
+ failureMessage?: string;
84
+ events: ChainedEvent[];
85
+ };
86
+ /** Row in the run list, as returned by `GET /v1/runs`. */
87
+ export type RunSummary = {
88
+ runId: string;
89
+ status: RunStatus;
90
+ agentKind: string;
91
+ pool: string;
92
+ prompt: string;
93
+ requestedBy: ActorRef;
94
+ createdAt: string;
95
+ updatedAt: string;
96
+ consentRequirements: string[];
97
+ hasReceipt: boolean;
98
+ continuation?: ContinuationRef;
99
+ };
100
+ /** Row in the runner list, as returned by `GET /v1/runners`. */
101
+ export type RunnerSummary = {
102
+ runnerId: string;
103
+ pool: string;
104
+ keyId: string;
105
+ enrolledAt: string;
106
+ };
package/dist/api.js ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Wire-level API contracts shared by the plane (server), SDK (client),
3
+ * runner, handoff SDK, CLI, and control panel. These are data contracts,
4
+ * not behavior: the plane implements them, everything else consumes them.
5
+ */
6
+ export {};
@@ -0,0 +1,14 @@
1
+ import type { ChainedEvent, RunEvent } from "./types.js";
2
+ /**
3
+ * Append an event to a hash chain. The genesis event's `prev` is the
4
+ * contract hash, which ties the whole chain to the signed contract.
5
+ */
6
+ export declare function appendEvent(chain: ChainedEvent[], event: RunEvent, genesisPrev: string, now?: () => string): ChainedEvent;
7
+ export type ChainVerification = {
8
+ ok: true;
9
+ } | {
10
+ ok: false;
11
+ brokenAtSeq: number;
12
+ reason: string;
13
+ };
14
+ export declare function verifyChain(events: ChainedEvent[], genesisPrev: string): ChainVerification;
package/dist/chain.js ADDED
@@ -0,0 +1,49 @@
1
+ import { hashCanonical } from "./hash.js";
2
+ function eventHash(input) {
3
+ return hashCanonical(input);
4
+ }
5
+ /**
6
+ * Append an event to a hash chain. The genesis event's `prev` is the
7
+ * contract hash, which ties the whole chain to the signed contract.
8
+ */
9
+ export function appendEvent(chain, event, genesisPrev, now = () => new Date().toISOString()) {
10
+ const last = chain[chain.length - 1];
11
+ const seq = last ? last.seq + 1 : 0;
12
+ const prev = last ? last.hash : genesisPrev;
13
+ const ts = now();
14
+ const chained = {
15
+ version: "warrant.event.v1",
16
+ seq,
17
+ ts,
18
+ prev,
19
+ event,
20
+ hash: eventHash({ seq, ts, prev, event })
21
+ };
22
+ chain.push(chained);
23
+ return chained;
24
+ }
25
+ export function verifyChain(events, genesisPrev) {
26
+ let expectedPrev = genesisPrev;
27
+ for (let i = 0; i < events.length; i++) {
28
+ const entry = events[i];
29
+ if (!entry)
30
+ return { ok: false, brokenAtSeq: i, reason: "missing entry" };
31
+ if (entry.seq !== i) {
32
+ return { ok: false, brokenAtSeq: i, reason: "sequence gap" };
33
+ }
34
+ if (entry.prev !== expectedPrev) {
35
+ return { ok: false, brokenAtSeq: i, reason: "prev hash mismatch" };
36
+ }
37
+ const recomputed = eventHash({
38
+ seq: entry.seq,
39
+ ts: entry.ts,
40
+ prev: entry.prev,
41
+ event: entry.event
42
+ });
43
+ if (recomputed !== entry.hash) {
44
+ return { ok: false, brokenAtSeq: i, reason: "event hash mismatch" };
45
+ }
46
+ expectedPrev = entry.hash;
47
+ }
48
+ return { ok: true };
49
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Versioned schema identifiers and shared enumerations, referenced instead
3
+ * of inlining string literals across packages. The literal-typed `as const`
4
+ * values still satisfy the corresponding `version: "..."` fields.
5
+ */
6
+ export { ACTOR_KINDS, AGENT_KINDS, CHECKPOINT_TIERS, DISCLOSURE_MODES, HEX_HASH_PATTERN, isAgentKind, isTerminalStatus, RUN_EVENT_TYPES, RUN_STATUSES, SESSION_ISOLATIONS, TERMINAL_RUN_STATUSES } from "./vocabulary.js";
7
+ export declare const PROTOCOL_VERSIONS: {
8
+ readonly contract: "warrant.contract.v1";
9
+ readonly receipt: "warrant.receipt.v1";
10
+ readonly event: "warrant.event.v1";
11
+ readonly manifest: "warrant.manifest.v1";
12
+ readonly policy: "warrant.policy.v1";
13
+ readonly checkpoint: "warrant.checkpoint.v1";
14
+ readonly envelope: "warrant.envelope.v1";
15
+ readonly bundle: "warrant.bundle.v1";
16
+ readonly toolJournal: "warrant.tooljournal.v1";
17
+ readonly sealed: "warrant.sealed.v1";
18
+ };
19
+ export declare const MODEL_FUSION_SCHEMA_NAMES: readonly ["model-call-record.v1", "harness-run-request.v1", "harness-run-result.v1", "harness-candidate-record.v1", "judge-synthesis-record.v1", "benchmark-task-record.v1", "artifact-ref.v1", "tool-call-plan.v1", "tool-execution-record.v1", "ensemble-receipt.v1"];
20
+ /**
21
+ * Length (in hex characters) of the public-key fingerprint embedded in a
22
+ * key id. 16 hex = 64 bits of a SHA-256 digest: ample collision resistance
23
+ * for identifying enrolled keys while keeping ids short and readable.
24
+ */
25
+ export declare const KEY_ID_HEX_LENGTH = 16;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Versioned schema identifiers and shared enumerations, referenced instead
3
+ * of inlining string literals across packages. The literal-typed `as const`
4
+ * values still satisfy the corresponding `version: "..."` fields.
5
+ */
6
+ export { ACTOR_KINDS, AGENT_KINDS, CHECKPOINT_TIERS, DISCLOSURE_MODES, HEX_HASH_PATTERN, isAgentKind, isTerminalStatus, RUN_EVENT_TYPES, RUN_STATUSES, SESSION_ISOLATIONS, TERMINAL_RUN_STATUSES } from "./vocabulary.js";
7
+ export const PROTOCOL_VERSIONS = {
8
+ contract: "warrant.contract.v1",
9
+ receipt: "warrant.receipt.v1",
10
+ event: "warrant.event.v1",
11
+ manifest: "warrant.manifest.v1",
12
+ policy: "warrant.policy.v1",
13
+ checkpoint: "warrant.checkpoint.v1",
14
+ envelope: "warrant.envelope.v1",
15
+ bundle: "warrant.bundle.v1",
16
+ toolJournal: "warrant.tooljournal.v1",
17
+ sealed: "warrant.sealed.v1"
18
+ };
19
+ export const MODEL_FUSION_SCHEMA_NAMES = [
20
+ "model-call-record.v1",
21
+ "harness-run-request.v1",
22
+ "harness-run-result.v1",
23
+ "harness-candidate-record.v1",
24
+ "judge-synthesis-record.v1",
25
+ "benchmark-task-record.v1",
26
+ "artifact-ref.v1",
27
+ "tool-call-plan.v1",
28
+ "tool-execution-record.v1",
29
+ "ensemble-receipt.v1"
30
+ ];
31
+ /**
32
+ * Length (in hex characters) of the public-key fingerprint embedded in a
33
+ * key id. 16 hex = 64 bits of a SHA-256 digest: ample collision resistance
34
+ * for identifying enrolled keys while keeping ids short and readable.
35
+ */
36
+ export const KEY_ID_HEX_LENGTH = 16;
@@ -0,0 +1,6 @@
1
+ import type { RunContract, Signature } from "./types.js";
2
+ /** Content hash of a contract, excluding signatures. */
3
+ export declare function contractHash(contract: RunContract): string;
4
+ export declare function signContract(contract: RunContract, privateKeyPem: string, publicKeyPem: string, signer: Signature["signer"]): RunContract;
5
+ export type KeyResolver = (keyId: string) => string | undefined;
6
+ export declare function verifyContractSignature(contract: RunContract, signer: Signature["signer"], resolvePublicKeyPem: KeyResolver): boolean;
@@ -0,0 +1,32 @@
1
+ import { hashCanonical } from "./hash.js";
2
+ import { keyIdFromPublicPem, signData, verifyData } from "./keys.js";
3
+ function signablePayload(contract) {
4
+ const { signatures: _signatures, ...unsigned } = contract;
5
+ return hashCanonical(unsigned);
6
+ }
7
+ /** Content hash of a contract, excluding signatures. */
8
+ export function contractHash(contract) {
9
+ return signablePayload(contract);
10
+ }
11
+ export function signContract(contract, privateKeyPem, publicKeyPem, signer) {
12
+ const payload = signablePayload(contract);
13
+ const signature = {
14
+ keyId: keyIdFromPublicPem(publicKeyPem),
15
+ alg: "ed25519",
16
+ signer,
17
+ sig: signData(privateKeyPem, payload)
18
+ };
19
+ return { ...contract, signatures: [...contract.signatures, signature] };
20
+ }
21
+ export function verifyContractSignature(contract, signer, resolvePublicKeyPem) {
22
+ const payload = signablePayload(contract);
23
+ const signature = contract.signatures.find((s) => s.signer === signer);
24
+ if (!signature)
25
+ return false;
26
+ const publicKeyPem = resolvePublicKeyPem(signature.keyId);
27
+ if (!publicKeyPem)
28
+ return false;
29
+ if (keyIdFromPublicPem(publicKeyPem) !== signature.keyId)
30
+ return false;
31
+ return verifyData(publicKeyPem, payload, signature.sig);
32
+ }
@@ -0,0 +1,67 @@
1
+ import type { AgentSpec } from "./types.js";
2
+ export type ExecutionEnv = {
3
+ /** Ambient variables intentionally inherited by name. */
4
+ inherit?: string[];
5
+ /** Secret store names mapped onto validated environment variable names. */
6
+ secrets?: {
7
+ env: string;
8
+ secretName: string;
9
+ }[];
10
+ /** Non-secret literal environment values. */
11
+ vars?: Record<string, string>;
12
+ /** Whether the runner should inject its governed egress proxy. */
13
+ egressProxy?: boolean;
14
+ };
15
+ export type ExecutionLogPolicy = {
16
+ stdout: "capture";
17
+ stderr: "merge" | "capture";
18
+ /** Maximum captured bytes before the backend terminates the execution. */
19
+ maxBytes?: number;
20
+ };
21
+ export type ExecutionSpec = {
22
+ kind: "shell";
23
+ script: string;
24
+ shell?: "sh" | "bash";
25
+ /** Workspace-relative directory. Defaults to ".". */
26
+ cwd?: string;
27
+ timeoutMs?: number;
28
+ env?: ExecutionEnv;
29
+ log?: ExecutionLogPolicy;
30
+ } | {
31
+ kind: "argv";
32
+ command: string;
33
+ args: string[];
34
+ /** Workspace-relative directory. Defaults to ".". */
35
+ cwd?: string;
36
+ timeoutMs?: number;
37
+ env?: ExecutionEnv;
38
+ log?: ExecutionLogPolicy;
39
+ } | {
40
+ kind: "agent";
41
+ agent: AgentSpec;
42
+ prompt: string;
43
+ timeoutMs?: number;
44
+ env?: ExecutionEnv;
45
+ log?: ExecutionLogPolicy;
46
+ };
47
+ /**
48
+ * The default execution intent for an agent and task when a request or
49
+ * contract carries no explicit `execution`: the "command" harness runs the
50
+ * task as one governed shell command; every other harness receives the
51
+ * task as its prompt. This is the single defaulting rule shared by the
52
+ * plane (contract issue + dry run), the handoff SDK, and the runner.
53
+ */
54
+ export declare function defaultExecutionSpec(agent: AgentSpec, prompt: string): ExecutionSpec;
55
+ /**
56
+ * Resolve the execution intent of a run request: the explicit `execution`
57
+ * when present, otherwise the shared default. The `agentKind` cast is the
58
+ * one sanctioned place a request's free-form agent string becomes an
59
+ * `AgentSpec`: the schema deliberately leaves it unconstrained so the
60
+ * policy engine (not parsing) decides permissibility.
61
+ */
62
+ export declare function executionFromRunRequest(request: {
63
+ agentKind: string;
64
+ agentVersion?: string;
65
+ prompt: string;
66
+ execution?: ExecutionSpec;
67
+ }): ExecutionSpec;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The default execution intent for an agent and task when a request or
3
+ * contract carries no explicit `execution`: the "command" harness runs the
4
+ * task as one governed shell command; every other harness receives the
5
+ * task as its prompt. This is the single defaulting rule shared by the
6
+ * plane (contract issue + dry run), the handoff SDK, and the runner.
7
+ */
8
+ export function defaultExecutionSpec(agent, prompt) {
9
+ if (agent.kind === "command")
10
+ return { kind: "shell", script: prompt };
11
+ return { kind: "agent", agent, prompt };
12
+ }
13
+ /**
14
+ * Resolve the execution intent of a run request: the explicit `execution`
15
+ * when present, otherwise the shared default. The `agentKind` cast is the
16
+ * one sanctioned place a request's free-form agent string becomes an
17
+ * `AgentSpec`: the schema deliberately leaves it unconstrained so the
18
+ * policy engine (not parsing) decides permissibility.
19
+ */
20
+ export function executionFromRunRequest(request) {
21
+ if (request.execution)
22
+ return request.execution;
23
+ return defaultExecutionSpec({
24
+ kind: request.agentKind,
25
+ ...(request.agentVersion ? { version: request.agentVersion } : {})
26
+ }, request.prompt);
27
+ }
@@ -0,0 +1,44 @@
1
+ import type { JsonValue } from "../jcs.js";
2
+ export declare const MODEL_FUSION_OPENAPI_SOURCE_HASH: "sha256:346c92f11550ae61a8571972f5db0be8bd5b479984a779d48e42fccf9cd929cb";
3
+ export declare const MODEL_FUSION_HARNESS_EXECUTOR_PATH: "/v1/harness-executions";
4
+ export type ModelFusionOpenApiPersistedJsonRecord = {
5
+ "schema": string;
6
+ "schema_version": "v1";
7
+ "schema_bundle_hash": string;
8
+ "persisted_json": Record<string, JsonValue>;
9
+ };
10
+ export type ModelFusionOpenApiArtifactRef = {
11
+ "artifact_id": string;
12
+ "kind": string;
13
+ "hash": string;
14
+ "redaction_status"?: "synthetic" | "redacted" | "raw";
15
+ };
16
+ export type ModelFusionOpenApiHarnessExecutionRequest = {
17
+ "request_id": string;
18
+ "task_id": string;
19
+ "source_repo": string;
20
+ "base_git_sha": string;
21
+ "harness_kind": string;
22
+ "prompt_hash": string;
23
+ "allowed_tools": string[];
24
+ "side_effects": string;
25
+ "harness_run_request": ModelFusionOpenApiPersistedJsonRecord;
26
+ };
27
+ export type ModelFusionOpenApiHarnessExecutionResult = {
28
+ "request_id": string;
29
+ "result_id": string;
30
+ "status": string;
31
+ "candidate_ids": string[];
32
+ "artifacts"?: ModelFusionOpenApiArtifactRef[];
33
+ "harness_run_result": ModelFusionOpenApiPersistedJsonRecord;
34
+ };
35
+ export type ModelFusionOpenApiErrorResponse = {
36
+ "error": string;
37
+ "code"?: string;
38
+ };
39
+ export type ExecuteHarnessTaskClientOptions = {
40
+ baseUrl: string;
41
+ fetch?: typeof fetch;
42
+ headers?: Record<string, string>;
43
+ };
44
+ export declare function executeHarnessTask(options: ExecuteHarnessTaskClientOptions, request: ModelFusionOpenApiHarnessExecutionRequest): Promise<ModelFusionOpenApiHarnessExecutionResult>;
@@ -0,0 +1,23 @@
1
+ /* eslint-disable */
2
+ // Generated by scripts/generate-model-fusion-openapi-sdk.mjs. Do not edit by hand.
3
+ // Source: packages/protocol/openapi/model-fusion-harness-executor.openapi.json
4
+ // Source hash: sha256:346c92f11550ae61a8571972f5db0be8bd5b479984a779d48e42fccf9cd929cb
5
+ export const MODEL_FUSION_OPENAPI_SOURCE_HASH = "sha256:346c92f11550ae61a8571972f5db0be8bd5b479984a779d48e42fccf9cd929cb";
6
+ export const MODEL_FUSION_HARNESS_EXECUTOR_PATH = "/v1/harness-executions";
7
+ export async function executeHarnessTask(options, request) {
8
+ const doFetch = options.fetch ?? fetch;
9
+ const response = await doFetch(new URL(MODEL_FUSION_HARNESS_EXECUTOR_PATH, options.baseUrl), {
10
+ method: "POST",
11
+ headers: {
12
+ "content-type": "application/json",
13
+ ...(options.headers ?? {})
14
+ },
15
+ body: JSON.stringify(request)
16
+ });
17
+ const body = (await response.json());
18
+ if (!response.ok) {
19
+ const error = body;
20
+ throw new Error(error.error ?? `executeHarnessTask failed with status ${response.status}`);
21
+ }
22
+ return body;
23
+ }
package/dist/hash.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ export declare const SHA256_PREFIX = "sha256:";
2
+ export declare function sha256Hex(data: string | Buffer): string;
3
+ export declare function sha256PrefixedHex(data: string | Buffer): string;
4
+ /** Content hash of a protocol object: sha256 over its canonical JSON. */
5
+ export declare function hashCanonical(value: unknown): string;
6
+ export declare function hashCanonicalSha256(value: unknown): string;
7
+ export declare function requestHash(value: unknown): string;
8
+ export declare function responseHash(value: unknown): string;
9
+ export declare function artifactHash(data: string | Buffer): string;
10
+ export declare function schemaBundleHash(schemas: Record<string, unknown>): string;
package/dist/hash.js ADDED
@@ -0,0 +1,31 @@
1
+ import { createHash } from "node:crypto";
2
+ import { canonicalize } from "./jcs.js";
3
+ export const SHA256_PREFIX = "sha256:";
4
+ export function sha256Hex(data) {
5
+ return createHash("sha256").update(data).digest("hex");
6
+ }
7
+ export function sha256PrefixedHex(data) {
8
+ return `${SHA256_PREFIX}${sha256Hex(data)}`;
9
+ }
10
+ /** Content hash of a protocol object: sha256 over its canonical JSON. */
11
+ export function hashCanonical(value) {
12
+ return sha256Hex(canonicalize(value));
13
+ }
14
+ export function hashCanonicalSha256(value) {
15
+ return sha256PrefixedHex(canonicalize(value));
16
+ }
17
+ export function requestHash(value) {
18
+ return hashCanonicalSha256(value);
19
+ }
20
+ export function responseHash(value) {
21
+ return hashCanonicalSha256(value);
22
+ }
23
+ export function artifactHash(data) {
24
+ return sha256PrefixedHex(data);
25
+ }
26
+ export function schemaBundleHash(schemas) {
27
+ const payload = Object.entries(schemas)
28
+ .sort(([left], [right]) => left.localeCompare(right))
29
+ .map(([path, schema]) => ({ path, schema }));
30
+ return hashCanonicalSha256(payload);
31
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @fusionkit/protocol — the open, versioned data contracts of the Warrant
3
+ * platform plus the primitives needed to create and verify them offline:
4
+ *
5
+ * - warrant.contract.v1 signed run authorization
6
+ * - warrant.receipt.v1 signed record of what actually happened
7
+ * - warrant.event.v1 hash-chained event log
8
+ * - warrant.manifest.v1 workspace capture manifest
9
+ * - warrant.policy.v1 org policy snapshot
10
+ * - warrant.checkpoint.v1 resumable state at a semantic boundary
11
+ * - warrant.envelope.v1 portable continuation (handoff) description
12
+ *
13
+ * Everything here is stable protocol surface: packages should consume these
14
+ * interfaces instead of recreating local string lists or proof logic.
15
+ */
16
+ export { ACTOR_KINDS, AGENT_KINDS, CHECKPOINT_TIERS, DISCLOSURE_MODES, HEX_HASH_PATTERN, isAgentKind, isTerminalStatus, MODEL_FUSION_SCHEMA_NAMES, PROTOCOL_VERSIONS, RUN_EVENT_TYPES, RUN_STATUSES, SESSION_ISOLATIONS, TERMINAL_RUN_STATUSES } from "./constants.js";
17
+ export { parseHostAllowlistEntry, parsePoolName, parseSecretName, parseWorkspaceManifestPath } from "./validators.js";
18
+ export { defaultExecutionSpec, executionFromRunRequest } from "./execution.js";
19
+ export type { ExecutionEnv, ExecutionLogPolicy, ExecutionSpec } from "./execution.js";
20
+ export { evaluateToolPolicy, modelFusionSideEffects, toolArgumentsHash, toolCallKey, toolSideEffectClassFromModelFusion } from "./tool-executor.js";
21
+ export type { ToolDefinition, ToolExecutionRequest, ToolExecutionResult, ToolExecutorBudget, ToolExecutorContract, ToolExecutorLimits, ToolExecutorMode, ToolPolicyDecision, ToolSideEffectClass } from "./tool-executor.js";
22
+ export { canonicalize } from "./jcs.js";
23
+ export type { JsonValue } from "./jcs.js";
24
+ export { artifactHash, hashCanonical, hashCanonicalSha256, requestHash, responseHash, schemaBundleHash, SHA256_PREFIX, sha256Hex, sha256PrefixedHex } from "./hash.js";
25
+ export { MODEL_FUSION_SCHEMA_BUNDLE_HASH, assertArtifactRefV1, assertBenchmarkTaskRecordV1, assertEnsembleReceiptV1, assertHarnessCandidateRecordV1, assertHarnessRunRequestV1, assertHarnessRunResultV1, assertJudgeSynthesisRecordV1, assertModelCallRecordV1, assertModelFusionRecord, assertToolCallPlanV1, assertToolExecutionRecordV1 } from "./model-fusion.js";
26
+ export { executeHarnessTask, MODEL_FUSION_HARNESS_EXECUTOR_PATH, MODEL_FUSION_OPENAPI_SOURCE_HASH } from "./generated/model-fusion-openapi.js";
27
+ export type { ExecuteHarnessTaskClientOptions, ModelFusionOpenApiArtifactRef, ModelFusionOpenApiErrorResponse, ModelFusionOpenApiHarnessExecutionRequest, ModelFusionOpenApiHarnessExecutionResult, ModelFusionOpenApiPersistedJsonRecord } from "./generated/model-fusion-openapi.js";
28
+ export type { ArtifactRefV1, ArtifactRef, BenchmarkScorer, BenchmarkScorerKind, BenchmarkSourceRepo, BenchmarkTaskKind, BenchmarkTaskRecordV1, ContractMetadataV1, EnsembleReceiptV1, HarnessCandidateRecordV1, HarnessRunRequestV1, HarnessRunResultV1, JudgeSynthesisDecision, JudgeSynthesisRecordV1, ModelCallRecordV1, ModelFusionArtifactKind, ModelFusionCapabilityStatus, ModelFusionChatMessage, ModelFusionChatRole, ModelFusionError, ModelFusionErrorKind, ModelFusionHarnessKind, ModelFusionRecordV1, ModelFusionRedactionStatus, ModelFusionSchemaName, ModelFusionSideEffects, ModelFusionStatus, ModelFusionUsage, ToolCallPlanV1, ToolExecutionRecordV1 } from "./model-fusion.js";
29
+ export { generateEd25519KeyPair, keyIdFromPublicPem, signData, verifyData } from "./keys.js";
30
+ export type { KeyPairPem } from "./keys.js";
31
+ export { contractHash, signContract } from "./contract.js";
32
+ export { appendEvent, verifyChain } from "./chain.js";
33
+ export type { ChainVerification } from "./chain.js";
34
+ export { signReceipt, verifyReceiptBundle, verifyRunnerReceipt } from "./receipt.js";
35
+ export type { BundleVerification } from "./receipt.js";
36
+ export { buildReceiptStory, summarizeRunEvent } from "./receipt-story.js";
37
+ export type { EventSummary, ReceiptStory } from "./receipt-story.js";
38
+ export { ambientTraceId, assertFusionTraceEvent, emitTrace, FUSION_TRACE_COMPONENTS, FUSION_TRACE_EVENT_SCHEMA, FUSION_TRACE_EVENT_TYPES, FUSION_TRACE_EVENT_VERSION, getTraceEmitter, isFusionTraceEvent, judgeFinalPayload, judgeRequestPayload, judgeThinkingPayload, modelCallFinishedPayload, modelCallStartedPayload, newSpanId, newTraceId, TRACE_CANDIDATE_HEADER, TRACE_ID_HEADER, TRACE_PARENT_SPAN_HEADER, TRACE_SPAN_HEADER, TraceEmitter } from "./trace.js";
39
+ export type { EmitInput, FusionTraceComponent, FusionTraceEvent, FusionTraceEventType } from "./trace.js";
40
+ export { PolicyDeniedError } from "./types.js";
41
+ export type { ActorRef, AgentKind, AgentSpec, ArtifactKind, AttestationTier, BudgetSpec, ChainedEvent, Checkpoint, CheckpointTier, ConsentRule, ContinuationRef, DataClassRule, DisclosureMode, DisclosureRecord, FailureClass, HandoffEnvelope, HandoffSource, HandoffTargetRef, KeyRef, ManifestFile, ModelUsageRecord, NetworkAccessRecord, NetworkPolicy, Policy, Receipt, ReceiptBundle, RetentionPolicy, RunContract, RunEvent, RunnerIdentity, RunnerSelector, RunStatus, SecretClaim, SecretReleaseRecord, SecretScopeRule, SemanticState, SessionIsolation, Signature, TaskSpec, ToolCallRecord, ToolJournal, WorkspaceManifest } from "./types.js";
42
+ export type { ClaimResult, DisclosureReport, PolicyDecision, RunnerSummary, RunRequest, RunRequestInput, RunSummary, RunView } from "./api.js";
package/dist/index.js ADDED
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @fusionkit/protocol — the open, versioned data contracts of the Warrant
3
+ * platform plus the primitives needed to create and verify them offline:
4
+ *
5
+ * - warrant.contract.v1 signed run authorization
6
+ * - warrant.receipt.v1 signed record of what actually happened
7
+ * - warrant.event.v1 hash-chained event log
8
+ * - warrant.manifest.v1 workspace capture manifest
9
+ * - warrant.policy.v1 org policy snapshot
10
+ * - warrant.checkpoint.v1 resumable state at a semantic boundary
11
+ * - warrant.envelope.v1 portable continuation (handoff) description
12
+ *
13
+ * Everything here is stable protocol surface: packages should consume these
14
+ * interfaces instead of recreating local string lists or proof logic.
15
+ */
16
+ export { ACTOR_KINDS, AGENT_KINDS, CHECKPOINT_TIERS, DISCLOSURE_MODES, HEX_HASH_PATTERN, isAgentKind, isTerminalStatus, MODEL_FUSION_SCHEMA_NAMES, PROTOCOL_VERSIONS, RUN_EVENT_TYPES, RUN_STATUSES, SESSION_ISOLATIONS, TERMINAL_RUN_STATUSES } from "./constants.js";
17
+ export { parseHostAllowlistEntry, parsePoolName, parseSecretName, parseWorkspaceManifestPath } from "./validators.js";
18
+ export { defaultExecutionSpec, executionFromRunRequest } from "./execution.js";
19
+ export { evaluateToolPolicy, modelFusionSideEffects, toolArgumentsHash, toolCallKey, toolSideEffectClassFromModelFusion } from "./tool-executor.js";
20
+ export { canonicalize } from "./jcs.js";
21
+ export { artifactHash, hashCanonical, hashCanonicalSha256, requestHash, responseHash, schemaBundleHash, SHA256_PREFIX, sha256Hex, sha256PrefixedHex } from "./hash.js";
22
+ export { MODEL_FUSION_SCHEMA_BUNDLE_HASH, assertArtifactRefV1, assertBenchmarkTaskRecordV1, assertEnsembleReceiptV1, assertHarnessCandidateRecordV1, assertHarnessRunRequestV1, assertHarnessRunResultV1, assertJudgeSynthesisRecordV1, assertModelCallRecordV1, assertModelFusionRecord, assertToolCallPlanV1, assertToolExecutionRecordV1 } from "./model-fusion.js";
23
+ export { executeHarnessTask, MODEL_FUSION_HARNESS_EXECUTOR_PATH, MODEL_FUSION_OPENAPI_SOURCE_HASH } from "./generated/model-fusion-openapi.js";
24
+ export { generateEd25519KeyPair, keyIdFromPublicPem, signData, verifyData } from "./keys.js";
25
+ export { contractHash, signContract } from "./contract.js";
26
+ export { appendEvent, verifyChain } from "./chain.js";
27
+ export { signReceipt, verifyReceiptBundle, verifyRunnerReceipt } from "./receipt.js";
28
+ export { buildReceiptStory, summarizeRunEvent } from "./receipt-story.js";
29
+ export { ambientTraceId, assertFusionTraceEvent, emitTrace, FUSION_TRACE_COMPONENTS, FUSION_TRACE_EVENT_SCHEMA, FUSION_TRACE_EVENT_TYPES, FUSION_TRACE_EVENT_VERSION, getTraceEmitter, isFusionTraceEvent, judgeFinalPayload, judgeRequestPayload, judgeThinkingPayload, modelCallFinishedPayload, modelCallStartedPayload, newSpanId, newTraceId, TRACE_CANDIDATE_HEADER, TRACE_ID_HEADER, TRACE_PARENT_SPAN_HEADER, TRACE_SPAN_HEADER, TraceEmitter } from "./trace.js";
30
+ export { PolicyDeniedError } from "./types.js";
package/dist/jcs.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * RFC 8785 (JSON Canonicalization Scheme) subset sufficient for Warrant
3
+ * protocol objects: members sorted by UTF-16 code units, ES number
4
+ * serialization (delegated to JSON.stringify, which implements the
5
+ * ECMA-262 algorithm JCS mandates), and no insignificant whitespace.
6
+ *
7
+ * Kept dependency-free on purpose: the offline verifier's canonicalizer is
8
+ * the most trust-critical code in the repo, so it is auditable in full here
9
+ * rather than delegated to a third-party canonicalization library.
10
+ */
11
+ export type JsonValue = null | boolean | number | string | JsonValue[] | {
12
+ [key: string]: JsonValue;
13
+ };
14
+ export declare function canonicalize(value: unknown): string;
package/dist/jcs.js ADDED
@@ -0,0 +1,49 @@
1
+ /**
2
+ * RFC 8785 (JSON Canonicalization Scheme) subset sufficient for Warrant
3
+ * protocol objects: members sorted by UTF-16 code units, ES number
4
+ * serialization (delegated to JSON.stringify, which implements the
5
+ * ECMA-262 algorithm JCS mandates), and no insignificant whitespace.
6
+ *
7
+ * Kept dependency-free on purpose: the offline verifier's canonicalizer is
8
+ * the most trust-critical code in the repo, so it is auditable in full here
9
+ * rather than delegated to a third-party canonicalization library.
10
+ */
11
+ export function canonicalize(value) {
12
+ if (value === null)
13
+ return "null";
14
+ switch (typeof value) {
15
+ case "boolean":
16
+ return value ? "true" : "false";
17
+ case "number": {
18
+ if (!Number.isFinite(value)) {
19
+ throw new Error("non-finite numbers are not representable in JCS");
20
+ }
21
+ // RFC 8785 specifies ECMAScript Number::toString for number output,
22
+ // which is exactly what JSON.stringify produces for a finite number;
23
+ // delegating here is correct, not a shortcut.
24
+ return JSON.stringify(value);
25
+ }
26
+ case "string":
27
+ return JSON.stringify(value);
28
+ case "object": {
29
+ if (Array.isArray(value)) {
30
+ return `[${value.map((item) => canonicalize(item === undefined ? null : item)).join(",")}]`;
31
+ }
32
+ const record = value;
33
+ const keys = Object.keys(record)
34
+ .filter((key) => record[key] !== undefined)
35
+ .sort();
36
+ const members = keys.map((key) => `${JSON.stringify(key)}:${canonicalize(record[key])}`);
37
+ return `{${members.join(",")}}`;
38
+ }
39
+ case "undefined":
40
+ case "function":
41
+ case "symbol":
42
+ case "bigint":
43
+ throw new Error(`type ${typeof value} is not representable in JCS`);
44
+ default: {
45
+ const exhausted = typeof value;
46
+ throw new Error(`unreachable: ${String(exhausted)}`);
47
+ }
48
+ }
49
+ }
package/dist/keys.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export type KeyPairPem = {
2
+ publicKeyPem: string;
3
+ privateKeyPem: string;
4
+ };
5
+ export declare function generateEd25519KeyPair(): KeyPairPem;
6
+ /**
7
+ * Stable identifier for a public key: the algorithm tag plus a truncated
8
+ * SHA-256 fingerprint of its PEM. The fingerprint length is a deliberate,
9
+ * shared constant (KEY_ID_HEX_LENGTH) — 64 bits is ample to identify an
10
+ * enrolled key while keeping ids short.
11
+ */
12
+ export declare function keyIdFromPublicPem(publicKeyPem: string): string;
13
+ export declare function signData(privateKeyPem: string, data: string | Buffer): string;
14
+ export declare function verifyData(publicKeyPem: string, data: string | Buffer, signatureB64: string): boolean;