ds-harness-remote 0.3.8
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/LICENSE +21 -0
- package/README.md +103 -0
- package/cordis.patch.yml +7 -0
- package/dist/adapters/agent-adapter.d.ts +35 -0
- package/dist/adapters/agent-adapter.d.ts.map +1 -0
- package/dist/adapters/agent-adapter.js +80 -0
- package/dist/adapters/agent-adapter.js.map +1 -0
- package/dist/adapters/permission-adapter.d.ts +13 -0
- package/dist/adapters/permission-adapter.d.ts.map +1 -0
- package/dist/adapters/permission-adapter.js +67 -0
- package/dist/adapters/permission-adapter.js.map +1 -0
- package/dist/adapters/session-adapter.d.ts +38 -0
- package/dist/adapters/session-adapter.d.ts.map +1 -0
- package/dist/adapters/session-adapter.js +230 -0
- package/dist/adapters/session-adapter.js.map +1 -0
- package/dist/adapters/workspace-adapter.d.ts +13 -0
- package/dist/adapters/workspace-adapter.d.ts.map +1 -0
- package/dist/adapters/workspace-adapter.js +21 -0
- package/dist/adapters/workspace-adapter.js.map +1 -0
- package/dist/api-proxy-switch.d.ts +33 -0
- package/dist/api-proxy-switch.d.ts.map +1 -0
- package/dist/api-proxy-switch.js +107 -0
- package/dist/api-proxy-switch.js.map +1 -0
- package/dist/bin/doctor.d.ts +3 -0
- package/dist/bin/doctor.d.ts.map +1 -0
- package/dist/bin/doctor.js +13 -0
- package/dist/bin/doctor.js.map +1 -0
- package/dist/client-runtime.d.ts +98 -0
- package/dist/client-runtime.d.ts.map +1 -0
- package/dist/client-runtime.js +421 -0
- package/dist/client-runtime.js.map +1 -0
- package/dist/client-secure-transport.d.ts +22 -0
- package/dist/client-secure-transport.d.ts.map +1 -0
- package/dist/client-secure-transport.js +129 -0
- package/dist/client-secure-transport.js.map +1 -0
- package/dist/client.d.ts +12 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.github.js +2938 -0
- package/dist/client.js +2938 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +33 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +80 -0
- package/dist/config.js.map +1 -0
- package/dist/connection-controller.d.ts +39 -0
- package/dist/connection-controller.d.ts.map +1 -0
- package/dist/connection-controller.js +170 -0
- package/dist/connection-controller.js.map +1 -0
- package/dist/control-runtime.d.ts +36 -0
- package/dist/control-runtime.d.ts.map +1 -0
- package/dist/control-runtime.js +265 -0
- package/dist/control-runtime.js.map +1 -0
- package/dist/event-sequencer.d.ts +23 -0
- package/dist/event-sequencer.d.ts.map +1 -0
- package/dist/event-sequencer.js +54 -0
- package/dist/event-sequencer.js.map +1 -0
- package/dist/harness-api-bridge.d.ts +55 -0
- package/dist/harness-api-bridge.d.ts.map +1 -0
- package/dist/harness-api-bridge.js +387 -0
- package/dist/harness-api-bridge.js.map +1 -0
- package/dist/identity-store.d.ts +45 -0
- package/dist/identity-store.d.ts.map +1 -0
- package/dist/identity-store.js +183 -0
- package/dist/identity-store.js.map +1 -0
- package/dist/ids.d.ts +2 -0
- package/dist/ids.d.ts.map +1 -0
- package/dist/ids.js +17 -0
- package/dist/ids.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16091 -0
- package/dist/index.js.map +7 -0
- package/dist/logging.d.ts +18 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +30 -0
- package/dist/logging.js.map +1 -0
- package/dist/pairing-controller.d.ts +52 -0
- package/dist/pairing-controller.d.ts.map +1 -0
- package/dist/pairing-controller.js +73 -0
- package/dist/pairing-controller.js.map +1 -0
- package/dist/pending-approvals.d.ts +14 -0
- package/dist/pending-approvals.d.ts.map +1 -0
- package/dist/pending-approvals.js +52 -0
- package/dist/pending-approvals.js.map +1 -0
- package/dist/remote-api-proxy.d.ts +12 -0
- package/dist/remote-api-proxy.d.ts.map +1 -0
- package/dist/remote-api-proxy.js +191 -0
- package/dist/remote-api-proxy.js.map +1 -0
- package/dist/remote-directory-browser.d.ts +16 -0
- package/dist/remote-directory-browser.d.ts.map +1 -0
- package/dist/remote-directory-browser.js +48 -0
- package/dist/remote-directory-browser.js.map +1 -0
- package/dist/rpc-router.d.ts +21 -0
- package/dist/rpc-router.d.ts.map +1 -0
- package/dist/rpc-router.js +93 -0
- package/dist/rpc-router.js.map +1 -0
- package/dist/server-api.d.ts +80 -0
- package/dist/server-api.d.ts.map +1 -0
- package/dist/server-api.js +405 -0
- package/dist/server-api.js.map +1 -0
- package/dist/server-connection.d.ts +70 -0
- package/dist/server-connection.d.ts.map +1 -0
- package/dist/server-connection.js +759 -0
- package/dist/server-connection.js.map +1 -0
- package/dist/server-credentials.d.ts +46 -0
- package/dist/server-credentials.d.ts.map +1 -0
- package/dist/server-credentials.js +71 -0
- package/dist/server-credentials.js.map +1 -0
- package/dist/service.d.ts +56 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +162 -0
- package/dist/service.js.map +1 -0
- package/dist/typert-gateway-switch.d.ts +19 -0
- package/dist/typert-gateway-switch.d.ts.map +1 -0
- package/dist/typert-gateway-switch.js +41 -0
- package/dist/typert-gateway-switch.js.map +1 -0
- package/dist/types.d.ts +20 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +12 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +12 -0
- package/dist/version.js.map +1 -0
- package/dist/werift-rtc.d.ts +85 -0
- package/dist/werift-rtc.d.ts.map +1 -0
- package/dist/werift-rtc.js +164 -0
- package/dist/werift-rtc.js.map +1 -0
- package/package.json +98 -0
- package/public.d.ts +19 -0
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import { createRpcResponse, encodeMessage, MAX_SECURE_MESSAGE_BYTES, } from '@dsh-remote/protocol';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { RpcError } from './rpc-router.js';
|
|
4
|
+
import { listRemoteDirectory } from './remote-directory-browser.js';
|
|
5
|
+
const callSchema = z.object({
|
|
6
|
+
method: z.string().min(1).max(80),
|
|
7
|
+
rpcId: z.string().min(1).max(128),
|
|
8
|
+
payload: z.unknown(),
|
|
9
|
+
}).strict();
|
|
10
|
+
const respondSchema = z.object({
|
|
11
|
+
message: z.object({
|
|
12
|
+
type: z.literal('client-response'),
|
|
13
|
+
rpcId: z.string().min(1).max(128),
|
|
14
|
+
result: z.unknown(),
|
|
15
|
+
}).strict(),
|
|
16
|
+
}).strict();
|
|
17
|
+
const streamOpenSchema = z.object({
|
|
18
|
+
streamId: z.string().min(1).max(128),
|
|
19
|
+
stream: z.enum(['mux', 'host']),
|
|
20
|
+
rpcId: z.string().min(1).max(128),
|
|
21
|
+
payload: z.object({
|
|
22
|
+
// Optional focus for a mux stream: only frames belonging to this session
|
|
23
|
+
// are forwarded. The Remote Web selects one session at a time, so without
|
|
24
|
+
// this every active session's events (potentially megabytes) would be
|
|
25
|
+
// pushed over the tunnel and stall the WebRTC data channel.
|
|
26
|
+
sessionId: z.string().min(1).max(128).optional(),
|
|
27
|
+
}).strict(),
|
|
28
|
+
}).strict();
|
|
29
|
+
const streamCloseSchema = z.object({ streamId: z.string().min(1).max(128) }).strict();
|
|
30
|
+
const permissionCommandSchema = z.object({
|
|
31
|
+
agentId: z.string().min(1).max(128),
|
|
32
|
+
line: z.string().regex(/^\/permission [a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
33
|
+
}).strict();
|
|
34
|
+
/**
|
|
35
|
+
* Harness API methods that are safe to expose to an authenticated remote UI.
|
|
36
|
+
* Settings, credentials, native open/picker calls, directory mutation, file
|
|
37
|
+
* contents, downloads, and attachment upload intentionally remain outside
|
|
38
|
+
* this bridge. Directory listing exposes metadata only for workspace picking.
|
|
39
|
+
*/
|
|
40
|
+
export const HARNESS_API_ALLOWLIST = [
|
|
41
|
+
'session.list',
|
|
42
|
+
'session.search',
|
|
43
|
+
'session.create',
|
|
44
|
+
'session.history',
|
|
45
|
+
'session.models',
|
|
46
|
+
'session.selectModel',
|
|
47
|
+
'session.rename',
|
|
48
|
+
'session.fork',
|
|
49
|
+
'session.prompt',
|
|
50
|
+
'session.updateQueue',
|
|
51
|
+
'session.cancel',
|
|
52
|
+
'subagent.list',
|
|
53
|
+
'subagent.history',
|
|
54
|
+
'subagent.prompt',
|
|
55
|
+
'subagent.interrupt',
|
|
56
|
+
'host.describe',
|
|
57
|
+
'host.listDirectory',
|
|
58
|
+
'workspace.list',
|
|
59
|
+
'workspace.create',
|
|
60
|
+
'workspace.rename',
|
|
61
|
+
'workspace.delete',
|
|
62
|
+
'workspace.insertBefore',
|
|
63
|
+
'workspace.insertSessionBefore',
|
|
64
|
+
'workspace.archiveSession',
|
|
65
|
+
'skill.list',
|
|
66
|
+
'agentPreset.list',
|
|
67
|
+
'agentPreset.select',
|
|
68
|
+
'agentPreset.read',
|
|
69
|
+
'goal.create',
|
|
70
|
+
'goal.edit',
|
|
71
|
+
'goal.pause',
|
|
72
|
+
'goal.resume',
|
|
73
|
+
'goal.complete',
|
|
74
|
+
'goal.clear',
|
|
75
|
+
'commands.execute',
|
|
76
|
+
'llm.providers',
|
|
77
|
+
'llm.models',
|
|
78
|
+
];
|
|
79
|
+
/**
|
|
80
|
+
* Native Harness ApiProxy call timeout. The Remote Web frontend gives each
|
|
81
|
+
* `harness.api.call` RPC a 60s window; this bridge must fail faster so the
|
|
82
|
+
* RPC error (not a silent Web-side timeout) reaches the peer and the pending
|
|
83
|
+
* call is released. 30s gives slow native methods room while still beating the
|
|
84
|
+
* Web-side 60s timer by a wide margin.
|
|
85
|
+
*/
|
|
86
|
+
const NATIVE_CALL_TIMEOUT_MS = 30_000;
|
|
87
|
+
const SESSION_HISTORY_PAGE_SIZES = [50, 30, 20, 12, 6, 3, 1];
|
|
88
|
+
export class HarnessApiBridge {
|
|
89
|
+
api;
|
|
90
|
+
publish;
|
|
91
|
+
maxStreams;
|
|
92
|
+
logger;
|
|
93
|
+
methods;
|
|
94
|
+
streams = new Map();
|
|
95
|
+
respondable = new Map();
|
|
96
|
+
mux;
|
|
97
|
+
host;
|
|
98
|
+
answer;
|
|
99
|
+
constructor(api, publish, maxStreams = 3, logger, typertGateway) {
|
|
100
|
+
this.api = api;
|
|
101
|
+
this.publish = publish;
|
|
102
|
+
this.maxStreams = maxStreams;
|
|
103
|
+
this.logger = logger;
|
|
104
|
+
this.methods = createMethodMap(api, typertGateway);
|
|
105
|
+
this.mux = api.events.mux.bind(api.events);
|
|
106
|
+
this.host = api.events.host.bind(api.events);
|
|
107
|
+
this.answer = api.respond.bind(api);
|
|
108
|
+
}
|
|
109
|
+
async call(input) {
|
|
110
|
+
const params = callSchema.parse(input);
|
|
111
|
+
const method = this.methods.get(params.method);
|
|
112
|
+
if (method === undefined)
|
|
113
|
+
throw deniedMethod(params.method);
|
|
114
|
+
const startedAt = performance.now();
|
|
115
|
+
const signal = AbortSignal.timeout(NATIVE_CALL_TIMEOUT_MS);
|
|
116
|
+
const request = { rpcId: params.rpcId, payload: params.payload };
|
|
117
|
+
try {
|
|
118
|
+
// Race the native call against the timeout: some native ApiProxy
|
|
119
|
+
// methods ignore AbortSignal, and without this the Host would never
|
|
120
|
+
// answer and the Web-side 60s timer would fire instead. A guaranteed
|
|
121
|
+
// local response turns that into a fast, explicit RPC error.
|
|
122
|
+
const callWithTimeout = (overridePayload) => withTimeout(method({ rpcId: params.rpcId, payload: overridePayload }, signal), NATIVE_CALL_TIMEOUT_MS, `Harness API call ${params.method} timed out after ${NATIVE_CALL_TIMEOUT_MS}ms`);
|
|
123
|
+
let response;
|
|
124
|
+
if (params.method === 'session.history') {
|
|
125
|
+
response = await callSessionHistory(callWithTimeout, params.payload, params.rpcId);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
response = await callWithTimeout(request.payload);
|
|
129
|
+
}
|
|
130
|
+
if (params.method === 'host.listDirectory' && needsRemoteDirectoryFallback(response)) {
|
|
131
|
+
const payload = typeof params.payload === 'object' && params.payload !== null ? params.payload : {};
|
|
132
|
+
const value = await listRemoteDirectory(typeof payload.path === 'string' ? payload.path : undefined, signal);
|
|
133
|
+
response = { rpcId: params.rpcId, result: { ok: true, value } };
|
|
134
|
+
}
|
|
135
|
+
this.logger?.debug('harness api call ok', {
|
|
136
|
+
method: params.method,
|
|
137
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
138
|
+
});
|
|
139
|
+
return response;
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
const durationMs = Math.round(performance.now() - startedAt);
|
|
143
|
+
this.logger?.warn('harness api call failed', {
|
|
144
|
+
method: params.method,
|
|
145
|
+
durationMs,
|
|
146
|
+
timedOut: signal.aborted,
|
|
147
|
+
reason: diagnosticReason(error),
|
|
148
|
+
});
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async respond(input) {
|
|
153
|
+
const params = respondSchema.parse(input);
|
|
154
|
+
this.logger?.debug('harness api respond', { rpcId: shortId(params.message.rpcId) });
|
|
155
|
+
if (!this.respondable.has(params.message.rpcId)) {
|
|
156
|
+
throw new RpcError('PERMISSION_NOT_PENDING', 'The response id was not emitted on this peer connection.');
|
|
157
|
+
}
|
|
158
|
+
const receipt = await this.answer(params.message);
|
|
159
|
+
if (receipt.accepted || receipt.reason === 'not-pending')
|
|
160
|
+
this.respondable.delete(params.message.rpcId);
|
|
161
|
+
return receipt;
|
|
162
|
+
}
|
|
163
|
+
openStream(input) {
|
|
164
|
+
const params = streamOpenSchema.parse(input);
|
|
165
|
+
if (this.streams.has(params.streamId))
|
|
166
|
+
throw new RpcError('REQUEST_CONFLICT', 'The Harness event stream is already open.');
|
|
167
|
+
if (this.streams.size >= this.maxStreams)
|
|
168
|
+
throw new RpcError('RATE_LIMITED', 'Too many Harness event streams are open.', undefined, true);
|
|
169
|
+
const controller = new AbortController();
|
|
170
|
+
const request = { rpcId: params.rpcId, payload: params.payload };
|
|
171
|
+
const stream = params.stream === 'mux'
|
|
172
|
+
? this.mux(request, controller.signal)
|
|
173
|
+
: this.host(request, controller.signal);
|
|
174
|
+
const focusSessionId = params.stream === 'mux' ? params.payload.sessionId : undefined;
|
|
175
|
+
const task = this.pump(params.streamId, stream, controller.signal, focusSessionId);
|
|
176
|
+
this.streams.set(params.streamId, { controller, task, ...(focusSessionId === undefined ? {} : { focusSessionId }) });
|
|
177
|
+
this.logger?.debug('harness api stream open', {
|
|
178
|
+
stream: params.stream,
|
|
179
|
+
streamId: shortId(params.streamId),
|
|
180
|
+
...(focusSessionId === undefined ? {} : { focusSessionId: shortId(focusSessionId) }),
|
|
181
|
+
});
|
|
182
|
+
return { opened: true, streamId: params.streamId };
|
|
183
|
+
}
|
|
184
|
+
closeStream(input) {
|
|
185
|
+
const params = streamCloseSchema.parse(input);
|
|
186
|
+
const active = this.streams.get(params.streamId);
|
|
187
|
+
if (active !== undefined) {
|
|
188
|
+
// Free the slot synchronously. A native ApiProxy stream may not observe
|
|
189
|
+
// the abort until its next frame, so a session-focused mux stream on an
|
|
190
|
+
// idle session could otherwise hold its slot forever and block the
|
|
191
|
+
// client's documented close-then-reopen session switch with
|
|
192
|
+
// RATE_LIMITED. The pump's finally performs a no-op delete later.
|
|
193
|
+
this.streams.delete(params.streamId);
|
|
194
|
+
active.controller.abort();
|
|
195
|
+
}
|
|
196
|
+
this.logger?.debug('harness api stream close', { streamId: shortId(params.streamId), closed: active !== undefined });
|
|
197
|
+
return { closed: active !== undefined, streamId: params.streamId };
|
|
198
|
+
}
|
|
199
|
+
async closeAll(reason = 'peer-disconnected') {
|
|
200
|
+
const streams = [...this.streams.values()];
|
|
201
|
+
this.streams.clear();
|
|
202
|
+
this.respondable.clear();
|
|
203
|
+
for (const stream of streams)
|
|
204
|
+
stream.controller.abort(reason);
|
|
205
|
+
// A native ApiProxy stream may not observe AbortSignal until its next
|
|
206
|
+
// frame. Waiting for every pump here would block a replacement peer from
|
|
207
|
+
// installing its message handler indefinitely. The detached pumps own
|
|
208
|
+
// their errors and terminal event publication, so abort and release them
|
|
209
|
+
// without holding up the authenticated connection handoff.
|
|
210
|
+
}
|
|
211
|
+
async pump(streamId, stream, signal, focusSessionId) {
|
|
212
|
+
let reason = 'completed';
|
|
213
|
+
try {
|
|
214
|
+
for await (const frame of stream) {
|
|
215
|
+
if (signal.aborted)
|
|
216
|
+
break;
|
|
217
|
+
if (focusSessionId !== undefined && frameSessionId(frame) !== undefined && frameSessionId(frame) !== focusSessionId) {
|
|
218
|
+
// Keep pushing to the native stream (the peer's upstream may still
|
|
219
|
+
// emit approvals for the focused session through the same pump) but
|
|
220
|
+
// do not forward other sessions' traffic over the tunnel.
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
this.trackRespondable(frame);
|
|
224
|
+
await this.publish('harness.api.frame', { streamId, frame });
|
|
225
|
+
}
|
|
226
|
+
if (signal.aborted)
|
|
227
|
+
reason = 'cancelled';
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
reason = signal.aborted ? 'cancelled' : 'failed';
|
|
231
|
+
}
|
|
232
|
+
finally {
|
|
233
|
+
this.streams.delete(streamId);
|
|
234
|
+
await this.publish('harness.api.stream.closed', { streamId, reason }).catch(() => undefined);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
trackRespondable(frame) {
|
|
238
|
+
const payload = frame.payload;
|
|
239
|
+
if (payload.type === 'approval/requested') {
|
|
240
|
+
this.respondable.set(String(frame.rpcId), `approval:${String(payload.approvalId)}`);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (payload.type === 'question/requested') {
|
|
244
|
+
this.respondable.set(String(frame.rpcId), `question:${String(frame.rpcId)}`);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (payload.type === 'approval/resolved') {
|
|
248
|
+
this.deleteRespondable(`approval:${String(payload.approvalId)}`);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (payload.type === 'question/resolved') {
|
|
252
|
+
this.respondable.delete(String(payload.questionRpcId));
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
deleteRespondable(value) {
|
|
256
|
+
for (const [rpcId, correlation] of this.respondable) {
|
|
257
|
+
if (correlation === value)
|
|
258
|
+
this.respondable.delete(rpcId);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function needsRemoteDirectoryFallback(response) {
|
|
263
|
+
const result = response.result;
|
|
264
|
+
return typeof result === 'object' && result !== null && 'ok' in result && result.ok === false
|
|
265
|
+
&& 'error' in result && typeof result.error === 'object' && result.error !== null
|
|
266
|
+
&& 'code' in result.error && result.error.code === 'directory-picker-unavailable';
|
|
267
|
+
}
|
|
268
|
+
function createMethodMap(api, typertGateway) {
|
|
269
|
+
const domains = api;
|
|
270
|
+
const methods = new Map();
|
|
271
|
+
for (const method of HARNESS_API_ALLOWLIST) {
|
|
272
|
+
if (method === 'commands.execute') {
|
|
273
|
+
// Commands live behind the official Typert registry (no ApiProxy
|
|
274
|
+
// `commands` domain). Dispatch them through the gateway when it is
|
|
275
|
+
// available; without it the method stays denied (fail-closed).
|
|
276
|
+
if (typertGateway === undefined)
|
|
277
|
+
continue;
|
|
278
|
+
const implementation = async (request, signal) => {
|
|
279
|
+
const args = permissionCommandSchema.parse(request.payload);
|
|
280
|
+
const [namespace, commandMethod] = method.split('.');
|
|
281
|
+
const value = await typertGateway.invoke({
|
|
282
|
+
namespace,
|
|
283
|
+
method: commandMethod,
|
|
284
|
+
args,
|
|
285
|
+
...(signal === undefined ? {} : { signal }),
|
|
286
|
+
});
|
|
287
|
+
return { rpcId: request.rpcId, result: { ok: true, value } };
|
|
288
|
+
};
|
|
289
|
+
methods.set(method, implementation);
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
const [wireDomain, action] = method.split('.');
|
|
293
|
+
const domain = domainProperty(wireDomain);
|
|
294
|
+
const implementation = domains[domain]?.[action];
|
|
295
|
+
if (typeof implementation !== 'function')
|
|
296
|
+
continue;
|
|
297
|
+
methods.set(method, implementation.bind(domains[domain]));
|
|
298
|
+
}
|
|
299
|
+
return methods;
|
|
300
|
+
}
|
|
301
|
+
function domainProperty(wireDomain) {
|
|
302
|
+
if (wireDomain === 'session')
|
|
303
|
+
return 'sessions';
|
|
304
|
+
if (wireDomain === 'subagent')
|
|
305
|
+
return 'subagents';
|
|
306
|
+
if (wireDomain === 'skill')
|
|
307
|
+
return 'skills';
|
|
308
|
+
if (wireDomain === 'agentPreset')
|
|
309
|
+
return 'agentPresets';
|
|
310
|
+
if (wireDomain === 'goal')
|
|
311
|
+
return 'goals';
|
|
312
|
+
return wireDomain;
|
|
313
|
+
}
|
|
314
|
+
function deniedMethod(method) {
|
|
315
|
+
return new RpcError('METHOD_NOT_ALLOWED', `Harness API method ${JSON.stringify(method)} is not available in remote mode.`);
|
|
316
|
+
}
|
|
317
|
+
function diagnosticReason(error) {
|
|
318
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
319
|
+
return message.replace(/[\r\n]+/g, ' ').slice(0, 160) || 'Unknown Harness API failure.';
|
|
320
|
+
}
|
|
321
|
+
/** Session id of a mux frame, or undefined for frames without one (e.g. stream/error). */
|
|
322
|
+
function frameSessionId(frame) {
|
|
323
|
+
const payload = frame.payload;
|
|
324
|
+
return typeof payload.sessionId === 'string' && payload.sessionId.length > 0 ? payload.sessionId : undefined;
|
|
325
|
+
}
|
|
326
|
+
function callSessionHistory(callWithTimeout, payload, rpcId) {
|
|
327
|
+
const fallbackPageSizes = sessionHistoryFallbackPageSizes(payloadMaxMessages(payload));
|
|
328
|
+
return callHistoryWithRetry(callWithTimeout, payload, rpcId, fallbackPageSizes);
|
|
329
|
+
}
|
|
330
|
+
async function callHistoryWithRetry(callWithTimeout, payload, rpcId, pageSizes) {
|
|
331
|
+
for (const maxMessages of pageSizes) {
|
|
332
|
+
const requestPayload = historyRequestPayload(payload, maxMessages);
|
|
333
|
+
const response = await callWithTimeout(requestPayload);
|
|
334
|
+
const request = createRpcResponse(rpcId, response.result);
|
|
335
|
+
if (encodeMessage(request).byteLength <= MAX_SECURE_MESSAGE_BYTES)
|
|
336
|
+
return response;
|
|
337
|
+
if (maxMessages === pageSizes[pageSizes.length - 1]) {
|
|
338
|
+
throw new RpcError('RESPONSE_TOO_LARGE', 'The Host response is too large for the remote channel. Request a smaller page.', { maxBytes: MAX_SECURE_MESSAGE_BYTES }, true);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
throw new RpcError('INTERNAL_ERROR', 'Failed to load session history with a fallback page size.');
|
|
342
|
+
}
|
|
343
|
+
function sessionHistoryFallbackPageSizes(requestedMaxMessages) {
|
|
344
|
+
const requested = normalizeSessionHistoryPageSize(requestedMaxMessages);
|
|
345
|
+
const sizes = [];
|
|
346
|
+
if (requested === undefined) {
|
|
347
|
+
sizes.push(...SESSION_HISTORY_PAGE_SIZES);
|
|
348
|
+
return sizes;
|
|
349
|
+
}
|
|
350
|
+
sizes.push(requested);
|
|
351
|
+
for (const value of SESSION_HISTORY_PAGE_SIZES) {
|
|
352
|
+
if (value < requested && !sizes.includes(value))
|
|
353
|
+
sizes.push(value);
|
|
354
|
+
}
|
|
355
|
+
return sizes;
|
|
356
|
+
}
|
|
357
|
+
function normalizeSessionHistoryPageSize(value) {
|
|
358
|
+
if (value === undefined)
|
|
359
|
+
return undefined;
|
|
360
|
+
if (!Number.isInteger(value))
|
|
361
|
+
return undefined;
|
|
362
|
+
if (value <= 0)
|
|
363
|
+
return undefined;
|
|
364
|
+
return Math.max(1, value);
|
|
365
|
+
}
|
|
366
|
+
function payloadMaxMessages(payload) {
|
|
367
|
+
if (payload === null || typeof payload !== 'object')
|
|
368
|
+
return undefined;
|
|
369
|
+
const value = payload.maxMessages;
|
|
370
|
+
return typeof value === 'number' && Number.isInteger(value) && value > 0 ? value : undefined;
|
|
371
|
+
}
|
|
372
|
+
function historyRequestPayload(payload, maxMessages) {
|
|
373
|
+
if (payload === null || typeof payload !== 'object' || Array.isArray(payload))
|
|
374
|
+
return { maxMessages };
|
|
375
|
+
return { ...payload, maxMessages };
|
|
376
|
+
}
|
|
377
|
+
function withTimeout(promise, ms, message) {
|
|
378
|
+
return new Promise((resolve, reject) => {
|
|
379
|
+
const timer = setTimeout(() => {
|
|
380
|
+
reject(new RpcError('TIMEOUT', message, undefined, true));
|
|
381
|
+
}, ms);
|
|
382
|
+
timer.unref?.();
|
|
383
|
+
promise.then(value => { clearTimeout(timer); resolve(value); }, error => { clearTimeout(timer); reject(error); });
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
function shortId(value) { return value.length <= 12 ? value : `${value.slice(0, 8)}…${value.slice(-4)}`; }
|
|
387
|
+
//# sourceMappingURL=harness-api-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness-api-bridge.js","sourceRoot":"","sources":["../src/harness-api-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export interface HostIdentity {
|
|
2
|
+
schemaVersion: 1;
|
|
3
|
+
deviceId: string;
|
|
4
|
+
name: string;
|
|
5
|
+
publicKey: string;
|
|
6
|
+
privateKey: string;
|
|
7
|
+
fingerprint: string;
|
|
8
|
+
}
|
|
9
|
+
export interface TrustedPeer {
|
|
10
|
+
deviceId: string;
|
|
11
|
+
name: string;
|
|
12
|
+
platform: string;
|
|
13
|
+
publicKey: string;
|
|
14
|
+
fingerprint: string;
|
|
15
|
+
trustedAt: number;
|
|
16
|
+
membershipId?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface IdentityStoreOptions {
|
|
19
|
+
directory?: string;
|
|
20
|
+
env?: NodeJS.ProcessEnv;
|
|
21
|
+
homeDirectory?: string;
|
|
22
|
+
}
|
|
23
|
+
export type RemoteDeviceRole = 'host' | 'client';
|
|
24
|
+
export declare class IdentityInvalidError extends Error {
|
|
25
|
+
readonly code = "IDENTITY_INVALID";
|
|
26
|
+
}
|
|
27
|
+
export declare class IdentityStore {
|
|
28
|
+
readonly directory: string;
|
|
29
|
+
private identity?;
|
|
30
|
+
private peers;
|
|
31
|
+
constructor(options?: IdentityStoreOptions);
|
|
32
|
+
loadOrCreate(deviceName: string): Promise<HostIdentity>;
|
|
33
|
+
current(): HostIdentity;
|
|
34
|
+
reset(deviceName: string): Promise<HostIdentity>;
|
|
35
|
+
listTrustedPeers(): TrustedPeer[];
|
|
36
|
+
trustedPeer(deviceId: string): TrustedPeer | undefined;
|
|
37
|
+
isTrusted(deviceId: string, publicKey: string): boolean;
|
|
38
|
+
trustPeer(input: Omit<TrustedPeer, 'fingerprint' | 'trustedAt'>): Promise<TrustedPeer>;
|
|
39
|
+
revokePeer(deviceId: string): Promise<boolean>;
|
|
40
|
+
private loadPeers;
|
|
41
|
+
private savePeers;
|
|
42
|
+
}
|
|
43
|
+
export declare function serverStorageDirectory(root: string, serverUrl: string, role: RemoteDeviceRole): string;
|
|
44
|
+
export declare function fingerprint(publicKey: string): string;
|
|
45
|
+
//# sourceMappingURL=identity-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-store.d.ts","sourceRoot":"","sources":["../src/identity-store.ts"],"names":[],"mappings":"AA8BA,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,CAAC,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,QAAQ,CAAA;AAEhD,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,sBAAqB;CACnC;AAED,qBAAa,aAAa;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,OAAO,CAAC,QAAQ,CAAC,CAAc;IAC/B,OAAO,CAAC,KAAK,CAAiC;gBAElC,OAAO,GAAE,oBAAyB;IAMxC,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAsC7D,OAAO,IAAI,YAAY;IAKjB,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAOtD,gBAAgB,IAAI,WAAW,EAAE;IAIjC,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAKtD,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAIjD,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,aAAa,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;IAYtF,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;YAMtC,SAAS;YAiBT,SAAS;CAMxB;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,MAAM,CAItG;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGrD"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { chmod, mkdir, readFile, rename, rm, stat, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import { fromBase64Url, generateKeyPair } from '@dsh-remote/crypto';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { uuidV7 } from './ids.js';
|
|
8
|
+
const identitySchema = z.object({
|
|
9
|
+
schemaVersion: z.literal(1),
|
|
10
|
+
deviceId: z.string().uuid(),
|
|
11
|
+
name: z.string().min(1).max(80),
|
|
12
|
+
publicKey: z.string().min(1),
|
|
13
|
+
}).strict();
|
|
14
|
+
const trustedPeerSchema = z.object({
|
|
15
|
+
deviceId: z.string().min(1),
|
|
16
|
+
name: z.string().min(1).max(80),
|
|
17
|
+
platform: z.string().min(1).max(40),
|
|
18
|
+
publicKey: z.string().min(1),
|
|
19
|
+
fingerprint: z.string().min(1),
|
|
20
|
+
trustedAt: z.number().int().nonnegative(),
|
|
21
|
+
membershipId: z.string().min(1).optional(),
|
|
22
|
+
}).strict();
|
|
23
|
+
const trustedPeersSchema = z.object({
|
|
24
|
+
schemaVersion: z.literal(1),
|
|
25
|
+
peers: z.array(trustedPeerSchema),
|
|
26
|
+
}).strict();
|
|
27
|
+
export class IdentityInvalidError extends Error {
|
|
28
|
+
code = 'IDENTITY_INVALID';
|
|
29
|
+
}
|
|
30
|
+
export class IdentityStore {
|
|
31
|
+
directory;
|
|
32
|
+
identity;
|
|
33
|
+
peers = new Map();
|
|
34
|
+
constructor(options = {}) {
|
|
35
|
+
const env = options.env ?? process.env;
|
|
36
|
+
const dshHome = env.DSH_HOME || join(options.homeDirectory ?? homedir(), '.dsh');
|
|
37
|
+
this.directory = options.directory ?? join(dshHome, 'remote');
|
|
38
|
+
}
|
|
39
|
+
async loadOrCreate(deviceName) {
|
|
40
|
+
await mkdir(this.directory, { recursive: true, mode: 0o700 });
|
|
41
|
+
await chmod(this.directory, 0o700);
|
|
42
|
+
const devicePath = join(this.directory, 'device.json');
|
|
43
|
+
const keyPath = join(this.directory, 'device.key');
|
|
44
|
+
const [hasDevice, hasKey] = await Promise.all([exists(devicePath), exists(keyPath)]);
|
|
45
|
+
if (hasDevice !== hasKey) {
|
|
46
|
+
throw new IdentityInvalidError('device identity is incomplete; repair it explicitly before reconnecting');
|
|
47
|
+
}
|
|
48
|
+
if (!hasDevice) {
|
|
49
|
+
const keys = generateKeyPair();
|
|
50
|
+
const record = { schemaVersion: 1, deviceId: uuidV7(), name: deviceName, publicKey: keys.publicKey };
|
|
51
|
+
await atomicJsonWrite(devicePath, record, 0o600);
|
|
52
|
+
await atomicTextWrite(keyPath, `${keys.privateKey}\n`, 0o600);
|
|
53
|
+
}
|
|
54
|
+
await assertPrivateMode(keyPath);
|
|
55
|
+
try {
|
|
56
|
+
let record = identitySchema.parse(JSON.parse(await readFile(devicePath, 'utf8')));
|
|
57
|
+
const privateKey = (await readFile(keyPath, 'utf8')).trim();
|
|
58
|
+
const regenerated = generateKeyPair(fromBase64Url(privateKey));
|
|
59
|
+
if (regenerated.publicKey !== record.publicKey) {
|
|
60
|
+
throw new IdentityInvalidError('device public and private keys do not match');
|
|
61
|
+
}
|
|
62
|
+
if (record.name !== deviceName) {
|
|
63
|
+
record = { ...record, name: deviceName };
|
|
64
|
+
await atomicJsonWrite(devicePath, record, 0o600);
|
|
65
|
+
}
|
|
66
|
+
this.identity = { ...record, privateKey, fingerprint: fingerprint(record.publicKey) };
|
|
67
|
+
await this.loadPeers();
|
|
68
|
+
return this.identity;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
if (error instanceof IdentityInvalidError)
|
|
72
|
+
throw error;
|
|
73
|
+
throw new IdentityInvalidError(`device identity is invalid: ${safeErrorMessage(error)}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
current() {
|
|
77
|
+
if (this.identity === undefined)
|
|
78
|
+
throw new Error('identity store has not been loaded');
|
|
79
|
+
return this.identity;
|
|
80
|
+
}
|
|
81
|
+
async reset(deviceName) {
|
|
82
|
+
await rm(this.directory, { recursive: true, force: true });
|
|
83
|
+
this.identity = undefined;
|
|
84
|
+
this.peers.clear();
|
|
85
|
+
return this.loadOrCreate(deviceName);
|
|
86
|
+
}
|
|
87
|
+
listTrustedPeers() {
|
|
88
|
+
return [...this.peers.values()].map(peer => ({ ...peer }));
|
|
89
|
+
}
|
|
90
|
+
trustedPeer(deviceId) {
|
|
91
|
+
const peer = this.peers.get(deviceId);
|
|
92
|
+
return peer === undefined ? undefined : { ...peer };
|
|
93
|
+
}
|
|
94
|
+
isTrusted(deviceId, publicKey) {
|
|
95
|
+
return this.peers.get(deviceId)?.publicKey === publicKey;
|
|
96
|
+
}
|
|
97
|
+
async trustPeer(input) {
|
|
98
|
+
this.current();
|
|
99
|
+
const peer = {
|
|
100
|
+
...input,
|
|
101
|
+
fingerprint: fingerprint(input.publicKey),
|
|
102
|
+
trustedAt: Date.now(),
|
|
103
|
+
};
|
|
104
|
+
this.peers.set(peer.deviceId, peer);
|
|
105
|
+
await this.savePeers();
|
|
106
|
+
return { ...peer };
|
|
107
|
+
}
|
|
108
|
+
async revokePeer(deviceId) {
|
|
109
|
+
const removed = this.peers.delete(deviceId);
|
|
110
|
+
if (removed)
|
|
111
|
+
await this.savePeers();
|
|
112
|
+
return removed;
|
|
113
|
+
}
|
|
114
|
+
async loadPeers() {
|
|
115
|
+
const path = join(this.directory, 'trusted-peers.json');
|
|
116
|
+
if (!(await exists(path))) {
|
|
117
|
+
await atomicJsonWrite(path, { schemaVersion: 1, peers: [] }, 0o600);
|
|
118
|
+
}
|
|
119
|
+
const parsed = trustedPeersSchema.parse(JSON.parse(await readFile(path, 'utf8')));
|
|
120
|
+
const peers = new Map();
|
|
121
|
+
for (const peer of parsed.peers) {
|
|
122
|
+
if (peer.fingerprint !== fingerprint(peer.publicKey)) {
|
|
123
|
+
throw new IdentityInvalidError(`trusted peer ${peer.deviceId} has an invalid fingerprint`);
|
|
124
|
+
}
|
|
125
|
+
if (peers.has(peer.deviceId))
|
|
126
|
+
throw new IdentityInvalidError(`trusted peer ${peer.deviceId} is duplicated`);
|
|
127
|
+
peers.set(peer.deviceId, peer);
|
|
128
|
+
}
|
|
129
|
+
this.peers = peers;
|
|
130
|
+
}
|
|
131
|
+
async savePeers() {
|
|
132
|
+
await atomicJsonWrite(join(this.directory, 'trusted-peers.json'), {
|
|
133
|
+
schemaVersion: 1,
|
|
134
|
+
peers: [...this.peers.values()],
|
|
135
|
+
}, 0o600);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
export function serverStorageDirectory(root, serverUrl, role) {
|
|
139
|
+
const origin = new URL(serverUrl).origin;
|
|
140
|
+
const scope = createHash('sha256').update(origin).digest('hex').slice(0, 24);
|
|
141
|
+
return join(root, 'servers', scope, role);
|
|
142
|
+
}
|
|
143
|
+
export function fingerprint(publicKey) {
|
|
144
|
+
const compact = createHash('sha256').update(fromBase64Url(publicKey)).digest('hex').slice(0, 12).toUpperCase();
|
|
145
|
+
return compact.match(/.{1,4}/g).join(' ');
|
|
146
|
+
}
|
|
147
|
+
async function assertPrivateMode(path) {
|
|
148
|
+
if (process.platform === 'win32')
|
|
149
|
+
return;
|
|
150
|
+
const mode = (await stat(path)).mode & 0o777;
|
|
151
|
+
if ((mode & 0o077) !== 0) {
|
|
152
|
+
throw new IdentityInvalidError(`private key permissions must be 0600, got ${mode.toString(8).padStart(3, '0')}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async function atomicJsonWrite(path, value, mode) {
|
|
156
|
+
await atomicTextWrite(path, `${JSON.stringify(value, null, 2)}\n`, mode);
|
|
157
|
+
}
|
|
158
|
+
async function atomicTextWrite(path, value, mode) {
|
|
159
|
+
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
160
|
+
const temporary = `${path}.${process.pid}.${uuidV7()}.tmp`;
|
|
161
|
+
await writeFile(temporary, value, { encoding: 'utf8', mode, flag: 'wx' });
|
|
162
|
+
await chmod(temporary, mode);
|
|
163
|
+
await rename(temporary, path);
|
|
164
|
+
await chmod(path, mode);
|
|
165
|
+
}
|
|
166
|
+
async function exists(path) {
|
|
167
|
+
try {
|
|
168
|
+
await stat(path);
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
if (isNodeError(error) && error.code === 'ENOENT')
|
|
173
|
+
return false;
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function isNodeError(error) {
|
|
178
|
+
return error instanceof Error && 'code' in error;
|
|
179
|
+
}
|
|
180
|
+
function safeErrorMessage(error) {
|
|
181
|
+
return error instanceof Error ? error.message : 'invalid identity data';
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=identity-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-store.js","sourceRoot":"","sources":["../src/identity-store.ts"],"names":[],"mappings":"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"}
|