super-dsh 0.1.3 → 0.1.4

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.
Files changed (115) hide show
  1. package/README.md +9 -8
  2. package/agent-agy/cordis.patch.yml +8 -4
  3. package/agent-agy/dist/agent-preset-agy.d.ts +23 -43
  4. package/agent-agy/dist/agent-preset-agy.js +29 -166
  5. package/agent-agy/dist/agent.d.ts +2 -1
  6. package/agent-agy/dist/agent.js +3 -2
  7. package/agent-agy/dist/agy-sessions.d.ts +2 -1
  8. package/agent-agy/dist/agy-sessions.js +2 -11
  9. package/agent-agy/dist/index.js +13 -12
  10. package/agent-agy/dist/world-plugin.d.ts +2 -1
  11. package/agent-agy/dist/world-plugin.js +16 -21
  12. package/agent-agy/package.json +6 -6
  13. package/agent-claude/cordis.patch.yml +8 -4
  14. package/agent-claude/dist/agent-preset-claude.js +29 -166
  15. package/agent-claude/dist/agent.js +10 -10
  16. package/agent-claude/dist/claude-client.js +22 -3
  17. package/agent-claude/dist/claude-home.js +0 -8
  18. package/agent-claude/dist/index.js +12 -15
  19. package/agent-claude/dist/session-map.js +2 -5
  20. package/agent-claude/dist/world-plugin.js +3 -3
  21. package/agent-claude/package.json +9 -9
  22. package/agent-codex/README.md +8 -8
  23. package/agent-codex/cordis.patch.yml +9 -5
  24. package/agent-codex/dist/agent-preset-codex.js +29 -168
  25. package/agent-codex/dist/agent.js +17 -12
  26. package/agent-codex/dist/codex-store.js +0 -9
  27. package/agent-codex/dist/index.js +13 -16
  28. package/agent-codex/dist/session-map.js +2 -5
  29. package/agent-codex/dist/world-plugin.js +15 -20
  30. package/agent-codex/package.json +14 -11
  31. package/agent-hermes/README.md +9 -8
  32. package/agent-hermes/cordis.patch.yml +8 -4
  33. package/agent-hermes/dist/agent-preset-hermes.js +29 -168
  34. package/agent-hermes/dist/agent.js +33 -19
  35. package/agent-hermes/dist/hermes-client.js +5 -5
  36. package/agent-hermes/dist/hermes-store.js +2 -11
  37. package/agent-hermes/dist/index.js +13 -12
  38. package/agent-hermes/dist/world-plugin.js +16 -21
  39. package/agent-hermes/package.json +14 -11
  40. package/agent-omp/README.md +2 -2
  41. package/agent-omp/cordis.patch.yml +12 -7
  42. package/agent-omp/dist/agent-preset-omp.js +30 -169
  43. package/agent-omp/dist/agent.js +13 -5
  44. package/agent-omp/dist/index.js +12 -22
  45. package/agent-omp/dist/mobile/gesture.js +2 -2
  46. package/agent-omp/dist/mobile/zoom-guard.js +4 -4
  47. package/agent-omp/dist/mobile-boot.js +2 -2
  48. package/agent-omp/dist/omp-cli.js +1 -1
  49. package/agent-omp/dist/omp-disk-discovery.js +1 -1
  50. package/agent-omp/dist/protocol.js +1 -1
  51. package/agent-omp/dist/sidecar-client.js +1 -1
  52. package/agent-omp/dist/world-plugin.js +22 -19
  53. package/agent-omp/package.json +18 -14
  54. package/agent-omp/sidecar/main.ts +2 -2
  55. package/agent-pi/README.md +5 -5
  56. package/agent-pi/cordis.patch.yml +8 -4
  57. package/agent-pi/dist/agent-preset-pi.js +29 -166
  58. package/agent-pi/dist/agent.js +18 -12
  59. package/agent-pi/dist/index.js +14 -16
  60. package/agent-pi/dist/pi-home.js +2 -12
  61. package/agent-pi/dist/world-plugin.js +16 -21
  62. package/agent-pi/package.json +14 -11
  63. package/cordis.patch.yml +31 -21
  64. package/package.json +30 -38
  65. package/{agent-hub → superd-hub}/cordis.patch.yml +3 -3
  66. package/{agent-hub → superd-hub}/dist/carrier.d.ts +9 -3
  67. package/{agent-hub → superd-hub}/dist/carrier.js +29 -3
  68. package/{agent-hub → superd-hub}/dist/gateway.d.ts +2 -2
  69. package/{agent-hub → superd-hub}/dist/gateway.js +1 -1
  70. package/{agent-hub → superd-hub}/dist/index.d.ts +5 -3
  71. package/{agent-hub → superd-hub}/dist/index.js +5 -3
  72. package/{agent-hub → superd-hub}/dist/roster.d.ts +2 -2
  73. package/{agent-hub → superd-hub}/dist/rpc.js +1 -1
  74. package/{agent-hub → superd-hub}/dist/spawn-world.d.ts +27 -6
  75. package/superd-hub/dist/spawn-world.js +277 -0
  76. package/superd-hub/dist/system-head.d.ts +69 -0
  77. package/superd-hub/dist/system-head.js +194 -0
  78. package/superd-hub/dist/web-trust.d.ts +112 -0
  79. package/superd-hub/dist/web-trust.js +126 -0
  80. package/{agent-hub → superd-hub}/dist/world-entry.d.ts +2 -2
  81. package/{agent-hub → superd-hub}/dist/world-entry.js +4 -4
  82. package/{agent-hub → superd-hub}/dist/world-host.d.ts +1 -1
  83. package/{agent-hub → superd-hub}/dist/world-join.d.ts +2 -1
  84. package/{agent-hub → superd-hub}/dist/world-join.js +16 -21
  85. package/{agent-hub → superd-hub}/dist/world-mount.d.ts +14 -6
  86. package/{agent-hub → superd-hub}/dist/world-mount.js +28 -7
  87. package/{agent-hub → superd-hub}/dist/world-mux.d.ts +21 -6
  88. package/superd-hub/dist/world-mux.js +392 -0
  89. package/{agent-hub → superd-hub}/dist/world-provision.d.ts +20 -4
  90. package/superd-hub/dist/world-provision.js +196 -0
  91. package/{agent-hub → superd-hub}/dist/world-web-server.js +7 -1
  92. package/{agent-hub → superd-hub}/package.json +9 -16
  93. package/agent-hub/dist/spawn-world.js +0 -72
  94. package/agent-hub/dist/world-mux.js +0 -224
  95. package/agent-hub/dist/world-provision.js +0 -122
  96. package/agent-hub/lib/client/index.js +0 -242
  97. package/client/index.js +0 -242
  98. /package/{agent-hub → superd-hub}/dist/agent-roster.d.ts +0 -0
  99. /package/{agent-hub → superd-hub}/dist/agent-roster.js +0 -0
  100. /package/{agent-hub → superd-hub}/dist/client-shim.d.ts +0 -0
  101. /package/{agent-hub → superd-hub}/dist/client-shim.js +0 -0
  102. /package/{agent-hub → superd-hub}/dist/envelope.d.ts +0 -0
  103. /package/{agent-hub → superd-hub}/dist/envelope.js +0 -0
  104. /package/{agent-hub → superd-hub}/dist/index-pass.d.ts +0 -0
  105. /package/{agent-hub → superd-hub}/dist/index-pass.js +0 -0
  106. /package/{agent-hub → superd-hub}/dist/labels.d.ts +0 -0
  107. /package/{agent-hub → superd-hub}/dist/labels.js +0 -0
  108. /package/{agent-hub → superd-hub}/dist/ownership.d.ts +0 -0
  109. /package/{agent-hub → superd-hub}/dist/ownership.js +0 -0
  110. /package/{agent-hub → superd-hub}/dist/roster.js +0 -0
  111. /package/{agent-hub → superd-hub}/dist/rpc.d.ts +0 -0
  112. /package/{agent-hub → superd-hub}/dist/targets.d.ts +0 -0
  113. /package/{agent-hub → superd-hub}/dist/targets.js +0 -0
  114. /package/{agent-hub → superd-hub}/dist/world-host.js +0 -0
  115. /package/{agent-hub → superd-hub}/dist/world-web-server.d.ts +0 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "super-dsh",
