super-dsh 0.3.1-d → 0.3.1-e
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/package.json +1 -1
- package/superd-hub/dist/a2a-host.d.ts +11 -3
- package/superd-hub/dist/a2a-host.js +7 -7
- package/superd-hub/dist/a2a-row.js +7 -1
- package/superd-hub/dist/carrier.d.ts +9 -7
- package/superd-hub/dist/carrier.js +3 -3
- package/superd-hub/dist/companions.js +8 -6
- package/superd-hub/dist/gateway.js +8 -1
- package/superd-hub/dist/hub-route.d.ts +5 -2
- package/superd-hub/dist/hub-route.js +6 -6
- package/superd-hub/dist/targets.d.ts +7 -0
- package/superd-hub/dist/world-lifecycle.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "super-dsh",
|
|
3
|
-
"version": "0.3.1-
|
|
3
|
+
"version": "0.3.1-e",
|
|
4
4
|
"description": "Super D for the DeepSeek Harness (DSH) — one dsh plugin that mounts the superd hub (runtime selector, roster, per-runtime agents) and joins local foreign-agent runtimes (OMP, Codex, Claude, Pi, Hermes, Antigravity) into the DSH Web UI. Each runtime keeps its native home and session store; the hub only bridges.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,6 +10,14 @@ export interface A2aHostOptions {
|
|
|
10
10
|
* ({@link bridgeTypertGateway}).
|
|
11
11
|
*/
|
|
12
12
|
nativeGateway?: RawTypertGatewayFace;
|
|
13
|
+
/**
|
|
14
|
+
* LAZY provider of ctx0's owner browser Peer (connection.browserPeer) —
|
|
15
|
+
* 0.2.1 gateways read peer.signal/principal on every invocation. A
|
|
16
|
+
* provider, not a value: typertGateway mounts before connection, so a
|
|
17
|
+
* wiring-time read would capture undefined forever; resolution happens
|
|
18
|
+
* per call, when connection is long live.
|
|
19
|
+
*/
|
|
20
|
+
nativePeer?: () => unknown;
|
|
13
21
|
}
|
|
14
22
|
/**
|
|
15
23
|
* The RAW typertGateway service face — upstream canonical stream order
|
|
@@ -20,8 +28,8 @@ export interface A2aHostOptions {
|
|
|
20
28
|
* mesh-gateway wire adapters (dual-face, 3rd-argument dispatch).
|
|
21
29
|
*/
|
|
22
30
|
export interface RawTypertGatewayFace {
|
|
23
|
-
dispatchRpc(endpoint: string, payload: unknown, signal: AbortSignal): Promise<unknown>;
|
|
24
|
-
openWireStream(endpoint: string, payload: unknown, uplink: undefined, peer:
|
|
31
|
+
dispatchRpc(endpoint: string, payload: unknown, signal: AbortSignal, peer: unknown): Promise<unknown>;
|
|
32
|
+
openWireStream(endpoint: string, payload: unknown, uplink: undefined, peer: unknown, signal: AbortSignal, control: AbortController): Promise<AsyncIterable<unknown>> | AsyncIterable<unknown>;
|
|
25
33
|
}
|
|
26
34
|
/**
|
|
27
35
|
* Bridge one RAW typertGateway instance to Task 2's 3-arg `A2aGateway` face
|
|
@@ -38,7 +46,7 @@ export interface RawTypertGatewayFace {
|
|
|
38
46
|
* @param real - a raw in-process typertGateway instance (ctx0's own or a local world's).
|
|
39
47
|
* @returns the gateway Task 2's service consumes.
|
|
40
48
|
*/
|
|
41
|
-
export declare function bridgeTypertGateway(real: RawTypertGatewayFace): A2aGateway;
|
|
49
|
+
export declare function bridgeTypertGateway(real: RawTypertGatewayFace, peer?: unknown): A2aGateway;
|
|
42
50
|
/**
|
|
43
51
|
* Build the gatewayFor resolver Task 2's service consumes: federated table
|
|
44
52
|
* first, shared target registry second, local id-map inversion third,
|
|
@@ -59,10 +59,10 @@ function localKeyOfA6(home, a6) {
|
|
|
59
59
|
* @param real - a raw in-process typertGateway instance (ctx0's own or a local world's).
|
|
60
60
|
* @returns the gateway Task 2's service consumes.
|
|
61
61
|
*/
|
|
62
|
-
export function bridgeTypertGateway(real) {
|
|
62
|
+
export function bridgeTypertGateway(real, peer) {
|
|
63
63
|
return {
|
|
64
|
-
dispatchRpc: (endpoint, payload, signal) => real.dispatchRpc(endpoint, payload, signal),
|
|
65
|
-
openWireStream: (endpoint, payload, signal) => real.openWireStream(endpoint, payload, undefined,
|
|
64
|
+
dispatchRpc: (endpoint, payload, signal) => real.dispatchRpc(endpoint, payload, signal, peer),
|
|
65
|
+
openWireStream: (endpoint, payload, signal) => real.openWireStream(endpoint, payload, undefined, peer, signal, new AbortController()),
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
@@ -95,17 +95,17 @@ export function resolveA2aGatewayFor(options) {
|
|
|
95
95
|
if (key === 'native') {
|
|
96
96
|
if (options.nativeGateway === undefined)
|
|
97
97
|
throw new A2aAddressError('unreachable', addr);
|
|
98
|
-
return bridgeTypertGateway(options.nativeGateway);
|
|
98
|
+
return bridgeTypertGateway(options.nativeGateway, options.nativePeer?.());
|
|
99
99
|
}
|
|
100
100
|
// The registry's declared GatewayFace (targets.ts) types the stream
|
|
101
101
|
// face as the 3-arg subset, but a LOCAL row's runtime object is the RAW
|
|
102
102
|
// typertGateway instance (world-join.ts registers it verbatim) — re-cast
|
|
103
103
|
// to RawTypertGatewayFace so the bridge above binds the canonical 6-arg
|
|
104
104
|
// positional order instead of the declared subset.
|
|
105
|
-
const
|
|
106
|
-
if (
|
|
105
|
+
const target = getTarget(key);
|
|
106
|
+
if (target?.gateway === undefined)
|
|
107
107
|
throw new A2aAddressError('unreachable', addr);
|
|
108
|
-
return bridgeTypertGateway(
|
|
108
|
+
return bridgeTypertGateway(target.gateway, target.peer);
|
|
109
109
|
}
|
|
110
110
|
// The a6 resolves nowhere — classify the miss (D7): a roster row exists →
|
|
111
111
|
// its plane is down; else the machine decides agent-vs-machine blame.
|
|
@@ -56,12 +56,18 @@ export function wireHubToolRow(ctx, opts = {}) {
|
|
|
56
56
|
// RAW instance in, bridged at the resolver (fix round 1: one shared
|
|
57
57
|
// bridge in a2a-host.ts covers the native seam AND all local world rows).
|
|
58
58
|
const raw = t.get('typertGateway');
|
|
59
|
+
// 0.2.1: every invocation reads the caller Peer — ctx0's owner browser
|
|
60
|
+
// Peer rides the native seam as a LAZY provider: typertGateway mounts
|
|
61
|
+
// BEFORE connection (the service registers in its constructor), so a
|
|
62
|
+
// wiring-time value would capture undefined forever; resolution happens
|
|
63
|
+
// per call, when connection is long live.
|
|
64
|
+
const nativePeer = () => ctx.get('connection')?.browserPeer;
|
|
59
65
|
// postoffice R4: ONE resolver, ONE ingest, TWO consumers — the initiator
|
|
60
66
|
// service's self-routing leg calls the very same ingest handler the HTTP
|
|
61
67
|
// endpoint calls (protocol-identical by construction). The service takes
|
|
62
68
|
// a LAZY provider: the ingest's delivery face buffers through the
|
|
63
69
|
// service's own buffer leg, so it can only be built after the service.
|
|
64
|
-
const gatewayFor = resolveA2aGatewayFor({ home, nativeGateway: raw });
|
|
70
|
+
const gatewayFor = resolveA2aGatewayFor({ home, nativeGateway: raw, nativePeer });
|
|
65
71
|
// Operational journal: the pure modules only format lines; this is
|
|
66
72
|
// where they meet the process console and land in the unit log (4999 rig
|
|
67
73
|
// / dev3 dsh.service journal). NOT ctx.logger: the pack composes no
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
import { type WorldRequest, type WorldResponse } from './world-web-server.js';
|
|
2
2
|
import { WorldMuxServer, type MuxFailure } from './world-mux.js';
|
|
3
|
-
/** The
|
|
3
|
+
/** The face of a world's typertGateway service instance the hub forwards through. */
|
|
4
4
|
export interface CarrierGatewayFace {
|
|
5
|
-
dispatchRpc(endpoint: string, payload: unknown, signal: AbortSignal): Promise<unknown>;
|
|
5
|
+
dispatchRpc(endpoint: string, payload: unknown, signal: AbortSignal, peer: unknown): Promise<unknown>;
|
|
6
6
|
/**
|
|
7
7
|
* Streams return an async iterable (upstream face is synchronous-returning).
|
|
8
8
|
* Canonical order: (endpoint, payload, uplink, peer, signal, control) — the
|
|
9
|
-
* carrier passes
|
|
10
|
-
* the mux controller's signal, and the controller
|
|
11
|
-
* native gateway's mux wires its own streams.
|
|
9
|
+
* carrier passes the world's owner browser Peer (0.2.1 gateways read it on
|
|
10
|
+
* every invocation), the mux controller's signal, and the controller
|
|
11
|
+
* itself, exactly as the native gateway's mux wires its own streams.
|
|
12
12
|
*/
|
|
13
|
-
openWireStream(endpoint: string, payload: unknown, uplink: AsyncIterable<unknown>, peer:
|
|
13
|
+
openWireStream(endpoint: string, payload: unknown, uplink: AsyncIterable<unknown>, peer: unknown, signal: AbortSignal, control: AbortController): Promise<AsyncIterable<unknown>> | AsyncIterable<unknown>;
|
|
14
14
|
}
|
|
15
15
|
export declare function writeJson(res: WorldResponse, status: number, body: string): void;
|
|
16
16
|
/** Deps the forwarding kernel needs to answer for one world's traffic. */
|
|
17
17
|
export interface ForwardOptions {
|
|
18
18
|
/** The addressed world's gateway instance. */
|
|
19
19
|
gateway: CarrierGatewayFace;
|
|
20
|
+
/** The addressed world's owner browser Peer (0.2.1 invocation identity). */
|
|
21
|
+
peer?: unknown;
|
|
20
22
|
/** World key addressing the world's published `/api` fetch handler. */
|
|
21
23
|
label: string;
|
|
22
24
|
/** URL prefix this carrier strips before the world sees the request (`/omp`, `/hub`). */
|
|
@@ -47,7 +49,7 @@ export declare function forwardWorldFetch(options: {
|
|
|
47
49
|
*/
|
|
48
50
|
export declare function forwardApiCall(options: ForwardOptions, req: WorldRequest, res: WorldResponse): Promise<void>;
|
|
49
51
|
/** One WorldMuxServer bound to `gateway` — the canonical openWireStream wiring in one place. */
|
|
50
|
-
export declare function worldMuxOf(gateway: CarrierGatewayFace, options?: {
|
|
52
|
+
export declare function worldMuxOf(gateway: CarrierGatewayFace, peer?: unknown, options?: {
|
|
51
53
|
heartbeatIntervalMs?: number;
|
|
52
54
|
failure?: (error: unknown) => MuxFailure;
|
|
53
55
|
}): WorldMuxServer;
|
|
@@ -177,7 +177,7 @@ export async function forwardApiCall(options, req, res) {
|
|
|
177
177
|
}
|
|
178
178
|
rpcId = envelope.rpcId;
|
|
179
179
|
const controller = new AbortController();
|
|
180
|
-
const result = await options.gateway.dispatchRpc(envelope.method, envelope.payload, controller.signal);
|
|
180
|
+
const result = await options.gateway.dispatchRpc(envelope.method, envelope.payload, controller.signal, options.peer);
|
|
181
181
|
// The gateway already returns a Result (`{ok:true,value}` | `{ok:false,error}`),
|
|
182
182
|
// which is exactly the server-response's `result` field.
|
|
183
183
|
writeJson(res, 200, serverResult(rpcId, result));
|
|
@@ -194,8 +194,8 @@ export async function forwardApiCall(options, req, res) {
|
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
/** One WorldMuxServer bound to `gateway` — the canonical openWireStream wiring in one place. */
|
|
197
|
-
export function worldMuxOf(gateway, options) {
|
|
198
|
-
return new WorldMuxServer((endpoint, payload, uplink, control) => Promise.resolve(gateway.openWireStream(endpoint, payload, uplink,
|
|
197
|
+
export function worldMuxOf(gateway, peer, options) {
|
|
198
|
+
return new WorldMuxServer((endpoint, payload, uplink, control) => Promise.resolve(gateway.openWireStream(endpoint, payload, uplink, peer, control.signal, control)), {
|
|
199
199
|
...(options?.heartbeatIntervalMs === undefined ? {} : { heartbeatIntervalMs: options.heartbeatIntervalMs }),
|
|
200
200
|
...(options?.failure === undefined ? {} : { failure: options.failure }),
|
|
201
201
|
});
|
|
@@ -3,8 +3,9 @@ import { createHash } from 'node:crypto';
|
|
|
3
3
|
import { readFile, mkdir, unlink, rmdir } from 'node:fs/promises';
|
|
4
4
|
import { join, dirname } from 'node:path';
|
|
5
5
|
import { writeFileAtomic } from '@deepseek-ai/dsh-atomic-write';
|
|
6
|
-
// done marks a CONFIRMED first use (Better observed installed)
|
|
7
|
-
//
|
|
6
|
+
// done marks a CONFIRMED first use (Better observed installed); removed marks a
|
|
7
|
+
// migrated legacy removal record. A receipt with attempted but neither done,
|
|
8
|
+
// error, nor removed is an interrupted first use — e.g. killed by the restart
|
|
8
9
|
// that installing Super itself triggers — and must re-arm, not suppress, the retry.
|
|
9
10
|
const message = (error) => error instanceof Error ? error.message : String(error);
|
|
10
11
|
async function optionalJson(path) {
|
|
@@ -48,9 +49,10 @@ export class BetterDashCompanion {
|
|
|
48
49
|
return this.initialized ??= (async () => {
|
|
49
50
|
const saved = await optionalJson(this.receipt);
|
|
50
51
|
if (saved !== undefined) {
|
|
51
|
-
// Never-resurrect applies
|
|
52
|
-
//
|
|
53
|
-
|
|
52
|
+
// Never-resurrect applies to a CONFIRMED first use, a recorded failure,
|
|
53
|
+
// or a migrated removal record; an interrupted first use (no done, no
|
|
54
|
+
// error, no removal marker) re-arms.
|
|
55
|
+
this.intent = saved.attempted && saved.done !== true && saved.error === undefined && saved.removed !== true
|
|
54
56
|
? { attempted: false } : saved;
|
|
55
57
|
await this.cleanLegacy();
|
|
56
58
|
return;
|
|
@@ -59,7 +61,7 @@ export class BetterDashCompanion {
|
|
|
59
61
|
// Any old registration was first use. An absent Better now means removal,
|
|
60
62
|
// including when Super has since changed version; never resurrect it.
|
|
61
63
|
if (old?.['super-dsh:better-dsh'] !== undefined) {
|
|
62
|
-
this.intent = { attempted: true };
|
|
64
|
+
this.intent = { attempted: true, removed: true };
|
|
63
65
|
await this.save();
|
|
64
66
|
await this.cleanLegacy();
|
|
65
67
|
}
|
|
@@ -90,7 +90,14 @@ export function apply(ctx, config) {
|
|
|
90
90
|
real: real,
|
|
91
91
|
authorize: (req, res) => connection.authorizeIndex(req, res),
|
|
92
92
|
requestRejection: (req) => connection.requestRejection(req),
|
|
93
|
-
gatewayOf: (label) =>
|
|
93
|
+
gatewayOf: (label) => {
|
|
94
|
+
const federated = federatedGatewayOf(label);
|
|
95
|
+
if (federated !== undefined)
|
|
96
|
+
return { key: label, gateway: federated };
|
|
97
|
+
// The stored face IS the service instance (canonical methods); targets.ts
|
|
98
|
+
// keeps a looser structural view for the mesh wire adapters.
|
|
99
|
+
return getTarget(label);
|
|
100
|
+
},
|
|
94
101
|
}), 'superd-hub: /hub route family');
|
|
95
102
|
// P4 §8.2: the PTY executor's upgrade route — same gate as the /hub family
|
|
96
103
|
// (authorizeIndex cookie auth first, then the browser-trust fence). The
|
|
@@ -63,8 +63,11 @@ export interface HubRouteOptions {
|
|
|
63
63
|
* answer, so even the demux 404s never speak to untrusted traffic.
|
|
64
64
|
*/
|
|
65
65
|
requestRejection?(req: unknown): number | undefined;
|
|
66
|
-
/** The live gateway of a registered label, or undefined (unknown / not yet spawned). */
|
|
67
|
-
gatewayOf(label: string):
|
|
66
|
+
/** The live target (gateway + owner peer) of a registered label, or undefined (unknown / not yet spawned). */
|
|
67
|
+
gatewayOf(label: string): {
|
|
68
|
+
gateway: CarrierGatewayFace;
|
|
69
|
+
peer?: unknown;
|
|
70
|
+
} | undefined;
|
|
68
71
|
}
|
|
69
72
|
/**
|
|
70
73
|
* Register the family on ctx0's webServer.
|
|
@@ -130,15 +130,15 @@ export function registerHubRoute(options) {
|
|
|
130
130
|
});
|
|
131
131
|
return;
|
|
132
132
|
}
|
|
133
|
-
const
|
|
134
|
-
if (
|
|
133
|
+
const target = options.gatewayOf(agent);
|
|
134
|
+
if (target === undefined) {
|
|
135
135
|
answer404(res, { error: 'unknown-agent', label: agent });
|
|
136
136
|
return;
|
|
137
137
|
}
|
|
138
138
|
// Consume the family plumbing: the kernel forwards a native-shaped URL
|
|
139
139
|
// (the kernel carries the same fence face as the carrier's own kernel).
|
|
140
140
|
req.url = worldUrlOf(req.url);
|
|
141
|
-
await forwardApiCall({ gateway, label: agent, mountPath: HUB_MOUNT_PATH, requestRejection: options.requestRejection }, req, res);
|
|
141
|
+
await forwardApiCall({ gateway: target.gateway, peer: target.peer, label: agent, mountPath: HUB_MOUNT_PATH, requestRejection: options.requestRejection }, req, res);
|
|
142
142
|
};
|
|
143
143
|
const handleUpgrade = (req, socket, head) => {
|
|
144
144
|
if (!gateUpgrade(options, req, socket))
|
|
@@ -155,8 +155,8 @@ export function registerHubRoute(options) {
|
|
|
155
155
|
rejectUpgrade(socket, 404, JSON.stringify({ error: 'foreign-only' }), 'application/json');
|
|
156
156
|
return;
|
|
157
157
|
}
|
|
158
|
-
const
|
|
159
|
-
if (
|
|
158
|
+
const target = options.gatewayOf(agent);
|
|
159
|
+
if (target === undefined) {
|
|
160
160
|
rejectUpgrade(socket, 404, JSON.stringify({ error: 'unknown-agent', label: agent }), 'application/json');
|
|
161
161
|
return;
|
|
162
162
|
}
|
|
@@ -165,7 +165,7 @@ export function registerHubRoute(options) {
|
|
|
165
165
|
// a heartbeat interval and a per-connection WebSocketServer; on socket
|
|
166
166
|
// close it must be CLOSED (world-mux clears the heartbeat only in close),
|
|
167
167
|
// or every reconnect leaks the timer plus the mux graph forever.
|
|
168
|
-
const mux = worldMuxOf(gateway);
|
|
168
|
+
const mux = worldMuxOf(target.gateway, target.peer);
|
|
169
169
|
socket.once?.('close', () => {
|
|
170
170
|
void mux.close().catch(() => undefined);
|
|
171
171
|
});
|
|
@@ -22,6 +22,13 @@ export interface ForeignTarget {
|
|
|
22
22
|
key: string;
|
|
23
23
|
/** The context's typertGateway service instance (or a wire adapter with the same face). */
|
|
24
24
|
gateway: GatewayFace;
|
|
25
|
+
/**
|
|
26
|
+
* The world's owner browser Peer (connection.browserPeer) for in-process
|
|
27
|
+
* faces — DSH 0.2.1 gateways read peer.signal/principal on every forwarded
|
|
28
|
+
* invocation, so the hub must present the world's shared owner identity.
|
|
29
|
+
* Wire adapters (mesh federation) omit it: the far end supplies its own.
|
|
30
|
+
*/
|
|
31
|
+
peer?: unknown;
|
|
25
32
|
}
|
|
26
33
|
/** Register (or replace) the target for a runtime key. */
|
|
27
34
|
export declare function registerForeignTarget(target: ForeignTarget): void;
|
|
@@ -48,7 +48,7 @@ export function ownWorld(ctx, entry, spawn, onFailure) {
|
|
|
48
48
|
unregisterForeignTarget(key);
|
|
49
49
|
setReady(key, false);
|
|
50
50
|
}, `superd.world.${key}: availability`);
|
|
51
|
-
target = { key, gateway: world.get('typertGateway') };
|
|
51
|
+
target = { key, gateway: world.get('typertGateway'), peer: world.get('connection')?.browserPeer };
|
|
52
52
|
registerForeignTarget(target);
|
|
53
53
|
setReady(key, true);
|
|
54
54
|
return world;
|