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