3
- "version": "0.1.3",
4
- "description": "Agent Worlds for the DeepSeek Harness (DSH) — one dsh plugin that mounts the agent hub (runtime selector, roster, per-runtime worlds) 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.",
3
+ "version": "0.1.4",
4
+ "description": "Super D for the DeepSeek Harness (DSH) — one dsh plugin that mounts the superd hub (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",
7
7
  "repository": {
@@ -9,27 +9,25 @@
9
9
  "url": "git+https://github.com/pgmi-builds/superd.git"
10
10
  },
11
11
  "exports": {
12
- ".": "./agent-hub/dist/index.js",
13
- "./hub": "./agent-hub/dist/index.js",
14
- "./join": "./agent-hub/dist/world-join.js",
15
- "./world/omp": "./agent-omp/dist/world-plugin.js",
16
- "./world/codex": "./agent-codex/dist/world-plugin.js",
17
- "./world/claude": "./agent-claude/dist/world-plugin.js",
18
- "./world/pi": "./agent-pi/dist/world-plugin.js",
19
- "./world/hermes": "./agent-hermes/dist/world-plugin.js",
20
- "./world/agy": "./agent-agy/dist/world-plugin.js",
21
- "./client": "./client/index.js",
12
+ ".": "./superd-hub/dist/index.js",
13
+ "./hub": "./superd-hub/dist/index.js",
14
+ "./join": "./superd-hub/dist/world-join.js",
15
+ "./agents/omp": "./agent-omp/dist/world-plugin.js",
16
+ "./agents/codex": "./agent-codex/dist/world-plugin.js",
17
+ "./agents/claude": "./agent-claude/dist/world-plugin.js",
18
+ "./agents/pi": "./agent-pi/dist/world-plugin.js",
19
+ "./agents/hermes": "./agent-hermes/dist/world-plugin.js",
20
+ "./agents/agy": "./agent-agy/dist/world-plugin.js",
22
21
  "./cordis.patch.yml": "./cordis.patch.yml",
23
- "./package.json": "./package.json"
22
+ "./package.json": "./package.json",
23
+ "./web-trust": "./superd-hub/dist/web-trust.js"
24
24
  },
