super-dsh 0.1.0 → 0.1.2

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 (178) hide show
  1. package/agent-agy/bridge/agy_bridge.py +250 -0
  2. package/agent-agy/bridge/gemini_openai_server.mjs +98 -0
  3. package/agent-agy/cordis.patch.yml +49 -0
  4. package/agent-agy/dist/adapter.d.ts +15 -0
  5. package/agent-agy/dist/adapter.js +42 -0
  6. package/agent-agy/dist/agent-preset-agy.d.ts +47 -0
  7. package/agent-agy/dist/agent-preset-agy.js +169 -0
  8. package/agent-agy/dist/agent-preset-projection.d.ts +31 -0
  9. package/agent-agy/dist/agent-preset-projection.js +33 -0
  10. package/agent-agy/dist/agent.d.ts +137 -0
  11. package/agent-agy/dist/agent.js +493 -0
  12. package/agent-agy/dist/agy-cli-client.d.ts +137 -0
  13. package/agent-agy/dist/agy-cli-client.js +301 -0
  14. package/agent-agy/dist/agy-client.d.ts +160 -0
  15. package/agent-agy/dist/agy-client.js +252 -0
  16. package/agent-agy/dist/agy-sessions.d.ts +24 -0
  17. package/agent-agy/dist/agy-sessions.js +116 -0
  18. package/agent-agy/dist/agy-store.d.ts +39 -0
  19. package/agent-agy/dist/agy-store.js +83 -0
  20. package/agent-agy/dist/inbox.d.ts +26 -0
  21. package/agent-agy/dist/inbox.js +53 -0
  22. package/agent-agy/dist/index.d.ts +80 -0
  23. package/agent-agy/dist/index.js +505 -0
  24. package/agent-agy/dist/models.d.ts +41 -0
  25. package/agent-agy/dist/models.js +74 -0
  26. package/agent-agy/dist/world-plugin.d.ts +9 -0
  27. package/agent-agy/dist/world-plugin.js +97 -0
  28. package/agent-agy/package.json +64 -0
  29. package/agent-claude/cordis.patch.yml +42 -0
  30. package/agent-claude/dist/adapter.js +62 -0
  31. package/agent-claude/dist/agent-preset-claude.js +169 -0
  32. package/agent-claude/dist/agent-preset-projection.js +30 -0
  33. package/agent-claude/dist/agent.js +1271 -0
  34. package/agent-claude/dist/claude-client.js +357 -0
  35. package/agent-claude/dist/claude-events.js +223 -0
  36. package/agent-claude/dist/claude-home.js +29 -0
  37. package/agent-claude/dist/commands.js +182 -0
  38. package/agent-claude/dist/content.js +134 -0
  39. package/agent-claude/dist/inbox.js +53 -0
  40. package/agent-claude/dist/index.js +555 -0
  41. package/agent-claude/dist/input-queue.js +64 -0
  42. package/agent-claude/dist/interaction.js +271 -0
  43. package/agent-claude/dist/models.js +158 -0
  44. package/agent-claude/dist/permission.js +120 -0
  45. package/agent-claude/dist/session-id.js +20 -0
  46. package/agent-claude/dist/session-map.js +165 -0
  47. package/agent-claude/dist/world-plugin.js +14 -0
  48. package/agent-claude/package.json +74 -0
  49. package/agent-codex/README.md +74 -0
  50. package/agent-codex/cordis.patch.yml +77 -0
  51. package/agent-codex/dist/adapter.js +55 -0
  52. package/agent-codex/dist/agent-preset-codex.js +171 -0
  53. package/agent-codex/dist/agent-preset-projection.js +37 -0
  54. package/agent-codex/dist/agent.js +1056 -0
  55. package/agent-codex/dist/app-home.js +65 -0
  56. package/agent-codex/dist/codex-client.js +469 -0
  57. package/agent-codex/dist/codex-events.js +297 -0
  58. package/agent-codex/dist/codex-store.js +190 -0
  59. package/agent-codex/dist/inbox.js +53 -0
  60. package/agent-codex/dist/index.js +605 -0
  61. package/agent-codex/dist/models.js +152 -0
  62. package/agent-codex/dist/permission.js +71 -0
  63. package/agent-codex/dist/session-map.js +170 -0
  64. package/agent-codex/dist/spike.js +46 -0
  65. package/agent-codex/dist/world-plugin.js +96 -0
  66. package/agent-codex/package.json +78 -0
  67. package/agent-hermes/README.md +144 -0
  68. package/agent-hermes/cordis.patch.yml +83 -0
  69. package/agent-hermes/dist/adapter.js +83 -0
  70. package/agent-hermes/dist/agent-preset-hermes.js +171 -0
  71. package/agent-hermes/dist/agent-preset-projection.js +34 -0
  72. package/agent-hermes/dist/agent.js +1068 -0
  73. package/agent-hermes/dist/hermes-client.js +953 -0
  74. package/agent-hermes/dist/hermes-events.js +289 -0
  75. package/agent-hermes/dist/hermes-store.js +158 -0
  76. package/agent-hermes/dist/inbox.js +53 -0
  77. package/agent-hermes/dist/index.js +541 -0
  78. package/agent-hermes/dist/models.js +324 -0
  79. package/agent-hermes/dist/permission.js +60 -0
  80. package/agent-hermes/dist/world-plugin.js +101 -0
  81. package/agent-hermes/package.json +76 -0
  82. package/agent-hub/cordis.patch.yml +12 -0
  83. package/agent-hub/dist/agent-roster.d.ts +34 -0
  84. package/agent-hub/dist/agent-roster.js +27 -0
  85. package/agent-hub/dist/carrier.d.ts +43 -0
  86. package/agent-hub/dist/carrier.js +241 -0
  87. package/agent-hub/dist/client-shim.d.ts +28 -0
  88. package/agent-hub/dist/client-shim.js +251 -0
  89. package/agent-hub/dist/envelope.d.ts +54 -0
  90. package/agent-hub/dist/envelope.js +92 -0
  91. package/agent-hub/dist/gateway.d.ts +28 -0
  92. package/agent-hub/dist/gateway.js +18 -0
  93. package/agent-hub/dist/index-pass.d.ts +22 -0
  94. package/agent-hub/dist/index-pass.js +47 -0
  95. package/agent-hub/dist/index.d.ts +29 -0
  96. package/agent-hub/dist/index.js +29 -0
  97. package/agent-hub/dist/labels.d.ts +45 -0
  98. package/agent-hub/dist/labels.js +83 -0
  99. package/agent-hub/dist/ownership.d.ts +37 -0
  100. package/agent-hub/dist/ownership.js +54 -0
  101. package/agent-hub/dist/roster.d.ts +28 -0
  102. package/agent-hub/dist/roster.js +38 -0
  103. package/agent-hub/dist/rpc.d.ts +38 -0
  104. package/agent-hub/dist/rpc.js +52 -0
  105. package/agent-hub/dist/spawn-world.d.ts +46 -0
  106. package/agent-hub/dist/spawn-world.js +72 -0
  107. package/agent-hub/dist/targets.d.ts +33 -0
  108. package/agent-hub/dist/targets.js +30 -0
  109. package/agent-hub/dist/world-entry.d.ts +31 -0
  110. package/agent-hub/dist/world-entry.js +51 -0
  111. package/agent-hub/dist/world-host.d.ts +69 -0
  112. package/agent-hub/dist/world-host.js +44 -0
  113. package/agent-hub/dist/world-join.d.ts +16 -0
  114. package/agent-hub/dist/world-join.js +122 -0
  115. package/agent-hub/dist/world-mount.d.ts +52 -0
  116. package/agent-hub/dist/world-mount.js +52 -0
  117. package/agent-hub/dist/world-mux.d.ts +72 -0
  118. package/agent-hub/dist/world-mux.js +224 -0
  119. package/agent-hub/dist/world-provision.d.ts +20 -0
  120. package/agent-hub/dist/world-provision.js +122 -0
  121. package/agent-hub/dist/world-web-server.d.ts +162 -0
  122. package/agent-hub/dist/world-web-server.js +248 -0
  123. package/agent-hub/lib/client/index.js +242 -0
  124. package/agent-hub/package.json +65 -0
  125. package/agent-omp/README.md +77 -0
  126. package/agent-omp/cordis.patch.yml +92 -0
  127. package/agent-omp/dist/adapter.js +36 -0
  128. package/agent-omp/dist/agent-preset-omp.js +171 -0
  129. package/agent-omp/dist/agent-preset-projection.js +36 -0
  130. package/agent-omp/dist/agent.js +1145 -0
  131. package/agent-omp/dist/app-home.js +86 -0
  132. package/agent-omp/dist/discovery.js +116 -0
  133. package/agent-omp/dist/inbox.js +53 -0
  134. package/agent-omp/dist/index.js +574 -0
  135. package/agent-omp/dist/knobs.js +50 -0
  136. package/agent-omp/dist/lazy-rpc.js +161 -0
  137. package/agent-omp/dist/mobile/gesture.js +148 -0
  138. package/agent-omp/dist/mobile/zoom-guard.js +294 -0
  139. package/agent-omp/dist/mobile-boot.js +38 -0
  140. package/agent-omp/dist/models.js +299 -0
  141. package/agent-omp/dist/omp-cli.js +147 -0
  142. package/agent-omp/dist/omp-disk-discovery.js +178 -0
  143. package/agent-omp/dist/omp-store.js +518 -0
  144. package/agent-omp/dist/pairing.js +45 -0
  145. package/agent-omp/dist/permission.js +96 -0
  146. package/agent-omp/dist/protocol.js +13 -0
  147. package/agent-omp/dist/rpc-types.js +1 -0
  148. package/agent-omp/dist/sdk-client.js +378 -0
  149. package/agent-omp/dist/sidecar-client.js +195 -0
  150. package/agent-omp/dist/store/adapter.js +47 -0
  151. package/agent-omp/dist/store/db.js +210 -0
  152. package/agent-omp/dist/store/index.js +59 -0
  153. package/agent-omp/dist/store/reconcile.js +51 -0
  154. package/agent-omp/dist/store/schema.js +40 -0
  155. package/agent-omp/dist/world-plugin.js +96 -0
  156. package/agent-omp/package.json +97 -0
  157. package/agent-omp/sidecar/main.ts +481 -0
  158. package/agent-pi/README.md +67 -0
  159. package/agent-pi/cordis.patch.yml +80 -0
  160. package/agent-pi/dist/adapter.js +53 -0
  161. package/agent-pi/dist/agent-preset-pi.js +169 -0
  162. package/agent-pi/dist/agent-preset-projection.js +29 -0
  163. package/agent-pi/dist/agent.js +949 -0
  164. package/agent-pi/dist/inbox.js +53 -0
  165. package/agent-pi/dist/index.js +595 -0
  166. package/agent-pi/dist/knobs.js +24 -0
  167. package/agent-pi/dist/models.js +200 -0
  168. package/agent-pi/dist/permission.js +66 -0
  169. package/agent-pi/dist/pi-client.js +224 -0
  170. package/agent-pi/dist/pi-events.js +155 -0
  171. package/agent-pi/dist/pi-home.js +55 -0
  172. package/agent-pi/dist/safe-json.js +25 -0
  173. package/agent-pi/dist/session-map.js +119 -0
  174. package/agent-pi/dist/world-plugin.js +97 -0
  175. package/agent-pi/package.json +77 -0
  176. package/cordis.patch.yml +22 -19
  177. package/package.json +88 -25
  178. package/client.js +0 -4
