@getorrery/client 0.0.0-stage → 0.2.2

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,94 @@
1
+ /**
2
+ * Orrery Cloud's event stream (platform decision 0024, plan 14 "Events"):
3
+ * `GET /api/v1/events` as Server-Sent Events, account-scoped. Each event names
4
+ * what changed (ids and a version, never content); a client re-reads it
5
+ * through the routes it already uses. `reset` means refresh everything.
6
+ *
7
+ * - [`SseParser`]: `text/event-stream` text in, events out, chunk by chunk
8
+ * (the ADE feeds it what its Rust side reads; a browser feeds it `fetch`'s body).
9
+ * - [`cloudEvents`]: the `fetch`-streaming client (headers, so not `EventSource`):
10
+ * the token in `Authorization`, never the query, and `Last-Event-ID` to resume.
11
+ * - [`backoffMs`]: the reconnect delay, 1 s doubling to 30 s.
12
+ *
13
+ * Browser-safe: `fetch`, `ReadableStream` and `TextDecoder` only.
14
+ */
15
+ /** One server-sent event. `event` is `message` when the block named none. */
16
+ export interface SseEvent {
17
+ id?: string;
18
+ event: string;
19
+ data: string;
20
+ }
21
+ /**
22
+ * An incremental `text/event-stream` parser (the WHATWG rules that matter
23
+ * here): `\n`, `\r\n` or `\r` end a line, a blank line ends an event, `:` lines
24
+ * are comments (Cloud's `: ping`), `data:` lines join with `\n`, `id:` is kept
25
+ * as [`lastEventId`] for the reconnect.
26
+ */
27
+ export declare class SseParser {
28
+ /** The last `id:` seen: what `Last-Event-ID` sends back. */
29
+ lastEventId: string | undefined;
30
+ private buffer;
31
+ private event;
32
+ private data;
33
+ private id;
34
+ /** Feed text; get the events it completed. */
35
+ push(text: string): SseEvent[];
36
+ private line;
37
+ }
38
+ /** What a Cloud event names (plan 14 "Events"). Unknown kinds are dropped by [`cloudEventOf`]. */
39
+ export type CloudEvent = {
40
+ kind: "machine";
41
+ machine_id: string;
42
+ host_id?: string;
43
+ version?: number;
44
+ } | {
45
+ kind: "host";
46
+ host_id: string;
47
+ version?: number;
48
+ } | {
49
+ kind: "session";
50
+ session_id: string;
51
+ machine_id: string;
52
+ change: "started" | "state" | "title" | "ended" | "deleted" | string;
53
+ version?: number;
54
+ } | {
55
+ kind: "lease";
56
+ session_id: string;
57
+ machine_id: string;
58
+ epoch: number;
59
+ handoff_id?: string;
60
+ version?: number;
61
+ } | {
62
+ kind: "config";
63
+ keys: string[];
64
+ machine_id?: string;
65
+ version?: number;
66
+ } | {
67
+ kind: "reset";
68
+ };
69
+ /** An SSE event as a [`CloudEvent`], or `null` for a kind or body this client does not know. */
70
+ export declare function cloudEventOf(e: SseEvent): CloudEvent | null;
71
+ /** The wait before reconnect attempt `attempt` (0-based): 1 s, 2 s, 4 s … at most 30 s. */
72
+ export declare function backoffMs(attempt: number, firstMs?: number, maxMs?: number): number;
73
+ /** `GET /events` refused: `status` 401 means sign in again. */
74
+ export declare class CloudEventsError extends Error {
75
+ readonly status: number;
76
+ constructor(message: string, status: number);
77
+ }
78
+ export interface CloudEventsOptions {
79
+ /** `https://cloud/api/v1/events`. */
80
+ url: string;
81
+ /** A person or client token: sent as `Authorization: Bearer`. */
82
+ token: string;
83
+ /** Resume after this event (`Last-Event-ID`). */
84
+ lastEventId?: string;
85
+ signal?: AbortSignal;
86
+ /** `fetch` (the global one when absent). */
87
+ fetch?: typeof fetch;
88
+ }
89
+ /**
90
+ * Read Cloud's event stream until it ends, the signal aborts, or it breaks
91
+ * (thrown). Every event carries the `id` to resume from. A refusal throws a
92
+ * [`CloudEventsError`] with the status.
93
+ */
94
+ export declare function cloudEvents(options: CloudEventsOptions): AsyncGenerator<SseEvent>;
@@ -0,0 +1,14 @@
1
+ import {
2
+ CloudEventsError,
3
+ SseParser,
4
+ backoffMs,
5
+ cloudEventOf,
6
+ cloudEvents
7
+ } from "./chunk-P3UGNLD6.js";
8
+ export {
9
+ CloudEventsError,
10
+ SseParser,
11
+ backoffMs,
12
+ cloudEventOf,
13
+ cloudEvents
14
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The fixture runner's disk half: Node only, exported from `@getorrery/client/node`.
3
+ */
4
+ import { type Scenario } from "./conformance.js";
5
+ export * from "./conformance.js";
6
+ /** Where the fixtures live, relative to this package. */
7
+ export declare function fixturesDir(): string;
8
+ /** Load one scenario file. Throws naming the file and the line. */
9
+ export declare function load(path: string): Scenario;
10
+ /** Load every `*.jsonl` scenario in a directory, sorted by name. */
11
+ export declare function loadAll(dir?: string): Scenario[];
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The fixture runner, shared by every TypeScript client.
3
+ *
4
+ * Browser-safe: this half parses a scenario from its text and replays it.
5
+ * Reading the fixtures from disk (`load`, `loadAll`, `fixturesDir`) is in
6
+ * `@getorrery/client/node`; a browser bundles the files' text instead.
7
+ *
8
+ * `sdk-ts` runs these and so does Ink (plan 09c). The **same files** the Rust
9
+ * SDK runs: a scenario only one language checks is a scenario that has stopped
10
+ * being a contract.
11
+ */
12
+ import { type Frame } from "./events.js";
13
+ import { type StoreState, SurfaceStore } from "./store.js";
14
+ /** One line of a scenario. */
15
+ export type Step = {
16
+ kind: "event";
17
+ frame: Frame;
18
+ }
19
+ /** A frame this build cannot even parse. It still consumes its `seq`. */
20
+ | {
21
+ kind: "unknown";
22
+ seq: number;
23
+ what: string;
24
+ } | {
25
+ kind: "expect";
26
+ state: StoreState;
27
+ };
28
+ /** One fixture file. */
29
+ export interface Scenario {
30
+ name: string;
31
+ path: string;
32
+ steps: Step[];
33
+ }
34
+ /** Parse one scenario from its text. Throws naming the file and the line. */
35
+ export declare function parse(text: string, name: string, path?: string): Scenario;
36
+ /** The frames of a scenario, in order: what a fixture-backed fake connection plays. */
37
+ export declare function framesOf(scenario: Scenario): Frame[];
38
+ /**
39
+ * How many scenarios there are — the whole set, exactly.
40
+ *
41
+ * The twin of `orrery_client::conformance::SCENARIO_COUNT`. Every client
42
+ * asserts this number rather than a floor of its own; two floors is how
43
+ * fixtures get deleted and only one suite notices.
44
+ *
45
+ * It counts the `*.jsonl` files in `clients/conformance` and nothing below it:
46
+ * `conformance/streams/` holds `ModelEvent` scripts for the fixture provider,
47
+ * not AG-UI scenarios for a renderer, and `loadAll` is deliberately not
48
+ * recursive.
49
+ */
50
+ export declare const SCENARIO_COUNT = 68;
51
+ /** Every checkpoint in a scenario, with the store as it stood at each. */
52
+ export declare function checkpoints(scenario: Scenario): Array<{
53
+ index: number;
54
+ actual: StoreState;
55
+ expected: StoreState;
56
+ }>;
57
+ /** Replay a scenario and hand back the store it produced. */
58
+ export declare function replay(scenario: Scenario): SurfaceStore;
@@ -0,0 +1,173 @@
1
+ /**
2
+ * The AG-UI events this client understands, and the frame that carries our seq.
3
+ *
4
+ * The tags come from `@ag-ui/core`'s own `EventType`, not from a list retyped
5
+ * here: that is what makes "an existing AG-UI client works unmodified" checkable
6
+ * rather than asserted. The surface half comes from `@getorrery/protocol`, which is
7
+ * generated from `orrery-proto`. Nothing in this file is a hand-written frame
8
+ * type.
9
+ */
10
+ import { EventType } from "@ag-ui/core";
11
+ import type { Outcome, SurfaceKind } from "@getorrery/protocol";
12
+ /** The `Custom` name a consent prompt rides under. */
13
+ export declare const CONSENT_REQUEST = "orrery.consent.request";
14
+ /** The `Custom` name a consent resolution rides under. */
15
+ export declare const CONSENT_RESOLVED = "orrery.consent.resolved";
16
+ /** The `Custom` name a turn's cancellation rides under. */
17
+ export declare const TURN_CANCELLED = "orrery.turn.cancelled";
18
+ /**
19
+ * The `Custom` name a placement rides under (decisions 0086, 0088): the
20
+ * `Placed` fields, its `surface`, and `text`, its text form, for a client that
21
+ * draws no panes. The store does not keep it; the UI document holds the same.
22
+ */
23
+ export declare const PLACED = "orrery.placed";
24
+ /** The `Custom` name a placement's removal rides under: `{id, owner}`. */
25
+ export declare const UNPLACED = "orrery.unplaced";
26
+ /**
27
+ * One RFC 6902 op, and nothing else (harness decision 0072): a stock AG-UI
28
+ * client drops a delta holding an op it does not know. Streamed text is an
29
+ * `add` onto `…/kind/chunks`, which the store folds into `kind.value`.
30
+ */
31
+ export type PatchOp = {
32
+ op: "replace";
33
+ path: string;
34
+ value: unknown;
35
+ } | {
36
+ op: "add";
37
+ path: string;
38
+ value: unknown;
39
+ } | {
40
+ op: "remove";
41
+ path: string;
42
+ };
43
+ /** An AG-UI event, as `orrery-agui` encodes it. */
44
+ export type AguiEvent = {
45
+ type: typeof EventType.RUN_STARTED;
46
+ threadId: string;
47
+ runId: string;
48
+ } | {
49
+ type: typeof EventType.RUN_FINISHED;
50
+ threadId: string;
51
+ runId: string;
52
+ result?: unknown;
53
+ outcome?: {
54
+ type: string;
55
+ };
56
+ usage?: unknown[];
57
+ } | {
58
+ type: typeof EventType.RUN_ERROR;
59
+ message: string;
60
+ code?: string | null;
61
+ result?: unknown;
62
+ usage?: unknown[];
63
+ } | {
64
+ type: typeof EventType.STEP_STARTED;
65
+ stepName: string;
66
+ } | {
67
+ type: typeof EventType.STEP_FINISHED;
68
+ stepName: string;
69
+ } | {
70
+ type: typeof EventType.TEXT_MESSAGE_START;
71
+ messageId: string;
72
+ role: string;
73
+ /** The extension segment this message belongs to (decision 0076 §3). */
74
+ subagentRunId?: string;
75
+ } | {
76
+ type: typeof EventType.TEXT_MESSAGE_CONTENT;
77
+ messageId: string;
78
+ delta: string;
79
+ } | {
80
+ type: typeof EventType.TEXT_MESSAGE_END;
81
+ messageId: string;
82
+ } | {
83
+ type: typeof EventType.TOOL_CALL_START;
84
+ toolCallId: string;
85
+ toolCallName: string;
86
+ parentMessageId?: string;
87
+ subagentRunId?: string;
88
+ } | {
89
+ type: typeof EventType.TOOL_CALL_ARGS;
90
+ toolCallId: string;
91
+ delta: string;
92
+ } | {
93
+ type: typeof EventType.TOOL_CALL_END;
94
+ toolCallId: string;
95
+ } | {
96
+ type: typeof EventType.TOOL_CALL_RESULT;
97
+ messageId: string;
98
+ toolCallId: string;
99
+ content: string;
100
+ outcome?: Outcome;
101
+ } | {
102
+ type: typeof EventType.REASONING_START;
103
+ messageId: string;
104
+ timestamp?: number;
105
+ } | {
106
+ type: typeof EventType.REASONING_MESSAGE_START;
107
+ messageId: string;
108
+ role: string;
109
+ } | {
110
+ type: typeof EventType.REASONING_MESSAGE_CONTENT;
111
+ messageId: string;
112
+ delta: string;
113
+ } | {
114
+ type: typeof EventType.REASONING_MESSAGE_END;
115
+ messageId: string;
116
+ } | {
117
+ type: typeof EventType.REASONING_END;
118
+ messageId: string;
119
+ timestamp?: number;
120
+ } | {
121
+ type: typeof EventType.SUBAGENT_STARTED;
122
+ subagentRunId: string;
123
+ /** `<ext>.model` or `<ext>.agent`. */
124
+ name: string;
125
+ description?: string;
126
+ parentToolCallId?: string;
127
+ } | {
128
+ type: typeof EventType.SUBAGENT_FINISHED;
129
+ subagentRunId: string;
130
+ result?: unknown;
131
+ outcome?: {
132
+ type: string;
133
+ };
134
+ } | {
135
+ type: typeof EventType.SUBAGENT_ERROR;
136
+ subagentRunId: string;
137
+ message: string;
138
+ code?: string | null;
139
+ } | {
140
+ type: typeof EventType.STATE_SNAPSHOT;
141
+ snapshot: unknown;
142
+ } | {
143
+ type: typeof EventType.STATE_DELTA;
144
+ delta: PatchOp[];
145
+ } | {
146
+ type: typeof EventType.CUSTOM;
147
+ name: string;
148
+ value: Record<string, unknown>;
149
+ };
150
+ /**
151
+ * An AG-UI event with our `seq` on it.
152
+ *
153
+ * `seq` is assigned once, per session, at the differ's output — never per
154
+ * connection — so it is on the frame rather than implied by the order a socket
155
+ * happened to deliver things in. `mergedFrom` is the first seq a coalesced
156
+ * frame stands for, without which a merge and a lost frame look the same.
157
+ */
158
+ export type Frame = AguiEvent & {
159
+ seq: number;
160
+ merged_from?: number;
161
+ };
162
+ /**
163
+ * A frame as it arrives, made a [`Frame`]: Orrery's extras ride in AG-UI's
164
+ * `metadata.orrery` on the wire (`seq`, `merged_from`, a tool result's
165
+ * `outcome`, a failed run's `result`) and sit beside the event here. A frame
166
+ * recorded with them beside the event already passes through. `null` when it
167
+ * carries no `seq`, so is not a frame.
168
+ */
169
+ export declare function frameOf(raw: unknown): Frame | null;
170
+ /** The first sequence number a frame accounts for. */
171
+ export declare function firstSeq(frame: Frame): number;
172
+ /** A surface kind we can still name after a patch has been applied to it. */
173
+ export type Kind = SurfaceKind;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * `@getorrery/client` — an AG-UI session and a `SurfaceStore`. Pure data, no drawing.
3
+ *
4
+ * The same two types as `clients/sdk-rs`, against the same conformance fixtures.
5
+ * The session half sits on stock `@ag-ui/client`, which is what makes "existing
6
+ * AG-UI clients work unmodified" a thing this repo checks rather than claims.
7
+ *
8
+ * ## Browser-safe
9
+ *
10
+ * This entry imports nothing from `node:` (checked by `test/entry.test.ts`), so
11
+ * a web page, the ADE's webview and a phone bundle it as is. What needs Node —
12
+ * the `orrery-client/1` channel over `ORRERY_ENDPOINT`, and reading the
13
+ * conformance fixtures from disk — is `@getorrery/client/node`.
14
+ *
15
+ * ## Transports
16
+ *
17
+ * `AguiSession` runs over a [`Transport`]: HTTP + SSE (`orrery serve` today)
18
+ * or WebSocket (the node's listener and the relay, one frame per message).
19
+ *
20
+ * ## A client never writes state
21
+ *
22
+ * AG-UI's shared state is bidirectional by design; ours is not. `StateSnapshot`
23
+ * and `StateDelta` flow outward only, and an edit a person makes arrives back as
24
+ * an `intent` the kernel validates. Anyone porting a component that expects to
25
+ * write state directly needs to know that.
26
+ *
27
+ * Implementation plan: `harness/docs/plans/08-protocol-transport.md`
28
+ */
29
+ export * from "./events.js";
30
+ export * from "./anim.js";
31
+ export * from "./store.js";
32
+ export * from "./transport.js";
33
+ export { HttpSseTransport, type HttpTransportOptions, sse } from "./transport-http.js";
34
+ export { WebSocketTransport, type WebSocketCtor, type WebSocketLike, type WebSocketTransportOptions, } from "./transport-ws.js";
35
+ export * from "./session.js";
36
+ export * from "./workspace.js";
37
+ export * from "./kept.js";
38
+ export * from "./cloud-events.js";
39
+ export * as conformance from "./conformance.js";
package/dist/index.js ADDED
@@ -0,0 +1,112 @@
1
+ import {
2
+ AGUI_PROTOCOL_VERSION,
3
+ ANIM,
4
+ AguiSession,
5
+ CONSENT_REQUEST,
6
+ CONSENT_RESOLVED,
7
+ ControlError,
8
+ DETACHED_TURN,
9
+ FrameHub,
10
+ HttpSseTransport,
11
+ MAX_FILE_BYTES,
12
+ MAX_MESSAGE_BYTES,
13
+ MOVED,
14
+ NOTICES,
15
+ OUT_OF_ORDER,
16
+ PLACED,
17
+ SESSION_CHANGES,
18
+ STATE_CHANGED,
19
+ SurfaceStore,
20
+ TURN_CANCELLED,
21
+ UNPLACED,
22
+ USER_MESSAGE,
23
+ WORKSPACE_COMMIT,
24
+ WORKSPACE_PUSH,
25
+ WORKSPACE_READ,
26
+ WORKSPACE_READ_CAP_BYTES,
27
+ WebSocketTransport,
28
+ afterOf,
29
+ choosingLine,
30
+ conformance_exports,
31
+ filePart,
32
+ firstSeq,
33
+ formatAddress,
34
+ frameOf,
35
+ framesOf,
36
+ keptTranscript,
37
+ movedOf,
38
+ parseAddress,
39
+ parseAnim,
40
+ parseEndpoint,
41
+ readKept,
42
+ resumeFrom,
43
+ sse,
44
+ thoughtMs,
45
+ workspaceCommit,
46
+ workspaceErrorCode,
47
+ workspacePush,
48
+ workspaceRead,
49
+ workspaceRequest
50
+ } from "./chunk-RQUTHT7N.js";
51
+ import {
52
+ CloudEventsError,
53
+ SseParser,
54
+ backoffMs,
55
+ cloudEventOf,
56
+ cloudEvents
57
+ } from "./chunk-P3UGNLD6.js";
58
+ export {
59
+ AGUI_PROTOCOL_VERSION,
60
+ ANIM,
61
+ AguiSession,
62
+ CONSENT_REQUEST,
63
+ CONSENT_RESOLVED,
64
+ CloudEventsError,
65
+ ControlError,
66
+ DETACHED_TURN,
67
+ FrameHub,
68
+ HttpSseTransport,
69
+ MAX_FILE_BYTES,
70
+ MAX_MESSAGE_BYTES,
71
+ MOVED,
72
+ NOTICES,
73
+ OUT_OF_ORDER,
74
+ PLACED,
75
+ SESSION_CHANGES,
76
+ STATE_CHANGED,
77
+ SseParser,
78
+ SurfaceStore,
79
+ TURN_CANCELLED,
80
+ UNPLACED,
81
+ USER_MESSAGE,
82
+ WORKSPACE_COMMIT,
83
+ WORKSPACE_PUSH,
84
+ WORKSPACE_READ,
85
+ WORKSPACE_READ_CAP_BYTES,
86
+ WebSocketTransport,
87
+ afterOf,
88
+ backoffMs,
89
+ choosingLine,
90
+ cloudEventOf,
91
+ cloudEvents,
92
+ conformance_exports as conformance,
93
+ filePart,
94
+ firstSeq,
95
+ formatAddress,
96
+ frameOf,
97
+ framesOf,
98
+ keptTranscript,
99
+ movedOf,
100
+ parseAddress,
101
+ parseAnim,
102
+ parseEndpoint,
103
+ readKept,
104
+ resumeFrom,
105
+ sse,
106
+ thoughtMs,
107
+ workspaceCommit,
108
+ workspaceErrorCode,
109
+ workspacePush,
110
+ workspaceRead,
111
+ workspaceRequest
112
+ };
package/dist/kept.d.ts ADDED
@@ -0,0 +1,82 @@
1
+ /**
2
+ * A session kept in Orrery Cloud (platform decision 0013, plan 12 step 2):
3
+ * the client's three-part cursor, reading the kept log a page at a time, and
4
+ * what the log reads as while its machine is offline.
5
+ *
6
+ * The wire is `GET /api/v1/sessions/:id/log?after=<epoch>,<seq>` (plan 12,
7
+ * "Wire"). Pure data: the caller fetches pages, this decides what to ask for
8
+ * and what is new.
9
+ */
10
+ /** Where a client is in a session's history (decision 0013 §6). */
11
+ export interface SessionCursor {
12
+ /** The lease epoch the frames were read under (Cloud's `epoch`). */
13
+ epoch?: number;
14
+ /** The last kept entry read from Cloud, `(epoch, seq)` with `epoch` above. */
15
+ entrySeq?: number;
16
+ /** The last live frame's `seq`, from the node's ring. */
17
+ frameSeq?: number;
18
+ }
19
+ /** One kept entry, decrypted: a row of the node's `sessions.db`. */
20
+ export interface KeptEntry {
21
+ epoch: number;
22
+ seq: number;
23
+ /** `branch`, `turn`, `entry` or `event`. */
24
+ kind: string;
25
+ /** `<kind>:<id or seq>`. */
26
+ key: string;
27
+ hash: string;
28
+ at: number;
29
+ body: unknown;
30
+ }
31
+ /** One page of `GET /sessions/:id/log`. */
32
+ export interface KeptPage {
33
+ session_id: string;
34
+ machine_id: string;
35
+ epoch: number;
36
+ lease: "held" | "expired";
37
+ entries: KeptEntry[];
38
+ next: {
39
+ epoch: number;
40
+ seq: number;
41
+ } | null;
42
+ }
43
+ /**
44
+ * How to (re)attach. Within one epoch, resume from the node's ring after
45
+ * `frameSeq`. When the epoch moved (a handoff, a node that restarted or was
46
+ * replaced), the frames held are partial: drop them and read the history
47
+ * again (decision 0013 §6).
48
+ */
49
+ export declare function resumeFrom(cursor: SessionCursor, epoch: number | undefined): {
50
+ since?: number;
51
+ replay: boolean;
52
+ };
53
+ /** The `after=` of a cursor: `<epoch>,<entry_seq>`, or nothing to read from the start. */
54
+ export declare function afterOf(cursor: SessionCursor): string | undefined;
55
+ /**
56
+ * Read the kept log after `cursor` until `next` is null. An entry already in
57
+ * `seen` (by `(epoch, seq)`) is skipped, so pages, polls and a re-read never
58
+ * draw one twice. Returns the new entries and the cursor past them.
59
+ */
60
+ export declare function readKept(page: (after: string | undefined) => Promise<KeptPage>, cursor: SessionCursor, seen: Set<string>): Promise<{
61
+ entries: KeptEntry[];
62
+ cursor: SessionCursor;
63
+ page: KeptPage | null;
64
+ }>;
65
+ /** What a kept log reads as: one item per message, reasoning or tool call. */
66
+ export type KeptItem = {
67
+ role: "user" | "assistant" | "thinking";
68
+ text: string;
69
+ key: string;
70
+ } | {
71
+ role: "tool";
72
+ name: string;
73
+ call: string;
74
+ ok: boolean | null;
75
+ key: string;
76
+ };
77
+ /**
78
+ * The transcript of kept `turn` entries, the way `orrery replay` reads the
79
+ * same rows: the person's words, the model's prose and reasoning, each tool
80
+ * call and how it settled. Runs, settings and events are not drawn.
81
+ */
82
+ export declare function keptTranscript(entries: readonly KeptEntry[]): KeptItem[];
package/dist/node.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * `@getorrery/client/node` — everything in `@getorrery/client`, plus what only runs
3
+ * in Node:
4
+ *
5
+ * - [`connectClient`]: `orrery-client/1` over `ORRERY_ENDPOINT` (a local pipe
6
+ * or stdio, through `@getorrery/ext`), for a client the host spawned;
7
+ * - `conformance.load` / `loadAll` / `fixturesDir`: the fixtures, from disk.
8
+ */
9
+ export * from "./index.js";
10
+ export * from "./channel.js";
11
+ export * as conformance from "./conformance-node.js";