@xenosystem/agent-interface-client 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.
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Attaching to a per-user Agent host โ€” the SURFACE side of ADE ยง2.7.
3
+ *
4
+ * ๐Ÿ”ด `attachToLocalAgentHost` attaches or refuses; it can never become the host. There is no
5
+ * `createHostTransport` parameter, so there is nothing it could construct even if asked โ€” the
6
+ * dangerous shape (a CLI started while no app is running WINS the lease and is then expected to
7
+ * *be* the host) is unrepresentable rather than merely forbidden.
8
+ *
9
+ * That property is why this file can live in a publishable package at all: everything here is
10
+ * what a thin client legitimately needs, and nothing here can take ownership. Acquisition and the
11
+ * host authority stay in the private `packages/host`.
12
+ */
13
+ import { XENO_AGENT_HOST_PROTOCOL_VERSION, } from '@xenosystem/agent-interface-contract';
14
+ import { inspectLocalAgentHostLease, isLeaseOwnerGone, readLocalAgentHostLeaseConnection, } from './lease.js';
15
+ import { LocalAgentHostRpcClientTransport, positiveInteger, resolveLocalAgentHostEndpoint, } from './transport.js';
16
+ export class LocalAgentHostAuthoritySession {
17
+ role;
18
+ descriptor;
19
+ transport;
20
+ server;
21
+ lease;
22
+ onAuthorityLost;
23
+ heartbeatTimer;
24
+ heartbeatPending = false;
25
+ closed = false;
26
+ constructor(options) {
27
+ this.role = options.role;
28
+ this.descriptor = { ...options.descriptor };
29
+ this.transport = options.transport;
30
+ this.server = options.server;
31
+ this.lease = options.lease;
32
+ this.onAuthorityLost = options.onAuthorityLost;
33
+ if (this.lease && options.heartbeatIntervalMs) {
34
+ this.heartbeatTimer = setInterval(() => { void this.heartbeat(); }, options.heartbeatIntervalMs);
35
+ this.heartbeatTimer.unref?.();
36
+ }
37
+ }
38
+ async close() {
39
+ if (this.closed)
40
+ return;
41
+ this.closed = true;
42
+ if (this.heartbeatTimer) {
43
+ clearInterval(this.heartbeatTimer);
44
+ this.heartbeatTimer = undefined;
45
+ }
46
+ this.transport.close();
47
+ await this.server?.close();
48
+ await this.lease?.release();
49
+ }
50
+ async heartbeat() {
51
+ if (this.closed || this.heartbeatPending || !this.lease)
52
+ return;
53
+ this.heartbeatPending = true;
54
+ try {
55
+ await this.lease.heartbeat();
56
+ }
57
+ catch (error) {
58
+ const failure = asError(error);
59
+ await this.close().catch(() => undefined);
60
+ this.onAuthorityLost?.(failure);
61
+ }
62
+ finally {
63
+ this.heartbeatPending = false;
64
+ }
65
+ }
66
+ }
67
+ /**
68
+ * Attach to a host someone else owns โ€” and NEVER become one.
69
+ *
70
+ * ๐Ÿ”ด This exists because `startLocalAgentHostAuthority` is acquire-or-attach,
71
+ * and for a surface that is the wrong shape in the most dangerous way: a CLI
72
+ * started while no app is running would WIN the lease and then be asked to
73
+ * build a host, which a thin client has no business owning. ADE ยง2.7 is
74
+ * explicit that `xeno-agent-cli` "becomes a client of the same per-user host";
75
+ * a client that can silently become the server is not that.
76
+ *
77
+ * ๐Ÿ”ด The defect is made UNREPRESENTABLE rather than documented: there is no
78
+ * `createHostTransport` parameter here, so there is nothing this function could
79
+ * construct even if it wanted to. It inspects, it connects, or it refuses with
80
+ * a reason.
81
+ */
82
+ export async function attachToLocalAgentHost(options) {
83
+ const protocolVersion = positiveInteger(options.protocolVersion) || XENO_AGENT_HOST_PROTOCOL_VERSION;
84
+ const connectTimeoutMs = positiveInteger(options.connectTimeoutMs) || 5_000;
85
+ const requestTimeoutMs = positiveInteger(options.requestTimeoutMs) || 30_000;
86
+ const descriptor = await inspectLocalAgentHostLease(options.rootDirectory);
87
+ if (!descriptor) {
88
+ return {
89
+ attached: false,
90
+ reason: 'no-host',
91
+ detail: 'No XENO Agent host is running for this user. Start the Agent app, or run the host detached.',
92
+ };
93
+ }
94
+ // ๐Ÿ”ด The SAME staleness rule the acquire path uses โ€” imported, not restated.
95
+ // A crashed owner leaves its lock file behind, and connecting to it would
96
+ // hang until the transport timed out with "unreachable", which reads as a
97
+ // network fault rather than a host that is simply gone.
98
+ if (isLeaseOwnerGone({
99
+ heartbeatAt: descriptor.heartbeatAt,
100
+ pid: descriptor.pid,
101
+ at: (options.now || Date.now)(),
102
+ ...(options.staleAfterMs === undefined ? {} : { staleAfterMs: options.staleAfterMs }),
103
+ ...(options.isProcessAlive ? { isProcessAlive: options.isProcessAlive } : {}),
104
+ })) {
105
+ return {
106
+ attached: false,
107
+ reason: 'host-gone',
108
+ detail: `The recorded Agent host (pid ${descriptor.pid}) is no longer running. Start the Agent app again.`,
109
+ };
110
+ }
111
+ if (descriptor.protocolVersion !== protocolVersion) {
112
+ return {
113
+ attached: false,
114
+ reason: 'protocol-mismatch',
115
+ hostProtocol: descriptor.protocolVersion,
116
+ clientProtocol: protocolVersion,
117
+ detail: `The running Agent host speaks protocol ${descriptor.protocolVersion} and this client speaks ${protocolVersion}. Update whichever is older.`,
118
+ };
119
+ }
120
+ const connection = await readLocalAgentHostLeaseConnection(options.rootDirectory);
121
+ if (!connection || connection.descriptor.instanceId !== descriptor.instanceId) {
122
+ // The host restarted between the inspection and the read. Refusing beats
123
+ // connecting to a different instance than the one just vetted.
124
+ return {
125
+ attached: false,
126
+ reason: 'unreachable',
127
+ detail: 'The Agent host changed while connecting. Retry.',
128
+ };
129
+ }
130
+ const transport = new LocalAgentHostRpcClientTransport({
131
+ endpoint: connection.descriptor.endpoint,
132
+ transportToken: connection.transportToken,
133
+ protocolVersion,
134
+ requestTimeoutMs,
135
+ });
136
+ try {
137
+ await connectBeforeDeadline(transport, connectTimeoutMs);
138
+ }
139
+ catch (error) {
140
+ transport.close();
141
+ return {
142
+ attached: false,
143
+ reason: 'unreachable',
144
+ detail: error instanceof Error ? error.message : String(error),
145
+ };
146
+ }
147
+ return {
148
+ attached: true,
149
+ session: new LocalAgentHostAuthoritySession({
150
+ // Always a client. There is no branch here that produces an owner, which
151
+ // is the property this function exists to guarantee.
152
+ role: 'attached-client',
153
+ descriptor: connection.descriptor,
154
+ transport,
155
+ }),
156
+ };
157
+ }
158
+ export async function connectBeforeDeadline(transport, timeoutMs) {
159
+ const deadline = Date.now() + timeoutMs;
160
+ let lastError;
161
+ do {
162
+ try {
163
+ await transport.connect();
164
+ return;
165
+ }
166
+ catch (error) {
167
+ lastError = asError(error);
168
+ if (!isRetryableConnectionError(lastError) || Date.now() >= deadline)
169
+ break;
170
+ await delay(Math.min(50, Math.max(1, deadline - Date.now())));
171
+ }
172
+ } while (Date.now() < deadline);
173
+ throw lastError || new Error('Unable to connect to the local Agent host authority.');
174
+ }
175
+ function isRetryableConnectionError(error) {
176
+ if (!('code' in error))
177
+ return false;
178
+ const code = error.code;
179
+ return code === 'ENOENT' || code === 'ECONNREFUSED' || code === 'EPIPE';
180
+ }
181
+ function delay(milliseconds) {
182
+ return new Promise((resolveDelay) => setTimeout(resolveDelay, milliseconds));
183
+ }
184
+ function asError(error) {
185
+ return error instanceof Error ? error : new Error(String(error));
186
+ }
187
+ //# sourceMappingURL=attach.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attach.js","sourceRoot":"","sources":["../../src/local/attach.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from './transport.js';
2
+ export * from './lease.js';
3
+ export * from './attach.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/local/index.ts"],"names":[],"mappings":"AAiBA,cAAc,gBAAgB,CAAA;AAI9B,cAAc,YAAY,CAAA;AAG1B,cAAc,aAAa,CAAA"}
@@ -0,0 +1,23 @@
1
+ // The Node-only local-IPC surface of the Agent host client.
2
+ //
3
+ // ๐Ÿ”ด This is a SEPARATE ENTRY POINT on purpose. `packages/client` is on the architecture
4
+ // guard's renderer-safe list, and `packages/ui` value-imports the main entry โ€” so anything
5
+ // re-exported from `../index.ts` lands in the ELECTRON RENDERER BUNDLE. These modules import
6
+ // `node:net`, `node:fs/promises` and `node:crypto`, which would break the secure renderer
7
+ // boundary that `AGENTS.md` makes an invariant.
8
+ //
9
+ // It mirrors the precedent already set by `@xenosystem/agent-interface-host/node`: Node-only
10
+ // capability lives behind a subpath the renderer never resolves, and the guard forbids
11
+ // renderer-safe code from importing it.
12
+ //
13
+ // A SURFACE (the CLI, ADE ยง2.7) imports this. The renderer imports the package root.
14
+ // The local-IPC wire protocol and client transport โ€” what a surface needs to attach to a
15
+ // per-user Agent host. Node-only by necessity; see transport.ts for why it is here rather
16
+ // than in `contract`.
17
+ export * from './transport.js';
18
+ // Lease READING โ€” finding a running host. Acquisition deliberately stays in the host package,
19
+ // so a surface structurally cannot take ownership.
20
+ export * from './lease.js';
21
+ // Attaching to a per-user host. Attaches or refuses; never becomes the host.
22
+ export * from './attach.js';
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/local/index.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,EAAE;AACF,yFAAyF;AACzF,2FAA2F;AAC3F,6FAA6F;AAC7F,0FAA0F;AAC1F,gDAAgD;AAChD,EAAE;AACF,6FAA6F;AAC7F,uFAAuF;AACvF,wCAAwC;AACxC,EAAE;AACF,qFAAqF;AAErF,yFAAyF;AACzF,0FAA0F;AAC1F,sBAAsB;AACtB,cAAc,gBAAgB,CAAA;AAE9B,8FAA8F;AAC9F,mDAAmD;AACnD,cAAc,YAAY,CAAA;AAE1B,6EAA6E;AAC7E,cAAc,aAAa,CAAA"}
@@ -0,0 +1,50 @@
1
+ export interface LocalAgentHostLeaseDescriptor {
2
+ schemaVersion: 1;
3
+ instanceId: string;
4
+ pid: number;
5
+ endpoint: string;
6
+ protocolVersion: number;
7
+ acquiredAt: number;
8
+ heartbeatAt: number;
9
+ }
10
+ export interface LocalAgentHostLeaseConnectionInfo {
11
+ descriptor: LocalAgentHostLeaseDescriptor;
12
+ /** Sensitive same-user bearer credential. Never expose this to a renderer or diagnostic export. */
13
+ transportToken: string;
14
+ }
15
+ export interface LocalAgentHostLeaseRecord extends LocalAgentHostLeaseDescriptor {
16
+ transportToken: string;
17
+ }
18
+ export declare const DEFAULT_LEASE_STALE_AFTER_MS = 15000;
19
+ /**
20
+ * Is the recorded owner gone?
21
+ *
22
+ * ๐Ÿ”ด TWO conditions, and the second is the one that matters. A missed
23
+ * heartbeat alone does not mean a dead host โ€” a process paused by a debugger,
24
+ * a laptop resumed from sleep, or a machine under load all produce one. Taking
25
+ * the lease from a LIVE owner is the split-brain the lease exists to prevent,
26
+ * so the pid must also be gone.
27
+ *
28
+ * Exported and shared because a second caller now needs the same question
29
+ * answered without acquiring anything: a surface deciding whether a host is
30
+ * actually there. Two spellings of "is the owner dead" would eventually
31
+ * disagree, and the two answers are "take over" and "connect".
32
+ */
33
+ export declare function isLeaseOwnerGone(input: {
34
+ heartbeatAt: number;
35
+ pid: number;
36
+ at: number;
37
+ staleAfterMs?: number;
38
+ isProcessAlive?: (pid: number) => boolean;
39
+ }): boolean;
40
+ export declare function inspectLocalAgentHostLease(rootDirectory: string): Promise<LocalAgentHostLeaseDescriptor | null>;
41
+ /**
42
+ * Reads connection material for another trusted main/host process owned by the
43
+ * same OS user. Callers must keep the token outside renderers, logs, and IPC.
44
+ */
45
+ export declare function readLocalAgentHostLeaseConnection(rootDirectory: string): Promise<LocalAgentHostLeaseConnectionInfo | null>;
46
+ export declare function readLeaseRecord(path: string): Promise<LocalAgentHostLeaseRecord>;
47
+ export declare function parseLeaseRecord(value: string): LocalAgentHostLeaseRecord;
48
+ export declare function publicDescriptor(record: LocalAgentHostLeaseRecord): LocalAgentHostLeaseDescriptor;
49
+ export declare function defaultProcessAlive(pid: number): boolean;
50
+ //# sourceMappingURL=lease.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lease.d.ts","sourceRoot":"","sources":["../../src/local/lease.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,6BAA6B;IAC5C,aAAa,EAAE,CAAC,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,eAAe,EAAE,MAAM,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,iCAAiC;IAChD,UAAU,EAAE,6BAA6B,CAAA;IACzC,mGAAmG;IACnG,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,yBAA0B,SAAQ,6BAA6B;IAC9E,cAAc,EAAE,MAAM,CAAA;CACvB;AAID,eAAO,MAAM,4BAA4B,QAAS,CAAA;AAElD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,WAAW,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,MAAM,CAAA;IACX,EAAE,EAAE,MAAM,CAAA;IACV,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;CAC1C,GAAG,OAAO,CAIV;AAID,wBAAsB,0BAA0B,CAC9C,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,6BAA6B,GAAG,IAAI,CAAC,CAQ/C;AAED;;;GAGG;AACH,wBAAsB,iCAAiC,CACrD,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,iCAAiC,GAAG,IAAI,CAAC,CAYnD;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAEtF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,yBAAyB,CAqBzE;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,yBAAyB,GAAG,6BAA6B,CAUjG;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQxD"}
@@ -0,0 +1,120 @@
1
+ import { isNodeError } from './transport.js';
2
+ /**
3
+ * Local Agent host lease โ€” the READ half.
4
+ *
5
+ * A surface needs to find and validate a running host: read the lease, decide whether its owner
6
+ * is gone, and pull the connection info. It must never be able to ACQUIRE one โ€” a thin client
7
+ * that can win the lease would then be asked to *be* the host, which ADE ยง2.7 explicitly rules
8
+ * out. Acquisition stays in `packages/host`, so the client cannot take ownership because the code
9
+ * to do it is not here.
10
+ *
11
+ * `isNodeError` and the parse/record helpers are exported for the host's acquire half; they are
12
+ * internal to the lease protocol and not part of the supported surface.
13
+ */
14
+ import { randomBytes } from 'node:crypto';
15
+ import { mkdir, open, readFile, unlink } from 'node:fs/promises';
16
+ import { join } from 'node:path';
17
+ export const DEFAULT_LEASE_STALE_AFTER_MS = 15_000;
18
+ /**
19
+ * Is the recorded owner gone?
20
+ *
21
+ * ๐Ÿ”ด TWO conditions, and the second is the one that matters. A missed
22
+ * heartbeat alone does not mean a dead host โ€” a process paused by a debugger,
23
+ * a laptop resumed from sleep, or a machine under load all produce one. Taking
24
+ * the lease from a LIVE owner is the split-brain the lease exists to prevent,
25
+ * so the pid must also be gone.
26
+ *
27
+ * Exported and shared because a second caller now needs the same question
28
+ * answered without acquiring anything: a surface deciding whether a host is
29
+ * actually there. Two spellings of "is the owner dead" would eventually
30
+ * disagree, and the two answers are "take over" and "connect".
31
+ */
32
+ export function isLeaseOwnerGone(input) {
33
+ const staleAfterMs = positiveInteger(input.staleAfterMs) || DEFAULT_LEASE_STALE_AFTER_MS;
34
+ const alive = input.isProcessAlive || defaultProcessAlive;
35
+ return input.at - input.heartbeatAt > staleAfterMs && !alive(input.pid);
36
+ }
37
+ export async function inspectLocalAgentHostLease(rootDirectory) {
38
+ const path = join(rootDirectory, 'agent-host.lock');
39
+ try {
40
+ return publicDescriptor(await readLeaseRecord(path));
41
+ }
42
+ catch (error) {
43
+ if (isNodeError(error, 'ENOENT'))
44
+ return null;
45
+ throw error;
46
+ }
47
+ }
48
+ /**
49
+ * Reads connection material for another trusted main/host process owned by the
50
+ * same OS user. Callers must keep the token outside renderers, logs, and IPC.
51
+ */
52
+ export async function readLocalAgentHostLeaseConnection(rootDirectory) {
53
+ const path = join(rootDirectory, 'agent-host.lock');
54
+ try {
55
+ const record = await readLeaseRecord(path);
56
+ return {
57
+ descriptor: publicDescriptor(record),
58
+ transportToken: record.transportToken,
59
+ };
60
+ }
61
+ catch (error) {
62
+ if (isNodeError(error, 'ENOENT'))
63
+ return null;
64
+ throw error;
65
+ }
66
+ }
67
+ export async function readLeaseRecord(path) {
68
+ return parseLeaseRecord(await readFile(path, 'utf8'));
69
+ }
70
+ export function parseLeaseRecord(value) {
71
+ let parsed;
72
+ try {
73
+ parsed = JSON.parse(value);
74
+ }
75
+ catch {
76
+ throw new Error('Agent host authority lease is malformed.');
77
+ }
78
+ if (!isRecord(parsed)
79
+ || parsed.schemaVersion !== 1
80
+ || typeof parsed.instanceId !== 'string'
81
+ || typeof parsed.pid !== 'number'
82
+ || typeof parsed.endpoint !== 'string'
83
+ || typeof parsed.protocolVersion !== 'number'
84
+ || typeof parsed.acquiredAt !== 'number'
85
+ || typeof parsed.heartbeatAt !== 'number'
86
+ || typeof parsed.transportToken !== 'string'
87
+ || parsed.transportToken.length < 32) {
88
+ throw new Error('Agent host authority lease is invalid.');
89
+ }
90
+ return parsed;
91
+ }
92
+ export function publicDescriptor(record) {
93
+ return {
94
+ schemaVersion: 1,
95
+ instanceId: record.instanceId,
96
+ pid: record.pid,
97
+ endpoint: record.endpoint,
98
+ protocolVersion: record.protocolVersion,
99
+ acquiredAt: record.acquiredAt,
100
+ heartbeatAt: record.heartbeatAt,
101
+ };
102
+ }
103
+ export function defaultProcessAlive(pid) {
104
+ if (!Number.isInteger(pid) || pid <= 0)
105
+ return false;
106
+ try {
107
+ process.kill(pid, 0);
108
+ return true;
109
+ }
110
+ catch (error) {
111
+ return isNodeError(error, 'EPERM');
112
+ }
113
+ }
114
+ function positiveInteger(value) {
115
+ return typeof value === 'number' && Number.isInteger(value) && value > 0 ? value : undefined;
116
+ }
117
+ function isRecord(value) {
118
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
119
+ }
120
+ //# sourceMappingURL=lease.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lease.js","sourceRoot":"","sources":["../../src/local/lease.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Local Agent host wire protocol โ€” framing plus the CLIENT transport.
3
+ *
4
+ * ๐Ÿ”ด This lives in the CLIENT package, not in `contract`, and the reason is load-bearing:
5
+ * `contract` is Node-free and must stay that way. A renderer reaches `contract/index.js`, and
6
+ * Vite fails a browser build on any `node:` builtin ("stat" is not exported by
7
+ * "__vite-browser-external") โ€” `browserBarrelPurity.test.ts` pins that. This module needs
8
+ * `node:net`, `node:crypto` and `node:fs/promises`, so it cannot go there.
9
+ *
10
+ * It is also why the split is client-package-and-below rather than contract-and-below: a surface
11
+ * that wants to ATTACH to a local host needs Node anyway.
12
+ *
13
+ * @packageDocumentation
14
+ */
15
+ import { type Socket } from 'node:net';
16
+ import { type AgentHostEvent, type AgentHostEventListener, type AgentHostInput, type AgentHostMethod, type AgentHostOutput, type AgentHostProtocolErrorCode, type AgentHostTransport, type AgentHostUnsubscribe } from '@xenosystem/agent-interface-contract';
17
+ export declare const LOCAL_AGENT_HOST_DEFAULT_MAX_FRAME_BYTES: number;
18
+ export declare const LOCAL_AGENT_HOST_ABSOLUTE_MAX_FRAME_BYTES: number;
19
+ export interface LocalRpcRequest {
20
+ kind: 'request';
21
+ id: string;
22
+ protocolVersion: number;
23
+ token: string;
24
+ method: AgentHostMethod;
25
+ input: unknown;
26
+ }
27
+ export type LocalRpcResponse = {
28
+ kind: 'response';
29
+ id: string;
30
+ ok: true;
31
+ output: unknown;
32
+ } | {
33
+ kind: 'response';
34
+ id: string;
35
+ ok: false;
36
+ error: {
37
+ code: AgentHostProtocolErrorCode;
38
+ message: string;
39
+ };
40
+ };
41
+ interface LocalRpcEvent {
42
+ kind: 'event';
43
+ event: AgentHostEvent;
44
+ }
45
+ export type LocalRpcServerMessage = LocalRpcResponse | LocalRpcEvent;
46
+ export interface LocalAgentHostRpcServerOptions {
47
+ transport: AgentHostTransport;
48
+ endpoint: string;
49
+ transportToken: string;
50
+ protocolVersion?: number;
51
+ maxFrameBytes?: number;
52
+ removeStaleEndpoint?: boolean;
53
+ }
54
+ export interface LocalAgentHostRpcClientOptions {
55
+ endpoint: string;
56
+ transportToken: string;
57
+ protocolVersion?: number;
58
+ maxFrameBytes?: number;
59
+ requestTimeoutMs?: number;
60
+ }
61
+ /** Node-side AgentHostTransport implementation for a local host authority. */
62
+ export declare class LocalAgentHostRpcClientTransport implements AgentHostTransport {
63
+ private readonly endpoint;
64
+ private readonly transportToken;
65
+ private readonly protocolVersion;
66
+ private readonly maxFrameBytes;
67
+ private readonly requestTimeoutMs;
68
+ private readonly listeners;
69
+ private readonly pending;
70
+ private readonly requestPrefix;
71
+ private requestSequence;
72
+ private socket;
73
+ private connectPromise;
74
+ constructor(options: LocalAgentHostRpcClientOptions);
75
+ get connected(): boolean;
76
+ connect(): Promise<void>;
77
+ request<M extends AgentHostMethod>(method: M, input: AgentHostInput<M>): Promise<AgentHostOutput<M>>;
78
+ subscribe(listener: AgentHostEventListener): AgentHostUnsubscribe;
79
+ close(): void;
80
+ private receive;
81
+ private disconnect;
82
+ }
83
+ export declare function resolveLocalAgentHostEndpoint(rootDirectory: string, scope?: string): string;
84
+ export declare class JsonLineDecoder {
85
+ private readonly maxFrameBytes;
86
+ private readonly onFrame;
87
+ private buffer;
88
+ constructor(maxFrameBytes: number, onFrame: (frame: string) => void);
89
+ push(chunk: Buffer): void;
90
+ }
91
+ export declare function writeFrame(socket: Socket, value: unknown, maxFrameBytes: number): void;
92
+ export declare function safeTokenEquals(left: string, right: string): boolean;
93
+ export declare function assertLocalRpcOptions(endpoint: string, transportToken: string): void;
94
+ export declare function positiveInteger(value: number | undefined): number | undefined;
95
+ export declare function resolveMaxFrameBytes(value: number | undefined): number;
96
+ export declare function asError(error: unknown): Error;
97
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
98
+ export declare function isNodeError(error: unknown, code: string): error is NodeJS.ErrnoException;
99
+ export {};
100
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/local/transport.ts"],"names":[],"mappings":"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"}