@workerdeck/server 3.1.0 → 3.3.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.
- package/build/index.d.mts +18 -1
- package/build/index.mjs +263 -20
- package/build/index.mjs.map +1 -1
- package/package.json +8 -6
package/build/index.d.mts
CHANGED
|
@@ -2,6 +2,7 @@ import { IncomingMessage, Server, ServerResponse } from "node:http";
|
|
|
2
2
|
import { AttachmentInput, BridgeAnswer, BrowserBridgeExecutor, ClaudeAuthProbe, CostLedgerState, EngineAdapter, EngineSessionOptions, HostToolDefinition, LanguageModel, LocalShellSource, McpConnection, ParkedExecution, Runner, RunnerSnapshot, SHELL_REFUSAL, SessionInstructions, SessionRunnerConfig, ShellDirectory, ToolExecutionCall, ToolExecutionResult, ToolExecutor, ToolSet } from "@workerdeck/core";
|
|
3
3
|
import { JobQueue, QueueAdapter } from "@workerdeck/queue";
|
|
4
4
|
import { ByModel, CreateSessionRequest, JobEvent, MessageAttachment, ModelRate, PricingTable, ProfileEngine, ProfileInfo, ProfileSpend, ProfileUsage, ProviderConfig, SdkSessionSummary, ServerFrame, SessionCapability, SessionInfo, SessionNotification, SessionWebhookConfig, ShellEndReason, ShellInfo, ShellOwner } from "@workerdeck/protocol";
|
|
5
|
+
import { RelayOp } from "@workerdeck/relay-client";
|
|
5
6
|
//#region src/services/bridge.d.ts
|
|
6
7
|
type BridgeHubOptions = {
|
|
7
8
|
timeoutMs?: number;
|
|
@@ -154,6 +155,20 @@ type PeerServiceOptions = {
|
|
|
154
155
|
maxHops?: number;
|
|
155
156
|
};
|
|
156
157
|
//#endregion
|
|
158
|
+
//#region src/services/peer-relay.d.ts
|
|
159
|
+
type RelayLinkOptions = {
|
|
160
|
+
url: string;
|
|
161
|
+
gateway: string;
|
|
162
|
+
key?: string;
|
|
163
|
+
keyFile?: string;
|
|
164
|
+
caFile?: string;
|
|
165
|
+
expose?: {
|
|
166
|
+
scope?: Record<string, string>;
|
|
167
|
+
allow?: RelayOp[];
|
|
168
|
+
};
|
|
169
|
+
log?: (message: string) => void;
|
|
170
|
+
};
|
|
171
|
+
//#endregion
|
|
157
172
|
//#region src/services/profile-store.d.ts
|
|
158
173
|
type ProfileStore = {
|
|
159
174
|
list(): ProfileInfo[] | Promise<ProfileInfo[]>;
|
|
@@ -354,6 +369,7 @@ type WorkerServerOptions = {
|
|
|
354
369
|
listSdkSessions?: SdkSessionLister;
|
|
355
370
|
queue?: QueueServerOptions;
|
|
356
371
|
peers?: PeerServiceOptions;
|
|
372
|
+
relay?: RelayLinkOptions;
|
|
357
373
|
notifications?: SessionNotificationOptions;
|
|
358
374
|
bridge?: BridgeHubOptions;
|
|
359
375
|
parking?: {
|
|
@@ -430,6 +446,7 @@ type WorkerServer = {
|
|
|
430
446
|
drain: (options?: DrainOptions) => Promise<DrainReport>;
|
|
431
447
|
releaseSession: (id: string) => CarriedSession | undefined;
|
|
432
448
|
adoptSession: (carried: CarriedSession) => boolean;
|
|
449
|
+
releaseRelay: () => void;
|
|
433
450
|
close: () => Promise<void>;
|
|
434
451
|
};
|
|
435
452
|
//#endregion
|
|
@@ -536,5 +553,5 @@ declare class ProfileUsageTracker {
|
|
|
536
553
|
usage(profile: string, now?: number): ProfileUsage | undefined;
|
|
537
554
|
}
|
|
538
555
|
//#endregion
|
|
539
|
-
export { AttachmentStore, type AttachmentStoreOptions, type Authenticator, BridgeHub, type BridgeHubOptions, type CarriedSession, type DiagnosticSink, type EngineRunnerContext, type FileSessionStoreOptions, type JsonWriteOptions, MemorySessionStore, type NotificationErrorContext, type ParkedSessionRecord, type ProcessRow, type ProcessTable, type ProducedFile, ProducedFileStore, type ProfileStore, ProfileUsageTracker, type ProviderRunnerOptions, type QueueServerOptions, type ReloadPlan, SHELL_REFUSAL, type SdkSessionLister, type SessionNotificationOptions, SessionNotifier, SessionParkManager, type SessionParkOptions, SessionRegistry, type SessionRegistryOptions, type SessionStore, type ShellAgentWriteOption, type ShellDirectoryDeps, type ShellRegistry, type ShellRegistryOptions, type ShellSink, SpendLedger, type SpendRecord, type SpendStore, type StoredSessionRecord, type StoredShellIndex, type StoredShellRecord, type WorkerServer, type WorkerServerOptions, createFileProfileStore, createFileSessionStore, createFileSpendStore, createMemoryProfileStore, createProviderRunner, createShellDirectory, createShellRegistry, createWorkerServer, dayKey, isDormant, isMissing, readJsonOr, reloadPlan, sandboxedProviderProfile, shellPermitted, toDurableRecord, writeFileAtomic, writeJsonAtomic };
|
|
556
|
+
export { AttachmentStore, type AttachmentStoreOptions, type Authenticator, BridgeHub, type BridgeHubOptions, type CarriedSession, type DiagnosticSink, type EngineRunnerContext, type FileSessionStoreOptions, type JsonWriteOptions, MemorySessionStore, type NotificationErrorContext, type ParkedSessionRecord, type ProcessRow, type ProcessTable, type ProducedFile, ProducedFileStore, type ProfileStore, ProfileUsageTracker, type ProviderRunnerOptions, type QueueServerOptions, type RelayLinkOptions, type ReloadPlan, SHELL_REFUSAL, type SdkSessionLister, type SessionNotificationOptions, SessionNotifier, SessionParkManager, type SessionParkOptions, SessionRegistry, type SessionRegistryOptions, type SessionStore, type ShellAgentWriteOption, type ShellDirectoryDeps, type ShellRegistry, type ShellRegistryOptions, type ShellSink, SpendLedger, type SpendRecord, type SpendStore, type StoredSessionRecord, type StoredShellIndex, type StoredShellRecord, type WorkerServer, type WorkerServerOptions, createFileProfileStore, createFileSessionStore, createFileSpendStore, createMemoryProfileStore, createProviderRunner, createShellDirectory, createShellRegistry, createWorkerServer, dayKey, isDormant, isMissing, readJsonOr, reloadPlan, sandboxedProviderProfile, shellPermitted, toDurableRecord, writeFileAtomic, writeJsonAtomic };
|
|
540
557
|
//# sourceMappingURL=index.d.mts.map
|
package/build/index.mjs
CHANGED
|
@@ -10,6 +10,7 @@ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "nod
|
|
|
10
10
|
import { chmod, mkdir, open, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
11
11
|
import { spawnSync } from "node:child_process";
|
|
12
12
|
import xtermHeadless from "@xterm/headless";
|
|
13
|
+
import { connectRelay, parseRelayPeerId } from "@workerdeck/relay-client";
|
|
13
14
|
//#region src/lifecycle.ts
|
|
14
15
|
const SOCKET_CLOSE_GRACE_MS = 250;
|
|
15
16
|
const CLOSE_DEADLINE_MS = 1e3;
|
|
@@ -4625,6 +4626,163 @@ function createFileSpendStore(path, onError) {
|
|
|
4625
4626
|
};
|
|
4626
4627
|
}
|
|
4627
4628
|
//#endregion
|
|
4629
|
+
//#region src/services/peer-relay.ts
|
|
4630
|
+
const CARRIED = Symbol.for("workerdeck.relay.carried");
|
|
4631
|
+
const slots = globalThis;
|
|
4632
|
+
const UNAVAILABLE = "Remote gateways are unavailable right now; only sessions on this gateway are listed.";
|
|
4633
|
+
function expandHome(path) {
|
|
4634
|
+
return path === "~" || path.startsWith("~/") ? `${homedir()}${path.slice(1)}` : path;
|
|
4635
|
+
}
|
|
4636
|
+
function identityOf(options) {
|
|
4637
|
+
return JSON.stringify([
|
|
4638
|
+
options.url,
|
|
4639
|
+
options.gateway,
|
|
4640
|
+
options.keyFile ?? "",
|
|
4641
|
+
options.key ? "inline" : "",
|
|
4642
|
+
options.caFile ?? "",
|
|
4643
|
+
options.expose?.allow ?? null
|
|
4644
|
+
]);
|
|
4645
|
+
}
|
|
4646
|
+
function remoteSummary(row) {
|
|
4647
|
+
return {
|
|
4648
|
+
id: `${row.gateway}:${row.id}`,
|
|
4649
|
+
gateway: row.gateway,
|
|
4650
|
+
engine: row.engine,
|
|
4651
|
+
status: row.status,
|
|
4652
|
+
title: row.title,
|
|
4653
|
+
project: row.project?.name,
|
|
4654
|
+
projectRoot: row.project?.root,
|
|
4655
|
+
cwd: row.cwd,
|
|
4656
|
+
profile: row.profile,
|
|
4657
|
+
model: row.model,
|
|
4658
|
+
contextUsage: row.contextUsage,
|
|
4659
|
+
lastActivityAt: row.lastActivityAt,
|
|
4660
|
+
pendingPermissionCount: row.pendingPermissionCount,
|
|
4661
|
+
allow: row.allow
|
|
4662
|
+
};
|
|
4663
|
+
}
|
|
4664
|
+
function remotePeek(gateway, peek) {
|
|
4665
|
+
const { allow: _allow, ...summary } = remoteSummary({
|
|
4666
|
+
...peek,
|
|
4667
|
+
gateway,
|
|
4668
|
+
allow: []
|
|
4669
|
+
});
|
|
4670
|
+
return {
|
|
4671
|
+
...summary,
|
|
4672
|
+
live: peek.live,
|
|
4673
|
+
checklist: peek.checklistItems,
|
|
4674
|
+
pendingApprovals: peek.pendingApprovals,
|
|
4675
|
+
recent: peek.recent
|
|
4676
|
+
};
|
|
4677
|
+
}
|
|
4678
|
+
async function readRelayKey(options) {
|
|
4679
|
+
if (options.key) return options.key;
|
|
4680
|
+
if (!options.keyFile) throw new Error("relay: set relay.keyFile (or WORKERDECK_RELAY_KEY) to the key `workerdeck relay enroll` printed");
|
|
4681
|
+
const key = (await readFile(expandHome(options.keyFile), "utf8")).trim();
|
|
4682
|
+
if (!key) throw new Error(`relay: ${options.keyFile} is empty`);
|
|
4683
|
+
return key;
|
|
4684
|
+
}
|
|
4685
|
+
function createRelayLink(options, peers, log) {
|
|
4686
|
+
const identity = identityOf(options);
|
|
4687
|
+
const exposed = options.expose?.scope;
|
|
4688
|
+
let connection;
|
|
4689
|
+
let closed = false;
|
|
4690
|
+
let released = false;
|
|
4691
|
+
const host = {
|
|
4692
|
+
snapshot: () => peers.relayEntries(exposed),
|
|
4693
|
+
peek: (_origin, sessionId, recent) => peers.relayPeek(sessionId, recent, exposed),
|
|
4694
|
+
send: (origin, sessionId, text) => peers.relaySend(origin, sessionId, text, exposed)
|
|
4695
|
+
};
|
|
4696
|
+
const carried = slots[CARRIED];
|
|
4697
|
+
if (carried) {
|
|
4698
|
+
delete slots[CARRIED];
|
|
4699
|
+
if (carried.identity === identity && carried.connection.state() !== "stopped") {
|
|
4700
|
+
carried.connection.setHost(host);
|
|
4701
|
+
connection = carried.connection;
|
|
4702
|
+
} else carried.connection.close();
|
|
4703
|
+
}
|
|
4704
|
+
if (!connection) (async () => {
|
|
4705
|
+
const key = await readRelayKey(options);
|
|
4706
|
+
const ca = options.caFile ? await readFile(expandHome(options.caFile)) : void 0;
|
|
4707
|
+
if (!closed) connection = connectRelay({
|
|
4708
|
+
url: options.url,
|
|
4709
|
+
gateway: options.gateway,
|
|
4710
|
+
key,
|
|
4711
|
+
ca,
|
|
4712
|
+
allow: options.expose?.allow,
|
|
4713
|
+
log
|
|
4714
|
+
}, host);
|
|
4715
|
+
})().catch((error) => log(error instanceof Error ? error.message : String(error)));
|
|
4716
|
+
const remoteTarget = parseRelayPeerId;
|
|
4717
|
+
const reachesRemote = async (from) => {
|
|
4718
|
+
const me = await peers.relaySender(from);
|
|
4719
|
+
return me.scope === void 0 || Object.keys(me.scope).length === 0;
|
|
4720
|
+
};
|
|
4721
|
+
return {
|
|
4722
|
+
directory: {
|
|
4723
|
+
list: async (from) => {
|
|
4724
|
+
const local = await peers.list(from);
|
|
4725
|
+
if (!connection || connection.state() !== "online" || !await reachesRemote(from)) return local;
|
|
4726
|
+
try {
|
|
4727
|
+
return [...local, ...(await connection.list(from)).map(remoteSummary)];
|
|
4728
|
+
} catch {
|
|
4729
|
+
return local;
|
|
4730
|
+
}
|
|
4731
|
+
},
|
|
4732
|
+
notice: async (from) => {
|
|
4733
|
+
if (!await reachesRemote(from)) return;
|
|
4734
|
+
return connection?.state() === "online" ? void 0 : UNAVAILABLE;
|
|
4735
|
+
},
|
|
4736
|
+
peek: async (from, sessionId, peekOptions) => {
|
|
4737
|
+
const target = remoteTarget(sessionId);
|
|
4738
|
+
if (!target) return peers.peek(from, sessionId, peekOptions);
|
|
4739
|
+
if (!connection || !await reachesRemote(from)) return;
|
|
4740
|
+
const peek = await connection.peek(from, target, peekOptions?.recent);
|
|
4741
|
+
return peek ? remotePeek(target.gateway, peek) : void 0;
|
|
4742
|
+
},
|
|
4743
|
+
send: async (from, sessionId, text, sendOptions) => {
|
|
4744
|
+
const target = remoteTarget(sessionId);
|
|
4745
|
+
if (!target) return peers.send(from, sessionId, text, sendOptions);
|
|
4746
|
+
if (!await reachesRemote(from)) return {
|
|
4747
|
+
delivered: false,
|
|
4748
|
+
reason: `no such session: ${sessionId}`
|
|
4749
|
+
};
|
|
4750
|
+
if (!connection || connection.state() !== "online") return {
|
|
4751
|
+
delivered: false,
|
|
4752
|
+
reason: "remote gateways are unavailable right now; try again later"
|
|
4753
|
+
};
|
|
4754
|
+
try {
|
|
4755
|
+
const result = await connection.send(from, target, text, sendOptions?.hops ?? peers.relayChain(from));
|
|
4756
|
+
return result.delivered ? {
|
|
4757
|
+
...result,
|
|
4758
|
+
sessionId
|
|
4759
|
+
} : result;
|
|
4760
|
+
} catch (error) {
|
|
4761
|
+
return {
|
|
4762
|
+
delivered: false,
|
|
4763
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
4764
|
+
};
|
|
4765
|
+
}
|
|
4766
|
+
}
|
|
4767
|
+
},
|
|
4768
|
+
nudge: () => connection?.nudge(),
|
|
4769
|
+
release: () => {
|
|
4770
|
+
if (connection && !closed) {
|
|
4771
|
+
released = true;
|
|
4772
|
+
slots[CARRIED] = {
|
|
4773
|
+
identity,
|
|
4774
|
+
connection
|
|
4775
|
+
};
|
|
4776
|
+
}
|
|
4777
|
+
},
|
|
4778
|
+
close: () => {
|
|
4779
|
+
closed = true;
|
|
4780
|
+
if (!released) connection?.close();
|
|
4781
|
+
connection = void 0;
|
|
4782
|
+
}
|
|
4783
|
+
};
|
|
4784
|
+
}
|
|
4785
|
+
//#endregion
|
|
4628
4786
|
//#region src/services/peers.ts
|
|
4629
4787
|
const DEFAULT_PER_MINUTE = 10;
|
|
4630
4788
|
const DEFAULT_MAX_HOPS = 12;
|
|
@@ -4632,6 +4790,33 @@ const WINDOW_MS = 6e4;
|
|
|
4632
4790
|
function visible(from, to) {
|
|
4633
4791
|
return to.id !== from.id && scopeMatches(from.scope, to.scope);
|
|
4634
4792
|
}
|
|
4793
|
+
function relayEntry(info, live) {
|
|
4794
|
+
const items = info.checklist;
|
|
4795
|
+
return {
|
|
4796
|
+
id: info.id,
|
|
4797
|
+
engine: info.engine,
|
|
4798
|
+
status: info.status,
|
|
4799
|
+
title: info.title,
|
|
4800
|
+
project: info.project ? {
|
|
4801
|
+
name: info.project.name,
|
|
4802
|
+
root: info.project.root
|
|
4803
|
+
} : void 0,
|
|
4804
|
+
cwd: info.cwd,
|
|
4805
|
+
profile: info.profile,
|
|
4806
|
+
model: info.model,
|
|
4807
|
+
permissionMode: info.permissionMode,
|
|
4808
|
+
contextUsage: info.contextUsage,
|
|
4809
|
+
checklist: items?.length ? {
|
|
4810
|
+
done: items.filter((item) => item.status === "completed").length,
|
|
4811
|
+
total: items.length
|
|
4812
|
+
} : void 0,
|
|
4813
|
+
numTurns: info.numTurns,
|
|
4814
|
+
createdAt: info.createdAt,
|
|
4815
|
+
lastActivityAt: info.lastActivityAt,
|
|
4816
|
+
pendingPermissionCount: info.pendingPermissionCount,
|
|
4817
|
+
live
|
|
4818
|
+
};
|
|
4819
|
+
}
|
|
4635
4820
|
function createPeerService(deps) {
|
|
4636
4821
|
const perMinute = deps.options?.perMinute ?? DEFAULT_PER_MINUTE;
|
|
4637
4822
|
const maxChars = deps.options?.maxMessageChars ?? PEER_MESSAGE_MAX_CHARS;
|
|
@@ -4659,6 +4844,19 @@ function createPeerService(deps) {
|
|
|
4659
4844
|
if (!info) throw new Error(`unknown sender session: ${from}`);
|
|
4660
4845
|
return info;
|
|
4661
4846
|
};
|
|
4847
|
+
const recentOf = (sessionId, recent) => {
|
|
4848
|
+
const limit = Math.min(Math.max(recent ?? PEER_RECENT_DEFAULT, 0), PEER_RECENT_MAX);
|
|
4849
|
+
const runner = registry().get(sessionId);
|
|
4850
|
+
const events = [];
|
|
4851
|
+
if (runner && limit > 0) runner.subscribe((event) => events.push(event), 0, {
|
|
4852
|
+
truncateResults: true,
|
|
4853
|
+
imageRefs: true
|
|
4854
|
+
})();
|
|
4855
|
+
return {
|
|
4856
|
+
runner,
|
|
4857
|
+
lines: recentLines(events, limit)
|
|
4858
|
+
};
|
|
4859
|
+
};
|
|
4662
4860
|
const underRateLimit = (from, to) => {
|
|
4663
4861
|
const key = `${from}->${to}`;
|
|
4664
4862
|
const now = Date.now();
|
|
@@ -4679,19 +4877,13 @@ function createPeerService(deps) {
|
|
|
4679
4877
|
const me = await sender(from);
|
|
4680
4878
|
const info = await infoOf(sessionId);
|
|
4681
4879
|
if (!info || !visible(me, info)) return;
|
|
4682
|
-
const
|
|
4683
|
-
const runner = registry().get(sessionId);
|
|
4684
|
-
const events = [];
|
|
4685
|
-
if (runner && limit > 0) runner.subscribe((event) => events.push(event), 0, {
|
|
4686
|
-
truncateResults: true,
|
|
4687
|
-
imageRefs: true
|
|
4688
|
-
})();
|
|
4880
|
+
const { runner, lines } = recentOf(sessionId, options?.recent);
|
|
4689
4881
|
return {
|
|
4690
4882
|
...peerSummary(info),
|
|
4691
4883
|
live: runner !== void 0,
|
|
4692
4884
|
checklist: info.checklist,
|
|
4693
4885
|
pendingApprovals: runner ? runner.pendingApprovals.map((request) => request.title ?? request.toolName) : [],
|
|
4694
|
-
recent:
|
|
4886
|
+
recent: lines
|
|
4695
4887
|
};
|
|
4696
4888
|
};
|
|
4697
4889
|
const send = async (from, sessionId, text, options) => {
|
|
@@ -4709,16 +4901,27 @@ function createPeerService(deps) {
|
|
|
4709
4901
|
delivered: false,
|
|
4710
4902
|
reason: `no such session: ${sessionId}`
|
|
4711
4903
|
};
|
|
4904
|
+
const hops = [...options?.hops ?? inbound.get(from) ?? [], from];
|
|
4905
|
+
return deliver(target, text, {
|
|
4906
|
+
kind: "peer",
|
|
4907
|
+
sessionId: from,
|
|
4908
|
+
name: me.title,
|
|
4909
|
+
engine: me.engine,
|
|
4910
|
+
hops
|
|
4911
|
+
}, from);
|
|
4912
|
+
};
|
|
4913
|
+
const deliver = async (target, text, origin, rateKey) => {
|
|
4914
|
+
const sessionId = target.id;
|
|
4712
4915
|
if (target.status === "closed" || target.status === "failed") return {
|
|
4713
4916
|
delivered: false,
|
|
4714
4917
|
reason: `session ${sessionId} is ${target.status}`
|
|
4715
4918
|
};
|
|
4716
|
-
const hops =
|
|
4919
|
+
const hops = origin.hops ?? [];
|
|
4717
4920
|
if (hops.length > maxHops) return {
|
|
4718
4921
|
delivered: false,
|
|
4719
4922
|
reason: `${hops.length} messages have passed between sessions without a person speaking; stop and ask your user before continuing.`
|
|
4720
4923
|
};
|
|
4721
|
-
if (!underRateLimit(
|
|
4924
|
+
if (!underRateLimit(rateKey, sessionId)) return {
|
|
4722
4925
|
delivered: false,
|
|
4723
4926
|
reason: `rate limit: at most ${perMinute} messages a minute to one session. Batch what you have to say.`
|
|
4724
4927
|
};
|
|
@@ -4728,13 +4931,6 @@ function createPeerService(deps) {
|
|
|
4728
4931
|
reason: `session ${sessionId} could not be woken`
|
|
4729
4932
|
};
|
|
4730
4933
|
const before = runner.info().status;
|
|
4731
|
-
const origin = {
|
|
4732
|
-
kind: "peer",
|
|
4733
|
-
sessionId: from,
|
|
4734
|
-
name: me.title,
|
|
4735
|
-
engine: me.engine,
|
|
4736
|
-
hops
|
|
4737
|
-
};
|
|
4738
4934
|
try {
|
|
4739
4935
|
runner.sendMessage(text, void 0, { origin });
|
|
4740
4936
|
} catch (error) {
|
|
@@ -4751,6 +4947,45 @@ function createPeerService(deps) {
|
|
|
4751
4947
|
queued: before === "running" || before === "awaiting_approval"
|
|
4752
4948
|
};
|
|
4753
4949
|
};
|
|
4950
|
+
const exposedInfo = async (sessionId, exposed) => {
|
|
4951
|
+
const info = await infoOf(sessionId);
|
|
4952
|
+
return info && info.status !== "closed" && scopeMatches(exposed, info.scope) ? info : void 0;
|
|
4953
|
+
};
|
|
4954
|
+
const relayEntries = async (exposed) => {
|
|
4955
|
+
const live = new Set(registry().list().map((info) => info.id));
|
|
4956
|
+
return (await allSessions()).filter((info) => info.status !== "closed" && scopeMatches(exposed, info.scope)).map((info) => relayEntry(info, live.has(info.id)));
|
|
4957
|
+
};
|
|
4958
|
+
const relayPeek = async (sessionId, recent, exposed) => {
|
|
4959
|
+
const info = await exposedInfo(sessionId, exposed);
|
|
4960
|
+
if (!info) return;
|
|
4961
|
+
const { runner, lines } = recentOf(sessionId, recent);
|
|
4962
|
+
return {
|
|
4963
|
+
...relayEntry(info, runner !== void 0),
|
|
4964
|
+
checklistItems: info.checklist,
|
|
4965
|
+
pendingApprovals: runner ? runner.pendingApprovals.map((request) => request.title ?? request.toolName) : [],
|
|
4966
|
+
recent: lines
|
|
4967
|
+
};
|
|
4968
|
+
};
|
|
4969
|
+
const relaySend = async (origin, sessionId, text, exposed) => {
|
|
4970
|
+
if (text.length === 0 || text.length > maxChars) return {
|
|
4971
|
+
delivered: false,
|
|
4972
|
+
reason: `message is ${text.length} characters; the limit is ${maxChars}. Write it to a file and send the path.`
|
|
4973
|
+
};
|
|
4974
|
+
const target = await exposedInfo(sessionId, exposed);
|
|
4975
|
+
if (!target) return {
|
|
4976
|
+
delivered: false,
|
|
4977
|
+
reason: `no such session: ${sessionId}`
|
|
4978
|
+
};
|
|
4979
|
+
const from = `${origin.gateway}:${origin.sessionId}`;
|
|
4980
|
+
return deliver(target, text, {
|
|
4981
|
+
kind: "peer",
|
|
4982
|
+
sessionId: from,
|
|
4983
|
+
hostId: origin.gateway,
|
|
4984
|
+
name: origin.name,
|
|
4985
|
+
engine: origin.engine,
|
|
4986
|
+
hops: origin.hops
|
|
4987
|
+
}, from);
|
|
4988
|
+
};
|
|
4754
4989
|
const mentions = async (from, text) => {
|
|
4755
4990
|
const tokens = scanPeerMentions(text);
|
|
4756
4991
|
if (tokens.length === 0) return [];
|
|
@@ -4797,7 +5032,12 @@ function createPeerService(deps) {
|
|
|
4797
5032
|
peek,
|
|
4798
5033
|
send,
|
|
4799
5034
|
mentions,
|
|
4800
|
-
watch
|
|
5035
|
+
watch,
|
|
5036
|
+
relaySender: sender,
|
|
5037
|
+
relayChain: (from) => [...inbound.get(from) ?? [], from],
|
|
5038
|
+
relayEntries,
|
|
5039
|
+
relayPeek,
|
|
5040
|
+
relaySend
|
|
4801
5041
|
};
|
|
4802
5042
|
}
|
|
4803
5043
|
//#endregion
|
|
@@ -5222,9 +5462,10 @@ function createWorkerServer(options = {}) {
|
|
|
5222
5462
|
options: options.peers
|
|
5223
5463
|
});
|
|
5224
5464
|
const shellDirectory = shells ? createShellDirectory(shells, { runnerFor: (id) => registry.get(id) }) : void 0;
|
|
5225
|
-
|
|
5465
|
+
const relay = peers && options.relay ? createRelayLink(options.relay, peers, options.relay.log ?? ((message) => diagnose(new Error(message), "relay"))) : void 0;
|
|
5466
|
+
let ownPeers = relay?.directory ?? peers;
|
|
5226
5467
|
let ownShells = shellDirectory;
|
|
5227
|
-
if (
|
|
5468
|
+
if (ownPeers) installPeerDirectory(ownPeers);
|
|
5228
5469
|
installShellDirectory(shellDirectory);
|
|
5229
5470
|
const factory = createSessionFactory({
|
|
5230
5471
|
adapterFor,
|
|
@@ -5341,6 +5582,7 @@ function createWorkerServer(options = {}) {
|
|
|
5341
5582
|
closeQueueSockets: queueSockets.clear,
|
|
5342
5583
|
diagnose,
|
|
5343
5584
|
releaseDirectories: () => {
|
|
5585
|
+
relay?.close();
|
|
5344
5586
|
ownPeers = void 0;
|
|
5345
5587
|
ownShells = void 0;
|
|
5346
5588
|
}
|
|
@@ -5383,6 +5625,7 @@ function createWorkerServer(options = {}) {
|
|
|
5383
5625
|
parking.adopt(runner, config);
|
|
5384
5626
|
return true;
|
|
5385
5627
|
},
|
|
5628
|
+
releaseRelay: () => relay?.release(),
|
|
5386
5629
|
drain: lifecycle.drain,
|
|
5387
5630
|
close: lifecycle.close
|
|
5388
5631
|
};
|