@@ -0,0 +1,46 @@
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: 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).
16
+ */
17
+ import { boot } from '@deepseek-ai/dsh-app-boot';
18
+ export interface SpawnWorldOptions {
19
+ /** App name for the spawned root (also its fiber label). */
20
+ appName: string;
21
+ /** Profile directory name under `<home>/profiles/`. */
22
+ profileName: string;
23
+ /** package.json of the @deepseek-ai installation that owns the bundle closure. */
24
+ installAnchor: string;
25
+ /**
26
+ * The world's own home root: profiles resolve from `<home>/profiles/<name>`.
27
+ * The caller passes the NESTED root (`<line home>/agents/<label>`) — every
28
+ * runtime owns one root, nothing is shared between runtimes.
29
+ */
30
+ home: string;
31
+ /**
32
+ * The world's DSH data root (sessions / settings / workspaces). Defaults to
33
+ * {@link home}. When it differs from `home`, the child tree's `dshHomePath`
34
+ * service is overridden in the boot `prepare` slot — which runs AFTER boot's
35
+ * own provide and BEFORE the plugin tree mounts, so every `!!js
36
+ * dshHomePath(...)` expression in the composition resolves inside this root
37
+ * (ADR 0008 constraint 2: per-context home can only be an in-tree service
38
+ * override; `process.env` is a shared resolver).
39
+ */
40
+ dataHome?: string;
41
+ /** Extra patch layers appended after the profile's own (e.g. an adapter's insert row). */
42
+ extraPatches?: Parameters<typeof boot>[2];
43
+ /** Override the bare-name resolution base (defaults to the install anchor's node_modules). */
44
+ bareModuleBaseUrl?: string;
45
+ }
46
+ export declare function spawnWorld(opts: SpawnWorldOptions): Promise<import("@deepseek-ai/cordis").Context>;
@@ -0,0 +1,72 @@
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: 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).
16
+ */
17
+ import { loadProfile, boot } from '@deepseek-ai/dsh-app-boot';
18
+ import { provideCmdline } from '@deepseek-ai/dsh-cmdline';
19
+ import { writeFileSync } from 'node:fs';
20
+ import { join } from 'node:path';
21
+ import { pathToFileURL } from 'node:url';
22
+ const EMPTY_ROOT = '[]\n';
23
+ export async function spawnWorld(opts) {
24
+ const profile = loadProfile(opts.appName, opts.profileName, opts.installAnchor, opts.home);
25
+ // Empty include root: the tree is composed entirely as patch layers
26
+ // (bundle rows in profile order + profile patch + extras).
27
+ writeFileSync(join(profile.dir, 'cordis.yml'), EMPTY_ROOT);
28
+ const patches = [
29
+ ...profile.layers.flatMap((l) => l.patches),
30
+ ...profile.patches,
31
+ ...(opts.extraPatches ?? []),
32
+ ];
33
+ // Bare plugin names resolve from the installation's node_modules (the
34
+ // anchor owns the complete plugin closure). Same cordis on both sides —
35
+ // no cross-copy Symbol split.
36
+ // Loader wants a file:// URL base; accept a plain path and normalize.
37
+ const rawBase = opts.bareModuleBaseUrl ?? join(opts.installAnchor, '..', 'node_modules', '/');
38
+ const bareModuleBaseUrl = rawBase.startsWith('file:')
39
+ ? rawBase
40
+ : pathToFileURL(rawBase.endsWith('/') ? rawBase : rawBase + '/').href;
41
+ // Embedding-host facts via the PUBLIC cmdline API (risk-2 probe: boot owns
42
+ // dshHomePath, so the prepare slot is for OUR provides — cmdlineArgs is not
43
+ // boot-provided and upstream documents the empty-args embedding path).
44
+ // Worlds take no flags and never open a browser; exit = dispose own fiber.
45
+ // LAN authorities for the world's trust fence (deploy-level, env-driven):
46
+ // the world webserver must accept the Host the browser actually sends.
47
+ const trusted = (process.env.AW_TRUSTED_HOSTS ?? '')
48
+ .split(/[\s,]+/).filter(Boolean)
49
+ .flatMap((h) => ['--trusted-host', h]);
50
+ let fiber;
51
+ const ctxW = await boot(opts.appName, join(profile.dir, 'cordis.yml'), patches, (ctx) => {
52
+ provideCmdline(ctx, {
53
+ args: ['--no-open', ...trusted],
54
+ exit: () => { void fiber?.dispose(); },
55
+ });
56
+ // This tree reads its own home from here on: sessions, settings.yaml,
57
+ // workspace store — all under the world's nested root.
58
+ //
59
+ // `set` (not `provide`): boot already registered `dshHomePath` on this
60
+ // root, and cordis refuses a second `provide` in the same scope
61
+ // ("service … has been registered at <root>"). `set` is the documented
62
+ // "overwrite a provided service's value" path for the owning fiber, which
63
+ // the prepare slot is — and ADR 0008 constraint 2 prescribes exactly this
64
+ // in-tree override (process.env is a shared resolver and must not change).
65
+ if (opts.dataHome !== undefined) {
66
+ const dataHome = opts.dataHome;
67
+ ctx.set('dshHomePath', (...segments) => join(dataHome, ...segments));
68
+ }
69
+ }, bareModuleBaseUrl);
70
+ fiber = ctxW.fiber;
71
+ return ctxW;
72
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Foreign target registry: which runtime key maps to which context's
3
+ * typertGateway SERVICE INSTANCE.
4
+ *
5
+ * The instance is the whole target: its two methods (dispatchRpc /
6
+ * openWireStream) address their upstream through their own owning context
7
+ * (ctx.typert, ctx.reflect) and their own instance state (remoteEvents,
8
+ * registered by that tree's api-remotes). Delegating a call to the instance
9
+ * therefore delegates BOTH address spaces at once — Cordis ctx and JS this.
10
+ * An out-of-process target (subprocess app / remote machine) implements the
11
+ * same GatewayFace over the wire (ADR 0007 loopback relay) — the caller
12
+ * cannot tell the difference.
13
+ */
14
+ /** The structural face of a typertGateway service instance. */
15
+ export interface GatewayFace {
16
+ dispatchRpc(endpoint: string, payload: unknown, signal: AbortSignal): Promise<unknown>;
17
+ openWireStream(endpoint: string, payload: unknown, signal: AbortSignal): AsyncIterable<unknown>;
18
+ }
19
+ /** One addressable runtime world behind the selector. */
20
+ export interface ForeignTarget {
21
+ /** Runtime key (`omp`, …) — what the selector addresses. */
22
+ key: string;
23
+ /** The context's typertGateway service instance (or a wire adapter with the same face). */
24
+ gateway: GatewayFace;
25
+ }
26
+ /** Register (or replace) the target for a runtime key. */
27
+ export declare function registerForeignTarget(target: ForeignTarget): void;
28
+ /** Drop a target (context disposed). */
29
+ export declare function unregisterForeignTarget(key: string): void;
30
+ /** Live runtime keys: the native world plus every registered foreign key. */
31
+ export declare function listRuntimeKeys(): string[];
32
+ /** Test/introspection hook. */
33
+ export declare function getTarget(key: string): ForeignTarget | undefined;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Foreign target registry: which runtime key maps to which context's
3
+ * typertGateway SERVICE INSTANCE.
4
+ *
5
+ * The instance is the whole target: its two methods (dispatchRpc /
6
+ * openWireStream) address their upstream through their own owning context
7
+ * (ctx.typert, ctx.reflect) and their own instance state (remoteEvents,
8
+ * registered by that tree's api-remotes). Delegating a call to the instance
9
+ * therefore delegates BOTH address spaces at once — Cordis ctx and JS this.
10
+ * An out-of-process target (subprocess app / remote machine) implements the
11
+ * same GatewayFace over the wire (ADR 0007 loopback relay) — the caller
12
+ * cannot tell the difference.
13
+ */
14
+ const targets = new Map();
15
+ /** Register (or replace) the target for a runtime key. */
16
+ export function registerForeignTarget(target) {
17
+ targets.set(target.key, target);
18
+ }
19
+ /** Drop a target (context disposed). */
20
+ export function unregisterForeignTarget(key) {
21
+ targets.delete(key);
22
+ }
23
+ /** Live runtime keys: the native world plus every registered foreign key. */
24
+ export function listRuntimeKeys() {
25
+ return ['native', ...targets.keys()];
26
+ }
27
+ /** Test/introspection hook. */
28
+ export function getTarget(key) {
29
+ return targets.get(key);
30
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * World-side mount plugin (AW-B DL1/DL3) — `@pgmi-builds/agent-hub/world`.
3
+ *
4
+ * Inserted into the WORLD root's composition (its own process-side root, no
5
+ * listener). It provides the virtual `webServer` for that root: every route the
6
+ * world's plugins register is translated to `/<label>+path` on ctx0's real
7
+ * webServer, so the world's whole web surface lands under its mount with no
8
+ * namespace list and no second socket.
9
+ *
10
+ * The RPC channel is NOT the world's: `WorldWebServer` swallows `/api*`, and the
11
+ * hub's carrier answers `/<label>/api` + `/<label>/api/remote.mux` in ctx0's
12
+ * auth domain, dispatching to this world's gateway instance. Non-envelope
13
+ * GET/HEAD traffic on `/<label>/api` is forwarded into the world's registered
14
+ * exact Fetch routes (session-log export and friends) through the shared
15
+ * `/api` fetch handler this plugin publishes into the cross-root registry
16
+ * (`world-host.ts`) — still behind ctx0's fence, never the world's own.
17
+
18
+ * auth domain, dispatching to this world's gateway instance.
19
+ */
20
+ import type { Context } from '@deepseek-ai/cordis';
21
+ /** Stable Cordis plugin name. */
22
+ export declare const name = "aw.world.mount";
23
+ /** Row config: which world this root is. */
24
+ export interface Config {
25
+ key: string;
26
+ }
27
+ /** Apply the world mount. @param ctx - the WORLD root context. @param config - `{ key }`. */
28
+ export declare function apply(ctx: Context, config?: {
29
+ key?: unknown;
30
+ }): void;
31
+ export default apply;
@@ -0,0 +1,51 @@
1
+ import { noteWorldServer, publishWorldFetch, takeHostMount } from './world-host.js';
2
+ import { WorldWebServer } from './world-web-server.js';
3
+ /** Stable Cordis plugin name. */
4
+ export const name = 'aw.world.mount';
5
+ /** Apply the world mount. @param ctx - the WORLD root context. @param config - `{ key }`. */
6
+ export function apply(ctx, config) {
7
+ const key = typeof config?.key === 'string' ? config.key : undefined;
8
+ if (key === undefined) {
9
+ ctx.logger?.warn?.('aw.world.mount: missing config.key — world not mounted');
10
+ return;
11
+ }
12
+ const mount = takeHostMount(key);
13
+ if (mount === undefined) {
14
+ ctx.logger?.warn?.(`aw.world.mount: no host mount registered for key ${JSON.stringify(key)}`);
15
+ return;
16
+ }
17
+ const worldWebServer = new WorldWebServer(mount.labelPath, mount.real, {
18
+ onIndexInject: (table) => { ctx.emit('webserver/index-inject', table); },
19
+ // One auth domain: the mount, not this world, decides who may read a page.
20
+ authorize: (req, res) => mount.authorize?.(req, res) ?? true,
21
+ });
22
+ noteWorldServer(key, worldWebServer);
23
+ ctx.reflect.provide('webServer', worldWebServer);
24
+ // The world's frontend-static still asks ITS OWN connection to authorize an
25
+ // index request. That gate is answered by the mount above: the browser came
26
+ // in through ctx0, the world is reached in-ctx, and the world's cookie secret
27
+ // belongs to its own nested home — so a second check here could only 401 an
28
+ // already-authorized read. Neutralize it instead of sharing credentials.
29
+ // The same connection also composes the world's `/api` fetch handler (exact
30
+ // Fetch routes + the gateway's RPC interceptor). It is published here so the
31
+ // hub's carrier can forward non-envelope GET/HEAD traffic on
32
+ // `/<label>/api` into the world's registered routes; auth stays in ctx0's
33
+ // domain because the carrier fences the request BEFORE this handler runs.
34
+ let dropWorldFetch;
35
+ ctx.inject(['connection'], (webCtx) => {
36
+ const connection = webCtx.get('connection');
37
+ if (connection === undefined)
38
+ return;
39
+ if (typeof connection.authorizeIndex === 'function') {
40
+ connection.authorizeIndex = () => true;
41
+ }
42
+ if (typeof connection.createSharedFetchHandler === 'function') {
43
+ dropWorldFetch = publishWorldFetch(key, connection.createSharedFetchHandler('/api'));
44
+ }
45
+ });
46
+ ctx.effect(() => () => {
47
+ worldWebServer.dispose();
48
+ dropWorldFetch?.();
49
+ }, 'aw.world.mount: virtual webServer');
50
+ }
51
+ export default apply;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Cross-root mount registry (AW-B DL1/DL3).
3
+ *
4
+ * A world runs as its OWN cordis ROOT (events are root-scoped — probe
5
+ * 2026-09-16), so ctx0 and the world cannot share service instances through
6
+ * the context tree. They DO share this module (the profile links
7
+ * `@pgmi-builds/agent-hub` at the same path), which is where the host hands the
8
+ * world everything it needs to mount itself:
9
+ *
10
+ * ctx0 hub → registerHostMount({ key, labelPath, real }) (before spawn)
11
+ * world → takeHostMount(key) → provides the virtual `webServer`
12
+ *
13
+ * No selection state: the key is the world's own identity, fixed at spawn.
14
+ */
15
+ import type { RealWebServerFace } from './world-web-server.js';
16
+ /** What a world needs to mount its surface onto ctx0's real webServer. */
17
+ export interface HostMount {
18
+ /** Runtime key (`omp`, `codex`, …) — equals the mount label. */
19
+ key: string;
20
+ /** Mount root (`/omp`). */
21
+ labelPath: string;
22
+ /** ctx0's webServer instance (live object, passed across roots). */
23
+ real: RealWebServerFace;
24
+ /**
25
+ * ctx0's index authorization (the SAME gate the native index goes through).
26
+ * The mount is the only ingress and answers the world's pages/assets itself,
27
+ * so auth is decided in ctx0's domain — by the cookie that authenticated
28
+ * `<label>` — and never by the world's own browser-auth gate (a different
29
+ * tree, a different secret). Returning false means the authorizer already
30
+ * answered (401, or the token→cookie 303).
31
+ */
32
+ authorize?(req: unknown, res: unknown): boolean;
33
+ }
34
+ /** Publish the host side of one world mount (idempotent replace). */
35
+ export declare function registerHostMount(mount: HostMount): () => void;
36
+ /** Record the virtual webServer a world root provided (diagnostics/tests). */
37
+ export declare function noteWorldServer(key: string, server: unknown): void;
38
+ /** The virtual webServer a world root provided, if it mounted yet. */
39
+ export declare function worldServerOf(key: string): unknown;
40
+ /** Read one host mount (called from inside the world root). */
41
+ export declare function takeHostMount(key: string): HostMount | undefined;
42
+ /** Keys with a published host mount. */
43
+ export declare function listHostMounts(): string[];
44
+ /**
45
+ * The structural face of a world connection's shared `/api` fetch handler
46
+ * (upstream `ConnectionFetchHandler` from `client/connection`): exact Fetch
47
+ * routes first, then the shared-channel RPC interceptor, then 404. Trust and
48
+ * authentication are NOT part of this face — upstream applies them in the
49
+ * physical carrier around it, which under a mount is the hub's carrier with
50
+ * ctx0's fence.
51
+ */
52
+ export interface WorldFetchHandler {
53
+ /** Resolve body handling for one request before any bytes are read. */
54
+ requestBodyMode(request: {
55
+ readonly method: string;
56
+ readonly url: URL;
57
+ }): 'buffered' | 'streaming';
58
+ /** Dispatch one already-authenticated request to its route owner. */
59
+ fetch(request: Request): Promise<Response>;
60
+ }
61
+ /**
62
+ * Publish one world's shared `/api` fetch handler so the carrier can forward
63
+ * non-envelope traffic on `/<label>/api` into the world's registered routes
64
+ * (session-log export and friends). Called from inside the world root
65
+ * (`world-entry`); read from the host root (`carrier`). Idempotent replace.
66
+ */
67
+ export declare function publishWorldFetch(key: string, handler: WorldFetchHandler): () => void;
68
+ /** The world's published shared `/api` fetch handler, if its root published one yet. */
69
+ export declare function worldFetchHandlerOf(key: string): WorldFetchHandler | undefined;
@@ -0,0 +1,44 @@
1
+ const mounts = new Map();
2
+ /** Publish the host side of one world mount (idempotent replace). */
3
+ export function registerHostMount(mount) {
4
+ mounts.set(mount.key, mount);
5
+ return () => {
6
+ if (mounts.get(mount.key) === mount)
7
+ mounts.delete(mount.key);
8
+ };
9
+ }
10
+ const servers = new Map();
11
+ /** Record the virtual webServer a world root provided (diagnostics/tests). */
12
+ export function noteWorldServer(key, server) {
13
+ servers.set(key, server);
14
+ }
15
+ /** The virtual webServer a world root provided, if it mounted yet. */
16
+ export function worldServerOf(key) {
17
+ return servers.get(key);
18
+ }
19
+ /** Read one host mount (called from inside the world root). */
20
+ export function takeHostMount(key) {
21
+ return mounts.get(key);
22
+ }
23
+ /** Keys with a published host mount. */
24
+ export function listHostMounts() {
25
+ return [...mounts.keys()];
26
+ }
27
+ const worldFetchHandlers = new Map();
28
+ /**
29
+ * Publish one world's shared `/api` fetch handler so the carrier can forward
30
+ * non-envelope traffic on `/<label>/api` into the world's registered routes
31
+ * (session-log export and friends). Called from inside the world root
32
+ * (`world-entry`); read from the host root (`carrier`). Idempotent replace.
33
+ */
34
+ export function publishWorldFetch(key, handler) {
35
+ worldFetchHandlers.set(key, handler);
36
+ return () => {
37
+ if (worldFetchHandlers.get(key) === handler)
38
+ worldFetchHandlers.delete(key);
39
+ };
40
+ }
41
+ /** The world's published shared `/api` fetch handler, if its root published one yet. */
42
+ export function worldFetchHandlerOf(key) {
43
+ return worldFetchHandlers.get(key);
44
+ }
@@ -0,0 +1,16 @@
1
+ /** Stable Cordis plugin name. */
2
+ export declare const name = "aw.world.join";
3
+ /** Row config: which world to join, under which roster label. */
4
+ export interface Config {
5
+ key: string;
6
+ label?: string;
7
+ }
8
+ /** Structural slice of the ctx0 services the join needs. */
9
+ interface HostContext {
10
+ provide(name: string, value: unknown): void;
11
+ inject(deps: string[], callback: (ctx: unknown) => void): unknown;
12
+ effect?(callback: () => () => void, label?: string): unknown;
13
+ }
14
+ /** Apply the join. @param ctx - the CTX0 root context. @param config - `{ key, label? }`. */
15
+ export declare function apply(ctx: HostContext, config?: Partial<Config>): void;
16
+ export default apply;
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Hub-side world joiner (AW-B DL1–DL5) — `@pgmi-builds/agent-hub/join`.
3
+ *
4
+ * Ruling R2 (2026-09-16): an adapter may ship STANDALONE only — joining the
5
+ * agent-worlds hub is the HUB side's job. This plugin is that job, generic:
6
+ * the ctx0 composition inserts one row with `{ key }` and the hub does the
7
+ * spawn/roster/mount wiring the adapter's own world plugin would otherwise
8
+ * carry (the omp/codex adapters ship active per-adapter plugins; the claude
9
+ * adapter's `/world` entry is deliberately inert and is joined HERE).
10
+ *
11
+ * 1. roster membership (activation IS membership, spec S2);
12
+ * 2. ctx0 publishes the host mount (real webServer instance) before spawn;
13
+ * 3. `spawnWorld` boots the sibling ROOT from the world's own nested home
14
+ * (`<home>/agents/<key>/profiles/web` — provisioned here via
15
+ * `provisionWorldProfile`, or by the line bootstrap when the adapter
16
+ * package is not resolvable from this module), with the world mount
17
+ * patches (no listener, virtual webServer);
18
+ * 4. the world's gateway becomes a foreign target; the carrier answers
19
+ * `/<key>/api` + `/<key>/api/remote.mux` in ctx0's auth domain.
20
+ *
21
+ * Cordis identifies a plugin by its module, so ONE joiner row per tree — a
22
+ * second joined world needs either its own adapter-side plugin (omp/codex
23
+ * shape) or this plugin promoted to per-row instances. The world's PROFILE
24
+ * (bundles incl. its adapter) is provisioned by `provisionWorldProfile`
25
+ * (registry installs) or the line bootstrap (dev); this row only spawns,
26
+ * registers and mounts what that profile composes.
27
+ */
28
+ import { mkdirSync } from 'node:fs';
29
+ import { resolveDshHome } from '@deepseek-ai/dsh-home-paths';
30
+ import { join } from 'node:path';
31
+ import { registerAgent, setReady } from './roster.js';
32
+ import { registerForeignTarget } from './targets.js';
33
+ import { spawnWorld } from './spawn-world.js';
34
+ import { provisionWorldProfile } from './world-provision.js';
35
+ import { registerHostMount } from './world-host.js';
36
+ import { mountWorld } from './carrier.js';
37
+ import { worldMountPatches } from './world-mount.js';
38
+ /** Stable Cordis plugin name. */
39
+ export const name = 'aw.world.join';
40
+ const ANCHOR = process.env.SUPERD_DSH_ANCHOR
41
+ ?? '/home/u1/.local/lib/node_modules/@deepseek-ai/dsh/package.json';
42
+ /** Apply the join. @param ctx - the CTX0 root context. @param config - `{ key, label? }`. */
43
+ export function apply(ctx, config) {
44
+ const key = typeof config?.key === 'string' ? config.key : undefined;
45
+ if (key === undefined || key === '' || key.includes('/')) {
46
+ ctx.provide('aw.world.join.error', `invalid config.key ${JSON.stringify(config?.key)}`);
47
+ return;
48
+ }
49
+ const label = typeof config?.label === 'string' && config.label !== '' ? config.label : key;
50
+ registerAgent({ key, label, ready: false });
51
+ // S7 nested home: the world's whole tree lives under `agents/<key>` (its
52
+ // profiles were provisioned there by the line bootstrap; DSH data lands
53
+ // inside the same root via spawnWorld's dataHome override).
54
+ // Harness resolver (env → ~/.dsh): a consumer install has no DSH_HOME and
55
+ // no cwd contract — deriving the world root from cwd spawns worlds into a
56
+ // garbage tree or throws inside apply() and kills the whole host boot.
57
+ const root = resolveDshHome();
58
+ const worldHome = join(root, 'agents', key);
59
+ mkdirSync(join(worldHome, 'profiles'), { recursive: true });
60
+ // Publish story: a foreign install has no line bootstrap, so the nested
61
+ // profile + @pgmi-builds links are provisioned HERE (idempotent; dev lines
62
+ // keep parity — smoke.mjs wrote the same layout, and AW_BARE_BASE still
63
+ // overrides the resolved base).
64
+ const bareBase = provisionWorldProfile({
65
+ key,
66
+ adapterPkg: '@pgmi-builds/agent-adapter-claude',
67
+ worldHome,
68
+ });
69
+ const world = (async () => {
70
+ // Wait for ctx0's listening stack: the mount needs the real webServer and
71
+ // the browser-trust fence from the live connection service.
72
+ const host = await new Promise((resolve) => {
73
+ ctx.inject(['webServer', 'connection'], (hostCtx) => { resolve(hostCtx); });
74
+ });
75
+ const real = host['webServer'];
76
+ const connection = host['connection'];
77
+ const dropHostMount = registerHostMount({
78
+ key,
79
+ labelPath: `/${key}`,
80
+ real,
81
+ // ctx0's index gate, applied by the mount to this world's pages and
82
+ // assets: the world is reached in-ctx and owns no listener, so ctx0
83
+ // decides auth (one auth domain).
84
+ authorize: (req, res) => connection.authorizeIndex(req, res),
85
+ });
86
+ const ctxW = await spawnWorld({
87
+ appName: `aw-${key}`,
88
+ profileName: 'web',
89
+ installAnchor: ANCHOR,
90
+ home: worldHome,
91
+ dataHome: worldHome,
92
+ // Adapter-local bundle names resolve from the profile's own
93
+ // node_modules (heal owns @deepseek-ai there; @pgmi-builds links are
94
+ // provisioned by provisionWorldProfile above, or by the line bootstrap
95
+ // when the adapter package was not resolvable — env wins over both).
96
+ bareModuleBaseUrl: process.env.AW_BARE_BASE ?? bareBase ?? undefined,
97
+ extraPatches: worldMountPatches(key),
98
+ });
99
+ const gateway = ctxW.get('typertGateway');
100
+ registerForeignTarget({ key, gateway });
101
+ const mounted = mountWorld({
102
+ real,
103
+ label: key,
104
+ gateway,
105
+ requestRejection: (request) => connection
106
+ .requestRejection(request),
107
+ });
108
+ setReady(key, true);
109
+ ctx.effect?.(() => () => {
110
+ mounted.dispose();
111
+ dropHostMount();
112
+ }, `aw.world.join: ${key} mount`);
113
+ return ctxW;
114
+ })().catch((cause) => {
115
+ // A failed world degrades to a not-ready roster row; a rejected provided
116
+ // promise would fail the entire host boot (loader entry apply).
117
+ console.error(`[super-dsh] ${key} world failed:`, cause);
118
+ return null;
119
+ });
120
+ ctx.provide(`aw.world.${key}`, world);
121
+ }
122
+ export default apply;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * World composition patches for the mount (AW-B DL1/DL3).
3
+ *
4
+ * A mounted world runs with NO listener and provides the virtual webServer
5
+ * from `<pkg>/world`. Three patches make that composition work:
6
+ *
7
+ * 1. `webserver` disabled — the world owns no socket; ctx0's listener is
8
+ * the only ingress.
9
+ * 2. `modules` inject webServer — client-modules probes
10
+ * `ctx.get('webServer')` WITHOUT declaring the dependency
11
+ * (`client/modules/src/index.ts:576`), so without this patch its row
12
+ * activates before the provider exists and boot fails. Patching the row's
13
+ * `inject` makes cordis WAIT for the provider, order-independent.
14
+ * 3. insert the world mount row — provides the virtual webServer inside the
15
+ * world root and translates every route its plugins declare.
16
+ *
17
+ * Patch layers are plain data: the patch engine applies arbitrary entry
18
+ * overrides (`vendor/include/src/index.ts:77-121`).
19
+ */
20
+ /** Id of the inserted world-mount row. */
21
+ export declare const WORLD_MOUNT_ROW_ID = "aw-world-mount";
22
+ /** Plugin name providing the world's virtual webServer. */
23
+ export declare const WORLD_MOUNT_PLUGIN = "@pgmi-builds/agent-hub/world";
24
+ /** Id of the inserted hub row (the same plugin ctx0 itself composes). */
25
+ export declare const WORLD_HUB_ROW_ID = "aw-agent-hub";
26
+ /** Plugin name of the hub itself — one UI, one roster, every runtime. */
27
+ export declare const WORLD_HUB_PLUGIN = "@pgmi-builds/agent-hub";
28
+ /** One patch layer understood by the loader (structural; no app-boot import). */
29
+ export type WorldPatchLayer = {
30
+ id: string;
31
+ disabled?: boolean;
32
+ inject?: readonly string[];
33
+ } | {
34
+ insert: ReadonlyArray<{
35
+ id: string;
36
+ name: string;
37
+ config?: Record<string, unknown>;
38
+ }>;
39
+ };
40
+ /**
41
+ * The layers that turn a listener-owning world into a mounted one:
42
+ *
43
+ * 1. `webserver` off — the world owns no socket (the hub serves its face);
44
+ * 2. `modules` waits for the virtual `webServer` the entry row provides;
45
+ * 3. the entry row itself (the world's mount identity);
46
+ * 4. the HUB ROW — the same `@pgmi-builds/agent-hub` native ctx0 composes, so
47
+ * the foreign agent gets the *identical* selector UI, and the roster it
48
+ * renders is read from the hub over the world's own `/api` channel.
49
+ * @param key - runtime key (`omp`, `codex`, …) — the mount label.
50
+ * @returns patch layers to append to the world's composition.
51
+ */
52
+ export declare function worldMountPatches(key: string): readonly WorldPatchLayer[];
@@ -0,0 +1,52 @@
1
+ /**
2
+ * World composition patches for the mount (AW-B DL1/DL3).
3
+ *
4
+ * A mounted world runs with NO listener and provides the virtual webServer
5
+ * from `<pkg>/world`. Three patches make that composition work:
6
+ *
7
+ * 1. `webserver` disabled — the world owns no socket; ctx0's listener is
8
+ * the only ingress.
9
+ * 2. `modules` inject webServer — client-modules probes
10
+ * `ctx.get('webServer')` WITHOUT declaring the dependency
11
+ * (`client/modules/src/index.ts:576`), so without this patch its row
12
+ * activates before the provider exists and boot fails. Patching the row's
13
+ * `inject` makes cordis WAIT for the provider, order-independent.
14
+ * 3. insert the world mount row — provides the virtual webServer inside the
15
+ * world root and translates every route its plugins declare.
16
+ *
17
+ * Patch layers are plain data: the patch engine applies arbitrary entry
18
+ * overrides (`vendor/include/src/index.ts:77-121`).
19
+ */
20
+ /** Id of the inserted world-mount row. */
21
+ export const WORLD_MOUNT_ROW_ID = 'aw-world-mount';
22
+ /** Plugin name providing the world's virtual webServer. */
23
+ export const WORLD_MOUNT_PLUGIN = '@pgmi-builds/agent-hub/world';
24
+ /** Id of the inserted hub row (the same plugin ctx0 itself composes). */
25
+ export const WORLD_HUB_ROW_ID = 'aw-agent-hub';
26
+ /** Plugin name of the hub itself — one UI, one roster, every runtime. */
27
+ export const WORLD_HUB_PLUGIN = '@pgmi-builds/agent-hub';
28
+ /**
29
+ * The layers that turn a listener-owning world into a mounted one:
30
+ *
31
+ * 1. `webserver` off — the world owns no socket (the hub serves its face);
32
+ * 2. `modules` waits for the virtual `webServer` the entry row provides;
33
+ * 3. the entry row itself (the world's mount identity);
34
+ * 4. the HUB ROW — the same `@pgmi-builds/agent-hub` native ctx0 composes, so
35
+ * the foreign agent gets the *identical* selector UI, and the roster it
36
+ * renders is read from the hub over the world's own `/api` channel.
37
+ * @param key - runtime key (`omp`, `codex`, …) — the mount label.
38
+ * @returns patch layers to append to the world's composition.
39
+ */
40
+ export function worldMountPatches(key) {
41
+ if (typeof key !== 'string' || key === '' || key.includes('/')) {
42
+ throw new Error(`world-mount: invalid key ${JSON.stringify(key)}`);
43
+ }
44
+ return [
45
+ { id: 'webserver', disabled: true },
46
+ { id: 'modules', inject: ['webServer'] },
47
+ { insert: [
48
+ { id: WORLD_MOUNT_ROW_ID, name: WORLD_MOUNT_PLUGIN, config: { key } },
49
+ { id: WORLD_HUB_ROW_ID, name: WORLD_HUB_PLUGIN },
50
+ ] },
51
+ ];
52
+ }