25
25
  "files": [
26
26
  "cordis.patch.yml",
27
- "client",
28
27
  "README.md",
29
- "agent-hub/dist",
30
- "agent-hub/lib",
31
- "agent-hub/package.json",
32
- "agent-hub/cordis.patch.yml",
28
+ "superd-hub/dist",
29
+ "superd-hub/package.json",
30
+ "superd-hub/cordis.patch.yml",
33
31
  "agent-omp/dist",
34
32
  "agent-omp/package.json",
35
33
  "agent-omp/cordis.patch.yml",
@@ -54,12 +52,6 @@
54
52
  "dsh": {
55
53
  "bundle": {
56
54
  "patch": "./cordis.patch.yml"
57
- },
58
- "client": {
59
- "inject": [
60
- "@deepseek-ai/dsh-client-ui-slots"
61
- ],
62
- "platform": "web"
63
55
  }
64
56
  },
65
57
  "dependencies": {
@@ -70,24 +62,24 @@
70
62
  "@openai/codex-sdk": "0.154.0",
71
63
  "bun": "^1.4.2",
72
64
  "ws": "^8.21.0",
73
- "zod": "3.25.76",
65
+ "zod": "4.4.3",
74
66
  "@modelcontextprotocol/sdk": "^1.29.0"
75
67
  },
76
68
  "peerDependencies": {
77
69
  "@deepseek-ai/cordis": "^4.0.1",
78
- "@deepseek-ai/dsh-agent": "0.1.5-rc.2",
79
- "@deepseek-ai/dsh-agent-presets": "0.1.5-rc.2",
80
- "@deepseek-ai/dsh-api-gateway": "*",
81
- "@deepseek-ai/dsh-commands": "0.1.5-rc.2",
82
- "@deepseek-ai/dsh-home-paths": "0.1.5-rc.2",
83
- "@deepseek-ai/dsh-host-webserver": "*",
84
- "@deepseek-ai/dsh-llm": "0.1.5-rc.2",
85
- "@deepseek-ai/dsh-scope": "0.1.5-rc.2",
86
- "@deepseek-ai/dsh-session": "0.1.5-rc.2",
87
- "@deepseek-ai/dsh-session-persistence": "0.1.5-rc.2",
88
- "@deepseek-ai/dsh-typert-protocol": "0.1.5-rc.2",
89
- "@deepseek-ai/dsh-user-approval": "0.1.5-rc.2",
90
- "@deepseek-ai/dsh-user-questions": "0.1.5-rc.2"
70
+ "@deepseek-ai/dsh-agent": ">=0.1.5-0 <0.3.0-0",
71
+ "@deepseek-ai/dsh-agent-presets": ">=0.1.5-0 <0.3.0-0",
72
+ "@deepseek-ai/dsh-api-gateway": ">=0.1.5-0 <0.3.0-0",
73
+ "@deepseek-ai/dsh-commands": ">=0.1.5-0 <0.3.0-0",
74
+ "@deepseek-ai/dsh-home-paths": ">=0.1.5-0 <0.3.0-0",
75
+ "@deepseek-ai/dsh-host-webserver": ">=0.1.5-0 <0.3.0-0",
76
+ "@deepseek-ai/dsh-llm": ">=0.1.5-0 <0.3.0-0",
77
+ "@deepseek-ai/dsh-scope": ">=0.1.5-0 <0.3.0-0",
78
+ "@deepseek-ai/dsh-session": ">=0.1.5-0 <0.3.0-0",
79
+ "@deepseek-ai/dsh-session-persistence": ">=0.1.5-0 <0.3.0-0",
80
+ "@deepseek-ai/dsh-typert-protocol": ">=0.1.5-0 <0.3.0-0",
81
+ "@deepseek-ai/dsh-user-approval": ">=0.1.5-0 <0.3.0-0",
82
+ "@deepseek-ai/dsh-user-questions": ">=0.1.5-0 <0.3.0-0"
91
83
  },
92
84
  "peerDependenciesMeta": {
93
85
  "@deepseek-ai/cordis": {
@@ -1,4 +1,4 @@
1
- # Mount the agent-hub host half BESIDE the upstream gateway.
1
+ # Mount the superd-hub host half BESIDE the upstream gateway.
2
2
  # The typert-gateway row STAYS ENABLED: disabling it also removed the
3
3
  # gateway package's client half from the browser module table (learned
4
4
  # 2026-09-10: session-controller's client requires
@@ -8,5 +8,5 @@
8
8
  # The /api/agent-runtime selector RPC face rides along (control plane,
9
9
  # always CTX0-local).
10
10
  - insert:
11
- - id: agent-hub
12
- name: '@pgmi-builds/agent-hub'
11
+ - id: superd-hub
12
+ name: '@pgmi-builds/superd-hub'
@@ -1,10 +1,16 @@
1
1
  import { type RealWebServerFace } from './world-web-server.js';
2
2
  import { type MuxFailure } from './world-mux.js';
3
- /** The two-method face of a world's typertGateway service instance. */
3
+ /** The three-method face of a world's typertGateway service instance. */
4
4
  export interface CarrierGatewayFace {
5
5
  dispatchRpc(endpoint: string, payload: unknown, signal: AbortSignal): Promise<unknown>;
6
- /** Streams return an async iterable (upstream face is synchronous-returning). */
7
- openWireStream(endpoint: string, payload: unknown, signal: AbortSignal): Promise<AsyncIterable<unknown>> | AsyncIterable<unknown>;
6
+ /**
7
+ * Streams return an async iterable (upstream face is synchronous-returning).
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.
12
+ */
13
+ openWireStream(endpoint: string, payload: unknown, uplink: AsyncIterable<unknown>, peer: undefined, signal: AbortSignal, control: AbortController): Promise<AsyncIterable<unknown>> | AsyncIterable<unknown>;
8
14
  }
9
15
  /** Options for mounting one world. */
10
16
  export interface MountWorldOptions {
@@ -5,12 +5,17 @@
5
5
  * - Task 4: unary RPC — `/<label>/api/<endpoint>` decodes the connection
6
6
  * envelope and dispatches into the ADDRESSED world's gateway instance.
7
7
  * - Task 6: mux — `/<label>/api/remote.mux` upgrade bridged to the same
8
- * instance (no shared selection anywhere).
8
+ * instance (no shared selection anywhere). Wire protocol is dsh 0.1.7's
9
+ * stream protocol incl. the client uplink (`item`/`end` frames).
9
10
  * - 2026-09-17 (H1): non-envelope GET/HEAD on `/<label>/api` forwards into
10
11
  * the owning world's registered exact Fetch routes — the world connection's
11
12
  * shared `/api` handler, published from `world-entry` via `world-host` —
12
13
  * still behind ctx0's fence, so `HEAD /<label>/api/session.export?...`
13
14
  * reaches the world's session-log-download route.
15
+ * - 2026-09-24: `/<label>/open-in-app/*` GETs bridge the same way — the
16
+ * world page's open-in-app feature polls its host routes relative to the
17
+ * mount base (`/omp/open-in-app/apps`), which live on the WORLD's
18
+ * connection, not ctx0's.
14
19
  *
15
20
  * The addressed world is the request's path. Nothing here reads a global.
16
21
  */
@@ -203,8 +208,29 @@ export function mountWorld(options) {
203
208
  path: apiPath,
204
209
  handler: handleUnary,
205
210
  }));
206
- // Mux: the world's own stream face behind the same mount prefix.
207
- const mux = new WorldMuxServer((endpoint, payload, signal) => Promise.resolve(options.gateway.openWireStream(endpoint, payload, signal)), {
211
+ // The world page's open-in-app feature polls its host routes relative to the
212
+ // mount base (`/omp/open-in-app/apps`); those exact routes live on the
213
+ // WORLD's connection, so they bridge exactly like the non-envelope `/api`
214
+ // GETs — behind ctx0's fence, answered by the owning world.
215
+ const openInAppPath = `${labelPath}/open-in-app`;
216
+ disposers.push(options.real.register({
217
+ kind: 'prefix',
218
+ path: openInAppPath,
219
+ handler: (async (req, res) => {
220
+ const rejection = options.requestRejection?.(req);
221
+ if (rejection !== undefined) {
222
+ writeText(res, rejection, rejection === 401 ? 'unauthorized' : 'forbidden');
223
+ return;
224
+ }
225
+ await bridgeWorldFetch(req, res);
226
+ }),
227
+ }));
228
+ // Mux: the world's own stream face behind the same mount prefix. The wire
229
+ // protocol is dsh 0.1.7's stream protocol — including the client uplink —
230
+ // and the world call uses the gateway's canonical argument order
231
+ // (endpoint, payload, uplink, peer, signal, control): the mux's controller
232
+ // supplies both the request signal and the logical-stream control.
233
+ const mux = new WorldMuxServer((endpoint, payload, uplink, control) => Promise.resolve(options.gateway.openWireStream(endpoint, payload, uplink, undefined, control.signal, control)), {
208
234
  ...(options.heartbeatIntervalMs === undefined ? {} : { heartbeatIntervalMs: options.heartbeatIntervalMs }),
209
235
  ...(options.failure === undefined ? {} : { failure: options.failure }),
210
236
  });
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @pgmi-builds/agent-hub — plugin entry (host half).
2
+ * @pgmi-builds/superd-hub — plugin entry (host half).
3
3
  *
4
4
  * DL7 (2026-09-16): there is NO server-side selected state. The module-level
5
5
  * selector and the instance-delegation wrapper that consumed it were removed;
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import type { Context } from '@deepseek-ai/cordis';
17
17
  /** Stable Cordis plugin name. */
18
- export declare const name = "agent-hub";
18
+ export declare const name = "superd-hub";
19
19
  /**
20
20
  * The plugin form (row contract): applied when the row mounts.
21
21
  *
@@ -1,7 +1,7 @@
1
1
  import { registerSelectorRpc, registryTargets } from './rpc.js';
2
2
  import { agentRosterRow } from './agent-roster.js';
3
3
  /** Stable Cordis plugin name. */
4
- export const name = 'agent-hub';
4
+ export const name = 'superd-hub';
5
5
  /**
6
6
  * The plugin form (row contract): applied when the row mounts.
7
7
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @pgmi-builds/agent-hub — host half public surface (Agent Worlds line).
2
+ * @pgmi-builds/superd-hub — host half public surface (Super D line).
3
3
  *
4
4
  * The line owns the switch and the gateway (per super-dsh/AGENTS.md):
5
5
  * the world inventory control plane + the foreign agent roster + the world
@@ -13,7 +13,7 @@ export { handleAgentRuntime, registerSelectorRpc, AGENT_RUNTIME_RPC_PATH, regist
13
13
  export { registerForeignTarget, unregisterForeignTarget, getTarget, listRuntimeKeys, type ForeignTarget, type GatewayFace } from './targets.js';
14
14
  export { registerAgent, unregisterAgent, setReady, listAgents, onRosterChanged, type RosterEntry } from './roster.js';
15
15
  export { spawnWorld, type SpawnWorldOptions } from './spawn-world.js';
16
- export { provisionWorldProfile, type ProvisionWorldOptions } from './world-provision.js';
16
+ export { provisionWorldProfile, resolveInstallAnchor, type ProvisionWorldOptions } from './world-provision.js';
17
17
  export { claimLabel, labelOf, releaseLabel, listLabels, type LabelClaim, type ClaimOptions } from './labels.js';
18
18
  export { WorldWebServer, stripLabelFromUrl, type WorldWebRoute, type WorldWebUpgradeRoute, type RealWebServerFace } from './world-web-server.js';
19
19
  export { parseClientRequest, serverResponse, serverError, serverResult, wireErrorOf, EnvelopeError, type ClientRequestEnvelope, type WireError } from './envelope.js';
@@ -23,7 +23,9 @@ export { renderClientShim } from './client-shim.js';
23
23
  export { agentLinks, agentRosterRow, AGENT_ROSTER_GLOBAL, type AgentLink } from './agent-roster.js';
24
24
  export { createOwnershipIndex, type OwnershipIndex, type OwnershipRow } from './ownership.js';
25
25
  export { registerHostMount, takeHostMount, listHostMounts, noteWorldServer, worldServerOf, type HostMount } from './world-host.js';
26
- export { worldMountPatches, WORLD_MOUNT_PLUGIN, WORLD_MOUNT_ROW_ID, type WorldPatchLayer } from './world-mount.js';
26
+ export { worldMountPatches, WORLD_MOUNT_PLUGIN, WORLD_MOUNT_ROW_ID, WORLD_WEB_TRUST_PLUGIN, WORLD_WEB_TRUST_ROW_ID, type WorldPatchLayer, } from './world-mount.js';
27
+ export { buildTrustScript, deriveDefaultPageAuthorities, type BootScriptRow, type TrustConfig, } from './web-trust.js';
28
+ export { withSystemHead, type HeadAwareSessionFace, type HeadPlaceholder, type WithSystemHead } from './system-head.js';
27
29
  export { default as worldApply, name as worldPluginName, type Config as WorldEntryConfig } from './world-entry.js';
28
30
  export { default as joinApply, name as worldJoinPluginName, type Config as WorldJoinConfig } from './world-join.js';
29
31
  export { default } from './gateway.js';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @pgmi-builds/agent-hub — host half public surface (Agent Worlds line).
2
+ * @pgmi-builds/superd-hub — host half public surface (Super D line).
3
3
  *
4
4
  * The line owns the switch and the gateway (per super-dsh/AGENTS.md):
5
5
  * the world inventory control plane + the foreign agent roster + the world
@@ -13,7 +13,7 @@ export { handleAgentRuntime, registerSelectorRpc, AGENT_RUNTIME_RPC_PATH, regist
13
13
  export { registerForeignTarget, unregisterForeignTarget, getTarget, listRuntimeKeys } from './targets.js';
14
14
  export { registerAgent, unregisterAgent, setReady, listAgents, onRosterChanged } from './roster.js';
15
15
  export { spawnWorld } from './spawn-world.js';
16
- export { provisionWorldProfile } from './world-provision.js';
16
+ export { provisionWorldProfile, resolveInstallAnchor } from './world-provision.js';
17
17
  export { claimLabel, labelOf, releaseLabel, listLabels } from './labels.js';
18
18
  export { WorldWebServer, stripLabelFromUrl } from './world-web-server.js';
19
19
  export { parseClientRequest, serverResponse, serverError, serverResult, wireErrorOf, EnvelopeError } from './envelope.js';
@@ -23,7 +23,9 @@ export { renderClientShim } from './client-shim.js';
23
23
  export { agentLinks, agentRosterRow, AGENT_ROSTER_GLOBAL } from './agent-roster.js';
24
24
  export { createOwnershipIndex } from './ownership.js';
25
25
  export { registerHostMount, takeHostMount, listHostMounts, noteWorldServer, worldServerOf } from './world-host.js';
26
- export { worldMountPatches, WORLD_MOUNT_PLUGIN, WORLD_MOUNT_ROW_ID } from './world-mount.js';
26
+ export { worldMountPatches, WORLD_MOUNT_PLUGIN, WORLD_MOUNT_ROW_ID, WORLD_WEB_TRUST_PLUGIN, WORLD_WEB_TRUST_ROW_ID, } from './world-mount.js';
27
+ export { buildTrustScript, deriveDefaultPageAuthorities, } from './web-trust.js';
28
+ export { withSystemHead } from './system-head.js';
27
29
  export { default as worldApply, name as worldPluginName } from './world-entry.js';
28
30
  export { default as joinApply, name as worldJoinPluginName } from './world-join.js';
29
31
  export { default } from './gateway.js';
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * No config file: an agent is in the roster exactly while its adapter
5
5
  * plugin is loaded and registered. Adapter plugins self-register on
6
- * activation (key/label/ready) and the RuntimeSeat chip consumes the
7
- * snapshot. Roster entries are inventory only: they carry NO selection —
6
+ * activation (key/label/ready). Roster entries are inventory only: they
7
+ * carry NO selection —
8
8
  * the addressed world is the request's mount path (`DL7`, 2026-09-16).
9
9
  * one authority.
10
10
  */
@@ -47,6 +47,6 @@ export function registerSelectorRpc(ctx, source) {
47
47
  methods: ['GET', 'POST'],
48
48
  requestBody: 'buffered',
49
49
  fetch: (request) => handleAgentRuntime(request, source),
50
- }), 'agent-hub: /api/agent-runtime route');
50
+ }), 'superd-hub: /api/agent-runtime route');
51
51
  });
