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.
- package/README.md +3 -3
- package/agent-agy/cordis.patch.yml +8 -4
- package/agent-agy/dist/agent-preset-agy.d.ts +23 -43
- package/agent-agy/dist/agent-preset-agy.js +29 -166
- package/agent-agy/dist/agent.d.ts +2 -1
- package/agent-agy/dist/agent.js +3 -2
- package/agent-agy/dist/agy-sessions.d.ts +2 -1
- package/agent-agy/dist/agy-sessions.js +2 -11
- package/agent-agy/dist/index.js +13 -12
- package/agent-agy/dist/world-plugin.d.ts +2 -1
- package/agent-agy/dist/world-plugin.js +31 -51
- package/agent-agy/package.json +6 -6
- package/agent-claude/cordis.patch.yml +8 -4
- package/agent-claude/dist/agent-preset-claude.js +29 -166
- package/agent-claude/dist/agent.js +10 -10
- package/agent-claude/dist/claude-client.js +22 -3
- package/agent-claude/dist/claude-home.js +0 -8
- package/agent-claude/dist/index.js +12 -15
- package/agent-claude/dist/session-map.js +2 -5
- package/agent-claude/dist/world-plugin.js +3 -3
- package/agent-claude/package.json +9 -9
- package/agent-codex/README.md +8 -8
- package/agent-codex/cordis.patch.yml +9 -5
- package/agent-codex/dist/agent-preset-codex.js +29 -168
- package/agent-codex/dist/agent.js +17 -12
- package/agent-codex/dist/codex-store.js +0 -9
- package/agent-codex/dist/index.js +13 -16
- package/agent-codex/dist/session-map.js +2 -5
- package/agent-codex/dist/world-plugin.js +31 -51
- package/agent-codex/package.json +14 -11
- package/agent-hermes/README.md +9 -8
- package/agent-hermes/cordis.patch.yml +8 -4
- package/agent-hermes/dist/agent-preset-hermes.js +29 -168
- package/agent-hermes/dist/agent.js +33 -19
- package/agent-hermes/dist/hermes-client.js +5 -5
- package/agent-hermes/dist/hermes-store.js +2 -11
- package/agent-hermes/dist/index.js +13 -12
- package/agent-hermes/dist/world-plugin.js +31 -52
- package/agent-hermes/package.json +14 -11
- package/agent-omp/README.md +2 -2
- package/agent-omp/cordis.patch.yml +12 -7
- package/agent-omp/dist/agent-preset-omp.js +30 -169
- package/agent-omp/dist/agent.js +13 -5
- package/agent-omp/dist/index.js +12 -22
- package/agent-omp/dist/mobile/gesture.js +2 -2
- package/agent-omp/dist/mobile/zoom-guard.js +4 -4
- package/agent-omp/dist/mobile-boot.js +2 -2
- package/agent-omp/dist/omp-cli.js +1 -1
- package/agent-omp/dist/omp-disk-discovery.js +1 -1
- package/agent-omp/dist/protocol.js +1 -1
- package/agent-omp/dist/sidecar-client.js +1 -1
- package/agent-omp/dist/world-plugin.js +37 -50
- package/agent-omp/package.json +18 -14
- package/agent-omp/sidecar/main.ts +2 -2
- package/agent-pi/README.md +5 -5
- package/agent-pi/cordis.patch.yml +8 -4
- package/agent-pi/dist/agent-preset-pi.js +29 -166
- package/agent-pi/dist/agent.js +18 -12
- package/agent-pi/dist/index.js +14 -16
- package/agent-pi/dist/pi-home.js +2 -12
- package/agent-pi/dist/world-plugin.js +31 -51
- package/agent-pi/package.json +14 -11
- package/client/index.js +1994 -150
- package/cordis.patch.yml +38 -15
- package/package.json +32 -30
- package/{agent-hub → superd-hub}/cordis.patch.yml +3 -3
- package/{agent-hub → superd-hub}/dist/agent-roster.d.ts +3 -1
- package/{agent-hub → superd-hub}/dist/agent-roster.js +4 -2
- package/superd-hub/dist/carrier.d.ts +62 -0
- package/superd-hub/dist/carrier.js +213 -0
- package/superd-hub/dist/fusion-transport.d.ts +148 -0
- package/superd-hub/dist/fusion-transport.js +397 -0
- package/{agent-hub → superd-hub}/dist/gateway.d.ts +9 -4
- package/superd-hub/dist/gateway.js +44 -0
- package/superd-hub/dist/hub-route.d.ts +74 -0
- package/superd-hub/dist/hub-route.js +188 -0
- package/{agent-hub → superd-hub}/dist/index.d.ts +14 -6
- package/{agent-hub → superd-hub}/dist/index.js +14 -6
- package/{agent-hub → superd-hub}/dist/roster.d.ts +2 -2
- package/{agent-hub → superd-hub}/dist/rpc.js +1 -1
- package/{agent-hub → superd-hub}/dist/spawn-world.d.ts +27 -6
- package/superd-hub/dist/spawn-world.js +279 -0
- package/superd-hub/dist/switch-core.d.ts +630 -0
- package/superd-hub/dist/switch-core.js +734 -0
- package/superd-hub/dist/system-head.d.ts +69 -0
- package/superd-hub/dist/system-head.js +194 -0
- package/superd-hub/dist/web-trust.d.ts +112 -0
- package/superd-hub/dist/web-trust.js +126 -0
- package/superd-hub/dist/world-entry.d.ts +38 -0
- package/superd-hub/dist/world-entry.js +47 -0
- package/{agent-hub → superd-hub}/dist/world-host.d.ts +15 -20
- package/superd-hub/dist/world-host.js +65 -0
- package/{agent-hub → superd-hub}/dist/world-join.d.ts +2 -1
- package/{agent-hub → superd-hub}/dist/world-join.js +30 -50
- package/superd-hub/dist/world-mount.d.ts +82 -0
- package/superd-hub/dist/world-mount.js +105 -0
- package/{agent-hub → superd-hub}/dist/world-mux.d.ts +21 -6
- package/superd-hub/dist/world-mux.js +392 -0
- package/{agent-hub → superd-hub}/dist/world-provision.d.ts +20 -4
- package/superd-hub/dist/world-provision.js +203 -0
- package/superd-hub/dist/world-web-server.d.ts +113 -0
- package/superd-hub/dist/world-web-server.js +99 -0
- package/superd-hub/lib/client/index.js +2086 -0
- package/{agent-hub → superd-hub}/package.json +12 -7
- package/agent-agy/dist/agent-preset-projection.d.ts +0 -31
- package/agent-agy/dist/agent-preset-projection.js +0 -33
- package/agent-claude/dist/agent-preset-projection.js +0 -30
- package/agent-codex/dist/agent-preset-projection.js +0 -37
- package/agent-codex/dist/app-home.js +0 -65
- package/agent-codex/dist/spike.js +0 -46
- package/agent-hermes/dist/agent-preset-projection.js +0 -34
- package/agent-hub/dist/carrier.d.ts +0 -43
- package/agent-hub/dist/carrier.js +0 -241
- package/agent-hub/dist/client-shim.d.ts +0 -28
- package/agent-hub/dist/client-shim.js +0 -251
- package/agent-hub/dist/gateway.js +0 -18
- package/agent-hub/dist/index-pass.d.ts +0 -22
- package/agent-hub/dist/index-pass.js +0 -47
- package/agent-hub/dist/labels.d.ts +0 -45
- package/agent-hub/dist/labels.js +0 -83
- package/agent-hub/dist/spawn-world.js +0 -72
- package/agent-hub/dist/world-entry.d.ts +0 -31
- package/agent-hub/dist/world-entry.js +0 -51
- package/agent-hub/dist/world-host.js +0 -44
- package/agent-hub/dist/world-mount.d.ts +0 -52
- package/agent-hub/dist/world-mount.js +0 -52
- package/agent-hub/dist/world-mux.js +0 -224
- package/agent-hub/dist/world-provision.js +0 -122
- package/agent-hub/dist/world-web-server.d.ts +0 -162
- package/agent-hub/dist/world-web-server.js +0 -248
- package/agent-hub/lib/client/index.js +0 -242
- package/agent-omp/dist/agent-preset-projection.js +0 -36
- package/agent-omp/dist/app-home.js +0 -86
- package/agent-pi/dist/agent-preset-projection.js +0 -29
- /package/{agent-hub → superd-hub}/dist/envelope.d.ts +0 -0
- /package/{agent-hub → superd-hub}/dist/envelope.js +0 -0
- /package/{agent-hub → superd-hub}/dist/ownership.d.ts +0 -0
- /package/{agent-hub → superd-hub}/dist/ownership.js +0 -0
- /package/{agent-hub → superd-hub}/dist/roster.js +0 -0
- /package/{agent-hub → superd-hub}/dist/rpc.d.ts +0 -0
- /package/{agent-hub → superd-hub}/dist/targets.d.ts +0 -0
- /package/{agent-hub → superd-hub}/dist/targets.js +0 -0
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Per-world virtual webServer (AW-B DL3).
|
|
3
|
-
*
|
|
4
|
-
* A world's plugins must be able to declare ANY path they like (`/api`,
|
|
5
|
-
* `/plugins`, `/whatever-name-i-like`). Enumerating those namespaces in the
|
|
6
|
-
* carrier is wrong by construction — a third-party plugin may declare a new
|
|
7
|
-
* one at any time. So this class translates at REGISTRATION time:
|
|
8
|
-
*
|
|
9
|
-
* world registers { kind, path } → real registers { kind, `${labelPath}${path}` }
|
|
10
|
-
* real receives /<label>/<path>/... → plugin handler sees /<path>/...
|
|
11
|
-
*
|
|
12
|
-
* Consequences:
|
|
13
|
-
* - any declared prefix lands under the label automatically; no list;
|
|
14
|
-
* - two worlds may both own `/api` (they become `/omp/api`, `/codex/api`);
|
|
15
|
-
* - ctx0 only ever sees the label namespaces, so a world cannot collide with
|
|
16
|
-
* ctx0's own routes.
|
|
17
|
-
*
|
|
18
|
-
* Index rows stay world-local: this instance owns its taps and emits nothing
|
|
19
|
-
* on the shared tree (worlds run as their own cordis ROOTS, whose event buses
|
|
20
|
-
* are isolated — probe 2026-09-16: emit on root B never reaches root A).
|
|
21
|
-
*/
|
|
22
|
-
import { renderIndexInjections } from '@deepseek-ai/dsh-host-webserver';
|
|
23
|
-
import { rewriteIndexHtml } from './index-pass.js';
|
|
24
|
-
import { renderClientShim } from './client-shim.js';
|
|
25
|
-
import { agentRosterRow } from './agent-roster.js';
|
|
26
|
-
function translatePath(labelPath, path) {
|
|
27
|
-
if (typeof path !== 'string' || !path.startsWith('/')) {
|
|
28
|
-
throw new Error(`world-web-server: route path must start with "/", got ${JSON.stringify(path)}`);
|
|
29
|
-
}
|
|
30
|
-
return path === '/' ? labelPath : `${labelPath}${path}`;
|
|
31
|
-
}
|
|
32
|
-
/** Remove the mount label from `req.url`, preserving the trailing query. */
|
|
33
|
-
export function stripLabelFromUrl(url, labelPath) {
|
|
34
|
-
const raw = typeof url === 'string' && url !== '' ? url : '/';
|
|
35
|
-
const queryAt = raw.indexOf('?');
|
|
36
|
-
const path = queryAt === -1 ? raw : raw.slice(0, queryAt);
|
|
37
|
-
const rest = queryAt === -1 ? '' : raw.slice(queryAt);
|
|
38
|
-
if (path === labelPath)
|
|
39
|
-
return `/${rest}`;
|
|
40
|
-
if (path.startsWith(`${labelPath}/`))
|
|
41
|
-
return `${path.slice(labelPath.length)}${rest}`;
|
|
42
|
-
return raw;
|
|
43
|
-
}
|
|
44
|
-
/** One world's web surface, mounted under `<labelPath>`. */
|
|
45
|
-
export class WorldWebServer {
|
|
46
|
-
labelPath;
|
|
47
|
-
real;
|
|
48
|
-
options;
|
|
49
|
-
disposers = [];
|
|
50
|
-
taps = [];
|
|
51
|
-
/**
|
|
52
|
-
* @param labelPath - mount root, e.g. `/omp` (no trailing slash).
|
|
53
|
-
* @param real - the ctx0 webServer this world's routes forward into.
|
|
54
|
-
* @param options - world-local index row source.
|
|
55
|
-
*/
|
|
56
|
-
constructor(labelPath, real, options = {}) {
|
|
57
|
-
this.labelPath = labelPath;
|
|
58
|
-
this.real = real;
|
|
59
|
-
this.options = options;
|
|
60
|
-
if (typeof labelPath !== 'string' || !labelPath.startsWith('/') || labelPath === '/' || labelPath.endsWith('/')) {
|
|
61
|
-
throw new Error(`world-web-server: labelPath must start with "/" and carry no trailing slash, got ${JSON.stringify(labelPath)}`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
/** The ctx0 listener port (read-through; the world owns no socket). */
|
|
65
|
-
get port() {
|
|
66
|
-
return this.real.port ?? 0;
|
|
67
|
-
}
|
|
68
|
-
/** The ctx0 bind host (read-through). */
|
|
69
|
-
get host() {
|
|
70
|
-
return this.real.host ?? '127.0.0.1';
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* The RPC channel belongs to the HUB, not to the world: the hub's carrier
|
|
74
|
-
* answers `/<label>/api/*` and `/<label>/api/remote.mux` with ctx0's auth
|
|
75
|
-
* domain, so the world's own connection/gateway registrations are swallowed
|
|
76
|
-
* here (returning a no-op disposer) instead of colliding on the real table.
|
|
77
|
-
* Non-envelope GET/HEAD traffic on `/<label>/api` still reaches the world's
|
|
78
|
-
* exact Fetch routes: `world-entry` publishes the world connection's shared
|
|
79
|
-
* `/api` fetch handler through `world-host`, and the carrier forwards into
|
|
80
|
-
* it AFTER ctx0's fence — the world's own browser-auth gate is never in the
|
|
81
|
-
* path (a different tree, a different secret).
|
|
82
|
-
*/
|
|
83
|
-
static hubOwned(path) {
|
|
84
|
-
return path === '/api' || path.startsWith('/api/');
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Mount-side authentication for one forwarded world route.
|
|
88
|
-
*
|
|
89
|
-
* The world's own browser-auth gate never sees a browser: it is reached
|
|
90
|
-
* in-ctx through this mount, and its cookie secret belongs to a different
|
|
91
|
-
* tree (every runtime is nested with its own home). So the decision is made
|
|
92
|
-
* here, with ctx0's connection: the same cookie that authenticated `<label>`
|
|
93
|
-
* in ctx0 authorizes its pages and assets.
|
|
94
|
-
*/
|
|
95
|
-
gate(handler) {
|
|
96
|
-
return (req, ...rest) => {
|
|
97
|
-
const res = rest[0];
|
|
98
|
-
// false => the authorizer already answered (401, or token→cookie 303).
|
|
99
|
-
if (res !== undefined && this.options.authorize !== undefined
|
|
100
|
-
&& !this.options.authorize(req, res))
|
|
101
|
-
return;
|
|
102
|
-
return handler(req, ...rest);
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
/** Register a world route; the real table stores its translated path. */
|
|
106
|
-
register(route) {
|
|
107
|
-
if (WorldWebServer.hubOwned(route.path))
|
|
108
|
-
return () => { };
|
|
109
|
-
return this.track(this.real.register({
|
|
110
|
-
kind: route.kind,
|
|
111
|
-
path: translatePath(this.labelPath, route.path),
|
|
112
|
-
handler: this.strip(this.gate(route.handler)),
|
|
113
|
-
}));
|
|
114
|
-
}
|
|
115
|
-
/** Register a world upgrade route (verbatim exact path; hub-owned RPC paths are swallowed). */
|
|
116
|
-
registerUpgrade(route) {
|
|
117
|
-
if (WorldWebServer.hubOwned(route.path))
|
|
118
|
-
return () => { };
|
|
119
|
-
return this.track(this.real.registerUpgrade({
|
|
120
|
-
path: translatePath(this.labelPath, route.path),
|
|
121
|
-
handler: this.strip(route.handler),
|
|
122
|
-
}));
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Claim the world's SPA fallback: the ctx0 fallback seat is already owned by
|
|
126
|
-
* native frontend-static, so the world's fallback lives as a PREFIX route on
|
|
127
|
-
* the mount path (`/<label>`), which also keeps it inside the label namespace.
|
|
128
|
-
*/
|
|
129
|
-
registerFallback(handler) {
|
|
130
|
-
// The world's index arrives HERE (its own frontend-static claims the
|
|
131
|
-
// fallback seat), so this is the route the mount must authenticate.
|
|
132
|
-
const gated = this.gate((req, ...rest) => handler(req, rest[0]));
|
|
133
|
-
return this.track(this.real.register({
|
|
134
|
-
kind: 'prefix',
|
|
135
|
-
path: this.labelPath,
|
|
136
|
-
handler: this.htmlRewrite(this.strip(gated)),
|
|
137
|
-
}));
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Fix up HTML on its way out. Two passes belong here, in this order:
|
|
141
|
-
*
|
|
142
|
-
* 1. the world's own frontend-static injects `<base href="/">` AFTER
|
|
143
|
-
* `renderIndex`, and the FIRST `<base>` wins in a document, so the mount
|
|
144
|
-
* base is re-pinned on the bytes actually sent;
|
|
145
|
-
* 2. the agent roster is injected LAST — its values are the mount paths of
|
|
146
|
-
* OTHER worlds (`/`, `/omp/`, `/codex/`), which the mount pass above
|
|
147
|
-
* would otherwise re-root under this world's label.
|
|
148
|
-
*/
|
|
149
|
-
htmlRewrite(handler) {
|
|
150
|
-
const labelPath = this.labelPath;
|
|
151
|
-
return (req, ...rest) => {
|
|
152
|
-
const res = rest[0];
|
|
153
|
-
const originalEnd = res?.end?.bind(res);
|
|
154
|
-
if (res !== undefined && originalEnd !== undefined) {
|
|
155
|
-
res.end = ((chunk, ...tail) => {
|
|
156
|
-
if (typeof chunk === 'string' || Buffer.isBuffer(chunk)) {
|
|
157
|
-
const text = typeof chunk === 'string' ? chunk : chunk.toString('utf8');
|
|
158
|
-
if (/<head[\s>]/i.test(text) && /<base\b/i.test(text)) {
|
|
159
|
-
const mounted = rewriteIndexHtml(text, labelPath);
|
|
160
|
-
// A world that composes the hub row emits its own roster row during
|
|
161
|
-
// renderIndex — i.e. BEFORE this mount pass, so its paths were
|
|
162
|
-
// already re-rooted. Drop every earlier copy and inject the one
|
|
163
|
-
// this pass has just built from unrewritten values.
|
|
164
|
-
const stale = /<script>globalThis\["__DSH_AGENT_ROSTER__"\][^<]*<\/script>/g;
|
|
165
|
-
const cleaned = mounted.replace(stale, '');
|
|
166
|
-
return originalEnd(renderIndexInjections(cleaned, [agentRosterRow()]), ...tail);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
return originalEnd(chunk, ...tail);
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
return handler(req, ...rest);
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
/** World-local raw index transform (never forwarded to ctx0's taps). */
|
|
176
|
-
tapIndex(transform) {
|
|
177
|
-
this.taps.push(transform);
|
|
178
|
-
return () => {
|
|
179
|
-
const at = this.taps.indexOf(transform);
|
|
180
|
-
if (at !== -1)
|
|
181
|
-
this.taps.splice(at, 1);
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
/** Apply this world's taps in registration order. */
|
|
185
|
-
applyIndexTaps(html) {
|
|
186
|
-
let out = html;
|
|
187
|
-
for (const transform of this.taps)
|
|
188
|
-
out = transform(out);
|
|
189
|
-
return out;
|
|
190
|
-
}
|
|
191
|
-
/** Collect this world's structured rows (supplied by the world root). */
|
|
192
|
-
collectIndexInjections() {
|
|
193
|
-
const table = [];
|
|
194
|
-
this.options.onIndexInject?.(table);
|
|
195
|
-
return table;
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Render the world's index: the client mount shim first (it must run before
|
|
199
|
-
* the app entry module), then the world's rows, then its taps, then the mount
|
|
200
|
-
* pass (base pinned at `/<label>/`, root-absolute strings re-rooted).
|
|
201
|
-
*
|
|
202
|
-
* The agent roster is injected LAST, after the mount pass: its values are
|
|
203
|
-
* mount paths of OTHER worlds (`/`, `/omp/`, `/codex/`), and the pass would
|
|
204
|
-
* happily re-root them under this world's label.
|
|
205
|
-
*/
|
|
206
|
-
renderIndex(html) {
|
|
207
|
-
const rows = [
|
|
208
|
-
{ kind: 'script', placement: 'head', text: renderClientShim(this.labelPath) },
|
|
209
|
-
// No hub-invented widget here: the world composes the hub's own client
|
|
210
|
-
// plugin (see worldMountPatches), so its selector IS the native one.
|
|
211
|
-
...this.collectIndexInjections(),
|
|
212
|
-
];
|
|
213
|
-
const rendered = this.applyIndexTaps(renderIndexInjections(html, rows));
|
|
214
|
-
// The roster rides the outbound pass (htmlRewrite), not this one: the mount
|
|
215
|
-
// rewrite above would re-root other worlds' paths under this label.
|
|
216
|
-
return rewriteIndexHtml(rendered, this.labelPath);
|
|
217
|
-
}
|
|
218
|
-
/** Unregister every translated route (world unloaded). */
|
|
219
|
-
dispose() {
|
|
220
|
-
for (const dispose of this.disposers.splice(0).reverse()) {
|
|
221
|
-
try {
|
|
222
|
-
dispose();
|
|
223
|
-
}
|
|
224
|
-
catch {
|
|
225
|
-
// release must never throw during teardown
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
this.taps.length = 0;
|
|
229
|
-
}
|
|
230
|
-
/** Wrap a plugin handler so it sees the world-relative URL. */
|
|
231
|
-
strip(handler) {
|
|
232
|
-
const labelPath = this.labelPath;
|
|
233
|
-
return (req, ...rest) => {
|
|
234
|
-
req.url = stripLabelFromUrl(req.url, labelPath);
|
|
235
|
-
return handler(req, ...rest);
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
track(dispose) {
|
|
239
|
-
const wrapped = () => {
|
|
240
|
-
const at = this.disposers.indexOf(wrapped);
|
|
241
|
-
if (at !== -1)
|
|
242
|
-
this.disposers.splice(at, 1);
|
|
243
|
-
dispose();
|
|
244
|
-
};
|
|
245
|
-
this.disposers.push(wrapped);
|
|
246
|
-
return wrapped;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
window.__ModuleLoader__.load({ id: "@pgmi-builds/agent-hub", factory: (require) => {
|
|
2
|
-
var module = { exports: {} }; var exports = module.exports;
|
|
3
|
-
//#region rolldown:runtime
|
|
4
|
-
var __create = Object.create;
|
|
5
|
-
var __defProp = Object.defineProperty;
|
|
6
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
9
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
12
|
-
key = keys[i];
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
14
|
-
get: ((k) => from[k]).bind(null, key),
|
|
15
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
21
|
-
value: mod,
|
|
22
|
-
enumerable: true
|
|
23
|
-
}) : target, mod));
|
|
24
|
-
|
|
25
|
-
//#endregion
|
|
26
|
-
let react = require("react");
|
|
27
|
-
react = __toESM(react);
|
|
28
|
-
let react_jsx_runtime = require("react/jsx-runtime");
|
|
29
|
-
react_jsx_runtime = __toESM(react_jsx_runtime);
|
|
30
|
-
|
|
31
|
-
//#region src/client/RuntimeSeat.tsx
|
|
32
|
-
const NATIVE = {
|
|
33
|
-
key: "native",
|
|
34
|
-
label: "DSH",
|
|
35
|
-
path: "/"
|
|
36
|
-
};
|
|
37
|
-
/** Fallback labels for the read-only face (which only reports keys). */
|
|
38
|
-
const RUNTIME_LABELS = {
|
|
39
|
-
native: "DSH",
|
|
40
|
-
omp: "OMP",
|
|
41
|
-
codex: "Codex"
|
|
42
|
-
};
|
|
43
|
-
function fromGlobal() {
|
|
44
|
-
const agents = globalThis.__DSH_AGENT_ROSTER__?.agents;
|
|
45
|
-
if (!Array.isArray(agents)) return void 0;
|
|
46
|
-
const links = [];
|
|
47
|
-
for (const entry of agents) {
|
|
48
|
-
if (typeof entry !== "object" || entry === null) continue;
|
|
49
|
-
const { key, label, path } = entry;
|
|
50
|
-
if (typeof key !== "string" || typeof path !== "string") continue;
|
|
51
|
-
links.push({
|
|
52
|
-
key,
|
|
53
|
-
label: typeof label === "string" ? label : RUNTIME_LABELS[key] ?? key,
|
|
54
|
-
path
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
return links.length > 0 ? links : void 0;
|
|
58
|
-
}
|
|
59
|
-
/** Normalize the current mount root: `/omp` and `/omp/` are the same page. */
|
|
60
|
-
function currentPath() {
|
|
61
|
-
const pathname = typeof location === "undefined" ? "/" : location.pathname;
|
|
62
|
-
if (pathname === "" || pathname === "/") return "/";
|
|
63
|
-
return pathname.endsWith("/") ? pathname : `${pathname}/`;
|
|
64
|
-
}
|
|
65
|
-
function RuntimeSeat({ wide }) {
|
|
66
|
-
const [agents, setAgents] = react.useState(() => fromGlobal() ?? [NATIVE]);
|
|
67
|
-
const [open, setOpen] = react.useState(false);
|
|
68
|
-
const rootRef = react.useRef(null);
|
|
69
|
-
react.useEffect(() => {
|
|
70
|
-
let cancelled = false;
|
|
71
|
-
fetch("/api/agent-runtime", { credentials: "same-origin" }).then((r) => r.ok ? r.json() : Promise.reject(/* @__PURE__ */ new Error(`HTTP ${r.status}`))).then((j) => {
|
|
72
|
-
if (cancelled) return;
|
|
73
|
-
if (Array.isArray(j?.agents)) {
|
|
74
|
-
const listed = [];
|
|
75
|
-
for (const entry of j.agents) {
|
|
76
|
-
if (typeof entry !== "object" || entry === null) continue;
|
|
77
|
-
const { key, label, path } = entry;
|
|
78
|
-
if (typeof key !== "string" || typeof path !== "string") continue;
|
|
79
|
-
listed.push({
|
|
80
|
-
key,
|
|
81
|
-
label: typeof label === "string" ? label : RUNTIME_LABELS[key] ?? key,
|
|
82
|
-
path
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
if (listed.length > 0) {
|
|
86
|
-
setAgents(listed);
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
if (!Array.isArray(j?.available)) return;
|
|
91
|
-
const links = [];
|
|
92
|
-
for (const key of j.available) {
|
|
93
|
-
if (typeof key !== "string") continue;
|
|
94
|
-
links.push(key === "native" ? NATIVE : {
|
|
95
|
-
key,
|
|
96
|
-
label: RUNTIME_LABELS[key] ?? key,
|
|
97
|
-
path: `/${key}/`
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
if (links.length > 0) setAgents(links);
|
|
101
|
-
}).catch(() => {});
|
|
102
|
-
return () => {
|
|
103
|
-
cancelled = true;
|
|
104
|
-
};
|
|
105
|
-
}, []);
|
|
106
|
-
react.useEffect(() => {
|
|
107
|
-
if (!open) return;
|
|
108
|
-
const onDown = (event) => {
|
|
109
|
-
if (rootRef.current !== null && !rootRef.current.contains(event.target)) setOpen(false);
|
|
110
|
-
};
|
|
111
|
-
document.addEventListener("mousedown", onDown);
|
|
112
|
-
return () => document.removeEventListener("mousedown", onDown);
|
|
113
|
-
}, [open]);
|
|
114
|
-
const here = currentPath();
|
|
115
|
-
const active = agents.find((agent) => agent.path === here) ?? NATIVE;
|
|
116
|
-
const styleBase = {
|
|
117
|
-
display: "flex",
|
|
118
|
-
alignItems: "center",
|
|
119
|
-
gap: 8,
|
|
120
|
-
width: "100%",
|
|
121
|
-
padding: wide ? "7px 10px" : "7px 0",
|
|
122
|
-
justifyContent: wide ? "flex-start" : "center",
|
|
123
|
-
border: "none",
|
|
124
|
-
borderRadius: 8,
|
|
125
|
-
background: "transparent",
|
|
126
|
-
color: "inherit",
|
|
127
|
-
font: "inherit",
|
|
128
|
-
fontSize: 13,
|
|
129
|
-
cursor: "pointer",
|
|
130
|
-
position: "relative"
|
|
131
|
-
};
|
|
132
|
-
const styleBadge = {
|
|
133
|
-
fontSize: 10,
|
|
134
|
-
lineHeight: 1.4,
|
|
135
|
-
padding: "1px 6px",
|
|
136
|
-
borderRadius: 999,
|
|
137
|
-
background: "color-mix(in srgb, currentColor 12%, transparent)",
|
|
138
|
-
whiteSpace: "nowrap"
|
|
139
|
-
};
|
|
140
|
-
const styleMenu = {
|
|
141
|
-
position: "absolute",
|
|
142
|
-
bottom: "calc(100% + 6px)",
|
|
143
|
-
left: 6,
|
|
144
|
-
right: 6,
|
|
145
|
-
zIndex: 40,
|
|
146
|
-
background: "var(--dsh-surface, #26262b)",
|
|
147
|
-
border: "1px solid color-mix(in srgb, currentColor 18%, transparent)",
|
|
148
|
-
borderRadius: 10,
|
|
149
|
-
boxShadow: "0 8px 24px rgba(0,0,0,.35)",
|
|
150
|
-
overflow: "hidden"
|
|
151
|
-
};
|
|
152
|
-
const styleItem = (isActive) => ({
|
|
153
|
-
display: "block",
|
|
154
|
-
width: "100%",
|
|
155
|
-
padding: "8px 12px",
|
|
156
|
-
border: "none",
|
|
157
|
-
background: isActive ? "color-mix(in srgb, currentColor 10%, transparent)" : "transparent",
|
|
158
|
-
color: "inherit",
|
|
159
|
-
font: "inherit",
|
|
160
|
-
fontSize: 13,
|
|
161
|
-
textAlign: "left",
|
|
162
|
-
cursor: "pointer"
|
|
163
|
-
});
|
|
164
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
165
|
-
ref: rootRef,
|
|
166
|
-
style: {
|
|
167
|
-
position: "relative",
|
|
168
|
-
width: "100%"
|
|
169
|
-
},
|
|
170
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
171
|
-
type: "button",
|
|
172
|
-
style: styleBase,
|
|
173
|
-
title: "Agent runtime — picking one opens that runtime's mount (/omp/, /codex/, …)",
|
|
174
|
-
onClick: () => {
|
|
175
|
-
setOpen((v) => !v);
|
|
176
|
-
},
|
|
177
|
-
children: wide ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
178
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
179
|
-
"aria-hidden": true,
|
|
180
|
-
children: "⌘"
|
|
181
|
-
}),
|
|
182
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
183
|
-
style: {
|
|
184
|
-
flex: 1,
|
|
185
|
-
textAlign: "left",
|
|
186
|
-
whiteSpace: "nowrap",
|
|
187
|
-
overflow: "hidden",
|
|
188
|
-
textOverflow: "ellipsis"
|
|
189
|
-
},
|
|
190
|
-
children: ["Agent · ", active.label]
|
|
191
|
-
}),
|
|
192
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
193
|
-
style: styleBadge,
|
|
194
|
-
children: "open"
|
|
195
|
-
})
|
|
196
|
-
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
197
|
-
"aria-hidden": true,
|
|
198
|
-
children: "⌘"
|
|
199
|
-
})
|
|
200
|
-
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
201
|
-
style: styleMenu,
|
|
202
|
-
children: agents.map((agent) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
203
|
-
href: agent.path,
|
|
204
|
-
style: {
|
|
205
|
-
...styleItem(agent.path === here),
|
|
206
|
-
textDecoration: "none"
|
|
207
|
-
},
|
|
208
|
-
"aria-current": agent.path === here ? "page" : void 0,
|
|
209
|
-
onClick: () => {
|
|
210
|
-
setOpen(false);
|
|
211
|
-
},
|
|
212
|
-
children: agent.path === here ? `${agent.label} ✓` : agent.label
|
|
213
|
-
}, agent.key))
|
|
214
|
-
})]
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
//#endregion
|
|
219
|
-
//#region src/client/index.ts
|
|
220
|
-
/** Required services (cordis fiber inject): the slot registry. */
|
|
221
|
-
const inject = ["slots"];
|
|
222
|
-
/**
|
|
223
|
-
* Mount the selector. Degrades silently when the slot service is absent (a
|
|
224
|
-
* composition without the sidebar renders nothing — a footer action is an
|
|
225
|
-
* optional occupant by contract).
|
|
226
|
-
*
|
|
227
|
-
* @param ctx - client root context.
|
|
228
|
-
*/
|
|
229
|
-
function apply(ctx) {
|
|
230
|
-
ctx.inject(["slots"], (raw) => {
|
|
231
|
-
const scope = raw;
|
|
232
|
-
scope.effect(() => scope.slots.inject("sidebar.footer.action", () => scope.slots.register({
|
|
233
|
-
name: "sidebar.footer.action",
|
|
234
|
-
id: "agent-runtime"
|
|
235
|
-
}, RuntimeSeat)), "agent-hub: runtime footer action");
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
//#endregion
|
|
240
|
-
exports.apply = apply;
|
|
241
|
-
exports.inject = inject;
|
|
242
|
-
return module.exports; } });
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The `agentPreset` session projection, owned by the bridge.
|
|
3
|
-
*
|
|
4
|
-
* Upstream registers this fold from the `dsh-agent-presets` package, which our
|
|
5
|
-
* patch disables (OMP replaces preset composition wholesale). But the Web UI
|
|
6
|
-
* depends on the projection regardless: the preset hero chip renders only when
|
|
7
|
-
* `session.projectionValues.agentPreset` resolves (`presetOf` in
|
|
8
|
-
* ui-agent-preset/seat-store.ts), and the session-header label reads it too.
|
|
9
|
-
* Without a registrant the projection is absent for every bridge session and
|
|
10
|
-
* both surfaces stay blank — roster or no roster (that was the "no omp mode"
|
|
11
|
-
* bug: the roster service answered `agentPresets/list` 200, yet nothing drove
|
|
12
|
-
* the per-session projection the chip gates on).
|
|
13
|
-
*
|
|
14
|
-
* Same fold as upstream (packages/preset/agent-presets/src/session.ts):
|
|
15
|
-
* initialized from the creation header, advanced by `agent-preset/selected`
|
|
16
|
-
* events, which this bridge already synthesizes (`"omp"`) on every session it
|
|
17
|
-
* prepares. Registered under the provider's own fiber via
|
|
18
|
-
* `ctx.inject(['sessionProjections'])`, so the key lives exactly as long as
|
|
19
|
-
* the provider is mounted.
|
|
20
|
-
*/
|
|
21
|
-
import { z } from "zod";
|
|
22
|
-
const agentPresetSchema = z.union([z.string(), z.null()]);
|
|
23
|
-
/** Current Session preset, initialized from its header and advanced by selection events. */
|
|
24
|
-
export const ompAgentPresetProjection = {
|
|
25
|
-
key: "agentPreset",
|
|
26
|
-
stateSchema: agentPresetSchema,
|
|
27
|
-
// omp-web is single-preset: default every session to "omp" so the header
|
|
28
|
-
// chip resolves for scan-native (never-resumed) sessions too, instead of
|
|
29
|
-
// only those whose log carries an `agent-preset/selected` event.
|
|
30
|
-
init: (header) => header.agentPreset ?? "omp",
|
|
31
|
-
apply: (state, event) => event.type === "agent-preset/selected"
|
|
32
|
-
? event.data.agentPreset
|
|
33
|
-
: state,
|
|
34
|
-
wire: { viewSchema: agentPresetSchema, view: (state) => state },
|
|
35
|
-
stateVersion: 1,
|
|
36
|
-
};
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OMP runtime app home bootstrap — idempotently creates the runtime's OMP home
|
|
3
|
-
* (`<DSH_HOME>/agents/omp/.omp`) and seeds it with the OMP config (config.yml /
|
|
4
|
-
* mcp.json / models.yml / .env) copied once from `~/.omp/agent`. Fail-soft: any
|
|
5
|
-
* error is reported and the host boot continues — the app home is derived state,
|
|
6
|
-
* never a boot gate.
|
|
7
|
-
*/
|
|
8
|
-
import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
9
|
-
import { join } from "node:path";
|
|
10
|
-
import { OMP_HOME, OMP_NATIVE_HOME } from "./knobs.js";
|
|
11
|
-
/** Config files seeded into the app home from the native OMP agent dir. */
|
|
12
|
-
export const APP_HOME_CONFIG_FILES = ["config.yml", "mcp.json", "models.yml", ".env"];
|
|
13
|
-
/**
|
|
14
|
-
* Comma/space separated `mcpServers` names the launcher refuses to inherit
|
|
15
|
-
* (`AW_OMP_MCP_EXCLUDE=zai-vision`). Deployment policy lives in the launcher, so
|
|
16
|
-
* this module never names a vendor.
|
|
17
|
-
*/
|
|
18
|
-
export const OMP_MCP_EXCLUDE_ENV = "AW_OMP_MCP_EXCLUDE";
|
|
19
|
-
/** Native OMP agent dir (`<OMP_NATIVE_HOME>/agent`) — the copy source. */
|
|
20
|
-
function defaultSourceAgentDir() {
|
|
21
|
-
return join(OMP_NATIVE_HOME, "agent");
|
|
22
|
-
}
|
|
23
|
-
/** Parse {@link OMP_MCP_EXCLUDE_ENV} into server names. */
|
|
24
|
-
function excludedMcpServers() {
|
|
25
|
-
return (process.env[OMP_MCP_EXCLUDE_ENV] ?? "")
|
|
26
|
-
.split(/[\s,]+/)
|
|
27
|
-
.map((name) => name.trim())
|
|
28
|
-
.filter((name) => name !== "");
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Drop excluded stdio MCP servers from the app home's `mcp.json`.
|
|
32
|
-
*
|
|
33
|
-
* Why this exists: the native `~/.omp/agent/mcp.json` carries a `npx -y
|
|
34
|
-
* @z_ai/mcp-server@latest` stdio server, and every spawned MCP child is a real
|
|
35
|
-
* process (a live npx install ~200 MB) that this runtime does not need. Seeding
|
|
36
|
-
* copies the file verbatim, so the filter runs after seeding and is idempotent:
|
|
37
|
-
* it only rewrites the document when a listed server was actually present.
|
|
38
|
-
*/
|
|
39
|
-
function pruneMcpServers(appHome, names, warn) {
|
|
40
|
-
if (names.length === 0)
|
|
41
|
-
return;
|
|
42
|
-
const file = join(appHome, "mcp.json");
|
|
43
|
-
if (!existsSync(file))
|
|
44
|
-
return;
|
|
45
|
-
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
46
|
-
const servers = parsed.mcpServers;
|
|
47
|
-
if (servers === undefined || typeof servers !== "object" || servers === null)
|
|
48
|
-
return;
|
|
49
|
-
const removed = names.filter((name) => Object.hasOwn(servers, name));
|
|
50
|
-
if (removed.length === 0)
|
|
51
|
-
return;
|
|
52
|
-
for (const name of removed)
|
|
53
|
-
delete servers[name];
|
|
54
|
-
writeFileSync(file, `${JSON.stringify(parsed, null, 2)}\n`);
|
|
55
|
-
warn?.(`omp-provider: pruned MCP servers from ${file}: ${removed.join(", ")}`);
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Ensure the app home exists and is seeded. Never overwrites an existing file
|
|
59
|
-
* (an already-provisioned app home wins); a missing source file is skipped.
|
|
60
|
-
* Returns the resolved app home path.
|
|
61
|
-
*/
|
|
62
|
-
export function ensureOmpAppHome(options = {}) {
|
|
63
|
-
const appHome = options.appHome ?? OMP_HOME;
|
|
64
|
-
const source = options.sourceAgentDir ?? defaultSourceAgentDir();
|
|
65
|
-
const files = options.files ?? APP_HOME_CONFIG_FILES;
|
|
66
|
-
try {
|
|
67
|
-
mkdirSync(appHome, { recursive: true });
|
|
68
|
-
for (const name of files) {
|
|
69
|
-
const dest = join(appHome, name);
|
|
70
|
-
if (existsSync(dest))
|
|
71
|
-
continue;
|
|
72
|
-
const src = join(source, name);
|
|
73
|
-
if (!existsSync(src))
|
|
74
|
-
continue;
|
|
75
|
-
copyFileSync(src, dest);
|
|
76
|
-
}
|
|
77
|
-
// Deployment policy, data-side: a seeded/kept `mcp.json` may still carry
|
|
78
|
-
// heavy stdio servers this runtime must not inherit (a vendor name does not
|
|
79
|
-
// belong in adapter code, so the launcher names them here).
|
|
80
|
-
pruneMcpServers(appHome, options.excludeMcpServers ?? excludedMcpServers(), options.warn);
|
|
81
|
-
}
|
|
82
|
-
catch (error) {
|
|
83
|
-
options.warn?.(`omp-provider: app-home bootstrap failed (fail-soft): ${String(error)}`);
|
|
84
|
-
}
|
|
85
|
-
return appHome;
|
|
86
|
-
}
|
|
@@ -1,29 +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 pi 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, and the
|
|
8
|
-
* session-header label reads it too. Without a registrant the projection is
|
|
9
|
-
* absent for every adapter session and both surfaces stay blank (the omp
|
|
10
|
-
* line's "no mode" bug).
|
|
11
|
-
*
|
|
12
|
-
* Same fold as upstream; adapter-pi is single-preset: default every session
|
|
13
|
-
* to "pi" so the header chip resolves for scan-native (never-resumed)
|
|
14
|
-
* sessions too. Registered under the provider's own fiber via
|
|
15
|
-
* `ctx.inject(['sessionProjections'])`.
|
|
16
|
-
*/
|
|
17
|
-
import { z } from "zod";
|
|
18
|
-
const agentPresetSchema = z.union([z.string(), z.null()]);
|
|
19
|
-
/** Current Session preset, initialized from its header and advanced by selection events. */
|
|
20
|
-
export const piAgentPresetProjection = {
|
|
21
|
-
key: "agentPreset",
|
|
22
|
-
stateSchema: agentPresetSchema,
|
|
23
|
-
init: (header) => header.agentPreset ?? "pi",
|
|
24
|
-
apply: (state, event) => event.type === "agent-preset/selected"
|
|
25
|
-
? event.data.agentPreset
|
|
26
|
-
: state,
|
|
27
|
-
wire: { viewSchema: agentPresetSchema, view: (state) => state },
|
|
28
|
-
stateVersion: 1,
|
|
29
|
-
};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|