super-dsh 0.1.5 → 0.1.6
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/agent-preset-projection.d.ts +31 -0
- package/agent-agy/dist/agent-preset-projection.js +33 -0
- package/agent-claude/dist/agent-preset-projection.js +30 -0
- package/agent-codex/dist/agent-preset-projection.js +37 -0
- package/agent-codex/dist/app-home.js +65 -0
- package/agent-codex/dist/spike.js +46 -0
- package/agent-hermes/dist/agent-preset-projection.js +34 -0
- package/agent-omp/dist/agent-preset-projection.js +36 -0
- package/agent-omp/dist/app-home.js +86 -0
- package/agent-pi/dist/agent-preset-projection.js +29 -0
- package/client/index.js +273 -93
- package/cordis.patch.yml +6 -5
- package/package.json +2 -2
- package/superd-hub/dist/agent-roster.d.ts +4 -0
- package/superd-hub/dist/agent-roster.js +2 -2
- package/superd-hub/dist/client-shim.d.ts +28 -0
- package/superd-hub/dist/client-shim.js +251 -0
- package/superd-hub/dist/fusion-transport.d.ts +23 -21
- package/superd-hub/dist/fusion-transport.js +12 -40
- package/superd-hub/dist/index-pass.d.ts +22 -0
- package/superd-hub/dist/index-pass.js +47 -0
- package/superd-hub/dist/index.d.ts +3 -3
- package/superd-hub/dist/index.js +3 -3
- package/superd-hub/dist/labels.d.ts +45 -0
- package/superd-hub/dist/labels.js +83 -0
- package/superd-hub/dist/roster.d.ts +4 -0
- package/superd-hub/dist/roster.js +9 -1
- package/superd-hub/dist/switch-core.d.ts +40 -0
- package/superd-hub/dist/switch-core.js +72 -0
- package/superd-hub/dist/toast-core.d.ts +43 -0
- package/superd-hub/dist/toast-core.js +63 -0
- package/superd-hub/dist/world-join.js +8 -3
- package/superd-hub/dist/world-mount.d.ts +27 -0
- package/superd-hub/dist/world-mount.js +67 -0
- package/superd-hub/lib/client/index.js +273 -93
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Label table (AW-B DL2/DL4): one world ↔ one mount path under the ctx0 origin.
|
|
3
|
+
*
|
|
4
|
+
* The addressed world is the request's path (`/<label>/...`), so the label is
|
|
5
|
+
* the ONLY routing key. Reserving it must be atomic against the real
|
|
6
|
+
* webServer's duplicate-registration throw — that throw is the only collision
|
|
7
|
+
* signal the framework offers (the route tables are private and there is no
|
|
8
|
+
* query API), so it is used here as the probe.
|
|
9
|
+
*
|
|
10
|
+
* A collision is a composition-level conflict and must be loud; an optional
|
|
11
|
+
* alternate root lets a deployment re-home instead of failing to boot.
|
|
12
|
+
*/
|
|
13
|
+
const claims = new Map();
|
|
14
|
+
function isRecordLike(value) {
|
|
15
|
+
return typeof value === 'object' && value !== null;
|
|
16
|
+
}
|
|
17
|
+
/** Reject keys that cannot be a single path segment. */
|
|
18
|
+
function assertKey(key) {
|
|
19
|
+
if (typeof key !== 'string' || key === '' || key.includes('/') || key.includes('?')) {
|
|
20
|
+
throw new Error(`labels: invalid label key ${JSON.stringify(key)} (one non-empty path segment required)`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function joinRoot(root, key) {
|
|
24
|
+
const trimmed = root.replace(/\/+$/, '');
|
|
25
|
+
return trimmed === '' ? `/${key}` : `${trimmed}/${key}`;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Reserve the mount path for `key`.
|
|
29
|
+
* @param key - runtime key (one path segment).
|
|
30
|
+
* @param opts - registration probe plus optional roots.
|
|
31
|
+
* @returns the live claim.
|
|
32
|
+
*/
|
|
33
|
+
export function claimLabel(key, opts) {
|
|
34
|
+
assertKey(key);
|
|
35
|
+
const existing = claims.get(key);
|
|
36
|
+
if (existing !== undefined) {
|
|
37
|
+
throw new Error(`labels: key ${JSON.stringify(key)} already claimed at "${existing.path}"`);
|
|
38
|
+
}
|
|
39
|
+
const roots = [opts.root ?? '', ...(opts.alternateRoots ?? [])];
|
|
40
|
+
const tried = [];
|
|
41
|
+
for (const root of roots) {
|
|
42
|
+
const path = joinRoot(root, key);
|
|
43
|
+
if (tried.includes(path))
|
|
44
|
+
continue;
|
|
45
|
+
tried.push(path);
|
|
46
|
+
let dispose;
|
|
47
|
+
try {
|
|
48
|
+
dispose = opts.register(path);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const claim = {
|
|
54
|
+
key,
|
|
55
|
+
path,
|
|
56
|
+
release: () => {
|
|
57
|
+
if (claims.get(key)?.path !== path)
|
|
58
|
+
return;
|
|
59
|
+
claims.delete(key);
|
|
60
|
+
dispose?.();
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
claims.set(key, claim);
|
|
64
|
+
return claim;
|
|
65
|
+
}
|
|
66
|
+
throw new Error(`labels: no free mount path for ${JSON.stringify(key)} (tried ${tried.map(p => `"${p}"`).join(', ')})`);
|
|
67
|
+
}
|
|
68
|
+
/** The reserved mount root for a key, or undefined when unclaimed. */
|
|
69
|
+
export function labelOf(key) {
|
|
70
|
+
return claims.get(key)?.path;
|
|
71
|
+
}
|
|
72
|
+
/** Release a key's claim; unknown keys are a no-op. */
|
|
73
|
+
export function releaseLabel(key) {
|
|
74
|
+
claims.get(key)?.release();
|
|
75
|
+
}
|
|
76
|
+
/** Claimed keys, registration order. */
|
|
77
|
+
export function listLabels() {
|
|
78
|
+
return [...claims.keys()];
|
|
79
|
+
}
|
|
80
|
+
/** Test/introspection helper: is this object a claim? */
|
|
81
|
+
export function isLabelClaim(value) {
|
|
82
|
+
return isRecordLike(value) && typeof value['key'] === 'string' && typeof value['path'] === 'string';
|
|
83
|
+
}
|
|
@@ -15,6 +15,8 @@ export interface RosterEntry {
|
|
|
15
15
|
label: string;
|
|
16
16
|
/** True once the adapter's world context is spawned and its target registered. */
|
|
17
17
|
ready: boolean;
|
|
18
|
+
/** True once the world's spawn REJECTED (world-join catch) — stays mounted for diagnosis. */
|
|
19
|
+
failed?: boolean;
|
|
18
20
|
}
|
|
19
21
|
/** Register an agent. Duplicate keys are a plugin bug — throw loud. */
|
|
20
22
|
export declare function registerAgent(entry: RosterEntry): void;
|
|
@@ -22,6 +24,8 @@ export declare function registerAgent(entry: RosterEntry): void;
|
|
|
22
24
|
export declare function unregisterAgent(key: string): void;
|
|
23
25
|
/** Flip readiness (world spawned / disposed). Unknown keys are a plugin bug. */
|
|
24
26
|
export declare function setReady(key: string, ready: boolean): void;
|
|
27
|
+
/** Flip failure (world spawn rejected). Unknown keys are a plugin bug. */
|
|
28
|
+
export declare function setFailed(key: string, failed: boolean): void;
|
|
25
29
|
/** Snapshot copy — callers can hold it without aliasing the roster. */
|
|
26
30
|
export declare function listAgents(): RosterEntry[];
|
|
27
31
|
/** Subscribe to roster changes; returns an unsubscribe function. */
|
|
@@ -9,7 +9,7 @@ function emit() {
|
|
|
9
9
|
export function registerAgent(entry) {
|
|
10
10
|
if (entries.has(entry.key))
|
|
11
11
|
throw new Error(`roster: duplicate agent key ${entry.key}`);
|
|
12
|
-
entries.set(entry.key, { ...entry });
|
|
12
|
+
entries.set(entry.key, { ...entry, failed: entry.failed ?? false });
|
|
13
13
|
emit();
|
|
14
14
|
}
|
|
15
15
|
/** Drop an agent (adapter plugin disposed). */
|
|
@@ -25,6 +25,14 @@ export function setReady(key, ready) {
|
|
|
25
25
|
e.ready = ready;
|
|
26
26
|
emit();
|
|
27
27
|
}
|
|
28
|
+
/** Flip failure (world spawn rejected). Unknown keys are a plugin bug. */
|
|
29
|
+
export function setFailed(key, failed) {
|
|
30
|
+
const e = entries.get(key);
|
|
31
|
+
if (!e)
|
|
32
|
+
throw new Error(`roster: unknown agent ${key}`);
|
|
33
|
+
e.failed = failed;
|
|
34
|
+
emit();
|
|
35
|
+
}
|
|
28
36
|
/** Snapshot copy — callers can hold it without aliasing the roster. */
|
|
29
37
|
export function listAgents() {
|
|
30
38
|
return [...entries.values()].map((e) => ({ ...e }));
|
|
@@ -628,3 +628,43 @@ export interface SwitchController {
|
|
|
628
628
|
* switch's pointer-restored view).
|
|
629
629
|
*/
|
|
630
630
|
export declare function createSwitchController(host: SwitchHost, options?: SwitchOptions): SwitchController;
|
|
631
|
+
/** What attemptSwitch does with a roster row: run the machine / report failure / wait for readiness. */
|
|
632
|
+
export type PreFlightDecision = 'run' | 'failed' | 'wait';
|
|
633
|
+
/** The roster fields the pre-flight reads (the projection carries both since C1 task 3). */
|
|
634
|
+
export interface PreFlightRow {
|
|
635
|
+
ready?: boolean;
|
|
636
|
+
failed?: boolean;
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* The pure pre-flight decision. `native` always runs; an absent row (roster
|
|
640
|
+
* fetch failed, or the key is not listed) also runs — the machine's roster
|
|
641
|
+
* probe is the authority on unknown targets, exactly as before C1.
|
|
642
|
+
*/
|
|
643
|
+
export declare function decidePreFlight(label: string, row: PreFlightRow | undefined): PreFlightDecision;
|
|
644
|
+
/** Default bound on one readiness wait (the page never locks behind a stuck world). */
|
|
645
|
+
export declare const WAIT_BOUND_MS = 120000;
|
|
646
|
+
/** Default poll interval for one readiness wait. */
|
|
647
|
+
export declare const WAIT_POLL_MS = 1000;
|
|
648
|
+
/** The waiter's injected faces (tests drive time and the roster by hand). */
|
|
649
|
+
export interface ReadinessWaiterFaces {
|
|
650
|
+
/** Read the target's roster row; undefined on any failure. */
|
|
651
|
+
fetchRow(): Promise<PreFlightRow | undefined>;
|
|
652
|
+
setTimeout(fn: () => void, ms: number): unknown;
|
|
653
|
+
clearTimeout(handle: unknown): void;
|
|
654
|
+
}
|
|
655
|
+
/** One bounded readiness wait. */
|
|
656
|
+
export interface ReadinessWaiter {
|
|
657
|
+
/** Resolves when the row flips ready ('ready'), reports failure ('failed'), the bound expires ('bound'), or the waiter is cancelled ('cancelled'). */
|
|
658
|
+
wait(label: string): Promise<'ready' | 'failed' | 'bound' | 'cancelled'>;
|
|
659
|
+
/** A newer switch attempt cancels a pending wait (it resolves 'cancelled'). */
|
|
660
|
+
cancel(): void;
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Build a bounded readiness waiter over injected faces. The poll re-reads
|
|
664
|
+
* the roster row every {@link ReadinessWaiterOptions.pollMs}; `failed`
|
|
665
|
+
* short-circuits immediately; the bound always terminates the wait.
|
|
666
|
+
*/
|
|
667
|
+
export declare function createReadinessWaiter(faces: ReadinessWaiterFaces, options?: {
|
|
668
|
+
boundMs?: number;
|
|
669
|
+
pollMs?: number;
|
|
670
|
+
}): ReadinessWaiter;
|
|
@@ -732,3 +732,75 @@ export function createSwitchController(host, options = {}) {
|
|
|
732
732
|
},
|
|
733
733
|
};
|
|
734
734
|
}
|
|
735
|
+
/**
|
|
736
|
+
* The pure pre-flight decision. `native` always runs; an absent row (roster
|
|
737
|
+
* fetch failed, or the key is not listed) also runs — the machine's roster
|
|
738
|
+
* probe is the authority on unknown targets, exactly as before C1.
|
|
739
|
+
*/
|
|
740
|
+
export function decidePreFlight(label, row) {
|
|
741
|
+
if (label === NATIVE_AGENT)
|
|
742
|
+
return 'run';
|
|
743
|
+
if (row === undefined)
|
|
744
|
+
return 'run';
|
|
745
|
+
if (row.failed === true)
|
|
746
|
+
return 'failed';
|
|
747
|
+
if (row.ready !== true)
|
|
748
|
+
return 'wait';
|
|
749
|
+
return 'run';
|
|
750
|
+
}
|
|
751
|
+
/** Default bound on one readiness wait (the page never locks behind a stuck world). */
|
|
752
|
+
export const WAIT_BOUND_MS = 120_000;
|
|
753
|
+
/** Default poll interval for one readiness wait. */
|
|
754
|
+
export const WAIT_POLL_MS = 1_000;
|
|
755
|
+
/**
|
|
756
|
+
* Build a bounded readiness waiter over injected faces. The poll re-reads
|
|
757
|
+
* the roster row every {@link ReadinessWaiterOptions.pollMs}; `failed`
|
|
758
|
+
* short-circuits immediately; the bound always terminates the wait.
|
|
759
|
+
*/
|
|
760
|
+
export function createReadinessWaiter(faces, options = {}) {
|
|
761
|
+
const boundMs = options.boundMs ?? WAIT_BOUND_MS;
|
|
762
|
+
const pollMs = options.pollMs ?? WAIT_POLL_MS;
|
|
763
|
+
let pending;
|
|
764
|
+
let pollHandle;
|
|
765
|
+
let boundHandle;
|
|
766
|
+
let settled = false;
|
|
767
|
+
const settle = (outcome) => {
|
|
768
|
+
if (settled)
|
|
769
|
+
return;
|
|
770
|
+
settled = true;
|
|
771
|
+
if (pollHandle !== undefined)
|
|
772
|
+
faces.clearTimeout(pollHandle);
|
|
773
|
+
if (boundHandle !== undefined)
|
|
774
|
+
faces.clearTimeout(boundHandle);
|
|
775
|
+
pending?.(outcome);
|
|
776
|
+
pending = undefined;
|
|
777
|
+
};
|
|
778
|
+
return {
|
|
779
|
+
wait(label) {
|
|
780
|
+
return new Promise((resolve) => {
|
|
781
|
+
pending = resolve;
|
|
782
|
+
boundHandle = faces.setTimeout(() => { settle('bound'); }, boundMs);
|
|
783
|
+
const tick = () => {
|
|
784
|
+
if (settled)
|
|
785
|
+
return;
|
|
786
|
+
void faces.fetchRow().then((row) => {
|
|
787
|
+
if (settled)
|
|
788
|
+
return;
|
|
789
|
+
if (row?.failed === true) {
|
|
790
|
+
settle('failed');
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
if (row?.ready === true) {
|
|
794
|
+
settle('ready');
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
pollHandle = faces.setTimeout(tick, pollMs);
|
|
798
|
+
}, () => { if (!settled)
|
|
799
|
+
pollHandle = faces.setTimeout(tick, pollMs); });
|
|
800
|
+
};
|
|
801
|
+
tick();
|
|
802
|
+
});
|
|
803
|
+
},
|
|
804
|
+
cancel() { settle('cancelled'); },
|
|
805
|
+
};
|
|
806
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Toast feedback core (C1 task 4) — the pure, host-half half of the
|
|
3
|
+
* official-primitive toast: the props seam and the module store. The React
|
|
4
|
+
* wrapper (the always-mounted host component + element factory) lives in
|
|
5
|
+
* `src/client/toast.ts`; this split mirrors switch-core (pure logic where
|
|
6
|
+
* tsc emits and node tests import; the DOM/React face is injected by the
|
|
7
|
+
* client lane).
|
|
8
|
+
*
|
|
9
|
+
* The toast copy rides the platform's `Toast` primitive — top-center
|
|
10
|
+
* banner, dark surface in both themes, warn-orange icon seat, green
|
|
11
|
+
* `tone="success"` — rendered by the HOST's React tree through the
|
|
12
|
+
* primitive's own body portal. Failure notices hold ~6 s: the primitive's
|
|
13
|
+
* docblock prescribes longer holds for failures that name what broke.
|
|
14
|
+
*
|
|
15
|
+
* @module superd-hub/toast-core
|
|
16
|
+
*/
|
|
17
|
+
/** Options: the toast tone and hold window. */
|
|
18
|
+
export interface SuperdToastOptions {
|
|
19
|
+
/** `'success'` renders the primitive's green check glyph. */
|
|
20
|
+
tone?: 'success';
|
|
21
|
+
/** Full-opacity hold before the fade; defaults to {@link TOAST_DEFAULT_HOLD_MS}. */
|
|
22
|
+
holdMs?: number;
|
|
23
|
+
}
|
|
24
|
+
/** Failures that name what broke need a longer read than a one-liner. */
|
|
25
|
+
export declare const TOAST_DEFAULT_HOLD_MS = 6000;
|
|
26
|
+
/** One pending toast: a monotonic sequence plus its resolved copy. */
|
|
27
|
+
export interface PendingSuperdToast {
|
|
28
|
+
readonly seq: number;
|
|
29
|
+
readonly text: string;
|
|
30
|
+
readonly options: SuperdToastOptions;
|
|
31
|
+
}
|
|
32
|
+
/** The exact props the official primitive receives (pure — the unit seam). */
|
|
33
|
+
export declare function toastProps(text: string, options?: SuperdToastOptions): {
|
|
34
|
+
text: string;
|
|
35
|
+
tone?: 'success';
|
|
36
|
+
holdMs: number;
|
|
37
|
+
};
|
|
38
|
+
/** Fire one toast (best-effort: without a mounted owner nothing renders). */
|
|
39
|
+
export declare function showSuperdToast(text: string, options?: SuperdToastOptions): void;
|
|
40
|
+
/** Clear a shown toast (the fade's `onDone`); stale sequences are no-ops. */
|
|
41
|
+
export declare function clearSuperdToast(done: number): void;
|
|
42
|
+
/** Subscribe to the store (the host's effect face); returns unsubscribe. */
|
|
43
|
+
export declare function onSuperdToast(fn: (toast: PendingSuperdToast | undefined) => void): () => void;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Toast feedback core (C1 task 4) — the pure, host-half half of the
|
|
3
|
+
* official-primitive toast: the props seam and the module store. The React
|
|
4
|
+
* wrapper (the always-mounted host component + element factory) lives in
|
|
5
|
+
* `src/client/toast.ts`; this split mirrors switch-core (pure logic where
|
|
6
|
+
* tsc emits and node tests import; the DOM/React face is injected by the
|
|
7
|
+
* client lane).
|
|
8
|
+
*
|
|
9
|
+
* The toast copy rides the platform's `Toast` primitive — top-center
|
|
10
|
+
* banner, dark surface in both themes, warn-orange icon seat, green
|
|
11
|
+
* `tone="success"` — rendered by the HOST's React tree through the
|
|
12
|
+
* primitive's own body portal. Failure notices hold ~6 s: the primitive's
|
|
13
|
+
* docblock prescribes longer holds for failures that name what broke.
|
|
14
|
+
*
|
|
15
|
+
* @module superd-hub/toast-core
|
|
16
|
+
*/
|
|
17
|
+
/** Failures that name what broke need a longer read than a one-liner. */
|
|
18
|
+
export const TOAST_DEFAULT_HOLD_MS = 6_000;
|
|
19
|
+
/** The exact props the official primitive receives (pure — the unit seam). */
|
|
20
|
+
export function toastProps(text, options = {}) {
|
|
21
|
+
const props = {
|
|
22
|
+
text,
|
|
23
|
+
holdMs: options.holdMs ?? TOAST_DEFAULT_HOLD_MS,
|
|
24
|
+
};
|
|
25
|
+
if (options.tone !== undefined)
|
|
26
|
+
props.tone = options.tone;
|
|
27
|
+
return props;
|
|
28
|
+
}
|
|
29
|
+
// ---- the module store (last-wins; transient notices never queue) ----------
|
|
30
|
+
let seq = 0;
|
|
31
|
+
let current;
|
|
32
|
+
const listeners = new Set();
|
|
33
|
+
function emit() {
|
|
34
|
+
for (const fn of [...listeners]) {
|
|
35
|
+
try {
|
|
36
|
+
fn(current);
|
|
37
|
+
}
|
|
38
|
+
catch { /* a broken listener never breaks the store */ }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Fire one toast (best-effort: without a mounted owner nothing renders). */
|
|
42
|
+
export function showSuperdToast(text, options = {}) {
|
|
43
|
+
current = { seq: ++seq, text, options };
|
|
44
|
+
emit();
|
|
45
|
+
}
|
|
46
|
+
/** Clear a shown toast (the fade's `onDone`); stale sequences are no-ops. */
|
|
47
|
+
export function clearSuperdToast(done) {
|
|
48
|
+
if (current === undefined || current.seq !== done)
|
|
49
|
+
return;
|
|
50
|
+
current = undefined;
|
|
51
|
+
emit();
|
|
52
|
+
}
|
|
53
|
+
/** Subscribe to the store (the host's effect face); returns unsubscribe. */
|
|
54
|
+
export function onSuperdToast(fn) {
|
|
55
|
+
listeners.add(fn);
|
|
56
|
+
// Initial push: an owner mounting after a toast fired still shows it
|
|
57
|
+
// (the host's effect subscribes post-mount).
|
|
58
|
+
try {
|
|
59
|
+
fn(current);
|
|
60
|
+
}
|
|
61
|
+
catch { /* a broken listener never breaks the store */ }
|
|
62
|
+
return () => { listeners.delete(fn); };
|
|
63
|
+
}
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
import { mkdirSync } from 'node:fs';
|
|
33
33
|
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths';
|
|
34
34
|
import { join } from 'node:path';
|
|
35
|
-
import { registerAgent, setReady } from './roster.js';
|
|
35
|
+
import { registerAgent, setFailed, setReady } from './roster.js';
|
|
36
36
|
import { registerForeignTarget } from './targets.js';
|
|
37
37
|
import { spawnWorld } from './spawn-world.js';
|
|
38
38
|
import { provisionWorldProfile, resolveInstallAnchor } from './world-provision.js';
|
|
@@ -92,9 +92,14 @@ export function apply(ctx, config) {
|
|
|
92
92
|
}, `superd-join: ${key} mount`);
|
|
93
93
|
return ctxW;
|
|
94
94
|
})().catch((cause) => {
|
|
95
|
-
// A failed world degrades to a
|
|
96
|
-
//
|
|
95
|
+
// A failed world degrades to a FAILED roster row (mount stays for
|
|
96
|
+
// diagnosis; ready stays false); a rejected provided promise would fail
|
|
97
|
+
// the entire host boot (loader entry apply).
|
|
97
98
|
console.error(`[super-dsh] ${key} world failed:`, cause);
|
|
99
|
+
try {
|
|
100
|
+
setFailed(key, true);
|
|
101
|
+
}
|
|
102
|
+
catch { /* roster row already gone */ }
|
|
98
103
|
return null;
|
|
99
104
|
});
|
|
100
105
|
ctx.provide(`superd.world.${key}`, world);
|
|
@@ -79,4 +79,31 @@ export type WorldPatchLayer = {
|
|
|
79
79
|
* @param key - runtime key (`omp`, `codex`, …) — the mount label.
|
|
80
80
|
* @returns patch layers to append to the world's composition.
|
|
81
81
|
*/
|
|
82
|
+
/**
|
|
83
|
+
* Wave-1 of world composition minimization (spec
|
|
84
|
+
* docs/specs/world-composition-minimization): native-agent machinery the
|
|
85
|
+
* foreign runtimes replace. Dependency-cleared 2026-09-27 against the KEEP
|
|
86
|
+
* set (api controllers, session core, adapters' agents/sessions/llm/
|
|
87
|
+
* agentDefaultModel/settings/agentPresets). Wave-2 candidates (client-ui
|
|
88
|
+
* family, tools, bash-sandbox, terminal-controller, …) live in the spec,
|
|
89
|
+
* NOT here.
|
|
90
|
+
*/
|
|
91
|
+
export declare const WORLD_WAVE1_DISABLED_ROWS: readonly string[];
|
|
92
|
+
/**
|
|
93
|
+
* Wave-2 of world composition minimization: the CLIENT lane. The
|
|
94
|
+
* multi-ctx-multi-ui → native-ui-only transition (0.1.5 / T-D) retired the
|
|
95
|
+
* world's own web UI (webserver/hmr/web-runtime/client-hmr above); wave-2
|
|
96
|
+
* completes it by stripping the browser-half rows of the web-app bundle —
|
|
97
|
+
* every dsh-client-* row plus the cordis client runner. In a world these
|
|
98
|
+
* only registered modules into a table no browser ever reads.
|
|
99
|
+
*
|
|
100
|
+
* Dependency-cleared 2026-09-27: the KEEP side (api controllers, gateway,
|
|
101
|
+
* session core, adapters) injects none of their services with ONE
|
|
102
|
+
* exceptions — `connection` (dsh-client-connection: the world's typert
|
|
103
|
+
* gateway injects it) and `modules` (dsh-client-modules: its activation
|
|
104
|
+
* work fails in world trees ("client bundles not found") and at least one
|
|
105
|
+
* fiber treats it as required — the load-bearing parking restatement
|
|
106
|
+
* `inject: [webServer]` keeps it waiting forever, superseding a disable).
|
|
107
|
+
*/
|
|
108
|
+
export declare const WORLD_WAVE2_DISABLED_ROWS: readonly string[];
|
|
82
109
|
export declare function worldMountPatches(key: string): readonly WorldPatchLayer[];
|
|
@@ -68,6 +68,63 @@ export function superdTrustedHosts(value) {
|
|
|
68
68
|
* @param key - runtime key (`omp`, `codex`, …) — the mount label.
|
|
69
69
|
* @returns patch layers to append to the world's composition.
|
|
70
70
|
*/
|
|
71
|
+
/**
|
|
72
|
+
* Wave-1 of world composition minimization (spec
|
|
73
|
+
* docs/specs/world-composition-minimization): native-agent machinery the
|
|
74
|
+
* foreign runtimes replace. Dependency-cleared 2026-09-27 against the KEEP
|
|
75
|
+
* set (api controllers, session core, adapters' agents/sessions/llm/
|
|
76
|
+
* agentDefaultModel/settings/agentPresets). Wave-2 candidates (client-ui
|
|
77
|
+
* family, tools, bash-sandbox, terminal-controller, …) live in the spec,
|
|
78
|
+
* NOT here.
|
|
79
|
+
*/
|
|
80
|
+
export const WORLD_WAVE1_DISABLED_ROWS = [
|
|
81
|
+
'agent-loop',
|
|
82
|
+
'mcp-resources',
|
|
83
|
+
// skills
|
|
84
|
+
'skill', 'skill-filesystem', 'skill-badge', 'tool-skill', 'ui-skill',
|
|
85
|
+
// jobs
|
|
86
|
+
'jobs', 'tool-jobs', 'ui-jobs', 'job-controller',
|
|
87
|
+
// subagents
|
|
88
|
+
'subagent', 'subagent-spawn-in-process', 'subagent-fork-in-process',
|
|
89
|
+
'tool-subagent-control', 'tool-subagent-list-agents', 'tool-subagent',
|
|
90
|
+
'tool-subagent-fork', 'tool-subagent-codex', 'tool-subagent-claude-code',
|
|
91
|
+
'subagent-model-selection-settings', 'ui-subagent', 'ui-settings-subagent',
|
|
92
|
+
'ui-settings-agent-loop',
|
|
93
|
+
];
|
|
94
|
+
/**
|
|
95
|
+
* Wave-2 of world composition minimization: the CLIENT lane. The
|
|
96
|
+
* multi-ctx-multi-ui → native-ui-only transition (0.1.5 / T-D) retired the
|
|
97
|
+
* world's own web UI (webserver/hmr/web-runtime/client-hmr above); wave-2
|
|
98
|
+
* completes it by stripping the browser-half rows of the web-app bundle —
|
|
99
|
+
* every dsh-client-* row plus the cordis client runner. In a world these
|
|
100
|
+
* only registered modules into a table no browser ever reads.
|
|
101
|
+
*
|
|
102
|
+
* Dependency-cleared 2026-09-27: the KEEP side (api controllers, gateway,
|
|
103
|
+
* session core, adapters) injects none of their services with ONE
|
|
104
|
+
* exceptions — `connection` (dsh-client-connection: the world's typert
|
|
105
|
+
* gateway injects it) and `modules` (dsh-client-modules: its activation
|
|
106
|
+
* work fails in world trees ("client bundles not found") and at least one
|
|
107
|
+
* fiber treats it as required — the load-bearing parking restatement
|
|
108
|
+
* `inject: [webServer]` keeps it waiting forever, superseding a disable).
|
|
109
|
+
*/
|
|
110
|
+
export const WORLD_WAVE2_DISABLED_ROWS = [
|
|
111
|
+
'cordis-client-runner',
|
|
112
|
+
'directory-picker-browse-surface',
|
|
113
|
+
'file-upload',
|
|
114
|
+
'locale',
|
|
115
|
+
'resources',
|
|
116
|
+
'ui-agent-preset', 'ui-approval', 'ui-attachment', 'ui-brand-official',
|
|
117
|
+
'ui-chat', 'ui-commands', 'ui-conversation', 'ui-cordis', 'ui-deliverables',
|
|
118
|
+
'ui-goal', 'ui-input-trigger', 'ui-layout', 'ui-message-feedback',
|
|
119
|
+
'ui-model-selection', 'ui-open-in-app', 'ui-permission', 'ui-plan',
|
|
120
|
+
'ui-plugin-manager', 'ui-reference', 'ui-renderer', 'ui-session',
|
|
121
|
+
'ui-settings', 'ui-settings-account', 'ui-settings-general',
|
|
122
|
+
'ui-settings-models', 'ui-settings-plugin-inventory', 'ui-settings-plugins',
|
|
123
|
+
'ui-settings-shell', 'ui-settings-web-search', 'ui-sidebar',
|
|
124
|
+
'ui-sidebar-browser', 'ui-sidebar-documentpreview', 'ui-sidebar-files',
|
|
125
|
+
'ui-sidebar-right', 'ui-sidebar-terminal', 'ui-theme', 'ui-tool',
|
|
126
|
+
'ui-trajectory', 'ui-user-questions', 'ui-workflow-run', 'ui-workspace',
|
|
127
|
+
];
|
|
71
128
|
export function worldMountPatches(key) {
|
|
72
129
|
if (typeof key !== 'string' || key === '' || key.includes('/')) {
|
|
73
130
|
throw new Error(`world-mount: invalid key ${JSON.stringify(key)}`);
|
|
@@ -96,10 +153,20 @@ export function worldMountPatches(key) {
|
|
|
96
153
|
// literals; the deploy-level trusted-host extras ride along).
|
|
97
154
|
{ id: 'web-runtime', disabled: true },
|
|
98
155
|
{ id: 'client-hmr', disabled: true },
|
|
156
|
+
// PARKED, not disabled: the modules row's activation work fails in world
|
|
157
|
+
// trees (no built client bundles) and the omp fiber treats it as
|
|
158
|
+
// required — waiting on the never-provided webServer keeps it inert
|
|
159
|
+
// without a startup failure (2026-09-27 wave-2 rig evidence).
|
|
99
160
|
{ id: 'modules', inject: ['webServer'] },
|
|
100
161
|
{ insert: [
|
|
101
162
|
{ id: WORLD_MOUNT_ROW_ID, name: WORLD_MOUNT_PLUGIN, config: { key } },
|
|
102
163
|
{ id: WORLD_HUB_ROW_ID, name: WORLD_HUB_PLUGIN },
|
|
103
164
|
] },
|
|
165
|
+
// Wave-1 minimization: the foreign runtimes replace the native agent
|
|
166
|
+
// machinery — these rows never mount in a world tree.
|
|
167
|
+
...WORLD_WAVE1_DISABLED_ROWS.map((id) => ({ id, disabled: true })),
|
|
168
|
+
// Wave-2 minimization: the client lane (native-ui-only completion) —
|
|
169
|
+
// no browser ever reads a world's module table.
|
|
170
|
+
...WORLD_WAVE2_DISABLED_ROWS.map((id) => ({ id, disabled: true })),
|
|
104
171
|
];
|
|
105
172
|
}
|