super-dsh 0.1.3 → 0.1.5

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 (142) hide show
  1. package/README.md +3 -3
  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 +31 -51
  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 +31 -51
  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 +31 -52
  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 +37 -50
  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 +31 -51
  62. package/agent-pi/package.json +14 -11
  63. package/client/index.js +1994 -150
  64. package/cordis.patch.yml +38 -15
  65. package/package.json +32 -30
  66. package/{agent-hub → superd-hub}/cordis.patch.yml +3 -3
  67. package/{agent-hub → superd-hub}/dist/agent-roster.d.ts +3 -1
  68. package/{agent-hub → superd-hub}/dist/agent-roster.js +4 -2
  69. package/superd-hub/dist/carrier.d.ts +62 -0
  70. package/superd-hub/dist/carrier.js +213 -0
  71. package/superd-hub/dist/fusion-transport.d.ts +148 -0
  72. package/superd-hub/dist/fusion-transport.js +397 -0
  73. package/{agent-hub → superd-hub}/dist/gateway.d.ts +9 -4
  74. package/superd-hub/dist/gateway.js +44 -0
  75. package/superd-hub/dist/hub-route.d.ts +74 -0
  76. package/superd-hub/dist/hub-route.js +188 -0
  77. package/{agent-hub → superd-hub}/dist/index.d.ts +14 -6
  78. package/{agent-hub → superd-hub}/dist/index.js +14 -6
  79. package/{agent-hub → superd-hub}/dist/roster.d.ts +2 -2
  80. package/{agent-hub → superd-hub}/dist/rpc.js +1 -1
  81. package/{agent-hub → superd-hub}/dist/spawn-world.d.ts +27 -6
  82. package/superd-hub/dist/spawn-world.js +279 -0
  83. package/superd-hub/dist/switch-core.d.ts +630 -0
  84. package/superd-hub/dist/switch-core.js +734 -0
  85. package/superd-hub/dist/system-head.d.ts +69 -0
  86. package/superd-hub/dist/system-head.js +194 -0
  87. package/superd-hub/dist/web-trust.d.ts +112 -0
  88. package/superd-hub/dist/web-trust.js +126 -0
  89. package/superd-hub/dist/world-entry.d.ts +38 -0
  90. package/superd-hub/dist/world-entry.js +47 -0
  91. package/{agent-hub → superd-hub}/dist/world-host.d.ts +15 -20
  92. package/superd-hub/dist/world-host.js +65 -0
  93. package/{agent-hub → superd-hub}/dist/world-join.d.ts +2 -1
  94. package/{agent-hub → superd-hub}/dist/world-join.js +30 -50
  95. package/superd-hub/dist/world-mount.d.ts +82 -0
  96. package/superd-hub/dist/world-mount.js +105 -0
  97. package/{agent-hub → superd-hub}/dist/world-mux.d.ts +21 -6
  98. package/superd-hub/dist/world-mux.js +392 -0
  99. package/{agent-hub → superd-hub}/dist/world-provision.d.ts +20 -4
  100. package/superd-hub/dist/world-provision.js +203 -0
  101. package/superd-hub/dist/world-web-server.d.ts +113 -0
  102. package/superd-hub/dist/world-web-server.js +99 -0
  103. package/superd-hub/lib/client/index.js +2086 -0
  104. package/{agent-hub → superd-hub}/package.json +12 -7
  105. package/agent-agy/dist/agent-preset-projection.d.ts +0 -31
  106. package/agent-agy/dist/agent-preset-projection.js +0 -33
  107. package/agent-claude/dist/agent-preset-projection.js +0 -30
  108. package/agent-codex/dist/agent-preset-projection.js +0 -37
  109. package/agent-codex/dist/app-home.js +0 -65
  110. package/agent-codex/dist/spike.js +0 -46
  111. package/agent-hermes/dist/agent-preset-projection.js +0 -34
  112. package/agent-hub/dist/carrier.d.ts +0 -43
  113. package/agent-hub/dist/carrier.js +0 -241
  114. package/agent-hub/dist/client-shim.d.ts +0 -28
  115. package/agent-hub/dist/client-shim.js +0 -251
  116. package/agent-hub/dist/gateway.js +0 -18
  117. package/agent-hub/dist/index-pass.d.ts +0 -22
  118. package/agent-hub/dist/index-pass.js +0 -47
  119. package/agent-hub/dist/labels.d.ts +0 -45
  120. package/agent-hub/dist/labels.js +0 -83
  121. package/agent-hub/dist/spawn-world.js +0 -72
  122. package/agent-hub/dist/world-entry.d.ts +0 -31
  123. package/agent-hub/dist/world-entry.js +0 -51
  124. package/agent-hub/dist/world-host.js +0 -44
  125. package/agent-hub/dist/world-mount.d.ts +0 -52
  126. package/agent-hub/dist/world-mount.js +0 -52
  127. package/agent-hub/dist/world-mux.js +0 -224
  128. package/agent-hub/dist/world-provision.js +0 -122
  129. package/agent-hub/dist/world-web-server.d.ts +0 -162
  130. package/agent-hub/dist/world-web-server.js +0 -248
  131. package/agent-hub/lib/client/index.js +0 -242
  132. package/agent-omp/dist/agent-preset-projection.js +0 -36
  133. package/agent-omp/dist/app-home.js +0 -86
  134. package/agent-pi/dist/agent-preset-projection.js +0 -29
  135. /package/{agent-hub → superd-hub}/dist/envelope.d.ts +0 -0
  136. /package/{agent-hub → superd-hub}/dist/envelope.js +0 -0
  137. /package/{agent-hub → superd-hub}/dist/ownership.d.ts +0 -0
  138. /package/{agent-hub → superd-hub}/dist/ownership.js +0 -0
  139. /package/{agent-hub → superd-hub}/dist/roster.js +0 -0
  140. /package/{agent-hub → superd-hub}/dist/rpc.d.ts +0 -0
  141. /package/{agent-hub → superd-hub}/dist/targets.d.ts +0 -0
  142. /package/{agent-hub → superd-hub}/dist/targets.js +0 -0
