super-dsh 0.1.2 → 0.1.3-d
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/dist/agy-sessions.d.ts +2 -1
- package/agent-agy/dist/agy-sessions.js +1 -10
- package/agent-agy/dist/world-plugin.js +2 -4
- package/agent-claude/dist/claude-client.js +4 -2
- package/agent-claude/dist/claude-home.js +0 -8
- package/agent-claude/dist/session-map.js +1 -4
- package/agent-codex/dist/codex-store.js +0 -9
- package/agent-codex/dist/session-map.js +1 -4
- package/agent-codex/dist/world-plugin.js +2 -4
- package/agent-codex/package.json +5 -2
- package/agent-hermes/dist/hermes-store.js +1 -10
- package/agent-hermes/dist/world-plugin.js +2 -4
- package/agent-hermes/package.json +5 -2
- package/agent-hub/dist/index.d.ts +1 -1
- package/agent-hub/dist/index.js +1 -1
- package/agent-hub/dist/world-join.js +2 -4
- package/agent-hub/dist/world-provision.d.ts +14 -0
- package/agent-hub/dist/world-provision.js +73 -14
- package/agent-omp/dist/world-plugin.js +2 -4
- package/agent-omp/package.json +6 -3
- package/agent-pi/dist/pi-home.js +1 -11
- package/agent-pi/dist/world-plugin.js +2 -4
- package/agent-pi/package.json +5 -2
- package/client/index.js +242 -0
- package/cordis.patch.yml +4 -1
- package/package.json +4 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** Prod homes that must never be resolved into (repo red line). */
|
|
1
2
|
/** One persisted DSH → Antigravity conversation pairing. */
|
|
2
3
|
export interface AgySessionRecord {
|
|
3
4
|
/** The SDK conversation id; `null` until the first turn materializes it. */
|
|
@@ -12,7 +13,7 @@ export interface AgySessionRecord {
|
|
|
12
13
|
export type AgySessionMap = Record<string, AgySessionRecord>;
|
|
13
14
|
/**
|
|
14
15
|
* The adapter's DSH-side world home. Form-A (boot home = DSH home root) nests
|
|
15
|
-
* `agents/agy`; Form-B (already `<root>/agents/agy`) passes through.
|
|
16
|
+
* `agents/agy`; Form-B (already `<root>/agents/agy`) passes through.
|
|
16
17
|
*/
|
|
17
18
|
export declare function resolveAgyWorldHome(home?: string): string;
|
|
18
19
|
export declare function sessionMapPath(home?: string): string;
|
|
@@ -12,23 +12,14 @@
|
|
|
12
12
|
* `conversationId` is `null` until the first turn materializes it.
|
|
13
13
|
*/
|
|
14
14
|
import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
15
|
-
import { homedir } from "node:os";
|
|
16
15
|
import { basename, dirname, join, resolve } from "node:path";
|
|
17
|
-
/** Prod homes that must never be resolved into (repo red line). */
|
|
18
|
-
const PROD_HOMES = [join(homedir(), ".dsh"), join(homedir(), ".superd")];
|
|
19
|
-
function assertNotProdHome(path, label) {
|
|
20
|
-
if (PROD_HOMES.includes(path) || PROD_HOMES.some((p) => path.startsWith(`${p}/`))) {
|
|
21
|
-
throw new Error(`agy-sessions: refusing prod home as ${label}: ${path}`);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
16
|
/**
|
|
25
17
|
* The adapter's DSH-side world home. Form-A (boot home = DSH home root) nests
|
|
26
|
-
* `agents/agy`; Form-B (already `<root>/agents/agy`) passes through.
|
|
18
|
+
* `agents/agy`; Form-B (already `<root>/agents/agy`) passes through.
|
|
27
19
|
*/
|
|
28
20
|
export function resolveAgyWorldHome(home) {
|
|
29
21
|
const base = resolve(home ?? process.env.DSH_HOME ?? join(process.cwd(), ".tests", "aw"));
|
|
30
22
|
const dir = basename(base) === "agy" && basename(dirname(base)) === "agents" ? base : join(base, "agents", "agy");
|
|
31
|
-
assertNotProdHome(dir, "agy world home");
|
|
32
23
|
return dir;
|
|
33
24
|
}
|
|
34
25
|
export function sessionMapPath(home) {
|
|
@@ -16,12 +16,10 @@
|
|
|
16
16
|
import { mkdirSync } from 'node:fs';
|
|
17
17
|
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths';
|
|
18
18
|
import { join } from 'node:path';
|
|
19
|
-
import { spawnWorld, registerAgent, setReady, registerForeignTarget, registerHostMount, mountWorld, worldMountPatches, provisionWorldProfile, } from '../../agent-hub/dist/index.js';
|
|
19
|
+
import { spawnWorld, registerAgent, setReady, registerForeignTarget, registerHostMount, mountWorld, worldMountPatches, provisionWorldProfile, resolveInstallAnchor, } from '../../agent-hub/dist/index.js';
|
|
20
20
|
export const name = 'aw.agent-adapter-agy';
|
|
21
21
|
/** Runtime key — also the mount label. */
|
|
22
22
|
const KEY = 'agy';
|
|
23
|
-
const ANCHOR = process.env.SUPERD_DSH_ANCHOR
|
|
24
|
-
?? '/home/u1/.local/lib/node_modules/@deepseek-ai/dsh/package.json';
|
|
25
23
|
export function apply(ctx) {
|
|
26
24
|
registerAgent({ key: KEY, label: 'Antigravity', ready: false });
|
|
27
25
|
// Harness resolver (env → ~/.dsh): a consumer install has no DSH_HOME and
|
|
@@ -62,7 +60,7 @@ export function apply(ctx) {
|
|
|
62
60
|
const ctxW = await spawnWorld({
|
|
63
61
|
appName: `aw-${KEY}`,
|
|
64
62
|
profileName: 'web',
|
|
65
|
-
installAnchor:
|
|
63
|
+
installAnchor: resolveInstallAnchor(), // lazy: never at module scope — import must stay side-effect-free
|
|
66
64
|
home: worldHome,
|
|
67
65
|
dataHome: worldHome,
|
|
68
66
|
// Adapter-local bundle names resolve from the profile's own
|
|
@@ -57,8 +57,10 @@
|
|
|
57
57
|
import { query as officialQuery } from "@anthropic-ai/claude-agent-sdk";
|
|
58
58
|
import { InputQueue } from "./input-queue.js";
|
|
59
59
|
import { projectClaudeEvent } from "./claude-events.js";
|
|
60
|
-
/** Host Claude Code binary driven through the SDK
|
|
61
|
-
|
|
60
|
+
/** Host Claude Code binary driven through the SDK bridge (spec ruling R5).
|
|
61
|
+
* PATH-resolved like any host CLI: $CLAUDE_EXECUTABLE wins, else a bare
|
|
62
|
+
* "claude" the SDK spawns through PATH. No machine-specific path ships. */
|
|
63
|
+
export const DEFAULT_CLAUDE_EXECUTABLE = "claude";
|
|
62
64
|
const defaultFactory = (o) => officialQuery({
|
|
63
65
|
prompt: o.prompt,
|
|
64
66
|
options: o.options,
|
|
@@ -9,14 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
11
|
import { join, resolve } from "node:path";
|
|
12
|
-
const PROD_HOMES = [join(homedir(), ".dsh"), join(homedir(), ".superd")];
|
|
13
12
|
/** Refuse any path that resolves into a production DSH home (repo red line). */
|
|
14
|
-
export function assertNotProdHome(path, label) {
|
|
15
|
-
const p = resolve(path);
|
|
16
|
-
if (PROD_HOMES.includes(p) || PROD_HOMES.some((prod) => p.startsWith(`${prod}/`))) {
|
|
17
|
-
throw new Error(`agent-claude: refusing prod home "${p}" for ${label} — set DSH_HOME to the test home`);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
13
|
/**
|
|
21
14
|
* The Claude app home: the NATIVE `~/.claude`, prod-home guarded. An ambient
|
|
22
15
|
* `CLAUDE_CONFIG_DIR` wins (tests pin an isolated home that way); the adapter
|
|
@@ -24,6 +17,5 @@ export function assertNotProdHome(path, label) {
|
|
|
24
17
|
*/
|
|
25
18
|
export function resolveClaudeHome() {
|
|
26
19
|
const claudeHome = resolve(process.env.CLAUDE_CONFIG_DIR ?? join(homedir(), ".claude"));
|
|
27
|
-
assertNotProdHome(claudeHome, "claudeHome");
|
|
28
20
|
return claudeHome;
|
|
29
21
|
}
|
|
@@ -26,23 +26,20 @@
|
|
|
26
26
|
*/
|
|
27
27
|
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
28
28
|
import { dirname, join, resolve } from "node:path";
|
|
29
|
-
import { assertNotProdHome } from "./claude-home.js";
|
|
30
29
|
/**
|
|
31
30
|
* The adapter's DSH-side state dir — the world's DSH home root
|
|
32
31
|
* (`<dshHome>/agents/claude`), never the Claude app home. Precedence:
|
|
33
32
|
* explicit world home (boot-provided `dshHomePath`), then `$DSH_HOME` (a hub
|
|
34
33
|
* home, so the world layout nests `agents/claude`), then the line's
|
|
35
|
-
* historical test-home default.
|
|
34
|
+
* historical test-home default.
|
|
36
35
|
*/
|
|
37
36
|
export function resolveClaudeStateDir(home) {
|
|
38
37
|
if (home !== undefined) {
|
|
39
38
|
const dir = resolve(home);
|
|
40
|
-
assertNotProdHome(dir, "claude state dir");
|
|
41
39
|
return dir;
|
|
42
40
|
}
|
|
43
41
|
const fallbackHome = resolve(process.env.DSH_HOME ?? join(process.cwd(), ".tests", "aw"));
|
|
44
42
|
const dir = join(fallbackHome, "agents", "claude");
|
|
45
|
-
assertNotProdHome(dir, "claude state dir");
|
|
46
43
|
return dir;
|
|
47
44
|
}
|
|
48
45
|
/** The map file's path at the world DSH-home root. */
|
|
@@ -20,12 +20,6 @@ import { closeSync, openSync, readdirSync, readSync, statSync } from "node:fs";
|
|
|
20
20
|
import { homedir } from "node:os";
|
|
21
21
|
import { join, resolve } from "node:path";
|
|
22
22
|
/** Prod homes that must never be resolved into (repo red line). */
|
|
23
|
-
const PROD_HOMES = [join(homedir(), ".dsh"), join(homedir(), ".superd")];
|
|
24
|
-
export function assertNotProdHome(path, label) {
|
|
25
|
-
if (PROD_HOMES.includes(path) || PROD_HOMES.some((p) => path.startsWith(`${p}/`))) {
|
|
26
|
-
throw new Error(`codex-store: refusing prod home as ${label}: ${path}`);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
23
|
/**
|
|
30
24
|
* Resolve the Codex CLI's app-data home — the NATIVE `~/.codex` (user ruling
|
|
31
25
|
* 2026-09-17, pi precedent): the installed app keeps its own home, so the
|
|
@@ -42,11 +36,9 @@ export function assertNotProdHome(path, label) {
|
|
|
42
36
|
export function resolveCodexHome() {
|
|
43
37
|
if (process.env.CODEX_HOME !== undefined) {
|
|
44
38
|
const env = resolve(process.env.CODEX_HOME);
|
|
45
|
-
assertNotProdHome(env, "codex home");
|
|
46
39
|
return env;
|
|
47
40
|
}
|
|
48
41
|
const native = join(homedir(), ".codex");
|
|
49
|
-
assertNotProdHome(native, "codex home");
|
|
50
42
|
return native;
|
|
51
43
|
}
|
|
52
44
|
/**
|
|
@@ -56,7 +48,6 @@ export function resolveCodexHome() {
|
|
|
56
48
|
*/
|
|
57
49
|
export function useCodexHome(path) {
|
|
58
50
|
const resolved = resolve(path);
|
|
59
|
-
assertNotProdHome(resolved, "codex home");
|
|
60
51
|
return resolved;
|
|
61
52
|
}
|
|
62
53
|
/** Bounded read budget: `session_meta` is the FIRST line, so this is generous. */
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
*/
|
|
20
20
|
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
21
21
|
import { dirname, join, resolve } from "node:path";
|
|
22
|
-
import { assertNotProdHome } from "./codex-store.js";
|
|
23
22
|
/** An `Error` carrying a stable {@link CodexResumeErrorCode}. */
|
|
24
23
|
export class CodexResumeError extends Error {
|
|
25
24
|
code;
|
|
@@ -35,17 +34,15 @@ export class CodexResumeError extends Error {
|
|
|
35
34
|
* (`<dshHome>/agents/codex`), never the codex app home. Precedence: explicit
|
|
36
35
|
* world home (boot-provided `dshHomePath`), then `$DSH_HOME` (a hub home, so
|
|
37
36
|
* the world layout nests `agents/codex`), then the line's historical test-home
|
|
38
|
-
* default.
|
|
37
|
+
* default.
|
|
39
38
|
*/
|
|
40
39
|
export function resolveCodexStateDir(home) {
|
|
41
40
|
if (home !== undefined) {
|
|
42
41
|
const dir = resolve(home);
|
|
43
|
-
assertNotProdHome(dir, "codex state dir");
|
|
44
42
|
return dir;
|
|
45
43
|
}
|
|
46
44
|
const fallbackHome = resolve(process.env.DSH_HOME ?? join(process.cwd(), ".tests", "aw"));
|
|
47
45
|
const dir = join(fallbackHome, "agents", "codex");
|
|
48
|
-
assertNotProdHome(dir, "codex state dir");
|
|
49
46
|
return dir;
|
|
50
47
|
}
|
|
51
48
|
/** The map file's path at the world DSH-home root. */
|
|
@@ -16,12 +16,10 @@
|
|
|
16
16
|
import { mkdirSync } from 'node:fs';
|
|
17
17
|
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths';
|
|
18
18
|
import { join } from 'node:path';
|
|
19
|
-
import { spawnWorld, registerAgent, setReady, registerForeignTarget, registerHostMount, mountWorld, worldMountPatches, provisionWorldProfile, } from '../../agent-hub/dist/index.js';
|
|
19
|
+
import { spawnWorld, registerAgent, setReady, registerForeignTarget, registerHostMount, mountWorld, worldMountPatches, provisionWorldProfile, resolveInstallAnchor, } from '../../agent-hub/dist/index.js';
|
|
20
20
|
export const name = 'aw.agent-adapter-codex';
|
|
21
21
|
/** Runtime key — also the mount label. */
|
|
22
22
|
const KEY = 'codex';
|
|
23
|
-
const ANCHOR = process.env.SUPERD_DSH_ANCHOR
|
|
24
|
-
?? '/home/u1/.local/lib/node_modules/@deepseek-ai/dsh/package.json';
|
|
25
23
|
export function apply(ctx) {
|
|
26
24
|
registerAgent({ key: KEY, label: 'Codex', ready: false });
|
|
27
25
|
// Harness resolver (env → ~/.dsh): a consumer install has no DSH_HOME and
|
|
@@ -61,7 +59,7 @@ export function apply(ctx) {
|
|
|
61
59
|
const ctxW = await spawnWorld({
|
|
62
60
|
appName: `aw-${KEY}`,
|
|
63
61
|
profileName: 'web',
|
|
64
|
-
installAnchor:
|
|
62
|
+
installAnchor: resolveInstallAnchor(), // lazy: never at module scope — import must stay side-effect-free
|
|
65
63
|
home: worldHome,
|
|
66
64
|
dataHome: worldHome,
|
|
67
65
|
// Adapter-local bundle names resolve from the profile's own
|
package/agent-codex/package.json
CHANGED
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@openai/codex": "0.154.0",
|
|
26
26
|
"@openai/codex-sdk": "0.154.0",
|
|
27
|
-
"@pgmi-builds/agent-hub": "file:../agent-hub",
|
|
28
27
|
"zod": "3.25.76"
|
|
29
28
|
},
|
|
30
29
|
"peerDependencies": {
|
|
@@ -35,7 +34,8 @@
|
|
|
35
34
|
"@deepseek-ai/dsh-scope": "0.1.5-rc.2",
|
|
36
35
|
"@deepseek-ai/dsh-session": "0.1.5-rc.2",
|
|
37
36
|
"@deepseek-ai/dsh-session-persistence": "0.1.5-rc.2",
|
|
38
|
-
"@deepseek-ai/dsh-typert-protocol": "0.1.5-rc.2"
|
|
37
|
+
"@deepseek-ai/dsh-typert-protocol": "0.1.5-rc.2",
|
|
38
|
+
"@pgmi-builds/agent-hub": "*"
|
|
39
39
|
},
|
|
40
40
|
"peerDependenciesMeta": {
|
|
41
41
|
"@deepseek-ai/cordis": {
|
|
@@ -61,6 +61,9 @@
|
|
|
61
61
|
},
|
|
62
62
|
"@deepseek-ai/dsh-typert-protocol": {
|
|
63
63
|
"optional": true
|
|
64
|
+
},
|
|
65
|
+
"@pgmi-builds/agent-hub": {
|
|
66
|
+
"optional": true
|
|
64
67
|
}
|
|
65
68
|
},
|
|
66
69
|
"devDependencies": {
|
|
@@ -19,15 +19,7 @@
|
|
|
19
19
|
* degrades to "unknown session" rather than breaking every operation.
|
|
20
20
|
*/
|
|
21
21
|
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
22
|
-
import { homedir } from "node:os";
|
|
23
22
|
import { basename, dirname, join, resolve } from "node:path";
|
|
24
|
-
/** Prod homes that must never be resolved into (repo red line). */
|
|
25
|
-
const PROD_HOMES = [join(homedir(), ".dsh"), join(homedir(), ".superd")];
|
|
26
|
-
function assertNotProdHome(path, label) {
|
|
27
|
-
if (PROD_HOMES.includes(path) || PROD_HOMES.some((p) => path.startsWith(`${p}/`))) {
|
|
28
|
-
throw new Error(`hermes-store: refusing prod home as ${label}: ${path}`);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
23
|
/**
|
|
32
24
|
* The adapter's DSH-side state dir — `<dshHome>/agents/hermes`. This is DSH-SIDE
|
|
33
25
|
* adapter state (the identity map), NOT hermes data: hermes keeps its native
|
|
@@ -40,13 +32,12 @@ function assertNotProdHome(path, label) {
|
|
|
40
32
|
* - Form-B: the boot-provided home is ALREADY the world home
|
|
41
33
|
* (`<root>/agents/hermes`) — passed through as-is, never double-nested.
|
|
42
34
|
* Precedence: explicit home (boot-provided `dshHomePath`), then `$DSH_HOME`,
|
|
43
|
-
* then the line's historical test-home default.
|
|
35
|
+
* then the line's historical test-home default.
|
|
44
36
|
*/
|
|
45
37
|
export function resolveHermesAppDir(home) {
|
|
46
38
|
const base = resolve(home ?? process.env.DSH_HOME ?? join(process.cwd(), ".tests", "aw"));
|
|
47
39
|
// Form-B world home is already `<root>/agents/hermes` — never double-nest.
|
|
48
40
|
const dir = basename(base) === "hermes" && basename(dirname(base)) === "agents" ? base : join(base, "agents", "hermes");
|
|
49
|
-
assertNotProdHome(dir, "hermes app dir");
|
|
50
41
|
return dir;
|
|
51
42
|
}
|
|
52
43
|
/** The map file's path inside the adapter's DSH-side app dir. */
|
|
@@ -17,12 +17,10 @@
|
|
|
17
17
|
import { mkdirSync } from 'node:fs';
|
|
18
18
|
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths';
|
|
19
19
|
import { join } from 'node:path';
|
|
20
|
-
import { spawnWorld, registerAgent, setReady, registerForeignTarget, registerHostMount, mountWorld, worldMountPatches, provisionWorldProfile, } from '../../agent-hub/dist/index.js';
|
|
20
|
+
import { spawnWorld, registerAgent, setReady, registerForeignTarget, registerHostMount, mountWorld, worldMountPatches, provisionWorldProfile, resolveInstallAnchor, } from '../../agent-hub/dist/index.js';
|
|
21
21
|
export const name = 'aw.agent-adapter-hermes';
|
|
22
22
|
/** Runtime key — also the mount label. */
|
|
23
23
|
const KEY = 'hermes';
|
|
24
|
-
const ANCHOR = process.env.SUPERD_DSH_ANCHOR
|
|
25
|
-
?? '/home/u1/.local/lib/node_modules/@deepseek-ai/dsh/package.json';
|
|
26
24
|
export function apply(ctx) {
|
|
27
25
|
registerAgent({ key: KEY, label: 'Hermes', ready: false });
|
|
28
26
|
// Harness resolver (env → ~/.dsh): a consumer install has no DSH_HOME and
|
|
@@ -66,7 +64,7 @@ export function apply(ctx) {
|
|
|
66
64
|
const ctxW = await spawnWorld({
|
|
67
65
|
appName: `aw-${KEY}`,
|
|
68
66
|
profileName: 'web',
|
|
69
|
-
installAnchor:
|
|
67
|
+
installAnchor: resolveInstallAnchor(), // lazy: never at module scope — import must stay side-effect-free
|
|
70
68
|
home: worldHome,
|
|
71
69
|
dataHome: worldHome,
|
|
72
70
|
// Adapter-local bundle names resolve from the profile's own
|
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
"test": "node --test test/*.test.mjs"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@pgmi-builds/agent-hub": "file:../agent-hub",
|
|
26
25
|
"zod": "3.25.76"
|
|
27
26
|
},
|
|
28
27
|
"peerDependencies": {
|
|
@@ -33,7 +32,8 @@
|
|
|
33
32
|
"@deepseek-ai/dsh-scope": "0.1.5-rc.2",
|
|
34
33
|
"@deepseek-ai/dsh-session": "0.1.5-rc.2",
|
|
35
34
|
"@deepseek-ai/dsh-session-persistence": "0.1.5-rc.2",
|
|
36
|
-
"@deepseek-ai/dsh-typert-protocol": "0.1.5-rc.2"
|
|
35
|
+
"@deepseek-ai/dsh-typert-protocol": "0.1.5-rc.2",
|
|
36
|
+
"@pgmi-builds/agent-hub": "*"
|
|
37
37
|
},
|
|
38
38
|
"peerDependenciesMeta": {
|
|
39
39
|
"@deepseek-ai/cordis": {
|
|
@@ -59,6 +59,9 @@
|
|
|
59
59
|
},
|
|
60
60
|
"@deepseek-ai/dsh-typert-protocol": {
|
|
61
61
|
"optional": true
|
|
62
|
+
},
|
|
63
|
+
"@pgmi-builds/agent-hub": {
|
|
64
|
+
"optional": true
|
|
62
65
|
}
|
|
63
66
|
},
|
|
64
67
|
"devDependencies": {
|
|
@@ -13,7 +13,7 @@ export { handleAgentRuntime, registerSelectorRpc, AGENT_RUNTIME_RPC_PATH, regist
|
|
|
13
13
|
export { registerForeignTarget, unregisterForeignTarget, getTarget, listRuntimeKeys, type ForeignTarget, type GatewayFace } from './targets.js';
|
|
14
14
|
export { registerAgent, unregisterAgent, setReady, listAgents, onRosterChanged, type RosterEntry } from './roster.js';
|
|
15
15
|
export { spawnWorld, type SpawnWorldOptions } from './spawn-world.js';
|
|
16
|
-
export { provisionWorldProfile, type ProvisionWorldOptions } from './world-provision.js';
|
|
16
|
+
export { provisionWorldProfile, resolveInstallAnchor, type ProvisionWorldOptions } from './world-provision.js';
|
|
17
17
|
export { claimLabel, labelOf, releaseLabel, listLabels, type LabelClaim, type ClaimOptions } from './labels.js';
|
|
18
18
|
export { WorldWebServer, stripLabelFromUrl, type WorldWebRoute, type WorldWebUpgradeRoute, type RealWebServerFace } from './world-web-server.js';
|
|
19
19
|
export { parseClientRequest, serverResponse, serverError, serverResult, wireErrorOf, EnvelopeError, type ClientRequestEnvelope, type WireError } from './envelope.js';
|
package/agent-hub/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ export { handleAgentRuntime, registerSelectorRpc, AGENT_RUNTIME_RPC_PATH, regist
|
|
|
13
13
|
export { registerForeignTarget, unregisterForeignTarget, getTarget, listRuntimeKeys } from './targets.js';
|
|
14
14
|
export { registerAgent, unregisterAgent, setReady, listAgents, onRosterChanged } from './roster.js';
|
|
15
15
|
export { spawnWorld } from './spawn-world.js';
|
|
16
|
-
export { provisionWorldProfile } from './world-provision.js';
|
|
16
|
+
export { provisionWorldProfile, resolveInstallAnchor } from './world-provision.js';
|
|
17
17
|
export { claimLabel, labelOf, releaseLabel, listLabels } from './labels.js';
|
|
18
18
|
export { WorldWebServer, stripLabelFromUrl } from './world-web-server.js';
|
|
19
19
|
export { parseClientRequest, serverResponse, serverError, serverResult, wireErrorOf, EnvelopeError } from './envelope.js';
|
|
@@ -31,14 +31,12 @@ import { join } from 'node:path';
|
|
|
31
31
|
import { registerAgent, setReady } from './roster.js';
|
|
32
32
|
import { registerForeignTarget } from './targets.js';
|
|
33
33
|
import { spawnWorld } from './spawn-world.js';
|
|
34
|
-
import { provisionWorldProfile } from './world-provision.js';
|
|
34
|
+
import { provisionWorldProfile, resolveInstallAnchor } from './world-provision.js';
|
|
35
35
|
import { registerHostMount } from './world-host.js';
|
|
36
36
|
import { mountWorld } from './carrier.js';
|
|
37
37
|
import { worldMountPatches } from './world-mount.js';
|
|
38
38
|
/** Stable Cordis plugin name. */
|
|
39
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
40
|
/** Apply the join. @param ctx - the CTX0 root context. @param config - `{ key, label? }`. */
|
|
43
41
|
export function apply(ctx, config) {
|
|
44
42
|
const key = typeof config?.key === 'string' ? config.key : undefined;
|
|
@@ -86,7 +84,7 @@ export function apply(ctx, config) {
|
|
|
86
84
|
const ctxW = await spawnWorld({
|
|
87
85
|
appName: `aw-${key}`,
|
|
88
86
|
profileName: 'web',
|
|
89
|
-
installAnchor:
|
|
87
|
+
installAnchor: resolveInstallAnchor(), // lazy: never at module scope — import must stay side-effect-free
|
|
90
88
|
home: worldHome,
|
|
91
89
|
dataHome: worldHome,
|
|
92
90
|
// Adapter-local bundle names resolve from the profile's own
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the running dsh installation's package.json — the anchor worlds
|
|
3
|
+
* resolve `@deepseek-ai` bundles and the fallback closure from.
|
|
4
|
+
*
|
|
5
|
+
* Precedence: `$SUPERD_DSH_ANCHOR` (the repo dev lines' contract — the
|
|
6
|
+
* launcher pins the checkout build), then a walk UP from the
|
|
7
|
+
* `@deepseek-ai/dsh-app-boot` this module resolved (the host always provides
|
|
8
|
+
* it) to the nearest ancestor package named `@deepseek-ai/dsh` — the
|
|
9
|
+
* packaged-install layout (`<install>/@deepseek-ai/dsh/node_modules/
|
|
10
|
+
* @deepseek-ai/dsh-app-boot`) lands on the install root in two hops. No
|
|
11
|
+
* machine-specific path ships in code.
|
|
12
|
+
* @throws when neither yields an installation (mis-launched composition).
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveInstallAnchor(): string;
|
|
1
15
|
export interface ProvisionWorldOptions {
|
|
2
16
|
/** Runtime key — also the mount label and the `agents/<key>` home segment. */
|
|
3
17
|
key: string;
|
|
@@ -32,14 +32,61 @@
|
|
|
32
32
|
* or null when the adapter sibling does not exist next to the hub (a foreign
|
|
33
33
|
* composition this module does not own — keep the caller's env/fallback path).
|
|
34
34
|
*/
|
|
35
|
-
import { existsSync, lstatSync, mkdirSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
35
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
36
36
|
import { dirname, join } from 'node:path';
|
|
37
37
|
import { fileURLToPath } from 'node:url';
|
|
38
38
|
import { createRequire } from 'node:module';
|
|
39
|
+
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths';
|
|
39
40
|
const HUB_SCOPE = '@pgmi-builds';
|
|
40
41
|
const HARNESS_SCOPE = '@deepseek-ai';
|
|
41
42
|
/** The profile bundles every world tree composes besides its adapter. */
|
|
42
43
|
const WORLD_BASE_BUNDLES = ['@deepseek-ai/dsh-base', '@deepseek-ai/dsh-web-app'];
|
|
44
|
+
/**
|
|
45
|
+
* Resolve the running dsh installation's package.json — the anchor worlds
|
|
46
|
+
* resolve `@deepseek-ai` bundles and the fallback closure from.
|
|
47
|
+
*
|
|
48
|
+
* Precedence: `$SUPERD_DSH_ANCHOR` (the repo dev lines' contract — the
|
|
49
|
+
* launcher pins the checkout build), then a walk UP from the
|
|
50
|
+
* `@deepseek-ai/dsh-app-boot` this module resolved (the host always provides
|
|
51
|
+
* it) to the nearest ancestor package named `@deepseek-ai/dsh` — the
|
|
52
|
+
* packaged-install layout (`<install>/@deepseek-ai/dsh/node_modules/
|
|
53
|
+
* @deepseek-ai/dsh-app-boot`) lands on the install root in two hops. No
|
|
54
|
+
* machine-specific path ships in code.
|
|
55
|
+
* @throws when neither yields an installation (mis-launched composition).
|
|
56
|
+
*/
|
|
57
|
+
export function resolveInstallAnchor() {
|
|
58
|
+
const fromEnv = process.env.SUPERD_DSH_ANCHOR;
|
|
59
|
+
if (fromEnv !== undefined && fromEnv !== '')
|
|
60
|
+
return fromEnv;
|
|
61
|
+
let dir = dirname(resolveHostPackageDir('@deepseek-ai/dsh-app-boot'));
|
|
62
|
+
while (true) {
|
|
63
|
+
const manifest = join(dir, 'package.json');
|
|
64
|
+
if (existsSync(manifest)) {
|
|
65
|
+
try {
|
|
66
|
+
const name = JSON.parse(readFileSync(manifest, 'utf8')).name;
|
|
67
|
+
if (name === '@deepseek-ai/dsh')
|
|
68
|
+
return manifest;
|
|
69
|
+
}
|
|
70
|
+
catch { /* malformed intermediate manifest — keep walking */ }
|
|
71
|
+
}
|
|
72
|
+
const parent = dirname(dir);
|
|
73
|
+
if (parent === dir) {
|
|
74
|
+
throw new Error('super-dsh: cannot derive the dsh installation anchor (set SUPERD_DSH_ANCHOR)');
|
|
75
|
+
}
|
|
76
|
+
dir = parent;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** First `node_modules` search-path candidate that exists for a specifier,
|
|
80
|
+
* resolved to its REALPATH — farm and pnpm links must not leak into the
|
|
81
|
+
* ancestor walk (the install tree only exists behind the symlink). */
|
|
82
|
+
function resolveHostPackageDir(spec) {
|
|
83
|
+
for (const searchPath of createRequire(import.meta.url).resolve.paths(`${spec}/x`) ?? []) {
|
|
84
|
+
const candidate = join(searchPath, spec);
|
|
85
|
+
if (existsSync(join(candidate, 'package.json')))
|
|
86
|
+
return realpathSync(candidate);
|
|
87
|
+
}
|
|
88
|
+
throw new Error(`super-dsh: cannot resolve ${spec} from the running host`);
|
|
89
|
+
}
|
|
43
90
|
/**
|
|
44
91
|
* Provision one world's nested profile (idempotent: rewrites profile files,
|
|
45
92
|
* re-links packages — lstat-safe against dangling links). Returns the
|
|
@@ -103,20 +150,32 @@ function provisionWorldProfileUnchecked(opts) {
|
|
|
103
150
|
rmSync(dst, { recursive: true, force: true });
|
|
104
151
|
symlinkSync(target, dst);
|
|
105
152
|
}
|
|
106
|
-
// The harness scope
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
153
|
+
// The harness scope for the world tree is a REAL scope directory of
|
|
154
|
+
// per-package symlinks UNIONED from two authoritative sources (farm first,
|
|
155
|
+
// installation fills the gaps — dev3 evidence: farm 244 entries missing 16
|
|
156
|
+
// newer packages the install's 260 has; ctx0 survives via the app-boot
|
|
157
|
+
// install-anchored resolver fallback, but a tree with an explicit bare
|
|
158
|
+
// base gets no such fallback). A single scope-level link cannot express
|
|
159
|
+
// that union, and a resolve.paths() walk from this module can pick the
|
|
160
|
+
// PROFILE's own partial pnpm scope (2 entries on dev3) — never use it.
|
|
161
|
+
const ANCHOR = resolveInstallAnchor();
|
|
162
|
+
const scopeSources = [
|
|
163
|
+
join(resolveDshHome(), 'profiles', 'node_modules', HARNESS_SCOPE),
|
|
164
|
+
join(dirname(ANCHOR), 'node_modules', HARNESS_SCOPE),
|
|
165
|
+
];
|
|
166
|
+
const scopeDst = join(linkRoot, HARNESS_SCOPE);
|
|
167
|
+
rmSync(scopeDst, { recursive: true, force: true });
|
|
168
|
+
mkdirSync(scopeDst, { recursive: true });
|
|
169
|
+
const linked = new Set();
|
|
170
|
+
for (const scopeSrc of scopeSources) {
|
|
171
|
+
if (!existsSync(scopeSrc))
|
|
113
172
|
continue;
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
173
|
+
for (const name of readdirSync(scopeSrc)) {
|
|
174
|
+
if (name.startsWith('.') || linked.has(name))
|
|
175
|
+
continue;
|
|
176
|
+
symlinkSync(join(scopeSrc, name), join(scopeDst, name));
|
|
177
|
+
linked.add(name);
|
|
178
|
+
}
|
|
120
179
|
}
|
|
121
180
|
return join(opts.worldHome, 'profiles', 'node_modules') + '/';
|
|
122
181
|
}
|
|
@@ -15,12 +15,10 @@
|
|
|
15
15
|
import { mkdirSync } from 'node:fs';
|
|
16
16
|
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths';
|
|
17
17
|
import { join } from 'node:path';
|
|
18
|
-
import { spawnWorld, registerAgent, setReady, registerForeignTarget, registerHostMount, mountWorld, worldMountPatches, provisionWorldProfile, } from '../../agent-hub/dist/index.js';
|
|
18
|
+
import { spawnWorld, registerAgent, setReady, registerForeignTarget, registerHostMount, mountWorld, worldMountPatches, provisionWorldProfile, resolveInstallAnchor, } from '../../agent-hub/dist/index.js';
|
|
19
19
|
export const name = 'aw.agent-adapter-omp';
|
|
20
20
|
/** Runtime key — also the mount label. */
|
|
21
21
|
const KEY = 'omp';
|
|
22
|
-
const ANCHOR = process.env.SUPERD_DSH_ANCHOR
|
|
23
|
-
?? '/home/u1/.local/lib/node_modules/@deepseek-ai/dsh/package.json';
|
|
24
22
|
export function apply(ctx) {
|
|
25
23
|
registerAgent({ key: KEY, label: 'OMP', ready: false });
|
|
26
24
|
// Harness resolver (env → ~/.dsh): a consumer install has no DSH_HOME and
|
|
@@ -61,7 +59,7 @@ export function apply(ctx) {
|
|
|
61
59
|
const ctxW = await spawnWorld({
|
|
62
60
|
appName: `aw-${KEY}`,
|
|
63
61
|
profileName: 'web',
|
|
64
|
-
installAnchor:
|
|
62
|
+
installAnchor: resolveInstallAnchor(), // lazy: never at module scope — import must stay side-effect-free
|
|
65
63
|
home: worldHome,
|
|
66
64
|
dataHome: worldHome,
|
|
67
65
|
// Adapter-local bundle names resolve from the profile's own
|
package/agent-omp/package.json
CHANGED
|
@@ -33,8 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@oh-my-pi/pi-coding-agent": "^18.1.14",
|
|
36
|
-
"bun": "^1.4.2"
|
|
37
|
-
"@pgmi-builds/agent-hub": "file:../agent-hub"
|
|
36
|
+
"bun": "^1.4.2"
|
|
38
37
|
},
|
|
39
38
|
"peerDependencies": {
|
|
40
39
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
@@ -45,7 +44,8 @@
|
|
|
45
44
|
"@deepseek-ai/dsh-session": "0.1.5-rc.2",
|
|
46
45
|
"@deepseek-ai/dsh-session-persistence": "0.1.5-rc.2",
|
|
47
46
|
"@deepseek-ai/dsh-typert-protocol": "0.1.5-rc.2",
|
|
48
|
-
"@deepseek-ai/dsh-home-paths": "0.1.5-rc.2"
|
|
47
|
+
"@deepseek-ai/dsh-home-paths": "0.1.5-rc.2",
|
|
48
|
+
"@pgmi-builds/agent-hub": "*"
|
|
49
49
|
},
|
|
50
50
|
"peerDependenciesMeta": {
|
|
51
51
|
"@deepseek-ai/cordis": {
|
|
@@ -74,6 +74,9 @@
|
|
|
74
74
|
},
|
|
75
75
|
"@deepseek-ai/dsh-home-paths": {
|
|
76
76
|
"optional": true
|
|
77
|
+
},
|
|
78
|
+
"@pgmi-builds/agent-hub": {
|
|
79
|
+
"optional": true
|
|
77
80
|
}
|
|
78
81
|
},
|
|
79
82
|
"devDependencies": {
|
package/agent-pi/dist/pi-home.js
CHANGED
|
@@ -16,19 +16,12 @@
|
|
|
16
16
|
* pi never reads this tree; it is DSH bookkeeping in the same class as the
|
|
17
17
|
* DSH session log.
|
|
18
18
|
*/
|
|
19
|
-
import { homedir } from "node:os";
|
|
20
19
|
import { join, resolve } from "node:path";
|
|
21
20
|
/** Prod homes that must never be resolved into (repo red line). */
|
|
22
|
-
const PROD_HOMES = [join(homedir(), ".dsh"), join(homedir(), ".superd")];
|
|
23
|
-
export function assertNotProdHome(path, label) {
|
|
24
|
-
if (PROD_HOMES.includes(path) || PROD_HOMES.some((p) => path.startsWith(`${p}/`))) {
|
|
25
|
-
throw new Error(`pi-home: refusing prod home as ${label}: ${path}`);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
21
|
/**
|
|
29
22
|
* Resolve the adapter's DSH-side state dir — `<dshHomePath>/agents/pi`.
|
|
30
23
|
* Precedence: explicit home (boot-provided `dshHomePath`), then `$DSH_HOME`,
|
|
31
|
-
* then the line's historical test-home default.
|
|
24
|
+
* then the line's historical test-home default.
|
|
32
25
|
*/
|
|
33
26
|
export function resolvePiStateDir(home) {
|
|
34
27
|
if (home !== undefined) {
|
|
@@ -37,16 +30,13 @@ export function resolvePiStateDir(home) {
|
|
|
37
30
|
// — that tree IS the pi world's root, so the state dir is the home itself
|
|
38
31
|
// (no second nest). Line/standalone form: nest once under agents/pi.
|
|
39
32
|
if (resolved.endsWith(join("agents", "pi"))) {
|
|
40
|
-
assertNotProdHome(resolved, "pi state dir");
|
|
41
33
|
return resolved;
|
|
42
34
|
}
|
|
43
35
|
const dir = join(resolved, "agents", "pi");
|
|
44
|
-
assertNotProdHome(dir, "pi state dir");
|
|
45
36
|
return dir;
|
|
46
37
|
}
|
|
47
38
|
const fallbackHome = resolve(process.env.DSH_HOME ?? join(process.cwd(), ".tests", "aw"));
|
|
48
39
|
const dir = join(fallbackHome, "agents", "pi");
|
|
49
|
-
assertNotProdHome(dir, "pi state dir");
|
|
50
40
|
return dir;
|
|
51
41
|
}
|
|
52
42
|
/** The dsh↔pi session mapping file inside the state dir. */
|
|
@@ -16,12 +16,10 @@
|
|
|
16
16
|
import { mkdirSync } from 'node:fs';
|
|
17
17
|
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths';
|
|
18
18
|
import { join } from 'node:path';
|
|
19
|
-
import { spawnWorld, registerAgent, setReady, registerForeignTarget, registerHostMount, mountWorld, worldMountPatches, provisionWorldProfile, } from '../../agent-hub/dist/index.js';
|
|
19
|
+
import { spawnWorld, registerAgent, setReady, registerForeignTarget, registerHostMount, mountWorld, worldMountPatches, provisionWorldProfile, resolveInstallAnchor, } from '../../agent-hub/dist/index.js';
|
|
20
20
|
export const name = 'aw.agent-adapter-pi';
|
|
21
21
|
/** Runtime key — also the mount label. */
|
|
22
22
|
const KEY = 'pi';
|
|
23
|
-
const ANCHOR = process.env.SUPERD_DSH_ANCHOR
|
|
24
|
-
?? '/home/u1/.local/lib/node_modules/@deepseek-ai/dsh/package.json';
|
|
25
23
|
export function apply(ctx) {
|
|
26
24
|
registerAgent({ key: KEY, label: 'Pi', ready: false });
|
|
27
25
|
// Harness resolver (env → ~/.dsh): a consumer install has no DSH_HOME and
|
|
@@ -62,7 +60,7 @@ export function apply(ctx) {
|
|
|
62
60
|
const ctxW = await spawnWorld({
|
|
63
61
|
appName: `aw-${KEY}`,
|
|
64
62
|
profileName: 'web',
|
|
65
|
-
installAnchor:
|
|
63
|
+
installAnchor: resolveInstallAnchor(), // lazy: never at module scope — import must stay side-effect-free
|
|
66
64
|
home: worldHome,
|
|
67
65
|
dataHome: worldHome,
|
|
68
66
|
// Adapter-local bundle names resolve from the profile's own
|
package/agent-pi/package.json
CHANGED
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@earendil-works/pi-coding-agent": "0.84.2",
|
|
26
|
-
"@pgmi-builds/agent-hub": "file:../agent-hub",
|
|
27
26
|
"zod": "3.25.76"
|
|
28
27
|
},
|
|
29
28
|
"peerDependencies": {
|
|
@@ -34,7 +33,8 @@
|
|
|
34
33
|
"@deepseek-ai/dsh-scope": "0.1.5-rc.2",
|
|
35
34
|
"@deepseek-ai/dsh-session": "0.1.5-rc.2",
|
|
36
35
|
"@deepseek-ai/dsh-session-persistence": "0.1.5-rc.2",
|
|
37
|
-
"@deepseek-ai/dsh-typert-protocol": "0.1.5-rc.2"
|
|
36
|
+
"@deepseek-ai/dsh-typert-protocol": "0.1.5-rc.2",
|
|
37
|
+
"@pgmi-builds/agent-hub": "*"
|
|
38
38
|
},
|
|
39
39
|
"peerDependenciesMeta": {
|
|
40
40
|
"@deepseek-ai/cordis": {
|
|
@@ -60,6 +60,9 @@
|
|
|
60
60
|
},
|
|
61
61
|
"@deepseek-ai/dsh-typert-protocol": {
|
|
62
62
|
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"@pgmi-builds/agent-hub": {
|
|
65
|
+
"optional": true
|
|
63
66
|
}
|
|
64
67
|
},
|
|
65
68
|
"devDependencies": {
|
package/client/index.js
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({ id: "super-dsh", 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; } });
|
package/cordis.patch.yml
CHANGED
|
@@ -16,8 +16,11 @@
|
|
|
16
16
|
# Profile-layer values (webserver port/host, settings path) stay in the USER's
|
|
17
17
|
# profile patch layer, never here.
|
|
18
18
|
- insert:
|
|
19
|
+
# BARE package row: subpath rows (…/world/omp) are permanently not client
|
|
20
|
+
# rows in client-modules' scan (exactPackageSpecifier), so THIS row is
|
|
21
|
+
# what registers the package's client half — the sidebar selector.
|
|
19
22
|
- id: agent-hub
|
|
20
|
-
name: 'super-dsh
|
|
23
|
+
name: 'super-dsh'
|
|
21
24
|
- id: aw-agent-adapter-omp
|
|
22
25
|
name: 'super-dsh/world/omp'
|
|
23
26
|
- id: aw-agent-adapter-codex
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "super-dsh",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3-d",
|
|
4
4
|
"description": "Agent Worlds for the DeepSeek Harness (DSH) — one dsh plugin that mounts the agent hub (runtime selector, roster, per-runtime worlds) and joins local foreign-agent runtimes (OMP, Codex, Claude, Pi, Hermes, Antigravity) into the DSH Web UI. Each runtime keeps its native home and session store; the hub only bridges.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"url": "git+https://github.com/pgmi-builds/superd.git"
|
|
10
10
|
},
|
|
11
11
|
"exports": {
|
|
12
|
+
".": "./agent-hub/dist/index.js",
|
|
12
13
|
"./hub": "./agent-hub/dist/index.js",
|
|
13
14
|
"./join": "./agent-hub/dist/world-join.js",
|
|
14
15
|
"./world/omp": "./agent-omp/dist/world-plugin.js",
|
|
@@ -17,12 +18,13 @@
|
|
|
17
18
|
"./world/pi": "./agent-pi/dist/world-plugin.js",
|
|
18
19
|
"./world/hermes": "./agent-hermes/dist/world-plugin.js",
|
|
19
20
|
"./world/agy": "./agent-agy/dist/world-plugin.js",
|
|
20
|
-
"./client": "./
|
|
21
|
+
"./client": "./client/index.js",
|
|
21
22
|
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
22
23
|
"./package.json": "./package.json"
|
|
23
24
|
},
|
|
24
25
|
"files": [
|
|
25
26
|
"cordis.patch.yml",
|
|
27
|
+
"client",
|
|
26
28
|
"README.md",
|
|
27
29
|
"agent-hub/dist",
|
|
28
30
|
"agent-hub/lib",
|