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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "super-dsh",
3
- "version": "0.3.1-d",
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: undefined, signal: AbortSignal, control: AbortController): Promise<AsyncIterable<unknown>> | AsyncIterable<unknown>;
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, undefined, signal, new AbortController()),
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 local = getTarget(key)?.gateway;
106
- if (local === undefined)
105
+ const target = getTarget(key);
106
+ if (target?.gateway === undefined)
107
107
  throw new A2aAddressError('unreachable', addr);
108
- return bridgeTypertGateway(local);
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 three-method face of a world's typertGateway service instance. */
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 no peer (ctx0's fence already authenticated the client),
10
- * the mux controller's signal, and the controller itself, exactly as the
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: undefined, signal: AbortSignal, control: AbortController): Promise<AsyncIterable<unknown>> | AsyncIterable<unknown>;
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, undefined, control.signal, control)), {
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). A receipt with attempted
7
- // but neither done nor error is an interrupted first use — e.g. killed by the restart
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 only to a CONFIRMED first use or a recorded
52
- // failure; an interrupted first use (no done, no error) re-arms.
53
- this.intent = saved.attempted && saved.done !== true && saved.error === undefined
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) => (federatedGatewayOf(label) ?? getTarget(label)?.gateway),
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): CarrierGatewayFace | undefined;
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 gateway = options.gatewayOf(agent);
134
- if (gateway === undefined) {
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 gateway = options.gatewayOf(agent);
159
- if (gateway === undefined) {
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;