@@ -1,13 +1,14 @@
1
1
  {
2
- "name": "@pgmi-builds/agent-hub",
2
+ "name": "@pgmi-builds/superd-hub",
3
3
  "version": "0.1.0",
4
- "description": "Agent Worlds hub host half: world inventory control plane, roster, world spawner and the single-origin per-world mount carrier (no server-side selection; the addressed world is the request's mount path)",
4
+ "description": "Super D hub host half: world inventory control plane, roster, world spawner and the single-origin per-world mount carrier (no server-side selection; the addressed world is the request's mount path)",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": "./dist/index.js",
8
8
  "./client": "./lib/client/index.js",
9
9
  "./world": "./dist/world-entry.js",
10
- "./join": "./dist/world-join.js"
10
+ "./join": "./dist/world-join.js",
11
+ "./web-trust": "./dist/web-trust.js"
11
12
  },
12
13
  "files": [
13
14
  "dist",
@@ -27,17 +28,19 @@
27
28
  },
28
29
  "scripts": {
29
30
  "build": "tsc -p .",
30
- "build-client": "node scripts/build-client.mjs",
31
+ "typecheck:client": "tsc -p tsconfig.client.json",
32
+ "build-client": "npm run typecheck:client && node scripts/build-client.mjs",
31
33
  "test": "node --test --test-force-exit test/*.test.mjs"
32
34
  },
33
35
  "dependencies": {
36
+ "js-yaml": "^4.3.2",
34
37
  "ws": "^8.21.0"
35
38
  },
36
39
  "peerDependencies": {
37
40
  "@deepseek-ai/cordis": "*",
38
- "@deepseek-ai/dsh-api-gateway": "*",
39
- "@deepseek-ai/dsh-host-webserver": "*",
40
- "@deepseek-ai/dsh-typert-protocol": "*"
41
+ "@deepseek-ai/dsh-api-gateway": ">=0.1.5-0 <0.3.0-0",
42
+ "@deepseek-ai/dsh-host-webserver": ">=0.1.5-0 <0.3.0-0",
43
+ "@deepseek-ai/dsh-typert-protocol": ">=0.1.5-0 <0.3.0-0"
41
44
  },
42
45
  "peerDependenciesMeta": {
43
46
  "@deepseek-ai/cordis": {
@@ -54,7 +57,9 @@
54
57
  }
55
58
  },
56
59
  "devDependencies": {
60
+ "@types/js-yaml": "^4.0.9",
57
61
  "@types/node": "^26.5.1",
62
+ "@types/react": "18.3.31",
58
63
  "tsdown": "^0.15.12",
59
64
  "typescript": "5.9.3"
60
65
  },