52
52
  }
@@ -9,12 +9,27 @@
9
9
  * test/boot-prepare-ordering.test.mjs. Data detachment at this stage comes
10
10
  * from the adapter side (foreign app-home redirection, spec §七).
11
11
  *
12
- * Profile resolution: loadProfile(name, profileName, installAnchor, home)
13
- * reads profiles under `<home>/profiles/<profileName>` and heals the
14
- * `@deepseek-ai/*` fallback farm into `<home>/profiles/node_modules` from
15
- * the install anchor (single instance — same physical installation).
12
+ * Profile resolution (2026-09-25 upstream alignment —
13
+ * docs/specs/world-resolution-upstream): loadProfile(name, profileName,
14
+ * installAnchor, home) reads profiles under `<home>/profiles/<profileName>`
15
+ * and writes nothing to disk. Before boot imports a single row, spawnWorld
16
+ * publishes THIS world into the HOST's live resolution table (the successor
17
+ * contract's sanctioned surface: an added linkedRoot covering the world
18
+ * tree + added table entries for the world's own `@pgmi-builds` packages +
19
+ * a generated peerDependencies block in the world profile manifest for
20
+ * routeLinked's peer gate). The world config's bare row names then resolve
21
+ * through the same interception the launcher uses; the per-world bare-URL
22
+ * farms and bareModuleBaseUrl are gone.
16
23
  */
