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,251 +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
- /** Escape a label for embedding in generated JavaScript. */
24
- function js(value) {
25
- return JSON.stringify(value);
26
- }
27
- /**
28
- * Render the shim as a classic script (parser-blocking head injection).
29
- * @param labelPath - mount root, e.g. `/omp`.
30
- * @returns JavaScript source.
31
- */
32
- export function renderClientShim(labelPath) {
33
- if (typeof labelPath !== 'string' || !labelPath.startsWith('/') || labelPath === '/' || labelPath.endsWith('/')) {
34
- throw new Error(`client-shim: labelPath must start with "/" and carry no trailing slash, got ${JSON.stringify(labelPath)}`);
35
- }
36
- const prefix = `${labelPath}/`;
37
- return `(() => {
38
- const LABEL = ${js(labelPath)}
39
- const PREFIX = ${js(prefix)}
40
-
41
- /** Re-root one pathname when it is same-origin root-absolute and not mounted yet. */
42
- const rewritePath = (path) => {
43
- if (typeof path !== 'string' || !path.startsWith('/') || path.startsWith('//')) return path
44
- if (path === LABEL || path.startsWith(PREFIX)) return path
45
- return PREFIX + path.slice(1)
46
- }
47
-
48
- const origin = () => {
49
- const loc = globalThis.location
50
- if (loc !== undefined && typeof loc.origin === 'string' && loc.origin !== 'null') return loc.origin
51
- return 'http://dsh.internal'
52
- }
53
-
54
- /** Same authority as the page (scheme-agnostic: ws/wss/http/https share host). */
55
- const sameAuthority = (url) => {
56
- try {
57
- return url.host === new URL(origin()).host
58
- } catch {
59
- return false
60
- }
61
- }
62
-
63
- /** Rewrite a full URL (absolute or relative); other authorities are untouched. */
64
- const rewriteUrl = (input) => {
65
- if (typeof input === 'string') {
66
- if (input.startsWith('/')) return rewritePath(input)
67
- try {
68
- const url = new URL(input, origin())
69
- if (!sameAuthority(url)) return input
70
- const next = rewritePath(url.pathname)
71
- if (next === url.pathname) return input
72
- url.pathname = next
73
- return url.href
74
- } catch {
75
- return input
76
- }
77
- }
78
- if (input !== null && typeof input === 'object' && typeof input.href === 'string') {
79
- try {
80
- const url = new URL(input.href)
81
- if (!sameAuthority(url)) return input
82
- const next = rewritePath(url.pathname)
83
- if (next === url.pathname) return input
84
- url.pathname = next
85
- return url
86
- } catch {
87
- return input
88
- }
89
- }
90
- return input
91
- }
92
-
93
- const nativeFetch = globalThis.fetch
94
- const shimFetch = (input, init) => {
95
- if (typeof nativeFetch !== 'function') throw new Error('client-shim: fetch is unavailable')
96
- if (typeof Request === 'function' && input instanceof Request) {
97
- const url = rewriteUrl(input.url)
98
- return nativeFetch(url === input.url ? input : new Request(url, input), init)
99
- }
100
- return nativeFetch(rewriteUrl(input), init)
101
- }
102
-
103
- const transport = (globalThis.__DSH_TRANSPORT__ = globalThis.__DSH_TRANSPORT__ || {})
104
- transport.rewrite = rewritePath
105
- transport.fetch = shimFetch
106
-
107
- // Construct through a Proxy, never a hand-rolled wrapper function: the
108
- // upstream client compares socket.readyState against WebSocket.OPEN, so the
109
- // native statics (CONNECTING/OPEN/CLOSING/CLOSED), prototype and instanceof
110
- // must survive the interception.
111
- const NativeWebSocket = globalThis.WebSocket
112
- if (typeof NativeWebSocket === 'function') {
113
- globalThis.WebSocket = new Proxy(NativeWebSocket, {
114
- construct: (Target, args) => new Target(rewriteUrl(args[0]), ...args.slice(1)),
115
- })
116
- }
117
-
118
- const NativeEventSource = globalThis.EventSource
119
-
120
- if (typeof NativeEventSource === 'function') {
121
- globalThis.EventSource = new Proxy(NativeEventSource, {
122
- construct: (Target, args) => new Target(rewriteUrl(args[0]), ...args.slice(1)),
123
- })
124
- }
125
-
126
- const NativeXhr = globalThis.XMLHttpRequest
127
- if (typeof NativeXhr === 'function' && NativeXhr.prototype !== undefined && typeof NativeXhr.prototype.open === 'function') {
128
- const nativeOpen = NativeXhr.prototype.open
129
- NativeXhr.prototype.open = function (method, url, ...rest) {
130
- return nativeOpen.call(this, method, rewriteUrl(url), ...rest)
131
- }
132
- }
133
-
134
- // Read by the file-upload service at construction time: present ⇒ the page
135
- // fetch carries uploads (no blob worker, and therefore no worker-scope XHR).
136
- globalThis.__DSH_FILE_UPLOAD__ = { fetch: shimFetch }
137
-
138
- // Narrow '/api' re-root helpers (2026-09-17 session-log 404, H1): upstream
139
- // client code (session-log-export) resolves the GLOBAL fetch at call time
140
- // and hands absolute ctx0-root URLs both to fetch and to a DETACHED
141
- // download anchor — neither is visible to the transport faces above.
142
- // Narrow rule: only root-absolute '/api' paths move under the mount;
143
- // relative, same-mount, and foreign URLs pass through untouched. Query and
144
- // hash survive because only the pathname is rewritten. The mount root comes
145
- // from this shim's argument, never from location.pathname. NOTE: the '/api'
146
- // literals below stay SINGLE-quoted on purpose — index-pass.ts rewrites
147
- // every DOUBLE-quoted root-absolute string in the served HTML, and a
148
- // doubled literal would silently disable these rewrites (regression tests
149
- // survive the mount HTML pass).
150
- const rewriteApiPath = (path) => {
151
- if (path === '/api' || path.startsWith('/api/')) return PREFIX + path.slice(1)
152
- return path
153
- }
154
- const rewriteApiUrl = (input) => {
155
- if (typeof input === 'string') {
156
- if (input.startsWith('/') && !input.startsWith('//')) return rewriteApiPath(input)
157
- try {
158
- const url = new URL(input, origin())
159
- if (!sameAuthority(url)) return input
160
- const next = rewriteApiPath(url.pathname)
161
- if (next === url.pathname) return input
162
- url.pathname = next
163
- return url.href
164
- } catch {
165
- return input
166
- }
167
- }
168
- if (input !== null && typeof input === 'object' && typeof input.href === 'string') {
169
- try {
170
- const url = new URL(input.href)
171
- if (!sameAuthority(url)) return input
172
- const next = rewriteApiPath(url.pathname)
173
- if (next === url.pathname) return input
174
- url.pathname = next
175
- return url
176
- } catch {
177
- return input
178
- }
179
- }
180
- return input
181
- }
182
- if (typeof nativeFetch === 'function' && globalThis.__DSH_FETCH_REWRITE__ !== true) {
183
- globalThis.__DSH_FETCH_REWRITE__ = true
184
- globalThis.fetch = (input, init) => nativeFetch(rewriteApiUrl(input), init)
185
- }
186
-
187
- // Download anchors (2026-09-18 H1 r2): upstream session-log-export hands
188
- // the UNREWRITTEN absolute URL to a DETACHED '<a download>' element and
189
- // calls .click() — detached clicks never propagate to document, so the r1
190
- // document-level capture listener could not see them, while its BLANKET
191
- // rewrite re-rooted the runtime selector's root-absolute anchors and broke
192
- // cross-world navigation (live-found 2026-09-18). Narrow seam: wrap
193
- // HTMLAnchorElement.prototype.click itself and rewrite ONLY anchors that
194
- // carry a 'download' attribute AND a same-authority root-absolute '/api'
195
- // href. Everything else — the runtime selector's links included — passes
196
- // through untouched.
197
- if (globalThis.HTMLAnchorElement !== undefined
198
- && globalThis.HTMLAnchorElement.prototype !== undefined
199
- && typeof globalThis.HTMLAnchorElement.prototype.click === 'function'
200
- && globalThis.__DSH_ANCHOR_CLICK_REWRITE__ !== true) {
201
- globalThis.__DSH_ANCHOR_CLICK_REWRITE__ = true
202
- const nativeAnchorClick = globalThis.HTMLAnchorElement.prototype.click
203
- globalThis.HTMLAnchorElement.prototype.click = function (...args) {
204
- try {
205
- if (this.hasAttribute('download')) {
206
- const current = this.getAttribute('href')
207
- if (typeof current === 'string' && current !== '') {
208
- const next = rewriteApiUrl(current)
209
- if (typeof next === 'string' && next !== current) this.setAttribute('href', next)
210
- }
211
- }
212
- } catch {
213
- /* best-effort: never break the click itself */
214
- }
215
- return nativeAnchorClick.apply(this, args)
216
- }
217
- }
218
-
219
- // Storage namespace (2026-09-16 storage findings P1): all worlds share one
220
-
221
- // origin, so bare localStorage keys would overwrite each other across
222
- // mounts. Prefix every key with the label; root '/' never injects this
223
- // shim and keeps bare keys. Never throws: attachPersistence only
224
- // console-errors on failure, so a throwing shim would silently disable
225
- // persistence.
226
- try {
227
- const StorageProto = globalThis.Storage && globalThis.Storage.prototype
228
- if (globalThis.localStorage !== undefined && StorageProto !== undefined
229
- && !globalThis.__DSH_STORAGE_NS__
230
- && typeof StorageProto.getItem === 'function'
231
- && typeof StorageProto.setItem === 'function'
232
- && typeof StorageProto.removeItem === 'function') {
233
- // NS derives from PREFIX, never LABEL: the mount HTML pass (index-pass)
234
- // rewrites every quoted root-absolute string EXCEPT "<label>/"-prefixed
235
- // ones, so the shim's LABEL="/omp" literal doubles to "/omp/omp" while
236
- // PREFIX="/omp/" is immune (live-found 2026-09-17, acceptance A2/A5).
237
- // The NS-from-PREFIX coupling is DELIBERATE: index-pass.ts rewrites double-quoted root-absolute strings except "<label>/"-prefixed ones, so LABEL="/omp" doubles while PREFIX="/omp/" survives; do NOT derive NS from LABEL.
238
- const NS = PREFIX.slice(1, -1) + ':'
239
- globalThis.__DSH_STORAGE_NS__ = NS
240
- const nativeGetItem = StorageProto.getItem
241
- const nativeSetItem = StorageProto.setItem
242
- const nativeRemoveItem = StorageProto.removeItem
243
- StorageProto.getItem = function (name) { return nativeGetItem.call(this, NS + name) }
244
- StorageProto.setItem = function (name, value) { return nativeSetItem.call(this, NS + name, value) }
245
- StorageProto.removeItem = function (name) { return nativeRemoveItem.call(this, NS + name) }
246
- }
247
- } catch {
248
- /* storage namespace is best-effort: never break the shim */
249
- }
250
- })()`;
251
- }
@@ -1,18 +0,0 @@
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;
@@ -1,22 +0,0 @@
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;
@@ -1,47 +0,0 @@
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
- }
@@ -1,45 +0,0 @@
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;
@@ -1,83 +0,0 @@
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
- }
@@ -1,72 +0,0 @@
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
- }
@@ -1,31 +0,0 @@
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;
@@ -1,51 +0,0 @@
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;
@@ -1,44 +0,0 @@
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
- }