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,92 @@
1
+ /**
2
+ * Connection unary envelope (AW-B DL5).
3
+ *
4
+ * Our carrier owns `/<label>/api/*` and therefore must speak the wire shape
5
+ * itself. The shape is fixed by upstream (`client/connection/src/rpc-host.ts`):
6
+ *
7
+ * request { type: 'client-request', rpcId, method, payload }
8
+ * response { type: 'server-response', rpcId, result: { ok: true, value } }
9
+ * { type: 'server-response', rpcId, result: { ok: false, error } }
10
+ *
11
+ * Endpoint segments follow upstream's pattern so a crafted path cannot smuggle
12
+ * anything the native route would have rejected.
13
+ */
14
+ /** Upstream's endpoint segment pattern (`rpc-host.ts`). */
15
+ export const ENDPOINT_SEGMENT_PATTERN = /^[A-Za-z0-9_$.-]+$/;
16
+ /** Envelope-level failure carrying the wire error to answer with. */
17
+ export class EnvelopeError extends Error {
18
+ wire;
19
+ constructor(wire) {
20
+ super(wire.message);
21
+ this.wire = wire;
22
+ this.name = 'EnvelopeError';
23
+ }
24
+ }
25
+ function badRequest(message) {
26
+ throw new EnvelopeError({ code: 'gateway/bad-request', message });
27
+ }
28
+ function isRecord(value) {
29
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
30
+ }
31
+ /**
32
+ * Decode one request body.
33
+ * @param text - raw body text.
34
+ * @returns the decoded envelope.
35
+ * @throws {EnvelopeError} when the body is not a valid client-request.
36
+ */
37
+ export function parseClientRequest(text) {
38
+ let raw;
39
+ try {
40
+ raw = JSON.parse(text);
41
+ }
42
+ catch {
43
+ badRequest('invalid client-request message');
44
+ }
45
+ if (!isRecord(raw))
46
+ badRequest('invalid client-request message');
47
+ if (raw['type'] !== 'client-request')
48
+ badRequest('invalid client-request message');
49
+ const rpcId = raw['rpcId'];
50
+ const method = raw['method'];
51
+ if (typeof rpcId !== 'string' || rpcId === '')
52
+ badRequest('invalid client-request message');
53
+ if (typeof method !== 'string' || method === '')
54
+ badRequest('invalid client-request message');
55
+ const segments = method.split('/');
56
+ if (segments.some(segment => segment === '' || !ENDPOINT_SEGMENT_PATTERN.test(segment))) {
57
+ badRequest('invalid client-request message');
58
+ }
59
+ return { rpcId, method, payload: raw['payload'] };
60
+ }
61
+ /** Serialize a successful server response from a raw value. */
62
+ export function serverResponse(rpcId, value) {
63
+ return JSON.stringify({ type: 'server-response', rpcId, result: { ok: true, value } });
64
+ }
65
+ /**
66
+ * Serialize a server response whose `result` is already a gateway Result
67
+ * (`{ ok: true, value }` | `{ ok: false, error }`). The typert gateway's
68
+ * `dispatchRpc` returns exactly that shape, so it is copied verbatim.
69
+ */
70
+ export function serverResult(rpcId, result) {
71
+ return JSON.stringify({ type: 'server-response', rpcId, result });
72
+ }
73
+ /** Serialize a failed server response. */
74
+ export function serverError(rpcId, error) {
75
+ return JSON.stringify({ type: 'server-response', rpcId, result: { ok: false, error } });
76
+ }
77
+ /** Normalize an unknown thrown value into a wire error. */
78
+ export function wireErrorOf(error) {
79
+ if (error instanceof EnvelopeError)
80
+ return error.wire;
81
+ if (isRecord(error)) {
82
+ const code = typeof error['code'] === 'string' ? error['code'] : undefined;
83
+ const message = typeof error['message'] === 'string' ? error['message'] : undefined;
84
+ if (code !== undefined) {
85
+ return { code, message: message ?? code, ...(error['details'] === undefined ? {} : { details: error['details'] }) };
86
+ }
87
+ }
88
+ return {
89
+ code: 'gateway/internal-error',
90
+ message: error instanceof Error ? error.message : String(error),
91
+ };
92
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @pgmi-builds/agent-hub — plugin entry (host half).
3
+ *
4
+ * DL7 (2026-09-16): there is NO server-side selected state. The module-level
5
+ * selector and the instance-delegation wrapper that consumed it were removed;
6
+ * world ownership is per-request and travels on the mount path:
7
+ *
8
+ * /<label>/... → that world's web surface (carrier.ts, AW-B)
9
+ * /api/... → ctx0/native, untouched (upstream route owner)
10
+ *
11
+ * This file therefore only mounts the CTX0-owned control plane today. The
12
+ * per-world mount registers through `carrier.ts` (AW-B tasks 2-9), which calls
13
+ * the addressed world's own `typertGateway` instance directly — again without
14
+ * any shared selection value.
15
+ */
16
+ import type { Context } from '@deepseek-ai/cordis';
17
+ /** Stable Cordis plugin name. */
18
+ export declare const name = "agent-hub";
19
+ /**
20
+ * The plugin form (row contract): applied when the row mounts.
21
+ *
22
+ * Two CTX0-owned contributions, neither carrying any selection value:
23
+ * - the world inventory control plane (read-only);
24
+ * - the agent roster row baked into ctx0's own index, so the selector lists
25
+ * every mount path the hub currently serves.
26
+ */
27
+ export declare function apply(ctx: Context): void;
28
+ export default apply;
@@ -0,0 +1,18 @@
1
+ import { registerSelectorRpc, registryTargets } from './rpc.js';
2
+ import { agentRosterRow } from './agent-roster.js';
3
+ /** Stable Cordis plugin name. */
4
+ export const name = 'agent-hub';
5
+ /**
6
+ * The plugin form (row contract): applied when the row mounts.
7
+ *
8
+ * Two CTX0-owned contributions, neither carrying any selection value:
9
+ * - the world inventory control plane (read-only);
10
+ * - the agent roster row baked into ctx0's own index, so the selector lists
11
+ * every mount path the hub currently serves.
12
+ */
13
+ export function apply(ctx) {
14
+ registerSelectorRpc(ctx, registryTargets);
15
+ const on = ctx.on;
16
+ on?.call(ctx, 'webserver/index-inject', (table) => { table.push(agentRosterRow()); });
17
+ }
18
+ export default apply;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Mount HTML pass (AW-B DL1/DL8 server half).
3
+ *
4
+ * The world dist is built with RELATIVE asset URLs (`./assets/...`), so a
5
+ * `<base>` pointing at the mount makes every relative reference resolve under
6
+ * `/<label>/`. Root-absolute strings (the boot graph's `/plugins/...` URLs,
7
+ * injected script sources, `href="/"`-style anchors) do NOT follow `<base>`,
8
+ * so they are re-rooted explicitly — one generic rule, no namespace list.
9
+ */
10
+ /**
11
+ * Rewrite a world index for serving under `<labelPath>/`.
12
+ *
13
+ * - pins `<base>` at the mount (inserting one after `<head>` when absent);
14
+ * - prefixes every double-quoted root-absolute string that is not already
15
+ * mounted and not protocol-relative (`//host/...`);
16
+ * - idempotent (a second pass changes nothing).
17
+ *
18
+ * @param html - the world's index.html (already rendered with its own rows).
19
+ * @param labelPath - mount root, e.g. `/omp`.
20
+ * @returns the mount-ready HTML.
21
+ */
22
+ export declare function rewriteIndexHtml(html: string, labelPath: string): string;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Mount HTML pass (AW-B DL1/DL8 server half).
3
+ *
4
+ * The world dist is built with RELATIVE asset URLs (`./assets/...`), so a
5
+ * `<base>` pointing at the mount makes every relative reference resolve under
6
+ * `/<label>/`. Root-absolute strings (the boot graph's `/plugins/...` URLs,
7
+ * injected script sources, `href="/"`-style anchors) do NOT follow `<base>`,
8
+ * so they are re-rooted explicitly — one generic rule, no namespace list.
9
+ */
10
+ /** Root of the mount including the trailing slash (`/omp` → `/omp/`). */
11
+ function mountPrefix(labelPath) {
12
+ return labelPath.endsWith('/') ? labelPath : `${labelPath}/`;
13
+ }
14
+ /**
15
+ * Rewrite a world index for serving under `<labelPath>/`.
16
+ *
17
+ * - pins `<base>` at the mount (inserting one after `<head>` when absent);
18
+ * - prefixes every double-quoted root-absolute string that is not already
19
+ * mounted and not protocol-relative (`//host/...`);
20
+ * - idempotent (a second pass changes nothing).
21
+ *
22
+ * @param html - the world's index.html (already rendered with its own rows).
23
+ * @param labelPath - mount root, e.g. `/omp`.
24
+ * @returns the mount-ready HTML.
25
+ */
26
+ export function rewriteIndexHtml(html, labelPath) {
27
+ if (typeof labelPath !== 'string' || !labelPath.startsWith('/') || labelPath === '/' || labelPath.endsWith('/')) {
28
+ throw new Error(`index-pass: labelPath must start with "/" and carry no trailing slash, got ${JSON.stringify(labelPath)}`);
29
+ }
30
+ const prefix = mountPrefix(labelPath);
31
+ let out = html;
32
+ if (/<base\b[^>]*>/i.test(out)) {
33
+ out = out.replace(/<base\b[^>]*>/i, `<base href="${prefix}">`);
34
+ }
35
+ else if (/<head(?:\s[^>]*)?>/i.test(out)) {
36
+ out = out.replace(/<head(?:\s[^>]*)?>/i, open => `${open}<base href="${prefix}">`);
37
+ }
38
+ out = out.replace(/"(\/[^"]*)"/g, (whole, path) => {
39
+ if (path.startsWith('//'))
40
+ return whole;
41
+ // Load-bearing contract: client-shim.ts derives its storage NS from the surviving "<label>/" literal (regression test: the storage NS survives the mount HTML pass). Changing this exclusion breaks that coupling.
42
+ if (path.startsWith(prefix))
43
+ return whole;
44
+ return `"${prefix}${path.slice(1)}"`;
45
+ });
46
+ return out;
47
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @pgmi-builds/agent-hub — host half public surface (Agent Worlds line).
3
+ *
4
+ * The line owns the switch and the gateway (per super-dsh/AGENTS.md):
5
+ * the world inventory control plane + the foreign agent roster + the world
6
+ * spawner, and (AW-B) the per-world mount carrier.
7
+ *
8
+ * DL7 (2026-09-16): the app-level selector value is GONE. World ownership is
9
+ * per-request: the addressed world is the mount path of the request
10
+ * (`/<label>/...`). `/api/*` stays ctx0/native and untouched.
11
+ */
12
+ export { handleAgentRuntime, registerSelectorRpc, AGENT_RUNTIME_RPC_PATH, registryTargets, type RuntimeTargetSource } from './rpc.js';
13
+ export { registerForeignTarget, unregisterForeignTarget, getTarget, listRuntimeKeys, type ForeignTarget, type GatewayFace } from './targets.js';
14
+ export { registerAgent, unregisterAgent, setReady, listAgents, onRosterChanged, type RosterEntry } from './roster.js';
15
+ export { spawnWorld, type SpawnWorldOptions } from './spawn-world.js';
16
+ export { provisionWorldProfile, type ProvisionWorldOptions } from './world-provision.js';
17
+ export { claimLabel, labelOf, releaseLabel, listLabels, type LabelClaim, type ClaimOptions } from './labels.js';
18
+ export { WorldWebServer, stripLabelFromUrl, type WorldWebRoute, type WorldWebUpgradeRoute, type RealWebServerFace } from './world-web-server.js';
19
+ export { parseClientRequest, serverResponse, serverError, serverResult, wireErrorOf, EnvelopeError, type ClientRequestEnvelope, type WireError } from './envelope.js';
20
+ export { WorldMuxServer, parseClientMessage, defaultFailure, type MuxOpen, type MuxFailure, type WorldMuxOptions } from './world-mux.js';
21
+ export { mountWorld, rewriteIndexHtml, type CarrierGatewayFace, type MountWorldOptions, type MountedWorld } from './carrier.js';
22
+ export { renderClientShim } from './client-shim.js';
23
+ export { agentLinks, agentRosterRow, AGENT_ROSTER_GLOBAL, type AgentLink } from './agent-roster.js';
24
+ export { createOwnershipIndex, type OwnershipIndex, type OwnershipRow } from './ownership.js';
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';
27
+ export { default as worldApply, name as worldPluginName, type Config as WorldEntryConfig } from './world-entry.js';
28
+ export { default as joinApply, name as worldJoinPluginName, type Config as WorldJoinConfig } from './world-join.js';
29
+ export { default } from './gateway.js';
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @pgmi-builds/agent-hub — host half public surface (Agent Worlds line).
3
+ *
4
+ * The line owns the switch and the gateway (per super-dsh/AGENTS.md):
5
+ * the world inventory control plane + the foreign agent roster + the world
6
+ * spawner, and (AW-B) the per-world mount carrier.
7
+ *
8
+ * DL7 (2026-09-16): the app-level selector value is GONE. World ownership is
9
+ * per-request: the addressed world is the mount path of the request
10
+ * (`/<label>/...`). `/api/*` stays ctx0/native and untouched.
11
+ */
12
+ export { handleAgentRuntime, registerSelectorRpc, AGENT_RUNTIME_RPC_PATH, registryTargets } from './rpc.js';
13
+ export { registerForeignTarget, unregisterForeignTarget, getTarget, listRuntimeKeys } from './targets.js';
14
+ export { registerAgent, unregisterAgent, setReady, listAgents, onRosterChanged } from './roster.js';
15
+ export { spawnWorld } from './spawn-world.js';
16
+ export { provisionWorldProfile } from './world-provision.js';
17
+ export { claimLabel, labelOf, releaseLabel, listLabels } from './labels.js';
18
+ export { WorldWebServer, stripLabelFromUrl } from './world-web-server.js';
19
+ export { parseClientRequest, serverResponse, serverError, serverResult, wireErrorOf, EnvelopeError } from './envelope.js';
20
+ export { WorldMuxServer, parseClientMessage, defaultFailure } from './world-mux.js';
21
+ export { mountWorld, rewriteIndexHtml } from './carrier.js';
22
+ export { renderClientShim } from './client-shim.js';
23
+ export { agentLinks, agentRosterRow, AGENT_ROSTER_GLOBAL } from './agent-roster.js';
24
+ export { createOwnershipIndex } from './ownership.js';
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';
27
+ export { default as worldApply, name as worldPluginName } from './world-entry.js';
28
+ export { default as joinApply, name as worldJoinPluginName } from './world-join.js';
29
+ export { default } from './gateway.js';
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Label table (AW-B DL2/DL4): one world ↔ one mount path under the ctx0 origin.
3
+ *
4
+ * The addressed world is the request's path (`/<label>/...`), so the label is
5
+ * the ONLY routing key. Reserving it must be atomic against the real
6
+ * webServer's duplicate-registration throw — that throw is the only collision
7
+ * signal the framework offers (the route tables are private and there is no
8
+ * query API), so it is used here as the probe.
9
+ *
10
+ * A collision is a composition-level conflict and must be loud; an optional
11
+ * alternate root lets a deployment re-home instead of failing to boot.
12
+ */
13
+ /** One reserved mount path. */
14
+ export interface LabelClaim {
15
+ /** Runtime key (`omp`, `codex`, …). */
16
+ readonly key: string;
17
+ /** Reserved mount root, e.g. `/omp` or `/_agents/omp` (no trailing slash). */
18
+ readonly path: string;
19
+ /** Release the claim (idempotent). */
20
+ release(): void;
21
+ }
22
+ /** How to reserve a path: the injected real-webServer registration. */
23
+ export interface ClaimOptions {
24
+ /** Attempt a prefix registration; throws when `(kind, path)` is already taken. */
25
+ register(path: string): () => void;
26
+ /** Optional root prefix (default: the origin root). */
27
+ root?: string;
28
+ /** Candidate roots to try, in order, when the clean path is taken. */
29
+ alternateRoots?: readonly string[];
30
+ }
31
+ /**
32
+ * Reserve the mount path for `key`.
33
+ * @param key - runtime key (one path segment).
34
+ * @param opts - registration probe plus optional roots.
35
+ * @returns the live claim.
36
+ */
37
+ export declare function claimLabel(key: string, opts: ClaimOptions): LabelClaim;
38
+ /** The reserved mount root for a key, or undefined when unclaimed. */
39
+ export declare function labelOf(key: string): string | undefined;
40
+ /** Release a key's claim; unknown keys are a no-op. */
41
+ export declare function releaseLabel(key: string): void;
42
+ /** Claimed keys, registration order. */
43
+ export declare function listLabels(): string[];
44
+ /** Test/introspection helper: is this object a claim? */
45
+ export declare function isLabelClaim(value: unknown): value is LabelClaim;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Label table (AW-B DL2/DL4): one world ↔ one mount path under the ctx0 origin.
3
+ *
4
+ * The addressed world is the request's path (`/<label>/...`), so the label is
5
+ * the ONLY routing key. Reserving it must be atomic against the real
6
+ * webServer's duplicate-registration throw — that throw is the only collision
7
+ * signal the framework offers (the route tables are private and there is no
8
+ * query API), so it is used here as the probe.
9
+ *
10
+ * A collision is a composition-level conflict and must be loud; an optional
11
+ * alternate root lets a deployment re-home instead of failing to boot.
12
+ */
13
+ const claims = new Map();
14
+ function isRecordLike(value) {
15
+ return typeof value === 'object' && value !== null;
16
+ }
17
+ /** Reject keys that cannot be a single path segment. */
18
+ function assertKey(key) {
19
+ if (typeof key !== 'string' || key === '' || key.includes('/') || key.includes('?')) {
20
+ throw new Error(`labels: invalid label key ${JSON.stringify(key)} (one non-empty path segment required)`);
21
+ }
22
+ }
23
+ function joinRoot(root, key) {
24
+ const trimmed = root.replace(/\/+$/, '');
25
+ return trimmed === '' ? `/${key}` : `${trimmed}/${key}`;
26
+ }
27
+ /**
28
+ * Reserve the mount path for `key`.
29
+ * @param key - runtime key (one path segment).
30
+ * @param opts - registration probe plus optional roots.
31
+ * @returns the live claim.
32
+ */
33
+ export function claimLabel(key, opts) {
34
+ assertKey(key);
35
+ const existing = claims.get(key);
36
+ if (existing !== undefined) {
37
+ throw new Error(`labels: key ${JSON.stringify(key)} already claimed at "${existing.path}"`);
38
+ }
39
+ const roots = [opts.root ?? '', ...(opts.alternateRoots ?? [])];
40
+ const tried = [];
41
+ for (const root of roots) {
42
+ const path = joinRoot(root, key);
43
+ if (tried.includes(path))
44
+ continue;
45
+ tried.push(path);
46
+ let dispose;
47
+ try {
48
+ dispose = opts.register(path);
49
+ }
50
+ catch {
51
+ continue;
52
+ }
53
+ const claim = {
54
+ key,
55
+ path,
56
+ release: () => {
57
+ if (claims.get(key)?.path !== path)
58
+ return;
59
+ claims.delete(key);
60
+ dispose?.();
61
+ },
62
+ };
63
+ claims.set(key, claim);
64
+ return claim;
65
+ }
66
+ throw new Error(`labels: no free mount path for ${JSON.stringify(key)} (tried ${tried.map(p => `"${p}"`).join(', ')})`);
67
+ }
68
+ /** The reserved mount root for a key, or undefined when unclaimed. */
69
+ export function labelOf(key) {
70
+ return claims.get(key)?.path;
71
+ }
72
+ /** Release a key's claim; unknown keys are a no-op. */
73
+ export function releaseLabel(key) {
74
+ claims.get(key)?.release();
75
+ }
76
+ /** Claimed keys, registration order. */
77
+ export function listLabels() {
78
+ return [...claims.keys()];
79
+ }
80
+ /** Test/introspection helper: is this object a claim? */
81
+ export function isLabelClaim(value) {
82
+ return isRecordLike(value) && typeof value['key'] === 'string' && typeof value['path'] === 'string';
83
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Session → world ownership index (AW-B DL9/DL10).
3
+ *
4
+ * The mount path addresses the world for UI traffic, but a session-scoped
5
+ * caller (resume, export, a deep link) may only carry a sessionId. Resolving it
6
+ * must be O(1) and must NEVER degrade into a probe waterfall: a miss triggers
7
+ * AT MOST one bounded refresh (in-flight refreshes coalesce), and a miss after
8
+ * that refresh is a miss — the caller fails where it asked instead of asking
9
+ * every world in turn.
10
+ */
11
+ /** One ownership row returned by a refresh. */
12
+ export interface OwnershipRow {
13
+ sessionId: string;
14
+ /** Runtime key (`native`, `omp`, …). */
15
+ key: string;
16
+ }
17
+ /** The ownership index surface. */
18
+ export interface OwnershipIndex {
19
+ /** Record (or overwrite) one ownership. */
20
+ set(sessionId: string, key: string): void;
21
+ /** Drop one ownership (session deleted). */
22
+ forget(sessionId: string): void;
23
+ /** Synchronous lookup; performs NO refresh. */
24
+ lookup(sessionId: string): string | undefined;
25
+ /** Lookup, then at most one bounded refresh, then lookup again. */
26
+ resolve(sessionId: string): Promise<string | undefined>;
27
+ /** Current index size (diagnostics/tests). */
28
+ size(): number;
29
+ /** Drop everything (world roster replaced). */
30
+ clear(): void;
31
+ }
32
+ /**
33
+ * Create an ownership index.
34
+ * @param refresh - optional bounded re-read of the ownership rows.
35
+ * @returns the index.
36
+ */
37
+ export declare function createOwnershipIndex(refresh?: () => Promise<readonly OwnershipRow[]>): OwnershipIndex;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Session → world ownership index (AW-B DL9/DL10).
3
+ *
4
+ * The mount path addresses the world for UI traffic, but a session-scoped
5
+ * caller (resume, export, a deep link) may only carry a sessionId. Resolving it
6
+ * must be O(1) and must NEVER degrade into a probe waterfall: a miss triggers
7
+ * AT MOST one bounded refresh (in-flight refreshes coalesce), and a miss after
8
+ * that refresh is a miss — the caller fails where it asked instead of asking
9
+ * every world in turn.
10
+ */
11
+ /**
12
+ * Create an ownership index.
13
+ * @param refresh - optional bounded re-read of the ownership rows.
14
+ * @returns the index.
15
+ */
16
+ export function createOwnershipIndex(refresh) {
17
+ const owners = new Map();
18
+ let inflight;
19
+ const runRefresh = () => {
20
+ if (inflight !== undefined)
21
+ return inflight;
22
+ const started = (async () => {
23
+ const rows = refresh === undefined ? [] : await refresh();
24
+ for (const row of rows)
25
+ owners.set(row.sessionId, row.key);
26
+ })();
27
+ inflight = started.finally(() => { inflight = undefined; });
28
+ return inflight;
29
+ };
30
+ return {
31
+ set(sessionId, key) {
32
+ owners.set(sessionId, key);
33
+ },
34
+ forget(sessionId) {
35
+ owners.delete(sessionId);
36
+ },
37
+ lookup(sessionId) {
38
+ return owners.get(sessionId);
39
+ },
40
+ async resolve(sessionId) {
41
+ const hit = owners.get(sessionId);
42
+ if (hit !== undefined)
43
+ return hit;
44
+ await runRefresh();
45
+ return owners.get(sessionId);
46
+ },
47
+ size() {
48
+ return owners.size;
49
+ },
50
+ clear() {
51
+ owners.clear();
52
+ },
53
+ };
54
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Foreign agent roster (S2: plugin-presence IS the roster).
3
+ *
4
+ * No config file: an agent is in the roster exactly while its adapter
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 —
8
+ * the addressed world is the request's mount path (`DL7`, 2026-09-16).
9
+ * one authority.
10
+ */
11
+ export interface RosterEntry {
12
+ /** Runtime key (`omp`, `codex`, …) — what the selector addresses. */
13
+ key: string;
14
+ /** Human label for the selector chip. */
15
+ label: string;
16
+ /** True once the adapter's world context is spawned and its target registered. */
17
+ ready: boolean;
18
+ }
19
+ /** Register an agent. Duplicate keys are a plugin bug — throw loud. */
20
+ export declare function registerAgent(entry: RosterEntry): void;
21
+ /** Drop an agent (adapter plugin disposed). */
22
+ export declare function unregisterAgent(key: string): void;
23
+ /** Flip readiness (world spawned / disposed). Unknown keys are a plugin bug. */
24
+ export declare function setReady(key: string, ready: boolean): void;
25
+ /** Snapshot copy — callers can hold it without aliasing the roster. */
26
+ export declare function listAgents(): RosterEntry[];
27
+ /** Subscribe to roster changes; returns an unsubscribe function. */
28
+ export declare function onRosterChanged(fn: (entries: RosterEntry[]) => void): () => void;
@@ -0,0 +1,38 @@
1
+ const entries = new Map();
2
+ const listeners = new Set();
3
+ function emit() {
4
+ const snap = listAgents();
5
+ for (const fn of listeners)
6
+ fn(snap);
7
+ }
8
+ /** Register an agent. Duplicate keys are a plugin bug — throw loud. */
9
+ export function registerAgent(entry) {
10
+ if (entries.has(entry.key))
11
+ throw new Error(`roster: duplicate agent key ${entry.key}`);
12
+ entries.set(entry.key, { ...entry });
13
+ emit();
14
+ }
15
+ /** Drop an agent (adapter plugin disposed). */
16
+ export function unregisterAgent(key) {
17
+ entries.delete(key);
18
+ emit();
19
+ }
20
+ /** Flip readiness (world spawned / disposed). Unknown keys are a plugin bug. */
21
+ export function setReady(key, ready) {
22
+ const e = entries.get(key);
23
+ if (!e)
24
+ throw new Error(`roster: unknown agent ${key}`);
25
+ e.ready = ready;
26
+ emit();
27
+ }
28
+ /** Snapshot copy — callers can hold it without aliasing the roster. */
29
+ export function listAgents() {
30
+ return [...entries.values()].map((e) => ({ ...e }));
31
+ }
32
+ /** Subscribe to roster changes; returns an unsubscribe function. */
33
+ export function onRosterChanged(fn) {
34
+ listeners.add(fn);
35
+ return () => {
36
+ listeners.delete(fn);
37
+ };
38
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Control-plane RPC face for the agents hub (DL7: NO server-side selection).
3
+ *
4
+ * Auth conclusion (upstream source, inherited from the shelved route): every
5
+ * upstream `/api/*` feature mounts via `ctx.connection.fetch.register(...)` —
6
+ * the client-connection service owns the single `/api` prefix webServer route
7
+ * and runs the Host/Origin browser-trust fence + persistent browser auth
8
+ * before dispatching. Registering our own webServer route would bypass that
9
+ * fence; we mount through `connection.fetch` and inherit it.
10
+ *
11
+ * This face is superd-owned control traffic and is ALWAYS answered by CTX0:
12
+ * it reports which worlds exist. It carries no selection: world ownership is
13
+ * per-request and travels on the mount path (`/<label>/...`, see carrier.ts),
14
+ * so two tabs on two worlds cannot step on each other.
15
+ */
16
+ import type { Context } from '@deepseek-ai/cordis';
17
+ /** The shared-channel Fetch route path this RPC face owns. */
18
+ export declare const AGENT_RUNTIME_RPC_PATH = "/api/agent-runtime";
19
+ /** What the RPC reads to compute the `available` list. */
20
+ export interface RuntimeTargetSource {
21
+ /** Registered runtime keys, including `native`. */
22
+ listRuntimes(): string[];
23
+ }
24
+ /** The live registry view: native plus every registered foreign context. */
25
+ export declare const registryTargets: RuntimeTargetSource;
26
+ /**
27
+ * The control-plane handler: world inventory only.
28
+ * @param request - the incoming `/api/agent-runtime` request.
29
+ * @param source - live runtime registry view.
30
+ * @returns the JSON response.
31
+ */
32
+ export declare function handleAgentRuntime(request: Request, source: RuntimeTargetSource): Promise<Response>;
33
+ /**
34
+ * Register the control-plane RPC face on the shared `/api` connection channel
35
+ * (behind the standard browser-trust + auth fence). No-op when the
36
+ * `connection` service is absent (e.g. fake-ctx unit tests).
37
+ */
38
+ export declare function registerSelectorRpc(ctx: Context, source: RuntimeTargetSource): void;
@@ -0,0 +1,52 @@
1
+ import { listRuntimeKeys } from './targets.js';
2
+ import { agentLinks } from './agent-roster.js';
3
+ /** The shared-channel Fetch route path this RPC face owns. */
4
+ export const AGENT_RUNTIME_RPC_PATH = '/api/agent-runtime';
5
+ /** The live registry view: native plus every registered foreign context. */
6
+ export const registryTargets = {
7
+ listRuntimes: listRuntimeKeys,
8
+ };
9
+ function json(status, body) {
10
+ return new Response(JSON.stringify(body), {
11
+ status,
12
+ headers: { 'content-type': 'application/json' },
13
+ });
14
+ }
15
+ /**
16
+ * The control-plane handler: world inventory only.
17
+ * @param request - the incoming `/api/agent-runtime` request.
18
+ * @param source - live runtime registry view.
19
+ * @returns the JSON response.
20
+ */
21
+ export async function handleAgentRuntime(request, source) {
22
+ const available = source.listRuntimes();
23
+ if (request.method === 'GET' || request.method === 'HEAD') {
24
+ // The selector asks this face for the roster: keys AND the mount path each
25
+ // key is addressed by. Read-only — the roster carries no selection.
26
+ return json(200, { available, agents: agentLinks() });
27
+ }
28
+ // A POST that used to switch a global selector has no meaning any more:
29
+ // the addressed world is the mount path of the request, not a shared value.
30
+ return json(400, {
31
+ error: 'selection is per-request (mount path); no server-side switch',
32
+ available,
33
+ });
34
+ }
35
+ /**
36
+ * Register the control-plane RPC face on the shared `/api` connection channel
37
+ * (behind the standard browser-trust + auth fence). No-op when the
38
+ * `connection` service is absent (e.g. fake-ctx unit tests).
39
+ */
40
+ export function registerSelectorRpc(ctx, source) {
41
+ ctx.inject(['connection'], (connCtx) => {
42
+ const fetchFace = Reflect.get(connCtx, 'connection')?.fetch;
43
+ if (fetchFace === undefined)
44
+ return; // connection not actually present (test ctx)
45
+ connCtx.effect(() => fetchFace.register({
46
+ path: AGENT_RUNTIME_RPC_PATH,
47
+ methods: ['GET', 'POST'],
48
+ requestBody: 'buffered',
49
+ fetch: (request) => handleAgentRuntime(request, source),
50
+ }), 'agent-hub: /api/agent-runtime route');
51
+ });
52
+ }