17
24
  import { boot } from '@deepseek-ai/dsh-app-boot';
25
+ /**
26
+ * The host (ctx0) surface spawnWorld needs: cordis `ctx.get`, which locates
27
+ * the launcher's `pluginPackages` table and `profileContext` facts. Structural
28
+ * on purpose — adapters pass their own minimal host context.
29
+ */
30
+ export interface WorldHostSurface {
31
+ get(name: string): unknown;
32
+ }
18
33
  export interface SpawnWorldOptions {
19
34
  /** App name for the spawned root (also its fiber label). */
20
35
  appName: string;
@@ -40,7 +55,13 @@ export interface SpawnWorldOptions {
40
55
  dataHome?: string;
41
56
  /** Extra patch layers appended after the profile's own (e.g. an adapter's insert row). */
42
57
  extraPatches?: Parameters<typeof boot>[2];
43
- /** Override the bare-name resolution base (defaults to the install anchor's node_modules). */
44
- bareModuleBaseUrl?: string;
58
+ /**
59
+ * The host (ctx0) context. When it carries the launcher's `pluginPackages`
60
+ * table, spawnWorld republishes a widened successor so this world's tree
61
+ * resolves through the host table exactly like a launcher profile (spec
62
+ * §2.1). Table-less harnesses (unit tests, embedders) omit it and keep
63
+ * native resolution.
64
+ */
65
+ host?: WorldHostSurface;
45
66
  }
46
67
  export declare function spawnWorld(opts: SpawnWorldOptions): Promise<import("@deepseek-ai/cordis").Context>;
@@ -0,0 +1,277 @@
1
+ /**
2
+ * spawnWorld (S2): spawn a sibling ROOT context for a foreign agent world
3
+ * from the CTX0 tree — the library form of the PoC (ADR 0008 mechanism,
4
+ * .scratch/multi-context-poc/spawner2.mjs collapsed into a function).
5
+ *
6
+ * AW-A posture: SHARED home (ADR 0008 constraint 2 fallback). The ctxN
7
+ * `dshHomePath` service override is an AW-C1 item (spec §三/§十一.2) — the
8
+ * boot() provide/prepare ordering fact is pinned by
9
+ * test/boot-prepare-ordering.test.mjs. Data detachment at this stage comes
10
+ * from the adapter side (foreign app-home redirection, spec §七).
11
+ *
12
+ * Profile resolution (2026-09-25 upstream alignment —
13
+ * docs/specs/world-resolution-upstream): loadProfile(name, profileName,
14
+ * installAnchor, home) reads profiles under `<home>/profiles/<profileName>`
15
+ * and writes nothing to disk. Before boot imports a single row, spawnWorld
16
+ * publishes THIS world into the HOST's live resolution table (the successor
17
+ * contract's sanctioned surface: an added linkedRoot covering the world
18
+ * tree + added table entries for the world's own `@pgmi-builds` packages +
19
+ * a generated peerDependencies block in the world profile manifest for
20
+ * routeLinked's peer gate). The world config's bare row names then resolve
21
+ * through the same interception the launcher uses; the per-world bare-URL
22
+ * farms and bareModuleBaseUrl are gone.
23
+ */
24
+ import { loadProfile, boot, composeEntries, createRuntimeResolution } from '@deepseek-ai/dsh-app-boot';
25
+ import { provideCmdline } from '@deepseek-ai/dsh-cmdline';
26
+ import { dump } from 'js-yaml';
27
+ import { entryListSchema } from '@deepseek-ai/cordis-plugin-include';
28
+ import { existsSync, writeFileSync, readFileSync, readdirSync, realpathSync } from 'node:fs';
29
+ import { join } from 'node:path';
30
+ /**
31
+ * Republish the host's live resolution with THIS world added as a linked
32
+ * root (spec §2.1, contract-legal form): `profilesDir`/`profileDir` are
33
+ * frozen per process ("a successor cannot change its profile scope"), so
34
+ * the world tree joins the table the way the successor contract sanctions —
35
+ * an added linkedRoot covering `<worldHome>`, added entries for the world's
36
+ * own `@pgmi-builds` packages (routeLinked resolves names from the table),
37
+ * and a generated `peerDependencies` block in the world profile manifest
38
+ * (routeLinked's peer gate reads the importer's ancestor manifests; the
39
+ * peers are the composed rows' bare names — deterministic, regenerated on
40
+ * every spawn, so upstream row additions self-heal on the next boot).
41
+ *
42
+ * Faithful reconstruction — reload the launcher's profile from
43
+ * `profileContext` facts and recompute: the service exposes no `current`,
44
+ * and a plugin add between host boot and now is picked up for free (each
45
+ * spawn re-publishes; worlds are spawn-time facts and never recompose, so a
46
+ * later host-side replace can only affect the next spawn).
47
+ */
48
+ async function publishWorldInHostResolutionTurn(packages, launcher, opts, worldProfileDir, peerNames) {
49
+ const profile = loadProfile('dsh', launcher.name, launcher.installAnchor, launcher.home);
50
+ const base = await createRuntimeResolution({ installAnchor: launcher.installAnchor, profile, home: launcher.home });
51
+ // routeLinked's peer gate: the gate reads ancestor manifests of the
52
+ // IMPORTER — and ctx.baseUrl is a DIRECTORY URL with a trailing slash, so
53
+ // the resolver's dirname() lands on `<worldHome>/profiles`, one level
54
+ // above the profile itself. Peers therefore go into BOTH manifests (the
55
+ // world profile's own and the profiles-level directory), regenerated
56
+ // idempotently on every spawn — upstream row additions self-heal next boot.
57
+ const peers = Object.fromEntries([...peerNames].sort().map((name) => [name, '*']));
58
+ for (const manifestDir of [worldProfileDir, join(opts.home, 'profiles')]) {
59
+ const manifestPath = join(manifestDir, 'package.json');
60
+ const manifest = existsSync(manifestPath)
61
+ ? JSON.parse(readFileSync(manifestPath, 'utf8'))
62
+ : { name: `superd-${opts.appName}-profiles`, private: true };
63
+ manifest.peerDependencies = peers;
64
+ writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
65
+ }
66
+ // The world's own packages become table entries (targets = the realpaths of
67
+ // the profile-local links provisionWorldProfile wrote). declarer MUST be a
68
+ // manifest PATH: the ESM interception rewrites the resolve parent to it
69
+ // (pathToFileURL(route.entry.declarer)).
70
+ const declarer = join(worldProfileDir, 'package.json');
71
+ const worldScope = join(worldProfileDir, 'node_modules', '@pgmi-builds');
72
+ const baseNames = new Set(base.entries.map((entry) => entry.name));
73
+ for (const name of readdirSync(worldScope, { withFileTypes: true })) {
74
+ if (!name.isDirectory() && !name.isSymbolicLink())
75
+ continue;
76
+ const pkgName = `@pgmi-builds/${name.name}`;
77
+ // A profile-declared package already covers the name (a consumer who
78
+ // properly installed our subpackages) — the base entry wins, never assert
79
+ // a divergent mapping over it.
80
+ if (baseNames.has(pkgName))
81
+ continue;
82
+ const packageDir = realpathSync(join(worldScope, name.name));
83
+ const pkgManifest = JSON.parse(readFileSync(join(packageDir, 'package.json'), 'utf8'));
84
+ // FIRST-WRITE-WINS: shared names (every world publishes superd-hub) must
85
+ // keep the first publisher's declarer — overwriting it with another
86
+ // world's manifest path trips "replacing X requires a process restart"
87
+ // (dev3 0.1.3-u evidence). Any manifest path satisfies the ESM redirect;
88
+ // the peer gate reads the IMPORTER's ancestors, not the declarer.
89
+ if (!publishedEntries.has(pkgName)) {
90
+ publishedEntries.set(pkgName, { name: pkgName, packageDir, version: pkgManifest.version, declarer, scope: 'profile' });
91
+ }
92
+ }
93
+ const rootName = `superd-world-${opts.appName}`;
94
+ if (!publishedRoots.has(rootName)) {
95
+ publishedRoots.set(rootName, { name: rootName, realPath: opts.home });
96
+ }
97
+ packages.replace({
98
+ ...base,
99
+ entries: [...base.entries, ...publishedEntries.values()],
100
+ linkedRoots: [...base.linkedRoots, ...publishedRoots.values()],
101
+ });
102
+ }
103
+ /** Bare package name of a module specifier (`@scope/pkg/sub` → `@scope/pkg`). */
104
+ function barePackageNameOf(specifier) {
105
+ if (!specifier || specifier[0] === '.' || specifier[0] === '/' || specifier[0] === '#' || specifier.includes(':'))
106
+ return undefined;
107
+ const first = specifier.indexOf('/');
108
+ if (specifier[0] !== '@')
109
+ return first < 0 ? specifier : specifier.slice(0, first);
110
+ if (first < 0)
111
+ return;
112
+ const second = specifier.indexOf('/', first + 1);
113
+ return second < 0 ? specifier : specifier.slice(0, second);
114
+ }
115
+ /**
116
+ * Cross-spawn accumulation (spec §2.1, dev3 0.1.3-t evidence): the service
117
+ * exposes no `current`, and every reconstruction starts from a fresh base —
118
+ * a successor that DROPS a prior world's additions trips the contract
119
+ * ("replacing X requires a process restart") and every world after the
120
+ * first falls back to native resolution. Each spawn therefore merges its
121
+ * additions into this process-wide accumulator, and successors always carry
122
+ * the union. Values are deterministic per world (stable worldHome and pack
123
+ * paths), so re-spawns re-assert identical mappings — contract-stable.
124
+ */
125
+ const publishedEntries = new Map();
126
+ const publishedRoots = new Map();
127
+ /**
128
+ * Serializes table publishing: the six world spawns run concurrently, and
129
+ * interleaved reconstruct→replace cycles assert divergent successors against
130
+ * a mid-flight current (dev3 0.1.3-u evidence). One publish at a time; a
131
+ * failed turn never blocks the next (the caller's fail-soft handles it).
132
+ */
133
+ let publishQueue = Promise.resolve();
134
+ async function publishWorldInHostResolution(host, opts, worldProfileDir, peerNames) {
135
+ const packages = host.get('pluginPackages');
136
+ const launcher = host.get('profileContext');
137
+ if (packages === undefined || launcher?.installAnchor === undefined || launcher.home === undefined || launcher.name === undefined)
138
+ return;
139
+ const turn = publishQueue.catch(() => { }).then(() => publishWorldInHostResolutionTurn(packages, launcher, opts, worldProfileDir, peerNames));
140
+ publishQueue = turn;
141
+ await turn;
142
+ }
143
+ export async function spawnWorld(opts) {
144
+ const profile = loadProfile(opts.appName, opts.profileName, opts.installAnchor, opts.home);
145
+ // THE FILE IS THE COMPOSITION (0.1.7 alignment): compose every layer
146
+ // (bundle patches in profile order + profile patch + spawn extras like
147
+ // worldMountPatches) ONCE here and write the FINAL row list into the
148
+ // include file. Boot mounts it with NO patch stream. Rationale: the
149
+ // include's runtime patch application provably dropped the spawn-time
150
+ // worldMountPatches in nested boots (webserver re-enabled on 3080, world
151
+ // rows gone — 2026-09-24 alignment evidence), while the composition itself
152
+ // is deterministic and dumpable with the loader's own dialect (`!!js`
153
+ // preserved via entryListSchema).
154
+ const composed = composeEntries(profile.layers.map((l) => l.patches).concat([profile.patches, ...(opts.extraPatches ?? [])]), () => { });
155
+ writeFileSync(join(profile.dir, 'cordis.yml'), dump(composed, { schema: entryListSchema, noRefs: true, lineWidth: -1 }) + '\n');
156
+ const patches = [];
157
+ if (process.env.SUPERD_TRACE === '1') {
158
+ // Alignment diagnostics: what the world tree will actually compose.
159
+ try {
160
+ const rows = composed;
161
+ const pick = (id) => rows.find((r) => r.id === id);
162
+ for (const id of ['webserver', 'hmr', 'modules', 'superd-world-mount', 'superd-hub', 'agent-preset-registry']) {
163
+ const row = pick(id);
164
+ process.stderr.write(`[spawn-world:${opts.appName}] ${id}: ${row === undefined ? 'ABSENT' : JSON.stringify({ disabled: row.disabled, inject: 'inject' in row ? row.inject : undefined, name: row.name })}\n`);
165
+ }
166
+ process.stderr.write(`[spawn-world:${opts.appName}] composed rows: ${rows.length}\n`);
167
+ process.stderr.write(`[spawn-world:${opts.appName}] patches tail: ${JSON.stringify(patches.slice(-3).map((p) => p.id ?? (Array.isArray(p.insert) ? `insert(${p.insert.length})` : '?')))}\n`);
168
+ }
169
+ catch (cause) {
170
+ process.stderr.write(`[spawn-world:${opts.appName}] trace compose failed: ${String(cause)}\n`);
171
+ }
172
+ }
173
+ // Host table first (spec §2.1): publish this world as a linked root of the
174
+ // live resolution BEFORE boot() mounts the root include — the world config's
175
+ // bare row names then resolve through the same interception the launcher
176
+ // uses. Fail-soft: a table-less or hostile host degrades to native
177
+ // resolution (the world fails loudly on its first missing import, never the
178
+ // host).
179
+ if (opts.host !== undefined) {
180
+ try {
181
+ const peerNames = new Set();
182
+ for (const row of composed) {
183
+ for (const specifier of [
184
+ ...(typeof row.name === 'string' ? [row.name] : []),
185
+ ...(Array.isArray(row.inject) ? row.inject.filter((s) => typeof s === 'string') : []),
186
+ ]) {
187
+ const bare = barePackageNameOf(specifier);
188
+ if (bare !== undefined)
189
+ peerNames.add(bare);
190
+ }
191
+ }
192
+ await publishWorldInHostResolution(opts.host, opts, profile.dir, peerNames);
193
+ }
194
+ catch (cause) {
195
+ process.stderr.write(`[spawn-world:${opts.appName}] host table publishing failed (${String(cause)}) — falling back to native resolution\n`);
196
+ }
197
+ }
198
+ // Embedding-host facts via the PUBLIC cmdline API (risk-2 probe: boot owns
199
+ // dshHomePath, so the prepare slot is for OUR provides — cmdlineArgs is not
200
+ // boot-provided and upstream documents the empty-args embedding path).
201
+ // Worlds take no flags and never open a browser; exit = dispose own fiber.
202
+ // LAN authorities for the world's trust fence (deploy-level, env-driven):
203
+ // the world webserver must accept the Host the browser actually sends.
204
+ const trusted = (process.env.SUPERD_TRUSTED_HOSTS ?? '')
205
+ .split(/[\s,]+/).filter(Boolean)
206
+ .flatMap((h) => ['--trusted-host', h]);
207
+ let fiber;
208
+ // Launcher parity (0.1.7): a profileContext-carrying tree runs the profile
209
+ // HMR row, whose init REQUIRES the appReady service (otherwise "Profile HMR
210
+ // requires application readiness"). The launcher owns the readiness signal
211
+ // and commits it after boot settles — worlds do the same inline.
212
+ let appReadyCommitted = false;
213
+ const appReadyListeners = new Set();
214
+ const appReady = {
215
+ service: {
216
+ onReady(listener) {
217
+ if (appReadyCommitted) {
218
+ listener();
219
+ return () => { };
220
+ }
221
+ appReadyListeners.add(listener);
222
+ return () => { appReadyListeners.delete(listener); };
223
+ },
224
+ },
225
+ commit() {
226
+ if (appReadyCommitted)
227
+ return;
228
+ appReadyCommitted = true;
229
+ for (const listener of [...appReadyListeners])
230
+ listener();
231
+ appReadyListeners.clear();
232
+ },
233
+ };
234
+ const ctxW = await boot(opts.appName, join(profile.dir, 'cordis.yml'), patches, (ctx) => {
235
+ provideCmdline(ctx, {
236
+ args: ['--no-open', ...trusted],
237
+ exit: () => { void fiber?.dispose(); },
238
+ ready: appReady.service,
239
+ });
240
+ // This tree reads its own home from here on: sessions, settings.yaml,
241
+ // workspace store — all under the world's nested root.
242
+ //
243
+ // `set` (not `provide`): boot already registered `dshHomePath` on this
244
+ // root, and cordis refuses a second `provide` in the same scope
245
+ // ("service … has been registered at <root>"). `set` is the documented
246
+ // "overwrite a provided service's value" path for the owning fiber, which
247
+ // the prepare slot is — and ADR 0008 constraint 2 prescribes exactly this
248
+ // in-tree override (process.env is a shared resolver and must not change).
249
+ if (opts.dataHome !== undefined) {
250
+ const dataHome = opts.dataHome;
251
+ ctx.set('dshHomePath', (...segments) => join(dataHome, ...segments));
252
+ }
253
+ // 0.1.7: profile-mounted services (settings …) inject `profileContext`,
254
+ // which only runProfile's prepare slot used to provide. Worlds boot
255
+ // directly, so provide the equivalent here — without it every world's
256
+ // provider row pends on `waiting for service: settings`. This also arms
257
+ // the row-admission compatibility preflight inside world trees (it no-ops
258
+ // without a profileContext, which would leave world rows unjudged).
259
+ ctx.provide('profileContext', {
260
+ name: opts.appName,
261
+ dir: profile.dir,
262
+ patchPath: profile.patchPath,
263
+ installAnchor: opts.installAnchor,
264
+ cwd: process.cwd(),
265
+ home: opts.home,
266
+ startedBundles: profile.layers.map((l) => l.packageName),
267
+ overlays: profile.patches,
268
+ telemetryDisabledEnv: process.env.DSH_TELEMETRY_DISABLED,
269
+ });
270
+ });
271
+ fiber = ctxW.fiber;
272
+ // Launcher parity: commit readiness only when the world tree actually
273
+ // settled with a Loader (runProfile's same condition).
274
+ if (ctxW.get('loader') !== undefined)
275
+ appReady.commit();
276
+ return ctxW;
277
+ }