@astrosheep/square 0.3.63 → 0.3.65
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.
- package/claude-plugin/.claude-plugin/plugin.json +3 -2
- package/claude-plugin/hooks/hooks.json +1 -22
- package/claude-plugin/hooks/register.js +119 -0
- package/claude-plugin/types.d.ts +7 -0
- package/codex-plugin/.codex-plugin/plugin.json +1 -1
- package/dist/activity-feed.d.ts +1 -10
- package/dist/activity-feed.js +1 -27
- package/dist/activity.js +57 -25
- package/dist/artifact.d.ts +1 -1
- package/dist/artifact.js +24 -25
- package/dist/attention-presentation.js +1 -0
- package/dist/automatic-session.d.ts +3 -1
- package/dist/automatic-session.js +21 -34
- package/dist/boundary-presentation.js +4 -13
- package/dist/canonical-path.d.ts +11 -0
- package/dist/canonical-path.js +47 -0
- package/dist/catch-decisions.js +14 -10
- package/dist/catch-selection.d.ts +6 -0
- package/dist/catch-selection.js +14 -0
- package/dist/claude-delivery.d.ts +11 -0
- package/dist/claude-delivery.js +145 -0
- package/dist/claude-mod.d.ts +8 -0
- package/dist/claude-mod.js +164 -0
- package/dist/cli/context.d.ts +0 -1
- package/dist/cli/context.js +9 -21
- package/dist/cli/harness-command.d.ts +0 -1
- package/dist/cli/harness-command.js +0 -6
- package/dist/cli/observation-commands.d.ts +1 -1
- package/dist/cli/observation-commands.js +31 -58
- package/dist/cli/program.js +20 -18
- package/dist/cli/registry.js +2 -2
- package/dist/cli/square-commands.js +10 -6
- package/dist/codex-boundary-state.d.ts +2 -2
- package/dist/codex-boundary-state.js +4 -4
- package/dist/codex-hook.js +12 -15
- package/dist/codex-queue.d.ts +2 -2
- package/dist/codex-queue.js +7 -5
- package/dist/decisions.d.ts +2 -6
- package/dist/decisions.js +16 -17
- package/dist/delivery-health.d.ts +1 -2
- package/dist/delivery-health.js +4 -5
- package/dist/delivery-operations.d.ts +2 -5
- package/dist/delivery-operations.js +77 -214
- package/dist/delivery.d.ts +25 -47
- package/dist/delivery.js +14 -46
- package/dist/diagnostic-redaction.js +7 -9
- package/dist/file-changes.d.ts +0 -1
- package/dist/file-changes.js +2 -19
- package/dist/harness-claude.js +8 -6
- package/dist/harness-codex.d.ts +0 -2
- package/dist/harness-codex.js +0 -2
- package/dist/harness-links.js +13 -17
- package/dist/harness.js +3 -7
- package/dist/help.js +4 -3
- package/dist/host-ledger-file-adapter.d.ts +17 -8
- package/dist/host-ledger-file-adapter.js +164 -80
- package/dist/host-ledger.d.ts +55 -50
- package/dist/inbox.d.ts +0 -3
- package/dist/inbox.js +88 -50
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/list.js +1 -4
- package/dist/mcp.js +24 -41
- package/dist/mention-parse.js +3 -9
- package/dist/model.d.ts +11 -2
- package/dist/model.js +1 -1
- package/dist/notifications.d.ts +3 -16
- package/dist/notifications.js +41 -122
- package/dist/opencode-delivery.d.ts +14 -0
- package/dist/opencode-delivery.js +171 -0
- package/dist/opencode.d.ts +39 -18
- package/dist/opencode.js +145 -40
- package/dist/packages/agent-delivery/src/claude-auth.d.ts +13 -0
- package/dist/packages/agent-delivery/src/claude-auth.js +75 -0
- package/dist/packages/agent-delivery/src/claude-native.d.ts +28 -0
- package/dist/packages/agent-delivery/src/claude-native.js +68 -0
- package/dist/packages/agent-delivery/src/claude.d.ts +14 -0
- package/dist/packages/agent-delivery/src/claude.js +66 -0
- package/dist/packages/agent-delivery/src/deadline.d.ts +11 -0
- package/dist/packages/agent-delivery/src/deadline.js +41 -0
- package/dist/packages/agent-delivery/src/errors.d.ts +16 -0
- package/dist/packages/agent-delivery/src/errors.js +41 -0
- package/dist/packages/agent-delivery/src/guards.d.ts +6 -0
- package/dist/packages/agent-delivery/src/guards.js +6 -0
- package/dist/packages/agent-delivery/src/index.d.ts +83 -0
- package/dist/packages/agent-delivery/src/index.js +110 -0
- package/dist/packages/agent-delivery/src/local-endpoint.d.ts +26 -0
- package/dist/packages/agent-delivery/src/local-endpoint.js +114 -0
- package/dist/packages/agent-delivery/src/opencode-native.d.ts +33 -0
- package/dist/packages/agent-delivery/src/opencode-native.js +75 -0
- package/dist/packages/agent-delivery/src/opencode.d.ts +14 -0
- package/dist/packages/agent-delivery/src/opencode.js +127 -0
- package/dist/packages/agent-delivery/src/paseo-native.d.ts +58 -0
- package/dist/packages/agent-delivery/src/paseo-native.js +122 -0
- package/dist/packages/agent-delivery/src/paseo.d.ts +19 -0
- package/dist/packages/agent-delivery/src/paseo.js +106 -0
- package/dist/packages/agent-delivery/src/pi-client.d.ts +10 -0
- package/dist/packages/agent-delivery/src/pi-client.js +106 -0
- package/dist/packages/agent-delivery/src/pi-protocol.d.ts +15 -0
- package/dist/packages/agent-delivery/src/pi-protocol.js +50 -0
- package/dist/packages/agent-delivery/src/pi-send.d.ts +23 -0
- package/dist/packages/agent-delivery/src/pi-send.js +4 -0
- package/dist/packages/agent-delivery/src/pi.d.ts +25 -0
- package/dist/packages/agent-delivery/src/pi.js +209 -0
- package/dist/packages/agent-delivery/src/types.d.ts +120 -0
- package/dist/participant-host.js +12 -13
- package/dist/participant-identity.d.ts +21 -0
- package/dist/participant-identity.js +32 -11
- package/dist/paseo-delivery.d.ts +2 -2
- package/dist/paseo-delivery.js +35 -27
- package/dist/paseo-timeline.js +25 -21
- package/dist/paseo.d.ts +2 -2
- package/dist/paseo.js +1 -2
- package/dist/ports.d.ts +7 -20
- package/dist/presentation-operations.js +16 -4
- package/dist/presentation.d.ts +19 -10
- package/dist/presentation.js +99 -177
- package/dist/registry.d.ts +15 -66
- package/dist/registry.js +45 -123
- package/dist/routes.d.ts +1 -28
- package/dist/routes.js +22 -104
- package/dist/runtime.d.ts +3 -9
- package/dist/runtime.js +14 -67
- package/dist/search.d.ts +0 -2
- package/dist/search.js +3 -10
- package/dist/square-actions.js +48 -72
- package/dist/square-application.js +32 -30
- package/dist/square-core.d.ts +3 -0
- package/dist/square-core.js +22 -5
- package/dist/square-facade.d.ts +2 -0
- package/dist/square-file-adapter.d.ts +2 -1
- package/dist/square-file-adapter.js +6 -9
- package/dist/square-projections.d.ts +40 -45
- package/dist/square-projections.js +60 -74
- package/dist/square-state.js +1 -4
- package/dist/square-storage.d.ts +5 -8
- package/dist/square-storage.js +13 -36
- package/dist/square-wiring.d.ts +2 -7
- package/dist/square-wiring.js +6 -24
- package/dist/stream.js +4 -6
- package/dist/time.js +2 -7
- package/dist/views.d.ts +6 -18
- package/dist/views.js +14 -21
- package/dist/wake-attempts.d.ts +2 -56
- package/dist/wake-attempts.js +15 -110
- package/dist/wake-eligibility.d.ts +43 -0
- package/dist/wake-eligibility.js +106 -0
- package/dist/wake-evidence.d.ts +32 -9
- package/dist/wake-evidence.js +29 -24
- package/dist/wake-sink.d.ts +13 -9
- package/dist/wake-sink.js +35 -54
- package/dist/watch.js +13 -21
- package/extensions/square-pi.js +27 -13
- package/guides/change-waits.md +1 -1
- package/guides/claude-native.md +101 -0
- package/guides/host-ledger.md +3 -1
- package/guides/participant.md +14 -7
- package/guides/pi-native-delivery.md +49 -0
- package/package.json +4 -3
- package/dist/claude-hook.d.ts +0 -10
- package/dist/claude-hook.js +0 -60
- package/dist/paseo-connection.d.ts +0 -15
- package/dist/paseo-connection.js +0 -141
- package/dist/presence.d.ts +0 -2
- package/dist/presence.js +0 -24
- package/dist/presented.d.ts +0 -2
- package/dist/presented.js +0 -10
- package/dist/state-cell.d.ts +0 -14
- package/dist/wake-port.d.ts +0 -23
- package/dist/wake-port.js +0 -27
- /package/dist/{state-cell.js → packages/agent-delivery/src/types.js} +0 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { DeliveryError } from './errors.js';
|
|
2
|
+
export interface SendOptions {
|
|
3
|
+
readonly timeoutMs?: number;
|
|
4
|
+
readonly signal?: AbortSignal;
|
|
5
|
+
}
|
|
6
|
+
export interface KeyedSendOptions extends SendOptions {
|
|
7
|
+
readonly id?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface Receipt {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly proof: 'written' | 'admitted' | 'observed';
|
|
12
|
+
}
|
|
13
|
+
export interface Steerable<O = SendOptions> {
|
|
14
|
+
steer(text: string, options?: O): Promise<Receipt>;
|
|
15
|
+
}
|
|
16
|
+
export interface Queueable<O = SendOptions> {
|
|
17
|
+
queue(text: string, options?: O): Promise<Receipt>;
|
|
18
|
+
}
|
|
19
|
+
export interface OpenCodeConnectOptions {
|
|
20
|
+
readonly harness: 'opencode';
|
|
21
|
+
readonly sessionId: string;
|
|
22
|
+
readonly endpoint?: {
|
|
23
|
+
readonly url: string;
|
|
24
|
+
readonly auth?: {
|
|
25
|
+
readonly type: 'basic';
|
|
26
|
+
readonly username: string;
|
|
27
|
+
readonly password: string;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
readonly registrationFile?: string;
|
|
31
|
+
readonly timeoutMs?: number;
|
|
32
|
+
readonly signal?: AbortSignal;
|
|
33
|
+
}
|
|
34
|
+
export interface ClaudeConnectOptions {
|
|
35
|
+
readonly harness: 'claude';
|
|
36
|
+
readonly sessionId: string;
|
|
37
|
+
readonly endpoint: string;
|
|
38
|
+
readonly token?: string;
|
|
39
|
+
readonly claudeHome?: string;
|
|
40
|
+
readonly timeoutMs?: number;
|
|
41
|
+
readonly signal?: AbortSignal;
|
|
42
|
+
}
|
|
43
|
+
export interface PiConnectOptions {
|
|
44
|
+
readonly harness: 'pi';
|
|
45
|
+
readonly sessionId: string;
|
|
46
|
+
readonly endpoint: string;
|
|
47
|
+
readonly timeoutMs?: number;
|
|
48
|
+
readonly signal?: AbortSignal;
|
|
49
|
+
}
|
|
50
|
+
export interface PaseoConnectOptions {
|
|
51
|
+
readonly harness: 'paseo';
|
|
52
|
+
readonly agentId: string;
|
|
53
|
+
readonly endpoint?: string;
|
|
54
|
+
readonly password?: string;
|
|
55
|
+
readonly authHeader?: string;
|
|
56
|
+
readonly localCredential?: string;
|
|
57
|
+
readonly paseoHome?: string;
|
|
58
|
+
readonly timeoutMs?: number;
|
|
59
|
+
readonly signal?: AbortSignal;
|
|
60
|
+
}
|
|
61
|
+
export type OpenCodeAgent = Steerable<KeyedSendOptions> & Queueable<KeyedSendOptions> & {
|
|
62
|
+
readonly harness: 'opencode';
|
|
63
|
+
readonly sessionId: string;
|
|
64
|
+
};
|
|
65
|
+
export type ClaudeAgent = Steerable & {
|
|
66
|
+
readonly harness: 'claude';
|
|
67
|
+
readonly sessionId: string;
|
|
68
|
+
};
|
|
69
|
+
export type PiAgent = Steerable & Queueable & {
|
|
70
|
+
readonly harness: 'pi';
|
|
71
|
+
readonly sessionId: string;
|
|
72
|
+
};
|
|
73
|
+
export type PaseoAgent = Steerable<KeyedSendOptions> & {
|
|
74
|
+
readonly harness: 'paseo';
|
|
75
|
+
readonly agentId: string;
|
|
76
|
+
};
|
|
77
|
+
export type Agent = OpenCodeAgent | ClaudeAgent | PiAgent | PaseoAgent;
|
|
78
|
+
export declare function connect(options: OpenCodeConnectOptions): Promise<OpenCodeAgent>;
|
|
79
|
+
export declare function connect(options: ClaudeConnectOptions): Promise<ClaudeAgent>;
|
|
80
|
+
export declare function connect(options: PiConnectOptions): Promise<PiAgent>;
|
|
81
|
+
export declare function connect(options: PaseoConnectOptions): Promise<PaseoAgent>;
|
|
82
|
+
export { DeliveryError };
|
|
83
|
+
export type { DeliveryErrorCode } from './errors.js';
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { ConnectionError, DeliveryError } from './errors.js';
|
|
2
|
+
import { isRecord } from './guards.js';
|
|
3
|
+
const codes = {
|
|
4
|
+
invalid_arguments: 'invalid_arguments', unsupported_platform: 'unsupported_platform',
|
|
5
|
+
service_unavailable: 'unavailable', authentication_failed: 'authentication_failed',
|
|
6
|
+
session_not_found: 'session_not_found', http_rejection: 'rejected',
|
|
7
|
+
unsupported_version: 'unsupported_version', invalid_response: 'invalid_response',
|
|
8
|
+
timeout: 'timeout', aborted: 'aborted', transport: 'transport',
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* One classification path for a connection failure, a send failure and the
|
|
12
|
+
* harness's own attempt state. Past the send precondition an unclassified
|
|
13
|
+
* failure may have reached the receiver.
|
|
14
|
+
*/
|
|
15
|
+
function failure(error, phase, id) {
|
|
16
|
+
if (error instanceof DeliveryError)
|
|
17
|
+
return error;
|
|
18
|
+
if (error instanceof ConnectionError)
|
|
19
|
+
return new DeliveryError(codes[error.code] ?? 'transport', false, id, error.status);
|
|
20
|
+
if (error instanceof TypeError)
|
|
21
|
+
return new DeliveryError('invalid_arguments', false, id);
|
|
22
|
+
const attempt = error;
|
|
23
|
+
if (typeof attempt?.state !== 'string')
|
|
24
|
+
return new DeliveryError('transport', phase === 'send', id);
|
|
25
|
+
const code = attempt.state === 'unavailable'
|
|
26
|
+
? attempt.code === 'aborted' ? 'aborted' : attempt.code === 'timeout' ? 'timeout'
|
|
27
|
+
: attempt.code === 'authentication_failed' ? 'authentication_failed' : 'unavailable'
|
|
28
|
+
: attempt.state === 'rejected' ? attempt.code === 'not_found' ? 'session_not_found' : 'rejected'
|
|
29
|
+
: codes[attempt.code ?? 'transport'] ?? 'transport';
|
|
30
|
+
return new DeliveryError(code, attempt.state === 'unknown', id ?? attempt.inputId, attempt.status);
|
|
31
|
+
}
|
|
32
|
+
const harnesses = {
|
|
33
|
+
opencode: {
|
|
34
|
+
harness: 'opencode', proof: 'admitted', accepted: 'accepted', coordinate: 'sessionId', keyed: true, queue: true,
|
|
35
|
+
id: (result) => result.inputId,
|
|
36
|
+
open: async (options) => {
|
|
37
|
+
const { connectExisting, sendText } = await import('./opencode.js');
|
|
38
|
+
const target = await connectExisting(options);
|
|
39
|
+
return { coordinate: target.sessionId, send: (text, value) => sendText(target, text, value) };
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
claude: {
|
|
43
|
+
harness: 'claude', proof: 'written', accepted: 'written', coordinate: 'sessionId', keyed: false, queue: false,
|
|
44
|
+
id: (result) => result.messageId,
|
|
45
|
+
open: async (options) => {
|
|
46
|
+
const { connectExisting, sendText } = await import('./claude.js');
|
|
47
|
+
const target = await connectExisting(options);
|
|
48
|
+
return { coordinate: target.sessionId, send: (text, value) => sendText(target, text, value) };
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
pi: {
|
|
52
|
+
harness: 'pi', proof: 'observed', accepted: 'observed', coordinate: 'sessionId', keyed: false, queue: true,
|
|
53
|
+
id: (result) => result.inputId,
|
|
54
|
+
open: async (options) => {
|
|
55
|
+
const { connectPi, sendPiText } = await import('./pi-client.js');
|
|
56
|
+
const target = await connectPi(options);
|
|
57
|
+
return { coordinate: target.sessionId, send: (text, value) => sendPiText(target, text, value) };
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
paseo: {
|
|
61
|
+
harness: 'paseo', proof: 'admitted', accepted: 'admitted', coordinate: 'agentId', keyed: true, queue: false,
|
|
62
|
+
id: (result) => result.inputId,
|
|
63
|
+
open: async (options) => {
|
|
64
|
+
const { connectPaseo, sendPaseoText } = await import('./paseo.js');
|
|
65
|
+
const target = await connectPaseo(options);
|
|
66
|
+
return { coordinate: target.agentId, send: (text, value) => sendPaseoText(target, text, value) };
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
export async function connect(options) {
|
|
71
|
+
const harness = isRecord(options) && typeof options.harness === 'string' ? options.harness : undefined;
|
|
72
|
+
// An own-key check keeps Object.prototype names out of the transport table.
|
|
73
|
+
const spec = harness !== undefined && Object.hasOwn(harnesses, harness) ? harnesses[harness] : undefined;
|
|
74
|
+
if (spec === undefined)
|
|
75
|
+
throw new DeliveryError('invalid_arguments');
|
|
76
|
+
let opened;
|
|
77
|
+
try {
|
|
78
|
+
opened = await spec.open(options);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
throw failure(error, 'connect');
|
|
82
|
+
}
|
|
83
|
+
const send = async (text, value, delivery) => {
|
|
84
|
+
const options = value === undefined ? {} : value;
|
|
85
|
+
if (!isRecord(options))
|
|
86
|
+
throw new DeliveryError('invalid_arguments');
|
|
87
|
+
// An unusable caller id is an argument precondition; the native sender rejects it.
|
|
88
|
+
const id = options.id;
|
|
89
|
+
try {
|
|
90
|
+
const result = await opened.send(text, spec.keyed
|
|
91
|
+
? { delivery, inputId: id, timeoutMs: options.timeoutMs, signal: options.signal }
|
|
92
|
+
: { delivery, timeoutMs: options.timeoutMs, signal: options.signal });
|
|
93
|
+
if (result.state !== spec.accepted)
|
|
94
|
+
throw failure(result, 'send', id);
|
|
95
|
+
return { id: spec.id(result), proof: spec.proof };
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
throw failure(error, 'send', id);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const agent = {
|
|
102
|
+
harness: spec.harness,
|
|
103
|
+
[spec.coordinate]: opened.coordinate,
|
|
104
|
+
steer: (text, value) => send(text, value, 'steer'),
|
|
105
|
+
};
|
|
106
|
+
if (spec.queue)
|
|
107
|
+
agent.queue = (text, value) => send(text, value, 'queue');
|
|
108
|
+
return Object.freeze(agent);
|
|
109
|
+
}
|
|
110
|
+
export { DeliveryError };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
export interface LocalEndpoint {
|
|
3
|
+
readonly kind: 'unix' | 'pipe';
|
|
4
|
+
/** What the socket connects to. */
|
|
5
|
+
readonly path: string;
|
|
6
|
+
/** What the native receiver fingerprints; also the auth key file digest input. */
|
|
7
|
+
readonly canonical: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A local endpoint is either a Windows named pipe or an absolute Unix socket
|
|
11
|
+
* path. There is no `stat().isSocket()` check: connecting is the existence check.
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseLocalEndpoint(raw: unknown): LocalEndpoint;
|
|
14
|
+
export declare class LocalEndpointError extends Error {
|
|
15
|
+
readonly code: 'unavailable' | 'aborted' | 'timeout' | 'transport';
|
|
16
|
+
readonly maybeDelivered: boolean;
|
|
17
|
+
constructor(code: LocalEndpointError['code'], maybeDelivered?: boolean);
|
|
18
|
+
}
|
|
19
|
+
export interface LocalConnectScope {
|
|
20
|
+
readonly signal?: AbortSignal;
|
|
21
|
+
readonly timeoutMs?: number;
|
|
22
|
+
}
|
|
23
|
+
/** Connect with bounded waiting. A connect failure is `unavailable`: nothing was written. */
|
|
24
|
+
export declare function connectLocal(endpoint: LocalEndpoint, scope?: LocalConnectScope): Promise<net.Socket>;
|
|
25
|
+
/** LF-delimited JSON frames. Any failure here is past the uncertainty boundary. */
|
|
26
|
+
export declare function writeFrames(socket: net.Socket, frames: object[]): Promise<void>;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
/** Claude's own pipe spelling: `\\.\pipe\<lowercased name>`. */
|
|
4
|
+
const PIPE = /^[\\/]{2}[.?][\\/]pipe[\\/](?:(LOCAL)[\\/])?([^\\/]+)$/i;
|
|
5
|
+
/**
|
|
6
|
+
* A local endpoint is either a Windows named pipe or an absolute Unix socket
|
|
7
|
+
* path. There is no `stat().isSocket()` check: connecting is the existence check.
|
|
8
|
+
*/
|
|
9
|
+
export function parseLocalEndpoint(raw) {
|
|
10
|
+
if (typeof raw !== 'string' || raw.includes('\0'))
|
|
11
|
+
throw new Error('Invalid local endpoint.');
|
|
12
|
+
const pipe = PIPE.exec(raw);
|
|
13
|
+
if (pipe) {
|
|
14
|
+
const canonical = `\\\\.\\pipe\\${pipe[2].toLowerCase()}`;
|
|
15
|
+
return { kind: 'pipe', path: canonical, canonical };
|
|
16
|
+
}
|
|
17
|
+
if (!(process.platform === 'win32' ? /^[A-Za-z]:[\\/]/.test(raw) : raw.startsWith('/')))
|
|
18
|
+
throw new Error('Invalid local endpoint.');
|
|
19
|
+
const limit = process.platform === 'darwin' ? 103 : process.platform === 'linux' ? 107 : undefined;
|
|
20
|
+
if (limit !== undefined && Buffer.byteLength(raw) > limit)
|
|
21
|
+
throw new Error('Invalid local endpoint.');
|
|
22
|
+
const canonical = resolve(raw);
|
|
23
|
+
return { kind: 'unix', path: canonical, canonical };
|
|
24
|
+
}
|
|
25
|
+
export class LocalEndpointError extends Error {
|
|
26
|
+
code;
|
|
27
|
+
maybeDelivered;
|
|
28
|
+
constructor(code, maybeDelivered = false) {
|
|
29
|
+
super(code);
|
|
30
|
+
this.name = 'LocalEndpointError';
|
|
31
|
+
this.code = code;
|
|
32
|
+
this.maybeDelivered = maybeDelivered;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function errnoCode(error) {
|
|
36
|
+
let code;
|
|
37
|
+
if (typeof error === 'object' && error !== null)
|
|
38
|
+
code = error.code;
|
|
39
|
+
if (code === 'ENOENT' || code === 'ECONNREFUSED' || code === 'EPIPE' || code === 'EBUSY' || code === 'EACCES')
|
|
40
|
+
return 'unavailable';
|
|
41
|
+
return 'transport';
|
|
42
|
+
}
|
|
43
|
+
/** Connect with bounded waiting. A connect failure is `unavailable`: nothing was written. */
|
|
44
|
+
export function connectLocal(endpoint, scope = {}) {
|
|
45
|
+
return new Promise((resolveSocket, reject) => {
|
|
46
|
+
const socket = new net.Socket();
|
|
47
|
+
let settled = false;
|
|
48
|
+
const timeout = scope.timeoutMs === undefined ? undefined : setTimeout(() => finish(new LocalEndpointError('timeout')), scope.timeoutMs);
|
|
49
|
+
// Error/close handlers stay attached past settling: an already scheduled I/O
|
|
50
|
+
// failure must not become an unhandled event once this promise is done.
|
|
51
|
+
const finish = (error) => {
|
|
52
|
+
if (settled)
|
|
53
|
+
return;
|
|
54
|
+
settled = true;
|
|
55
|
+
if (timeout !== undefined)
|
|
56
|
+
clearTimeout(timeout);
|
|
57
|
+
scope.signal?.removeEventListener('abort', aborted);
|
|
58
|
+
socket.removeListener('connect', connected);
|
|
59
|
+
if (error) {
|
|
60
|
+
socket.destroy();
|
|
61
|
+
reject(error);
|
|
62
|
+
}
|
|
63
|
+
else
|
|
64
|
+
resolveSocket(socket);
|
|
65
|
+
};
|
|
66
|
+
const aborted = () => finish(new LocalEndpointError('aborted'));
|
|
67
|
+
const connected = () => finish();
|
|
68
|
+
const failed = (error) => finish(new LocalEndpointError(errnoCode(error)));
|
|
69
|
+
socket.once('connect', connected);
|
|
70
|
+
socket.once('error', failed);
|
|
71
|
+
socket.once('close', () => { if (!settled)
|
|
72
|
+
finish(new LocalEndpointError('unavailable')); });
|
|
73
|
+
scope.signal?.addEventListener('abort', aborted, { once: true });
|
|
74
|
+
if (scope.signal?.aborted) {
|
|
75
|
+
aborted();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
socket.connect(endpoint.path);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
failed(error);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/** LF-delimited JSON frames. Any failure here is past the uncertainty boundary. */
|
|
87
|
+
export function writeFrames(socket, frames) {
|
|
88
|
+
const payload = frames.map((frame) => JSON.stringify(frame)).join('\n') + '\n';
|
|
89
|
+
return new Promise((resolveWrite, reject) => {
|
|
90
|
+
let settled = false;
|
|
91
|
+
// Error/close handlers stay attached past settling, so a later I/O failure is
|
|
92
|
+
// swallowed here instead of surfacing as an unhandled socket event.
|
|
93
|
+
const finish = (error) => {
|
|
94
|
+
if (settled)
|
|
95
|
+
return;
|
|
96
|
+
settled = true;
|
|
97
|
+
if (error) {
|
|
98
|
+
reject(error);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
resolveWrite();
|
|
102
|
+
};
|
|
103
|
+
const failed = (error) => finish(new LocalEndpointError(errnoCode(error), true));
|
|
104
|
+
socket.once('error', failed);
|
|
105
|
+
socket.once('close', () => finish(new LocalEndpointError('transport', true)));
|
|
106
|
+
socket.end(payload, 'utf8', (error) => {
|
|
107
|
+
if (error) {
|
|
108
|
+
failed(error);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
finish();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { OpenCodeDeliveryResult, OpenCodeSendTextOptions } from './types.js';
|
|
2
|
+
/** Injected native capability. No endpoint discovery or SDK initialization. */
|
|
3
|
+
export interface OpenCodeSessionCapability {
|
|
4
|
+
get(input: {
|
|
5
|
+
sessionID: string;
|
|
6
|
+
}, options?: {
|
|
7
|
+
signal: AbortSignal;
|
|
8
|
+
}): Promise<unknown>;
|
|
9
|
+
prompt(input: {
|
|
10
|
+
sessionID: string;
|
|
11
|
+
id: string;
|
|
12
|
+
text: string;
|
|
13
|
+
delivery: 'steer' | 'queue';
|
|
14
|
+
resume: true;
|
|
15
|
+
}, options?: {
|
|
16
|
+
signal: AbortSignal;
|
|
17
|
+
}): Promise<unknown>;
|
|
18
|
+
}
|
|
19
|
+
export interface OpenCodeNativeSession {
|
|
20
|
+
readonly sessionId: string;
|
|
21
|
+
readonly session: OpenCodeSessionCapability;
|
|
22
|
+
}
|
|
23
|
+
export declare function isNativeSession(value: unknown, sessionId: string): value is Record<string, unknown>;
|
|
24
|
+
/** Validate an explicit existing identity against the receiving backend. */
|
|
25
|
+
export declare function connectNative(options: {
|
|
26
|
+
sessionId: string;
|
|
27
|
+
session: OpenCodeSessionCapability;
|
|
28
|
+
timeoutMs?: number;
|
|
29
|
+
signal?: AbortSignal;
|
|
30
|
+
}): Promise<OpenCodeNativeSession>;
|
|
31
|
+
export declare function createNativeInputId(): string;
|
|
32
|
+
/** Submit once. Deadline/cancellation bounds waiting, not in-process native custody. */
|
|
33
|
+
export declare function sendNativeText(target: OpenCodeNativeSession, text: string, options?: OpenCodeSendTextOptions): Promise<OpenCodeDeliveryResult>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { deadline, validSignal, validTimeout } from './deadline.js';
|
|
3
|
+
import { ConnectionError } from './errors.js';
|
|
4
|
+
const record = (v) => typeof v === 'object' && v !== null;
|
|
5
|
+
const identity = (v) => typeof v === 'string' && v.trim().length > 0;
|
|
6
|
+
export function isNativeSession(value, sessionId) {
|
|
7
|
+
return record(value) && value.id === sessionId;
|
|
8
|
+
}
|
|
9
|
+
/** Validate an explicit existing identity against the receiving backend. */
|
|
10
|
+
export async function connectNative(options) {
|
|
11
|
+
if (!record(options) || !identity(options.sessionId) || !record(options.session) ||
|
|
12
|
+
typeof options.session.get !== 'function' || typeof options.session.prompt !== 'function' ||
|
|
13
|
+
!validTimeout(options.timeoutMs) || !validSignal(options.signal))
|
|
14
|
+
throw new ConnectionError('invalid_arguments');
|
|
15
|
+
const scope = deadline(options.timeoutMs, options.signal);
|
|
16
|
+
try {
|
|
17
|
+
scope.check();
|
|
18
|
+
const session = await scope.wait(options.session.get({ sessionID: options.sessionId }, { signal: scope.signal }));
|
|
19
|
+
scope.check();
|
|
20
|
+
if (!isNativeSession(session, options.sessionId))
|
|
21
|
+
throw new ConnectionError('invalid_response');
|
|
22
|
+
return { sessionId: options.sessionId, session: options.session };
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
if (scope.code !== undefined)
|
|
26
|
+
throw new ConnectionError(scope.code);
|
|
27
|
+
if (error instanceof ConnectionError)
|
|
28
|
+
throw error;
|
|
29
|
+
throw new ConnectionError('service_unavailable');
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
scope.close();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function admission(value, sessionId, inputId) {
|
|
36
|
+
return record(value) && value.id === inputId && value.sessionID === sessionId &&
|
|
37
|
+
value.type === 'user' && (value.delivery === 'steer' || value.delivery === 'queue') &&
|
|
38
|
+
record(value.payload) && typeof value.payload.text === 'string' &&
|
|
39
|
+
record(value.time) && typeof value.time.created === 'number' &&
|
|
40
|
+
Number.isFinite(value.time.created) && value.time.created >= 0;
|
|
41
|
+
}
|
|
42
|
+
export function createNativeInputId() { return `msg_${randomUUID()}`; }
|
|
43
|
+
/** Submit once. Deadline/cancellation bounds waiting, not in-process native custody. */
|
|
44
|
+
export async function sendNativeText(target, text, options = {}) {
|
|
45
|
+
if (!record(target) || !identity(target.sessionId) || !record(target.session) || typeof target.session.prompt !== 'function' ||
|
|
46
|
+
typeof text !== 'string' || text.length === 0 || !record(options) ||
|
|
47
|
+
!validTimeout(options.timeoutMs) || !validSignal(options.signal) ||
|
|
48
|
+
(options.delivery !== undefined && options.delivery !== 'steer' && options.delivery !== 'queue') ||
|
|
49
|
+
(options.inputId !== undefined && (typeof options.inputId !== 'string' || !options.inputId.startsWith('msg_') || options.inputId.length <= 4))) {
|
|
50
|
+
throw new TypeError('Invalid sendText arguments.');
|
|
51
|
+
}
|
|
52
|
+
const inputId = options.inputId ?? createNativeInputId();
|
|
53
|
+
const attempt = { harness: 'opencode', sessionId: target.sessionId, inputId };
|
|
54
|
+
const scope = deadline(options.timeoutMs, options.signal);
|
|
55
|
+
let invoked = false;
|
|
56
|
+
try {
|
|
57
|
+
scope.check();
|
|
58
|
+
invoked = true;
|
|
59
|
+
const value = await scope.wait(target.session.prompt({
|
|
60
|
+
sessionID: target.sessionId, id: inputId, text, delivery: options.delivery ?? 'steer', resume: true,
|
|
61
|
+
}, { signal: scope.signal }));
|
|
62
|
+
scope.check();
|
|
63
|
+
if (!admission(value, target.sessionId, inputId))
|
|
64
|
+
return { ...attempt, state: 'unknown', code: 'invalid_response' };
|
|
65
|
+
const receipt = value;
|
|
66
|
+
return { ...attempt, state: 'accepted', inboxId: receipt.id, delivery: receipt.delivery };
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return invoked ? { ...attempt, state: 'unknown', code: scope.code ?? 'transport' }
|
|
70
|
+
: { ...attempt, state: 'unavailable', code: scope.code ?? 'aborted' };
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
scope.close();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Endpoint } from '@opencode/client/service';
|
|
2
|
+
import type { OpenCodeDeliveryResult, OpenCodeTarget, OpenCodeSendTextOptions } from './types.js';
|
|
3
|
+
export interface OpenCodeConnectExistingOptions {
|
|
4
|
+
readonly harness: 'opencode';
|
|
5
|
+
readonly sessionId: string;
|
|
6
|
+
readonly endpoint?: Endpoint;
|
|
7
|
+
readonly registrationFile?: string;
|
|
8
|
+
readonly timeoutMs?: number;
|
|
9
|
+
readonly signal?: AbortSignal;
|
|
10
|
+
}
|
|
11
|
+
/** Resolve an existing service and persisted session. Never starts or stops a service. */
|
|
12
|
+
export declare function connectExisting(options: OpenCodeConnectExistingOptions): Promise<OpenCodeTarget>;
|
|
13
|
+
/** Submit once through the shared native sender; HTTP metadata alone refines rejection. */
|
|
14
|
+
export declare function sendText(target: OpenCodeTarget, text: string, options?: OpenCodeSendTextOptions): Promise<OpenCodeDeliveryResult>;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { isAbsolute } from 'node:path';
|
|
2
|
+
import { OpenCode } from '@opencode/client';
|
|
3
|
+
import { Service } from '@opencode/client/service';
|
|
4
|
+
import { deadline, validSignal, validTimeout } from './deadline.js';
|
|
5
|
+
import { ConnectionError } from './errors.js';
|
|
6
|
+
import { isIdentity, isRecord } from './guards.js';
|
|
7
|
+
import { isNativeSession, sendNativeText } from './opencode-native.js';
|
|
8
|
+
const endpoints = new WeakMap();
|
|
9
|
+
const isV2 = (version) => /^2\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(version);
|
|
10
|
+
function endpointValid(value) {
|
|
11
|
+
if (!isRecord(value) || typeof value.url !== 'string')
|
|
12
|
+
return false;
|
|
13
|
+
try {
|
|
14
|
+
const url = new URL(value.url);
|
|
15
|
+
// Secrets belong only in auth, never URL userinfo/query/fragment. No redirects.
|
|
16
|
+
if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password || url.search || url.hash)
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return value.auth === undefined || (isRecord(value.auth) && value.auth.type === 'basic' &&
|
|
23
|
+
typeof value.auth.username === 'string' && typeof value.auth.password === 'string');
|
|
24
|
+
}
|
|
25
|
+
/** SDK transport observation: never parse or expose arbitrary error bodies. */
|
|
26
|
+
function transport(endpoint, scope) {
|
|
27
|
+
let dispatched = false;
|
|
28
|
+
let status;
|
|
29
|
+
const client = OpenCode.make({
|
|
30
|
+
baseUrl: endpoint.url,
|
|
31
|
+
headers: Service.headers(endpoint),
|
|
32
|
+
fetch: async (input, init) => {
|
|
33
|
+
scope.check();
|
|
34
|
+
dispatched = true;
|
|
35
|
+
status = undefined;
|
|
36
|
+
const response = await globalThis.fetch(input, { ...init, redirect: 'manual' });
|
|
37
|
+
status = response.status;
|
|
38
|
+
return response;
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
return { client, get dispatched() { return dispatched; }, get status() { return status; } };
|
|
42
|
+
}
|
|
43
|
+
function connectionFailure(status, phase) {
|
|
44
|
+
if (status === 401 || status === 403)
|
|
45
|
+
return new ConnectionError('authentication_failed', status);
|
|
46
|
+
if (status === 404 && phase === 'session')
|
|
47
|
+
return new ConnectionError('session_not_found', status);
|
|
48
|
+
if (status !== undefined && status !== 200)
|
|
49
|
+
return new ConnectionError('http_rejection', status);
|
|
50
|
+
return new ConnectionError(status === 200 ? 'invalid_response' : 'service_unavailable');
|
|
51
|
+
}
|
|
52
|
+
/** Resolve an existing service and persisted session. Never starts or stops a service. */
|
|
53
|
+
export async function connectExisting(options) {
|
|
54
|
+
if (!isRecord(options) || options.harness !== 'opencode' || !isIdentity(options.sessionId) ||
|
|
55
|
+
!validTimeout(options.timeoutMs) || !validSignal(options.signal) ||
|
|
56
|
+
(options.endpoint !== undefined && options.registrationFile !== undefined) ||
|
|
57
|
+
(options.endpoint !== undefined && !endpointValid(options.endpoint)) ||
|
|
58
|
+
(options.registrationFile !== undefined &&
|
|
59
|
+
(typeof options.registrationFile !== 'string' || !isAbsolute(options.registrationFile)))) {
|
|
60
|
+
throw new ConnectionError('invalid_arguments');
|
|
61
|
+
}
|
|
62
|
+
const scope = deadline(options.timeoutMs, options.signal);
|
|
63
|
+
let current;
|
|
64
|
+
let phase = 'health';
|
|
65
|
+
try {
|
|
66
|
+
scope.check();
|
|
67
|
+
const endpoint = options.endpoint ?? await scope.wait(Service.discover({
|
|
68
|
+
file: options.registrationFile,
|
|
69
|
+
version: isV2,
|
|
70
|
+
}));
|
|
71
|
+
// Discover may finish later than the caller deadline: never continue from it.
|
|
72
|
+
scope.check();
|
|
73
|
+
if (endpoint === undefined)
|
|
74
|
+
throw new ConnectionError('service_unavailable');
|
|
75
|
+
if (!endpointValid(endpoint))
|
|
76
|
+
throw new ConnectionError('invalid_response');
|
|
77
|
+
const privateEndpoint = {
|
|
78
|
+
url: endpoint.url,
|
|
79
|
+
...(endpoint.auth === undefined ? {} : { auth: { ...endpoint.auth } }),
|
|
80
|
+
};
|
|
81
|
+
current = transport(privateEndpoint, scope);
|
|
82
|
+
const info = await scope.wait(current.client.server.info({ signal: scope.signal }));
|
|
83
|
+
scope.check();
|
|
84
|
+
if (!isRecord(info) || typeof info.version !== 'string' ||
|
|
85
|
+
!Number.isInteger(info.pid) || info.pid < 0)
|
|
86
|
+
throw new ConnectionError('invalid_response');
|
|
87
|
+
if (!isV2(info.version))
|
|
88
|
+
throw new ConnectionError('unsupported_version');
|
|
89
|
+
phase = 'session';
|
|
90
|
+
const session = await scope.wait(current.client.session.get({ sessionID: options.sessionId }, { signal: scope.signal }));
|
|
91
|
+
scope.check();
|
|
92
|
+
if (!isNativeSession(session, options.sessionId))
|
|
93
|
+
throw new ConnectionError('invalid_response');
|
|
94
|
+
const target = Object.freeze({ harness: 'opencode', sessionId: options.sessionId });
|
|
95
|
+
endpoints.set(target, privateEndpoint);
|
|
96
|
+
return target;
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
if (scope.code !== undefined)
|
|
100
|
+
throw new ConnectionError(scope.code);
|
|
101
|
+
if (error instanceof ConnectionError)
|
|
102
|
+
throw error;
|
|
103
|
+
throw connectionFailure(current?.status, phase);
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
scope.close();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/** Submit once through the shared native sender; HTTP metadata alone refines rejection. */
|
|
110
|
+
export async function sendText(target, text, options = {}) {
|
|
111
|
+
if (!isRecord(target) || !endpoints.has(target)) {
|
|
112
|
+
throw new TypeError('Invalid sendText arguments.');
|
|
113
|
+
}
|
|
114
|
+
const current = transport(endpoints.get(target), { check() { } });
|
|
115
|
+
const result = await sendNativeText({ sessionId: target.sessionId, session: current.client.session }, text, options);
|
|
116
|
+
if (result.state !== 'unknown')
|
|
117
|
+
return result;
|
|
118
|
+
// Only native validation/auth/not-found/conflict responses establish rejection.
|
|
119
|
+
// A proxy or backend can fail after durable admission, including with a 5xx.
|
|
120
|
+
if (current.status !== undefined && [400, 401, 403, 404, 409].includes(current.status)) {
|
|
121
|
+
return { harness: result.harness, sessionId: result.sessionId, inputId: result.inputId,
|
|
122
|
+
state: 'rejected', code: 'http_rejection', status: current.status };
|
|
123
|
+
}
|
|
124
|
+
if (!current.dispatched)
|
|
125
|
+
return { ...result, state: 'unavailable', code: result.code === 'timeout' ? 'timeout' : 'aborted' };
|
|
126
|
+
return { ...result, code: current.status === 200 && result.code === 'transport' ? 'invalid_response' : result.code };
|
|
127
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** A resolved daemon coordinate: one WebSocket URL and, for IPC, its socket path. */
|
|
2
|
+
export interface PaseoDaemonTarget {
|
|
3
|
+
readonly url: string;
|
|
4
|
+
readonly socketPath?: string;
|
|
5
|
+
/** A password spelled into a tcp:// endpoint, when that endpoint carries one. */
|
|
6
|
+
readonly password?: string;
|
|
7
|
+
}
|
|
8
|
+
/** Authentication for one daemon connection; the daemon client claims at most one. */
|
|
9
|
+
export interface PaseoCredential {
|
|
10
|
+
readonly authHeader?: string;
|
|
11
|
+
readonly password?: string;
|
|
12
|
+
readonly localCredential?: () => string | undefined;
|
|
13
|
+
}
|
|
14
|
+
/** One projected timeline entry, as far as a wake boundary check reads it. */
|
|
15
|
+
export interface PaseoAgentTimeline {
|
|
16
|
+
readonly agent?: {
|
|
17
|
+
readonly status?: string;
|
|
18
|
+
};
|
|
19
|
+
readonly entries?: readonly {
|
|
20
|
+
readonly item: {
|
|
21
|
+
readonly type?: string;
|
|
22
|
+
readonly callId?: string;
|
|
23
|
+
readonly status?: string;
|
|
24
|
+
};
|
|
25
|
+
}[];
|
|
26
|
+
}
|
|
27
|
+
/** The daemon client subset every Paseo caller uses; the SDK stays a dynamic import. */
|
|
28
|
+
export interface PaseoClient {
|
|
29
|
+
connect(): Promise<void>;
|
|
30
|
+
close(): Promise<void>;
|
|
31
|
+
sendAgentMessage(agentId: string, text: string, options: {
|
|
32
|
+
messageId: string;
|
|
33
|
+
activeTurnBehavior: 'steer';
|
|
34
|
+
}): Promise<unknown>;
|
|
35
|
+
fetchAgentTimeline(agentId: string, options: {
|
|
36
|
+
direction: 'tail';
|
|
37
|
+
limit: number;
|
|
38
|
+
projection: 'projected';
|
|
39
|
+
timeout: number;
|
|
40
|
+
}): Promise<PaseoAgentTimeline>;
|
|
41
|
+
}
|
|
42
|
+
/** `~/` expansion plus the daemon's default home directory. */
|
|
43
|
+
export declare function paseoHome(explicit?: string, env?: NodeJS.ProcessEnv): string;
|
|
44
|
+
/** One resolution for every Paseo caller. Never starts or stops anything. */
|
|
45
|
+
export declare function resolvePaseoDaemon(endpoint: string | undefined, env?: NodeJS.ProcessEnv, home?: string): PaseoDaemonTarget | undefined;
|
|
46
|
+
/** Explicit credential first, then the endpoint's own password, then the daemon's local credential, then `PASEO_PASSWORD`. */
|
|
47
|
+
export declare function daemonCredential(options: {
|
|
48
|
+
readonly authHeader?: string;
|
|
49
|
+
readonly password?: string;
|
|
50
|
+
readonly localCredential?: string;
|
|
51
|
+
/** The password spelled into the resolved endpoint, when it carries one. */
|
|
52
|
+
readonly endpointPassword?: string;
|
|
53
|
+
}, env?: NodeJS.ProcessEnv, home?: string): PaseoCredential;
|
|
54
|
+
/**
|
|
55
|
+
* Open one daemon connection. The SDK and `ws` load only when a Paseo call actually
|
|
56
|
+
* runs, so importing this module never pulls an optional peer dependency.
|
|
57
|
+
*/
|
|
58
|
+
export declare function openPaseoClient(target: PaseoDaemonTarget, credential?: PaseoCredential, timeoutMs?: number): Promise<PaseoClient>;
|