@@ -1,31 +0,0 @@
1
- /**
2
- * The `agentPreset` session projection, owned by the adapter.
3
- *
4
- * Upstream registers this fold from the `dsh-agent-presets` package, which our
5
- * patch disables (the Antigravity provider replaces preset composition
6
- * wholesale). But the Web UI depends on the projection regardless: the preset
7
- * hero chip renders only when `session.projectionValues.agentPreset` resolves
8
- * (presetOf in ui-agent-preset/seat-store.ts), and the session-header label
9
- * reads it too. Without a registrant the projection is absent for every
10
- * adapter session and both surfaces stay blank — roster or no roster.
11
- *
12
- * Same fold as upstream (packages/preset/agent-presets/src/session.ts):
13
- * initialized from the creation header, advanced by `agent-preset/selected`
14
- * events, which this adapter synthesizes (`"agy"`) on every session it
15
- * prepares. Registered under the provider's own fiber via
16
- * `ctx.inject(['sessionProjections'])`, so the key lives exactly as long as
17
- * the provider is mounted.
18
- */
19
- import { z } from "zod";
20
- /** Current Session preset, initialized from its header and advanced by selection events. */
21
- export declare const agyAgentPresetProjection: {
22
- key: "agentPreset";
23
- stateSchema: z.ZodUnion<readonly [z.ZodString, z.ZodNull]>;
24
- init: (header: import("@deepseek-ai/dsh-session").SessionHeader) => string;
25
- apply: (state: string | null, event: import("@deepseek-ai/dsh-session").SessionEvent) => string | null;
26
- wire: {
27
- viewSchema: z.ZodUnion<readonly [z.ZodString, z.ZodNull]>;
28
- view: (state: string | null) => string | null;
29
- };
30
- stateVersion: number;
31
- };
@@ -1,33 +0,0 @@
1
- /**
2
- * The `agentPreset` session projection, owned by the adapter.
3
- *
4
- * Upstream registers this fold from the `dsh-agent-presets` package, which our
5
- * patch disables (the Antigravity provider replaces preset composition
6
- * wholesale). But the Web UI depends on the projection regardless: the preset
7
- * hero chip renders only when `session.projectionValues.agentPreset` resolves
8
- * (presetOf in ui-agent-preset/seat-store.ts), and the session-header label
9
- * reads it too. Without a registrant the projection is absent for every
10
- * adapter session and both surfaces stay blank — roster or no roster.
11
- *
12
- * Same fold as upstream (packages/preset/agent-presets/src/session.ts):
13
- * initialized from the creation header, advanced by `agent-preset/selected`
14
- * events, which this adapter synthesizes (`"agy"`) on every session it
15
- * prepares. Registered under the provider's own fiber via
16
- * `ctx.inject(['sessionProjections'])`, so the key lives exactly as long as
17
- * the provider is mounted.
18
- */
19
- import { z } from "zod";
20
- const agentPresetSchema = z.union([z.string(), z.null()]);
21
- /** Current Session preset, initialized from its header and advanced by selection events. */
22
- export const agyAgentPresetProjection = {
23
- key: "agentPreset",
24
- stateSchema: agentPresetSchema,
25
- // adapter-agy is single-preset: default every session to "agy" so the
26
- // header chip resolves for scan-native (never-resumed) sessions too.
27
- init: (header) => header.agentPreset ?? "agy",
28
- apply: (state, event) => event.type === "agent-preset/selected"
29
- ? event.data.agentPreset
30
- : state,
31
- wire: { viewSchema: agentPresetSchema, view: (state) => state },
32
- stateVersion: 1,
33
- };
@@ -1,30 +0,0 @@
1
- /**
2
- * The `agentPreset` session projection, owned by the adapter.
3
- *
4
- * Upstream registers this fold from the `dsh-agent-presets` package, which
5
- * the bundle patch disables (the claude provider replaces preset composition
6
- * wholesale). But the Web UI depends on the projection regardless: the
7
- * preset hero chip renders only when `session.projectionValues.agentPreset`
8
- * resolves, and the session-header label reads it too. Without a registrant
9
- * the projection is absent for every adapter session and both surfaces stay
10
- * blank — roster or no roster (the omp line's "no mode" bug, re-observed as
11
- * the claude "degraded preset" finding).
12
- *
13
- * Same fold as upstream; adapter-claude is single-preset: default every
14
- * session to "claude" so the header chip resolves for sessions whose log
15
- * carries no `agent-preset/selected` event yet. Registered under the
16
- * provider's own fiber via `ctx.inject(['sessionProjections'])`.
17
- */
18
- import { z } from "zod";
19
- const agentPresetSchema = z.union([z.string(), z.null()]);
20
- /** Current Session preset, initialized from its header and advanced by selection events. */
21
- export const claudeAgentPresetProjection = {
22
- key: "agentPreset",
23
- stateSchema: agentPresetSchema,
24
- init: (header) => header.agentPreset ?? "claude",
25
- apply: (state, event) => event.type === "agent-preset/selected"
26
- ? event.data.agentPreset
27
- : state,
28
- wire: { viewSchema: agentPresetSchema, view: (state) => state },
29
- stateVersion: 1,
30
- };
@@ -1,37 +0,0 @@
1
- /**
2
- * The `agentPreset` session projection, owned by the adapter.
3
- *
4
- * Upstream registers this fold from the `dsh-agent-presets` package, which our
5
- * patch disables (the Codex provider replaces preset composition wholesale).
6
- * But the Web UI depends on the projection regardless: the preset hero chip
7
- * renders only when `session.projectionValues.agentPreset` resolves
8
- * (`presetOf` in ui-agent-preset/seat-store.ts), and the session-header label
9
- * reads it too. Without a registrant the projection is absent for every
10
- * adapter session and both surfaces stay blank — roster or no roster (that
11
- * was the "no mode" bug on the omp line: the roster service answered
12
- * agentPresets/list 200, yet nothing drove the per-session projection the
13
- * chip gates on).
14
- *
15
- * Same fold as upstream (packages/preset/agent-presets/src/session.ts):
16
- * initialized from the creation header, advanced by `agent-preset/selected`
17
- * events, which this adapter synthesizes (`"codex"`) on every session it
18
- * prepares. Registered under the provider's own fiber via
19
- * `ctx.inject(['sessionProjections'])`, so the key lives exactly as long as
20
- * the provider is mounted.
21
- */
22
- import { z } from "zod";
23
- const agentPresetSchema = z.union([z.string(), z.null()]);
24
- /** Current Session preset, initialized from its header and advanced by selection events. */
25
- export const codexAgentPresetProjection = {
26
- key: "agentPreset",
27
- stateSchema: agentPresetSchema,
28
- // adapter-codex is single-preset: default every session to "codex" so the
29
- // header chip resolves for scan-native (never-resumed) sessions too,
30
- // instead of only those whose log carries an `agent-preset/selected` event.
31
- init: (header) => header.agentPreset ?? "codex",
32
- apply: (state, event) => event.type === "agent-preset/selected"
33
- ? event.data.agentPreset
34
- : state,
35
- wire: { viewSchema: agentPresetSchema, view: (state) => state },
36
- stateVersion: 1,
37
- };
@@ -1,65 +0,0 @@
1
- /**
2
- * Codex runtime app home bootstrap — idempotently creates the codex home and
3
- * seeds it with the Codex CLI's own config set (config.toml / model catalog /
4
- * auth) copied once from the native `~/.codex`.
5
- *
6
- * Why this is required, not cosmetic: a Codex home without `config.toml` makes
7
- * the CLI fall back to its built-in OpenAI provider, so every turn dies on
8
- * `wss://api.openai.com/v1/responses` with a region block (403 "Country,
9
- * region, or territory not supported"). The native home is where the user's
10
- * provider wiring lives (e.g. a local proxy: `model_provider = "custom"`,
11
- * `base_url = "http://127.0.0.1:15721/v1"`, `model = "glm-5.3-flash"`), and the
12
- * world deliberately runs with its own CODEX_HOME — so the config has to travel.
13
- *
14
- * Same manners as the OMP twin: never overwrites an existing file (a
15
- * provisioned app home wins), skips missing sources, and is fail-soft — the app
16
- * home is derived state, never a boot gate.
17
- */
18
- import { copyFileSync, existsSync, mkdirSync } from "node:fs";
19
- import { homedir } from "node:os";
20
- import { join } from "node:path";
21
- import { resolveCodexHome } from "./codex-store.js";
22
- /**
23
- * Config files seeded into the codex home. `config.toml` names the provider and
24
- * model, `cc-switch-model-catalog.json` is what its `model_catalog_json` key
25
- * points at (a relative path, hence the same directory), and `auth.json` is the
26
- * CLI's own credential record.
27
- */
28
- export const CODEX_HOME_CONFIG_FILES = ["config.toml", "cc-switch-model-catalog.json", "auth.json"];
29
- /** Native codex home — the copy source (`AW_CODEX_SEED_HOME` overrides). */
30
- export function defaultCodexSeedHome() {
31
- const configured = process.env.AW_CODEX_SEED_HOME;
32
- return configured !== undefined && configured !== "" ? configured : join(homedir(), ".codex");
33
- }
34
- /**
35
- * Ensure the codex home exists and carries the CLI config set.
36
- *
37
- * @param options - target/source/files overrides.
38
- * @returns the resolved codex home path (always, even on a failed seed).
39
- */
40
- export function ensureCodexAppHome(options = {}) {
41
- const codexHome = options.codexHome ?? resolveCodexHome();
42
- const source = options.seedHome ?? defaultCodexSeedHome();
43
- const files = options.files ?? CODEX_HOME_CONFIG_FILES;
44
- const seeded = [];
45
- try {
46
- mkdirSync(codexHome, { recursive: true });
47
- for (const name of files) {
48
- const dest = join(codexHome, name);
49
- if (existsSync(dest))
50
- continue;
51
- const src = join(source, name);
52
- if (!existsSync(src))
53
- continue;
54
- copyFileSync(src, dest);
55
- seeded.push(name);
56
- }
57
- if (seeded.length > 0) {
58
- options.warn?.(`codex-provider: app home ${codexHome} seeded from ${source} (${seeded.join(", ")})`);
59
- }
60
- }
61
- catch (error) {
62
- options.warn?.(`codex-provider: app-home bootstrap failed (fail-soft): ${String(error)}`);
63
- }
64
- return codexHome;
65
- }
@@ -1,46 +0,0 @@
1
- /**
2
- * AW-E Task 1 spike (P0 gate): prove `@openai/codex-sdk@0.154.0` drives a real
3
- * turn against the local cc-switch provider (glm-5.2) under an ISOLATED
4
- * CODEX_HOME, and capture the raw ThreadEvent chain for the Task 2 projection
5
- * fixtures. The SDK spawns its own exact-pinned codex binary — the 0.153.4
6
- * CLI on PATH is never consulted (version-mix safety, 2026-09-10 fact).
7
- */
8
- import { Codex } from "@openai/codex-sdk";
9
- function lastOfType(events, type) {
10
- for (let i = events.length - 1; i >= 0; i -= 1) {
11
- const evt = events[i];
12
- if (evt.type === type)
13
- return evt;
14
- }
15
- return undefined;
16
- }
17
- /** Run one real streamed turn and collect the full event chain. */
18
- export async function runSpike(opts) {
19
- const codex = new Codex({
20
- // env REPLACES process.env (SDK contract) — carry it forward + redirect home.
21
- env: { ...process.env, CODEX_HOME: opts.codexHome },
22
- });
23
- const thread = codex.startThread({
24
- workingDirectory: opts.cwd,
25
- skipGitRepoCheck: true,
26
- approvalPolicy: "never",
27
- sandboxMode: "read-only",
28
- });
29
- const events = [];
30
- const streamed = await thread.runStreamed(opts.prompt ?? "Reply with exactly: ok");
31
- for await (const evt of streamed.events) {
32
- events.push(evt);
33
- if (evt.type === "turn.failed") {
34
- const error = evt.error;
35
- throw new Error(`spike turn failed: ${error?.message ?? "unknown"}`);
36
- }
37
- }
38
- const completed = lastOfType(events, "turn.completed");
39
- const message = lastOfType(events, "item.completed");
40
- return {
41
- threadId: thread.id ?? "",
42
- finalResponse: message?.item?.text ?? "",
43
- usage: completed?.usage ?? null,
44
- events,
45
- };
46
- }
@@ -1,34 +0,0 @@
1
- /**
2
- * The `agentPreset` session projection, owned by the adapter.
3
- *
4
- * Upstream registers this fold from the `dsh-agent-presets` package, which our
5
- * patch disables (the Hermes provider replaces preset composition wholesale).
6
- * But the Web UI depends on the projection regardless: the preset hero chip
7
- * renders only when `session.projectionValues.agentPreset` resolves
8
- * (`presetOf` in ui-agent-preset/seat-store.ts), and the session-header label
9
- * reads it too. Without a registrant the projection is absent for every
10
- * adapter session and both surfaces stay blank — roster or no roster.
11
- *
12
- * Same fold as upstream (packages/preset/agent-presets/src/session.ts):
13
- * initialized from the creation header, advanced by `agent-preset/selected`
14
- * events, which this adapter synthesizes (`"hermes"`) on every session it
15
- * prepares. Registered under the provider's own fiber via
16
- * `ctx.inject(['sessionProjections'])`, so the key lives exactly as long as
17
- * the provider is mounted.
18
- */
19
- import { z } from "zod";
20
- const agentPresetSchema = z.union([z.string(), z.null()]);
21
- /** Current Session preset, initialized from its header and advanced by selection events. */
22
- export const hermesAgentPresetProjection = {
23
- key: "agentPreset",
24
- stateSchema: agentPresetSchema,
25
- // adapter-hermes is single-preset: default every session to "hermes" so the
26
- // header chip resolves for scan-native (never-resumed) sessions too,
27
- // instead of only those whose log carries an `agent-preset/selected` event.
28
- init: (header) => header.agentPreset ?? "hermes",
29
- apply: (state, event) => event.type === "agent-preset/selected"
30
- ? event.data.agentPreset
31
- : state,
32
- wire: { viewSchema: agentPresetSchema, view: (state) => state },
33
- stateVersion: 1,
34
- };
@@ -1,43 +0,0 @@
1
- import { type RealWebServerFace } from './world-web-server.js';
2
- import { type MuxFailure } from './world-mux.js';
3
- /** The two-method face of a world's typertGateway service instance. */
4
- export interface CarrierGatewayFace {
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>;
8
- }
9
- /** Options for mounting one world. */
10
- export interface MountWorldOptions {
11
- /** The ctx0 webServer the translated routes register on. */
12
- real: RealWebServerFace;
13
- /** Runtime key: the mount label (`omp` → `/omp`). */
14
- label: string;
15
- /** The addressed world's gateway instance. */
16
- gateway: CarrierGatewayFace;
17
- /** ctx0's browser-trust fence: returns an HTTP status to reject with. */
18
- requestRejection?(req: unknown): number | undefined;
19
- /** Max request body bytes (mirrors the connection default). */
20
- maxBodyBytes?: number;
21
- /** Mux ping interval (upstream default 30s). */
22
- heartbeatIntervalMs?: number;
23
- /** Error → wire failure mapper for the world's streams. */
24
- failure?(error: unknown): MuxFailure;
25
- }
26
- /** The live mount handle. */
27
- export interface MountedWorld {
28
- /** Mount root (`/omp`). */
29
- readonly labelPath: string;
30
- /** Unary channel root (`/omp/api`). */
31
- readonly apiPath: string;
32
- /** Mux websocket path (`/omp/api/remote.mux`). */
33
- readonly muxPath: string;
34
- /** Unregister everything this mount installed. */
35
- dispose(): void;
36
- }
37
- /**
38
- * Mount one world on the shared ctx0 webServer.
39
- * @param options - see {@link MountWorldOptions}.
40
- * @returns the live mount handle.
41
- */
42
- export declare function mountWorld(options: MountWorldOptions): MountedWorld;
43
- export { rewriteIndexHtml } from './index-pass.js';
@@ -1,241 +0,0 @@
1
- /**
2
- * ctx0 WebCarrier (AW-B DL1/DL5): mounts one world's traffic under `/<label>`.
3
- *
4
- * Responsibilities (grow per AW-B task):
5
- * - Task 4: unary RPC — `/<label>/api/<endpoint>` decodes the connection
6
- * envelope and dispatches into the ADDRESSED world's gateway instance.
7
- * - Task 6: mux — `/<label>/api/remote.mux` upgrade bridged to the same
8
- * instance (no shared selection anywhere).
9
- * - 2026-09-17 (H1): non-envelope GET/HEAD on `/<label>/api` forwards into
10
- * the owning world's registered exact Fetch routes — the world connection's
11
- * shared `/api` handler, published from `world-entry` via `world-host` —
12
- * still behind ctx0's fence, so `HEAD /<label>/api/session.export?...`
13
- * reaches the world's session-log-download route.
14
- *
15
- * The addressed world is the request's path. Nothing here reads a global.
16
- */
17
- import { EnvelopeError, parseClientRequest, serverError, serverResult, wireErrorOf, } from './envelope.js';
18
- import { stripLabelFromUrl } from './world-web-server.js';
19
- import { worldFetchHandlerOf } from './world-host.js';
20
- import { WorldMuxServer } from './world-mux.js';
21
- /** Default body cap, aligned with the connection service. */
22
- const DEFAULT_MAX_BODY_BYTES = 1024 * 1024;
23
- async function readBody(req, limit) {
24
- const carrier = req;
25
- const chunks = [];
26
- let size = 0;
27
- if (typeof carrier[Symbol.asyncIterator] === 'function') {
28
- for await (const chunk of carrier) {
29
- const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));
30
- size += buf.byteLength;
31
- if (size > limit)
32
- throw new EnvelopeError({ code: 'gateway/bad-request', message: 'request body too large' });
33
- chunks.push(buf);
34
- }
35
- return Buffer.concat(chunks).toString('utf8');
36
- }
37
- if (typeof carrier.on !== 'function')
38
- return '';
39
- return await new Promise((resolve, reject) => {
40
- carrier.on?.('data', (chunk) => {
41
- const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk ?? ''));
42
- size += buf.byteLength;
43
- if (size > limit) {
44
- reject(new EnvelopeError({ code: 'gateway/bad-request', message: 'request body too large' }));
45
- return;
46
- }
47
- chunks.push(buf);
48
- });
49
- carrier.on?.('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
50
- carrier.on?.('error', (error) => reject(error instanceof Error ? error : new Error(String(error))));
51
- });
52
- }
53
- /** Reject an upgrade on the raw socket (no ws ownership transfer). */
54
- function rejectUpgrade(socket, status) {
55
- const reason = status === 401 ? 'Unauthorized' : 'Forbidden';
56
- const body = reason.toLowerCase();
57
- const writable = socket;
58
- writable.write?.(`HTTP/1.1 ${status} ${reason}\r\n`
59
- + 'Connection: close\r\n'
60
- + 'Content-Type: text/plain; charset=utf-8\r\n'
61
- + `Content-Length: ${String(Buffer.byteLength(body, 'utf8'))}\r\n\r\n`
62
- + body);
63
- writable.destroy?.();
64
- }
65
- function writeJson(res, status, body) {
66
- const carrier = res;
67
- carrier.writeHead?.(status, { 'content-type': 'application/json' });
68
- res.end(body);
69
- }
70
- /** Write a plain-text answer (the shape upstream's own 404/413 answers use). */
71
- function writeText(res, status, body) {
72
- const carrier = res;
73
- carrier.writeHead?.(status, { 'content-type': 'text/plain; charset=utf-8' });
74
- res.end(body);
75
- }
76
- /**
77
- * Mount one world on the shared ctx0 webServer.
78
- * @param options - see {@link MountWorldOptions}.
79
- * @returns the live mount handle.
80
- */
81
- export function mountWorld(options) {
82
- const labelPath = `/${options.label}`;
83
- const apiPath = `${labelPath}/api`;
84
- const muxPath = `${apiPath}/remote.mux`;
85
- const maxBody = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
86
- const disposers = [];
87
- const forwardsFetchMethod = (req) => {
88
- const method = req.method;
89
- return method === 'GET' || method === 'HEAD';
90
- };
91
- /**
92
- * Forward one non-envelope GET/HEAD request into the owning world's shared
93
- * `/api` fetch handler (exact Fetch routes first, then the gateway's RPC
94
- * interceptor, then 404 — the upstream composition). The ctx0 fence has
95
- * already answered by the time we get here; the world's own browser-auth
96
- * gate is never consulted (a different tree, a different secret).
97
- */
98
- const bridgeWorldFetch = async (req, res) => {
99
- const worldFetch = worldFetchHandlerOf(options.label);
100
- if (worldFetch === undefined) {
101
- writeText(res, 404, 'not found');
102
- return;
103
- }
104
- const method = (req.method ?? 'GET');
105
- const resCarrier = res;
106
- // Client-disconnect detection rides the response (same reason as the
107
- // upstream node:http bridge: the request 'close' fires as soon as a
108
- // bodyless GET is consumed).
109
- const abort = new AbortController();
110
- const onClose = () => {
111
- if (resCarrier.writableEnded !== true)
112
- abort.abort();
113
- };
114
- resCarrier.once?.('close', onClose);
115
- let headersSent = false;
116
- try {
117
- const headers = {};
118
- for (const [name, value] of Object.entries(req.headers ?? {})) {
119
- if (typeof value === 'string')
120
- headers[name.toLowerCase()] = value;
121
- }
122
- // The world route owns the world-relative URL: strip the mount label,
123
- // keep the query (the session-export route reads it from searchParams).
124
- const request = new Request(new URL(stripLabelFromUrl(req.url, labelPath), 'http://dsh.internal'), { method, headers, signal: abort.signal });
125
- const response = await worldFetch.fetch(request);
126
- res.writeHead(response.status, Object.fromEntries(response.headers.entries()));
127
- headersSent = true;
128
- if (response.body === null) {
129
- res.end();
130
- return;
131
- }
132
- for await (const chunk of response.body) {
133
- // Backpressure: wait for drain instead of buffering unboundedly; a
134
- // socket close resolves the wait and the aborted signal ends the stream.
135
- if (resCarrier.write?.(chunk) === false && typeof resCarrier.once === 'function') {
136
- await new Promise((resolve) => {
137
- const done = () => {
138
- resCarrier.off?.('drain', done);
139
- resCarrier.off?.('close', done);
140
- resolve();
141
- };
142
- resCarrier.once?.('drain', done);
143
- resCarrier.once?.('close', done);
144
- });
145
- }
146
- }
147
- res.end();
148
- }
149
- catch {
150
- // The world route owns its statuses; only carrier-level faults land here.
151
- if (!headersSent)
152
- writeText(res, 500, 'carrier fetch bridge failure');
153
- else
154
- resCarrier.destroy?.();
155
- }
156
- finally {
157
- resCarrier.off?.('close', onClose);
158
- }
159
- };
160
- const handleUnary = async (req, res) => {
161
- const rejection = options.requestRejection?.(req);
162
- if (rejection !== undefined) {
163
- writeJson(res, rejection, JSON.stringify({ error: rejection === 401 ? 'unauthorized' : 'forbidden' }));
164
- return;
165
- }
166
- let rpcId = 'invalid-request';
167
- try {
168
- const text = await readBody(req, maxBody);
169
- let envelope;
170
- try {
171
- envelope = parseClientRequest(text);
172
- }
173
- catch (error) {
174
- // Non-envelope GET/HEAD traffic on the shared mount prefix belongs to
175
- // the world's own registered fetch routes; envelopes (and every other
176
- // method) keep the transport-level 400 below.
177
- if (error instanceof EnvelopeError && forwardsFetchMethod(req)) {
178
- await bridgeWorldFetch(req, res);
179
- return;
180
- }
181
- throw error;
182
- }
183
- rpcId = envelope.rpcId;
184
- const controller = new AbortController();
185
- const result = await options.gateway.dispatchRpc(envelope.method, envelope.payload, controller.signal);
186
- // The gateway already returns a Result (`{ok:true,value}` | `{ok:false,error}`),
187
- // which is exactly the server-response's `result` field.
188
- writeJson(res, 200, serverResult(rpcId, result));
189
- }
190
- catch (error) {
191
- const wire = wireErrorOf(error);
192
- // Envelope-level failures are transport-level 400s; dispatch failures are
193
- // business results carried inside a 200 server-response (upstream shape).
194
- if (error instanceof EnvelopeError) {
195
- writeJson(res, 400, serverError(rpcId, wire));
196
- return;
197
- }
198
- writeJson(res, 200, serverError(rpcId, wire));
199
- }
200
- };
201
- disposers.push(options.real.register({
202
- kind: 'prefix',
203
- path: apiPath,
204
- handler: handleUnary,
205
- }));
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)), {
208
- ...(options.heartbeatIntervalMs === undefined ? {} : { heartbeatIntervalMs: options.heartbeatIntervalMs }),
209
- ...(options.failure === undefined ? {} : { failure: options.failure }),
210
- });
211
- disposers.push(options.real.registerUpgrade({
212
- path: muxPath,
213
- handler: ((req, socket, head) => {
214
- const rejection = options.requestRejection?.(req);
215
- if (rejection !== undefined) {
216
- rejectUpgrade(socket, rejection === 401 ? 401 : 403);
217
- return;
218
- }
219
- return mux.handleUpgrade(req, socket, head);
220
- }),
221
- }));
222
- disposers.push(() => { void mux.close().catch(() => undefined); });
223
- return {
224
- labelPath,
225
- apiPath,
226
- muxPath,
227
- dispose() {
228
- for (const dispose of disposers.splice(0).reverse()) {
229
- try {
230
- dispose();
231
- }
232
- catch {
233
- // teardown must not throw
234
- }
235
- }
236
- },
237
- };
238
- }
239
- // The mount HTML pass lives in its own module; re-exported here so the carrier
240
- // remains the single import surface for mount behaviour.
241
- export { rewriteIndexHtml } from './index-pass.js';
@@ -1,28 +0,0 @@
1
- /**
2
- * Client mount shim (AW-B DL8).
3
- *
4
- * ONE head script installs every client-side break point:
5
- * - `__DSH_TRANSPORT__.fetch` → the Connection RPC fetch (URL object input)
6
- * - `WebSocket` / `EventSource` / `XMLHttpRequest` constructors → path rewrite
7
- * - `__DSH_FILE_UPLOAD__` → uploads bypass the blob worker + its XHR
8
- * - Storage.prototype get/set/remove → per-world key namespace
9
- * - `globalThis.fetch` → global-fetch calls asking for ctx0-root `/api`
10
- * URLs (2026-09-17 H1: upstream session-log-export resolves the GLOBAL
11
- * fetch at call time; narrow `/api`-only rule, query + hash preserved)
12
- * - `HTMLAnchorElement.prototype.click` → download-anchor clicks re-rooted
13
- * (2026-09-18 H1 r2: upstream hands the UNREWRITTEN absolute URL to a
14
- * DETACHED `<a download>` and clicks it — detached clicks never reach
15
- * document, so a document-level listener cannot see them, and a blanket
16
- * rewrite breaks the runtime selector's root-absolute anchors
17
- * (live-found 2026-09-18). Narrow rule: ONLY anchors carrying a
18
- * `download` attribute AND a same-authority root-absolute `/api` href.)
19
- * The rule is namespace-agnostic: a same-origin root-absolute URL is re-rooted
20
- * under the mount (`/omp`), nothing else is touched. That covers every prefix
21
- * a plugin may declare later — no list to keep in sync.
22
- */
23
- /**
24
- * Render the shim as a classic script (parser-blocking head injection).
25
- * @param labelPath - mount root, e.g. `/omp`.
26
- * @returns JavaScript source.
27
- */
28
- export declare function renderClientShim(labelPath: string): string;