@deepseek-ai/dsh-app-boot 0.2.1-alpha.1 → 0.2.1-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +20 -23
- package/README.md +14 -14
- package/README.zh.md +14 -14
- package/lib/index.js +399 -87
- package/lib/types/index.d.ts +43 -21
- package/lib/types/official-bundle-packages.d.ts +4 -0
- package/lib/types/official-bundles.d.ts +12 -0
- package/lib/types/official-bundles.generated.d.ts +5 -0
- package/lib/types/package-meta.d.ts +1 -1
- package/lib/types/profile-context.d.ts +7 -0
- package/lib/types/profile-resolution/legacy-links.d.ts +8 -1
- package/lib/types/profile-resolution/resolver.d.ts +14 -6
- package/lib/types/profile-resolution/service.d.ts +3 -1
- package/lib/worker/profile-resolution-bootstrap.js +133 -11
- package/package.json +21 -22
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRequire, isBuiltin } from "node:module";
|
|
2
2
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
3
|
-
import fs, { existsSync, mkdirSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
|
+
import fs, { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { inspect, parseEnv } from "node:util";
|
|
5
5
|
import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep, win32 } from "node:path";
|
|
6
6
|
import * as yaml from "js-yaml";
|
|
@@ -441,7 +441,7 @@ async function setProfileVersionExemption(profileDir, packageVersion, runtimeVer
|
|
|
441
441
|
}
|
|
442
442
|
//#endregion
|
|
443
443
|
//#region lib/types/profile-resolution/legacy-links.js
|
|
444
|
-
/** Package directory canonicalization through the active runtime carrier's filesystem. */
|
|
444
|
+
/** Package directory and resource canonicalization through the active runtime carrier's filesystem. */
|
|
445
445
|
/**
|
|
446
446
|
* Return whether the process reads application modules from pkg's virtual filesystem.
|
|
447
447
|
* @returns whether pkg owns the module filesystem.
|
|
@@ -457,6 +457,15 @@ function isPackagedExecutable() {
|
|
|
457
457
|
function realModuleDirectory(path) {
|
|
458
458
|
return isPackagedExecutable() ? realpathSync(path) : realpathSync.native(path);
|
|
459
459
|
}
|
|
460
|
+
/** Canonicalize a module resource, preserving physical file aliases.
|
|
461
|
+
* SEA archive files are symlink-free and support stat and reads, while their containing directories support realpath.
|
|
462
|
+
* @param path Existing module resource path.
|
|
463
|
+
* @returns Canonical resource path under the active carrier's filesystem.
|
|
464
|
+
* @throws When the resource or its directory cannot be inspected or resolved.
|
|
465
|
+
*/
|
|
466
|
+
function realModuleFile(path) {
|
|
467
|
+
return !isPackagedExecutable() || lstatSync(path).isSymbolicLink() ? realpathSync(path) : join(realModuleDirectory(dirname(path)), basename(path));
|
|
468
|
+
}
|
|
460
469
|
//#endregion
|
|
461
470
|
//#region lib/types/profile.js
|
|
462
471
|
/**
|
|
@@ -555,10 +564,17 @@ const DEFAULT_PROFILE_BUNDLES = ["@deepseek-ai/dsh-base"];
|
|
|
555
564
|
* [admission](../../../../.agents/notes/implemented/architecture/2026-09-21-experimental-capabilities-as-optional-bundles.md)).
|
|
556
565
|
*/
|
|
557
566
|
const OPTIONAL_BUNDLES = [
|
|
567
|
+
"@deepseek-ai/dsh-experimental-session-search",
|
|
568
|
+
"@deepseek-ai/dsh-experimental-ralph-bundle",
|
|
569
|
+
"@deepseek-ai/dsh-experimental-terminal-bundle",
|
|
570
|
+
"@deepseek-ai/dsh-experimental-badge-skill-bundle",
|
|
571
|
+
"@deepseek-ai/dsh-experimental-session-titles-bundle",
|
|
558
572
|
"@deepseek-ai/dsh-experimental-agent-team-profile",
|
|
559
573
|
"@deepseek-ai/dsh-experimental-voice-input-bundle",
|
|
574
|
+
"@deepseek-ai/dsh-experimental-cot-translation-bundle",
|
|
560
575
|
"@deepseek-ai/dsh-experimental-auto-review",
|
|
561
|
-
"@deepseek-ai/dsh-experimental-inspector-profile"
|
|
576
|
+
"@deepseek-ai/dsh-experimental-inspector-profile",
|
|
577
|
+
"@deepseek-ai/dsh-experimental-tool-worktree"
|
|
562
578
|
];
|
|
563
579
|
const PROFILE_PATCH_TEMPLATE = `# Your patch layer for this dsh profile, applied after every bundle layer:
|
|
564
580
|
# a top-level YAML array of loader patch entries (id-targeted config
|
|
@@ -1079,6 +1095,15 @@ function resolveTelemetryPatch(disabledEnv, hasRow) {
|
|
|
1079
1095
|
disabled: true
|
|
1080
1096
|
};
|
|
1081
1097
|
}
|
|
1098
|
+
/** Read the selected bundles' patches, which apply before the profile patch file.
|
|
1099
|
+
* @param binName Diagnostic prefix for malformed or missing configuration.
|
|
1100
|
+
* @param context Data supplied by the profile launcher.
|
|
1101
|
+
* @param initialProfile Already loaded startup profile; omitted reads the current files.
|
|
1102
|
+
* @returns Bundle patches in application order.
|
|
1103
|
+
*/
|
|
1104
|
+
function readBundlePatches(binName, context, initialProfile) {
|
|
1105
|
+
return (initialProfile ?? loadProfileDirectory(binName, context.dir, context.installAnchor, { userLayer: false })).layers.flatMap((layer) => layer.patches);
|
|
1106
|
+
}
|
|
1082
1107
|
/** Read current bundle and user layers with the launch-time overlays.
|
|
1083
1108
|
* @param binName Diagnostic prefix for malformed or missing configuration.
|
|
1084
1109
|
* @param context Data supplied by the profile launcher.
|
|
@@ -1086,9 +1111,8 @@ function resolveTelemetryPatch(disabledEnv, hasRow) {
|
|
|
1086
1111
|
* @returns Detached ordered patches; this function does not update the Loader.
|
|
1087
1112
|
*/
|
|
1088
1113
|
function readProfilePatches(binName, context, initialProfile) {
|
|
1089
|
-
const profile = initialProfile ?? loadProfileDirectory(binName, context.dir, context.installAnchor, { userLayer: false });
|
|
1090
1114
|
const patches = structuredClone([
|
|
1091
|
-
...
|
|
1115
|
+
...readBundlePatches(binName, context, initialProfile),
|
|
1092
1116
|
...initialProfile?.patches ?? loadOptionalPatches(binName, context.patchPath) ?? [],
|
|
1093
1117
|
...loadOptionalPatches(binName, join(context.home, "cordis.patch.yml")) ?? [],
|
|
1094
1118
|
...context.overlays
|
|
@@ -1222,6 +1246,14 @@ function sanitizeProfile(binName, profileDir, bundles) {
|
|
|
1222
1246
|
/** In-memory profile package routing for Node's default ESM and CommonJS loaders. */
|
|
1223
1247
|
const WORKER_RESOLUTION_KEY = "@deepseek-ai/dsh-app-boot/profile-resolution";
|
|
1224
1248
|
const EMPTY_ATTRIBUTES = Object.freeze({});
|
|
1249
|
+
/** A successor resolution the running process cannot adopt, such as a retained mapping in another directory; it waits for a restart. */
|
|
1250
|
+
var ResolutionRestartRequired = class extends Error {
|
|
1251
|
+
/** @param message Diagnostic naming the rejected changes. */
|
|
1252
|
+
constructor(message) {
|
|
1253
|
+
super(message);
|
|
1254
|
+
this.name = "ResolutionRestartRequired";
|
|
1255
|
+
}
|
|
1256
|
+
};
|
|
1225
1257
|
/**
|
|
1226
1258
|
* Split a bare request into its package name without allocating path segments.
|
|
1227
1259
|
* @param request - module specifier to classify.
|
|
@@ -1235,6 +1267,15 @@ function barePackageName(request) {
|
|
|
1235
1267
|
const second = request.indexOf("/", first + 1);
|
|
1236
1268
|
return second < 0 ? request : request.slice(0, second);
|
|
1237
1269
|
}
|
|
1270
|
+
/** The JavaScript and native real paths of an existing directory; none for a directory that no longer exists. */
|
|
1271
|
+
function realSpellings(path) {
|
|
1272
|
+
try {
|
|
1273
|
+
const native = Reflect.get(realpathSync, "native");
|
|
1274
|
+
return [realpathSync(path), ...typeof native === "function" ? [String(Reflect.apply(native, realpathSync, [path]))] : []];
|
|
1275
|
+
} catch (_error) {
|
|
1276
|
+
return [];
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1238
1279
|
function canonicalPath(path) {
|
|
1239
1280
|
try {
|
|
1240
1281
|
return realpathSync(path);
|
|
@@ -1249,7 +1290,10 @@ function prefixes(path) {
|
|
|
1249
1290
|
}
|
|
1250
1291
|
function compileResolution(resolution) {
|
|
1251
1292
|
return {
|
|
1252
|
-
entries: new Map(resolution.entries.map((entry) => [entry.name,
|
|
1293
|
+
entries: new Map(resolution.entries.map((entry) => [entry.name, {
|
|
1294
|
+
...entry,
|
|
1295
|
+
realDir: canonicalPath(entry.packageDir)
|
|
1296
|
+
}])),
|
|
1253
1297
|
profilesDir: resolution.profilesDir,
|
|
1254
1298
|
profileDir: resolution.profileDir,
|
|
1255
1299
|
profilePaths: prefixes(resolution.profilesDir),
|
|
@@ -1412,11 +1456,65 @@ function sameResolution(left, right) {
|
|
|
1412
1456
|
if (left === right) return true;
|
|
1413
1457
|
return canonicalPath(left) === canonicalPath(right);
|
|
1414
1458
|
}
|
|
1459
|
+
/** A directory as given and in its JavaScript and native real paths, each with a trailing separator. */
|
|
1460
|
+
function spellings(dir) {
|
|
1461
|
+
const result = new Set([dir + sep]);
|
|
1462
|
+
for (const real of realSpellings(dir)) result.add(real + sep);
|
|
1463
|
+
return [...result];
|
|
1464
|
+
}
|
|
1465
|
+
/**
|
|
1466
|
+
* The previous real directories of packages that moved, each mapped to the current one. Node keeps the real path of
|
|
1467
|
+
* every link it resolved through and never refreshes it, so a lookup through a link that now points elsewhere still
|
|
1468
|
+
* selects a file below the target Node saw first; {@link MovedDirectories.relocate} selects the same file below the
|
|
1469
|
+
* current target instead.
|
|
1470
|
+
*/
|
|
1471
|
+
var MovedDirectories = class {
|
|
1472
|
+
/** Previous directory to current directory, both with a trailing separator. */
|
|
1473
|
+
targets = /* @__PURE__ */ new Map();
|
|
1474
|
+
/**
|
|
1475
|
+
* Record that a package moved from one directory to another. Every spelling of the previous directory leads to the
|
|
1476
|
+
* current one. A directory that an earlier move led to the previous one now leads to the current one as well, since
|
|
1477
|
+
* Node still selects files below the earliest target.
|
|
1478
|
+
* @param from Previous real directory.
|
|
1479
|
+
* @param to Current real directory.
|
|
1480
|
+
*/
|
|
1481
|
+
record(from, to) {
|
|
1482
|
+
const previous = spellings(from);
|
|
1483
|
+
const current = to + sep;
|
|
1484
|
+
for (const [key, value] of this.targets) if (previous.includes(value)) this.targets.set(key, current);
|
|
1485
|
+
for (const key of previous) this.targets.set(key, current);
|
|
1486
|
+
}
|
|
1487
|
+
/**
|
|
1488
|
+
* Forget the previous directories that are current again, in any spelling, and records that lead to themselves.
|
|
1489
|
+
* @param current The real directories the published resolution maps.
|
|
1490
|
+
*/
|
|
1491
|
+
forget(current) {
|
|
1492
|
+
const active = /* @__PURE__ */ new Set();
|
|
1493
|
+
for (const dir of current) for (const spelling of spellings(dir)) active.add(spelling);
|
|
1494
|
+
for (const [key, value] of [...this.targets]) if (active.has(key) || key === value) this.targets.delete(key);
|
|
1495
|
+
}
|
|
1496
|
+
/**
|
|
1497
|
+
* The same file below the current directory when it exists, for a file below a previous directory that an importer
|
|
1498
|
+
* outside that directory selected. An importer inside the previous directory keeps its own package's files. The
|
|
1499
|
+
* innermost previous directory decides.
|
|
1500
|
+
* @param filename Selected file.
|
|
1501
|
+
* @param parent Importer path.
|
|
1502
|
+
* @returns The file to load.
|
|
1503
|
+
*/
|
|
1504
|
+
relocate(filename, parent) {
|
|
1505
|
+
let from = "";
|
|
1506
|
+
for (const dir of this.targets.keys()) if (filename.startsWith(dir) && dir.length > from.length) from = dir;
|
|
1507
|
+
if (from === "" || parent?.startsWith(from) === true) return filename;
|
|
1508
|
+
const relocated = this.targets.get(from) + filename.slice(from.length);
|
|
1509
|
+
return existsSync(relocated) ? relocated : filename;
|
|
1510
|
+
}
|
|
1511
|
+
};
|
|
1415
1512
|
/** One mutable pointer to the immutable runtime resolution. */
|
|
1416
1513
|
var ResolutionRouter = class {
|
|
1417
1514
|
nodeModulePaths;
|
|
1418
1515
|
current;
|
|
1419
1516
|
linkedTargets;
|
|
1517
|
+
moved = new MovedDirectories();
|
|
1420
1518
|
constructor(resolution, nodeModulePaths) {
|
|
1421
1519
|
this.nodeModulePaths = nodeModulePaths;
|
|
1422
1520
|
this.current = compileResolution(resolution);
|
|
@@ -1425,21 +1523,49 @@ var ResolutionRouter = class {
|
|
|
1425
1523
|
replace(successor) {
|
|
1426
1524
|
const entries = new Map(successor.entries.map((entry) => [entry.name, entry]));
|
|
1427
1525
|
if (successor.profilesDir !== this.current.profilesDir || successor.profileDir !== this.current.profileDir) throw new Error("profile resolution: a successor cannot change its profile scope");
|
|
1526
|
+
const rejected = [];
|
|
1527
|
+
const moves = [];
|
|
1428
1528
|
for (const [name, current] of this.current.entries) {
|
|
1429
1529
|
const next = entries.get(name);
|
|
1430
1530
|
if (next === void 0 && current.scope === "profile") continue;
|
|
1431
|
-
if (next
|
|
1531
|
+
if (next !== void 0 && current.scope === "profile" && next.scope === "profile") {
|
|
1532
|
+
if (current.realDir === canonicalPath(next.packageDir)) continue;
|
|
1533
|
+
rejected.push(`profile resolution: replacing ${JSON.stringify(name)} requires a process restart`);
|
|
1534
|
+
continue;
|
|
1535
|
+
}
|
|
1536
|
+
if (next === void 0 || !sameResolution(current.packageDir, next.packageDir) || current.scope === "installation" && !sameResolution(current.declarer, next.declarer) || current.scope === "installation" && current.version !== next.version || current.scope !== next.scope) rejected.push(`profile resolution: replacing ${JSON.stringify(name)} requires a process restart`);
|
|
1432
1537
|
}
|
|
1433
1538
|
const localPackageNames = new Set(successor.localPackageNames);
|
|
1434
|
-
for (const name of localPackageNames) if (!this.current.localPackageNames.has(name) && this.current.entries.has(name))
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1539
|
+
for (const name of localPackageNames) if (!this.current.localPackageNames.has(name) && this.current.entries.has(name)) rejected.push(`profile resolution: overriding ${JSON.stringify(name)} locally requires a process restart`);
|
|
1540
|
+
const targets = new Map(this.linkedTargets);
|
|
1541
|
+
for (const [name, previous] of this.linkedTargets) {
|
|
1542
|
+
const root = successor.linkedRoots.find((candidate) => candidate.name === name);
|
|
1543
|
+
const entry = entries.get(name);
|
|
1544
|
+
const target = root?.realPath ?? (entry?.scope === "profile" ? canonicalPath(entry.packageDir) : void 0);
|
|
1545
|
+
if (target === void 0 || sameResolution(previous, target)) continue;
|
|
1546
|
+
moves.push([previous, target]);
|
|
1547
|
+
targets.set(name, target);
|
|
1438
1548
|
}
|
|
1549
|
+
if (rejected.length > 0) throw new ResolutionRestartRequired(rejected.join("; "));
|
|
1439
1550
|
const next = compileResolution(successor);
|
|
1440
|
-
for (const { name, realPath } of successor.linkedRoots)
|
|
1551
|
+
for (const { name, realPath } of successor.linkedRoots) targets.set(name, realPath);
|
|
1552
|
+
this.linkedTargets = targets;
|
|
1553
|
+
for (const [from, to] of moves) this.moved.record(from, to);
|
|
1554
|
+
const current = [];
|
|
1555
|
+
for (const entry of next.entries.values()) current.push(entry.realDir);
|
|
1556
|
+
for (const root of successor.linkedRoots) current.push(root.realPath);
|
|
1557
|
+
this.moved.forget(current);
|
|
1441
1558
|
this.current = next;
|
|
1442
1559
|
}
|
|
1560
|
+
/**
|
|
1561
|
+
* The file to load instead of one Node selected through a link that has moved since; see {@link MovedDirectories}.
|
|
1562
|
+
* @param filename Selected file.
|
|
1563
|
+
* @param parent Importer path.
|
|
1564
|
+
* @returns The file to load.
|
|
1565
|
+
*/
|
|
1566
|
+
relocate(filename, parent) {
|
|
1567
|
+
return this.moved.relocate(filename, parent);
|
|
1568
|
+
}
|
|
1443
1569
|
/** Whether a module path has an interception layer: it lies in the profiles tree, the active profile, or a linked root. */
|
|
1444
1570
|
hasInterceptionLayerForPath(path) {
|
|
1445
1571
|
return findInterceptionLayer(path, this.current) !== void 0;
|
|
@@ -1758,7 +1884,23 @@ function installRuntimeInterception(resolution) {
|
|
|
1758
1884
|
delegatedEsm = previous;
|
|
1759
1885
|
}
|
|
1760
1886
|
};
|
|
1761
|
-
|
|
1887
|
+
const relocate = (result, parent) => {
|
|
1888
|
+
if (!result.url.startsWith("file:")) return result;
|
|
1889
|
+
const url = new URL(result.url);
|
|
1890
|
+
const filename = fileURLToPath(url);
|
|
1891
|
+
const relocated = router.relocate(filename, parent?.startsWith("file:") === true ? fileURLToPath(parent) : void 0);
|
|
1892
|
+
if (relocated === filename) return result;
|
|
1893
|
+
url.pathname = pathToFileURL(relocated).pathname;
|
|
1894
|
+
return {
|
|
1895
|
+
...result,
|
|
1896
|
+
url: url.href
|
|
1897
|
+
};
|
|
1898
|
+
};
|
|
1899
|
+
return (request, parent, attributes) => {
|
|
1900
|
+
const result = adapted(request, parent, attributes);
|
|
1901
|
+
/* v8 ignore next -- Node 24+ resolves synchronously; the Node 22 matrix covers its Promise result */
|
|
1902
|
+
return result instanceof Promise ? result.then((resolved) => relocate(resolved, parent)) : relocate(result, parent);
|
|
1903
|
+
};
|
|
1762
1904
|
};
|
|
1763
1905
|
let restoreEsm;
|
|
1764
1906
|
/* v8 ignore else -- CI coverage runs Node 24 v2; the Node 22 matrix exercises the v1 adapter */
|
|
@@ -1882,7 +2024,11 @@ function installRuntimeInterception(resolution) {
|
|
|
1882
2024
|
delegatedCjs--;
|
|
1883
2025
|
}
|
|
1884
2026
|
};
|
|
1885
|
-
|
|
2027
|
+
const relocatedFilename = (request, parent, main, options) => {
|
|
2028
|
+
const filename = wrappedFilename(request, parent, main, options);
|
|
2029
|
+
return isAbsolute(filename) ? router.relocate(filename, parent?.filename ?? void 0) : filename;
|
|
2030
|
+
};
|
|
2031
|
+
cjs._resolveFilename = relocatedFilename;
|
|
1886
2032
|
return {
|
|
1887
2033
|
packageDir(specifier, parentURL) {
|
|
1888
2034
|
return router.packageDir(specifier, parentURL);
|
|
@@ -1892,7 +2038,7 @@ function installRuntimeInterception(resolution) {
|
|
|
1892
2038
|
},
|
|
1893
2039
|
dispose() {
|
|
1894
2040
|
/* v8 ignore else -- interceptions are disposed in reverse installation order */
|
|
1895
|
-
if (cjs._resolveFilename ===
|
|
2041
|
+
if (cjs._resolveFilename === relocatedFilename) cjs._resolveFilename = originalFilename;
|
|
1896
2042
|
restoreEsm();
|
|
1897
2043
|
}
|
|
1898
2044
|
};
|
|
@@ -1931,17 +2077,17 @@ function iconOf(specifier, packageName, parentURL, manifestPath, value) {
|
|
|
1931
2077
|
label = manifestPath;
|
|
1932
2078
|
const root = realpathSync(dirname(manifestPath));
|
|
1933
2079
|
target = resolve(root, icon);
|
|
1934
|
-
const local = relative(root,
|
|
2080
|
+
const local = relative(root, realModuleFile(target));
|
|
1935
2081
|
if (local === ".." || local.startsWith(`..${sep}`) || isAbsolute(local)) throw new Error(`${label}: icon must remain inside its manifest directory`);
|
|
1936
2082
|
} else {
|
|
1937
2083
|
const exported = optionalResourcePath(`${specifier}/icon`, parentURL);
|
|
1938
2084
|
if (exported === void 0) return void 0;
|
|
1939
2085
|
target = label = exported;
|
|
1940
|
-
assertPackageOwned(
|
|
2086
|
+
assertPackageOwned(realModuleFile(target), packageName);
|
|
1941
2087
|
}
|
|
1942
2088
|
const mediaType = ICON_MEDIA_TYPES.get(extname(target).toLowerCase());
|
|
1943
2089
|
if (mediaType === void 0) throw new Error(`${label}: icon must be SVG, PNG, JPEG, or WebP`);
|
|
1944
|
-
const file =
|
|
2090
|
+
const file = realModuleFile(target);
|
|
1945
2091
|
const stat = statSync(file);
|
|
1946
2092
|
if (!stat.isFile()) throw new Error(`${label}: icon must be a regular file`);
|
|
1947
2093
|
if (stat.size > MAX_ICON_BYTES) throw new Error(`${label}: icon exceeds 256 KiB`);
|
|
@@ -1959,7 +2105,7 @@ function assertPackageOwned(file, name) {
|
|
|
1959
2105
|
}
|
|
1960
2106
|
/**
|
|
1961
2107
|
* Resolve a plugin resource through the active Node ESM resolver without evaluating it.
|
|
1962
|
-
* @param specifier -
|
|
2108
|
+
* @param specifier - plugin module or exported resource specifier.
|
|
1963
2109
|
* @param parentURL - owning module-resolution base.
|
|
1964
2110
|
* @returns the local filesystem path selected by Node and the active profile.
|
|
1965
2111
|
* @throws when the resolver is unavailable or the resource cannot resolve to a local file.
|
|
@@ -2241,6 +2387,42 @@ function prepareProfilePatches(ctx, patches, parentURL, binName = "dsh") {
|
|
|
2241
2387
|
return rows.length === 0 ? [] : [{ insert: rows }];
|
|
2242
2388
|
}
|
|
2243
2389
|
//#endregion
|
|
2390
|
+
//#region lib/types/official-bundle-packages.js
|
|
2391
|
+
/** Package admission shared by offline catalog generation and release ordering. */
|
|
2392
|
+
/** Public DSH release members available through the ordinary on-demand bundle installer. */
|
|
2393
|
+
const ON_DEMAND_BUNDLES = ["@deepseek-ai/dsh-subagent-claude-code", "@deepseek-ai/dsh-subagent-codex"];
|
|
2394
|
+
//#endregion
|
|
2395
|
+
//#region lib/types/official-bundles.generated.js
|
|
2396
|
+
/** Generated offline Official bundle metadata. Run pnpm gen-official-bundle-catalog; do not edit. */
|
|
2397
|
+
/** Official on-demand entries, independent of installed packages and registry availability. */
|
|
2398
|
+
const OFFICIAL_ON_DEMAND_CATALOG = [{
|
|
2399
|
+
packageName: "@deepseek-ai/dsh-subagent-claude-code",
|
|
2400
|
+
meta: {
|
|
2401
|
+
title: {
|
|
2402
|
+
"en": "Claude Code subagent",
|
|
2403
|
+
"zh": "Claude Code 子智能体"
|
|
2404
|
+
},
|
|
2405
|
+
description: {
|
|
2406
|
+
"en": "Delegate one task to Claude Code using its native authentication and settings.",
|
|
2407
|
+
"zh": "使用 Claude Code 原生认证和设置委派单个任务。"
|
|
2408
|
+
},
|
|
2409
|
+
icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzYiIGhlaWdodD0iMzYiIHZpZXdCb3g9IjAgMCAzNiAzNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB4PSIxNC45ODkzIiB5PSIxNS4xODc3IiB3aWR0aD0iMTIuMjM2NSIgaGVpZ2h0PSIxMi4yMzY1IiByeD0iMiIgZmlsbD0idXJsKCNkc2hfcGx1Z2luX2FydF9SMGEpIiBmaWxsLW9wYWNpdHk9IjAuOCI+PC9yZWN0PjxyZWN0IHg9IjguODcxMDkiIHk9IjkuMDY5NyIgd2lkdGg9IjEyLjIzNjUiIGhlaWdodD0iMTIuMjM2NSIgcng9IjIiIGZpbGw9InVybCgjZHNoX3BsdWdpbl9hcnRfUjBiKSIgZmlsbC1vcGFjaXR5PSIwLjgiPjwvcmVjdD48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9ImRzaF9wbHVnaW5fYXJ0X1IwYSIgeDE9IjIxLjEwNzUiIHkxPSIxNS4xODc3IiB4Mj0iMjEuMTA3NSIgeTI9IjI3LjQyNDMiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBzdG9wLWNvbG9yPSIjNDVFN0E0Ij48L3N0b3A+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDU5MDlEIj48L3N0b3A+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImRzaF9wbHVnaW5fYXJ0X1IwYiIgeDE9IjE0Ljk4OTQiIHkxPSI5LjA2OTciIHgyPSIxNC45ODk0IiB5Mj0iMjEuMzA2MyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIHN0b3AtY29sb3I9IiM2OUI5RkYiPjwvc3RvcD48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMzMjRERTIiPjwvc3RvcD48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48L3N2Zz4K"
|
|
2410
|
+
}
|
|
2411
|
+
}, {
|
|
2412
|
+
packageName: "@deepseek-ai/dsh-subagent-codex",
|
|
2413
|
+
meta: {
|
|
2414
|
+
title: {
|
|
2415
|
+
"en": "Codex subagent",
|
|
2416
|
+
"zh": "Codex 子智能体"
|
|
2417
|
+
},
|
|
2418
|
+
description: {
|
|
2419
|
+
"en": "Delegate one task to Codex using its native authentication and settings.",
|
|
2420
|
+
"zh": "使用 Codex 原生认证和设置委派单个任务。"
|
|
2421
|
+
},
|
|
2422
|
+
icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzYiIGhlaWdodD0iMzYiIHZpZXdCb3g9IjAgMCAzNiAzNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB4PSIxNC45ODkzIiB5PSIxNS4xODc3IiB3aWR0aD0iMTIuMjM2NSIgaGVpZ2h0PSIxMi4yMzY1IiByeD0iMiIgZmlsbD0idXJsKCNkc2hfcGx1Z2luX2FydF9SMGEpIiBmaWxsLW9wYWNpdHk9IjAuOCI+PC9yZWN0PjxyZWN0IHg9IjguODcxMDkiIHk9IjkuMDY5NyIgd2lkdGg9IjEyLjIzNjUiIGhlaWdodD0iMTIuMjM2NSIgcng9IjIiIGZpbGw9InVybCgjZHNoX3BsdWdpbl9hcnRfUjBiKSIgZmlsbC1vcGFjaXR5PSIwLjgiPjwvcmVjdD48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9ImRzaF9wbHVnaW5fYXJ0X1IwYSIgeDE9IjIxLjEwNzUiIHkxPSIxNS4xODc3IiB4Mj0iMjEuMTA3NSIgeTI9IjI3LjQyNDMiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBzdG9wLWNvbG9yPSIjNDVFN0E0Ij48L3N0b3A+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDU5MDlEIj48L3N0b3A+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImRzaF9wbHVnaW5fYXJ0X1IwYiIgeDE9IjE0Ljk4OTQiIHkxPSI5LjA2OTciIHgyPSIxNC45ODk0IiB5Mj0iMjEuMzA2MyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIHN0b3AtY29sb3I9IiM2OUI5RkYiPjwvc3RvcD48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMzMjRERTIiPjwvc3RvcD48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48L3N2Zz4K"
|
|
2423
|
+
}
|
|
2424
|
+
}];
|
|
2425
|
+
//#endregion
|
|
2244
2426
|
//#region lib/types/config-schema/native.js
|
|
2245
2427
|
/** Identity checks at the plugin-export and lazy-builder boundaries. */
|
|
2246
2428
|
/**
|
|
@@ -3310,10 +3492,14 @@ var PluginPackages = class extends Service {
|
|
|
3310
3492
|
interception.dispose();
|
|
3311
3493
|
}, "profile package resolution");
|
|
3312
3494
|
}
|
|
3495
|
+
/** The published runtime resolution, or `undefined` when Node resolves packages alone. */
|
|
3496
|
+
get resolution() {
|
|
3497
|
+
return this.current;
|
|
3498
|
+
}
|
|
3313
3499
|
/**
|
|
3314
3500
|
* Publish a complete successor generation for this process and subsequently created Workers.
|
|
3315
3501
|
* Profile mappings and local package names may be removed after their plugins stop; linked roots may also be removed.
|
|
3316
|
-
* Retained profile mappings may change their declarer, but not their normalized directory
|
|
3502
|
+
* Retained profile mappings may change their declarer and version, but not their normalized directory or scope;
|
|
3317
3503
|
* installation mappings must remain unchanged. Publication does not unload modules or clear Node caches.
|
|
3318
3504
|
* @param successor - fully constructed generation accepted by {@link RuntimeInterception.replace}.
|
|
3319
3505
|
*/
|
|
@@ -3561,7 +3747,30 @@ function loadLayeredEnv(binName, cwd = process.cwd(), warn = (line) => void proc
|
|
|
3561
3747
|
}
|
|
3562
3748
|
const bootstrapIncludes = /* @__PURE__ */ new WeakMap();
|
|
3563
3749
|
const userPatchesSchema = entryListSchema;
|
|
3564
|
-
/**
|
|
3750
|
+
/**
|
|
3751
|
+
* Recompose the profile from its complete patch list, together with its runtime resolution. The rows the generation no
|
|
3752
|
+
* longer lists are removed first and their disposal finishes while their packages are still mapped; the latest
|
|
3753
|
+
* generation of an installed, recomputable resolution is published; the compatibility preflight reads the published
|
|
3754
|
+
* packages; the generation is applied to the root Include; entries that ran, and enabled entries whose import failed,
|
|
3755
|
+
* start afterwards when the update left them without a running fiber; and activation is judged. A failure before the generation applies,
|
|
3756
|
+
* including a publication the resolution rejects, which reports `package-moved`, puts the removed rows back at their
|
|
3757
|
+
* places, starting them again, and starts the entries that ran again. An entry waiting for a service is reported as a
|
|
3758
|
+
* warning unless it is required. Patches are copied with `structuredClone`, so they hold no functions.
|
|
3759
|
+
* @param ctx Booted root context.
|
|
3760
|
+
* @param patches Complete ordered patch list.
|
|
3761
|
+
* @param binName Diagnostic prefix.
|
|
3762
|
+
* @param options What the caller already did and requires.
|
|
3763
|
+
* @returns Diagnostics for unchanged pre-existing inactive entries, and the restart reason of a rejected publication.
|
|
3764
|
+
* @throws When the root Include is missing; the latest resolution cannot be read or published; preparation or the
|
|
3765
|
+
* Loader update rejects; or for a new or changed failure, an inactive required entry, a failed entry that ran, or a
|
|
3766
|
+
* healthy fiber whose disposal rejected.
|
|
3767
|
+
*/
|
|
3768
|
+
function recomposeProfile(ctx, patches, binName, options = {}) {
|
|
3769
|
+
return recompose(ctx, patches, binName, options, true);
|
|
3770
|
+
}
|
|
3771
|
+
/**
|
|
3772
|
+
* Apply a complete patch list to the root Include and judge activation, leaving the runtime resolution and entries
|
|
3773
|
+
* whose import failed as they are.
|
|
3565
3774
|
* @param ctx Booted root context.
|
|
3566
3775
|
* @param patches Complete ordered patch list.
|
|
3567
3776
|
* @param binName Diagnostic prefix.
|
|
@@ -3569,33 +3778,141 @@ const userPatchesSchema = entryListSchema;
|
|
|
3569
3778
|
* @returns Diagnostics for unchanged pre-existing inactive entries; new or changed failures reject.
|
|
3570
3779
|
*/
|
|
3571
3780
|
async function reconcileProfilePatches(ctx, patches, binName, requiredIds = []) {
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3781
|
+
return (await recompose(ctx, patches, binName, { requiredIds }, false)).warnings;
|
|
3782
|
+
}
|
|
3783
|
+
async function recompose(ctx, patches, binName, options, withResolution) {
|
|
3784
|
+
const { requiredIds = [], running = [] } = options;
|
|
3785
|
+
let applying = false;
|
|
3786
|
+
let stopped = [];
|
|
3787
|
+
try {
|
|
3788
|
+
const entry = bootstrapIncludes.get(ctx);
|
|
3789
|
+
if (entry === void 0) throw new Error(`${binName}: profile reload requires the root Include entry`);
|
|
3790
|
+
const previousFailures = (await inactiveEntries(ctx, false)).map((failure) => ({
|
|
3791
|
+
entry: failure.entry,
|
|
3792
|
+
fiber: failure.entry.fiber,
|
|
3793
|
+
options: JSON.stringify(failure.entry.options),
|
|
3794
|
+
diagnostic: failure.entry.fiber?.uid ? reloadDiagnostic(failure) : void 0
|
|
3795
|
+
}));
|
|
3796
|
+
const previousFibers = [...ctx.loader.entries()].flatMap((row) => row.fiber === void 0 ? [] : [{
|
|
3797
|
+
fiber: row.fiber,
|
|
3798
|
+
failed: row.fiber.state === FIBER_FAILED || row.fiber.state === FIBER_DISPOSED
|
|
3799
|
+
}]);
|
|
3800
|
+
const { patches: previous = [], ...includeConfig } = entry.options.config;
|
|
3801
|
+
const current = withResolution ? ctx.get("pluginPackages")?.resolution : void 0;
|
|
3802
|
+
const successor = current instanceof ProfileRuntimeResolution ? await current.computeLatestResolution() : void 0;
|
|
3803
|
+
if (successor !== void 0) {
|
|
3804
|
+
const listed = rowIds(structuredClone(patches));
|
|
3805
|
+
const composed = rowIds(structuredClone(previous));
|
|
3806
|
+
const tree = entry.subgroup?.tree;
|
|
3807
|
+
const dropped = [...ctx.loader.entries()].filter((row) => row.parent.tree === tree && composed.has(row.options.id) && !listed.has(row.options.id));
|
|
3808
|
+
const ids = new Set(dropped.map((row) => row.options.id));
|
|
3809
|
+
const topmost = dropped.filter((row) => !ids.has(row.parent.ctx.fiber.entry?.options.id));
|
|
3810
|
+
stopped = topmost.map((row) => ({
|
|
3811
|
+
group: row.parent,
|
|
3812
|
+
options: structuredClone(row.options),
|
|
3813
|
+
index: row.parent.data.indexOf(row.options)
|
|
3814
|
+
}));
|
|
3815
|
+
if (topmost.length > 0) {
|
|
3816
|
+
const fibers = dropped.flatMap((row) => row.fiber === void 0 ? [] : [row.fiber]);
|
|
3817
|
+
for (const row of topmost) {
|
|
3818
|
+
row.options.disabled = true;
|
|
3819
|
+
row.parent.remove(row.options.id);
|
|
3820
|
+
}
|
|
3821
|
+
await Promise.allSettled(fibers.map((fiber) => fiber.await()));
|
|
3822
|
+
await ctx.loader.await();
|
|
3823
|
+
}
|
|
3824
|
+
try {
|
|
3825
|
+
publish(ctx, successor);
|
|
3826
|
+
} catch (error) {
|
|
3827
|
+
if (!(error instanceof ResolutionRestartRequired)) throw error;
|
|
3828
|
+
return {
|
|
3829
|
+
warnings: [],
|
|
3830
|
+
restartReason: "package-moved"
|
|
3831
|
+
};
|
|
3832
|
+
}
|
|
3833
|
+
}
|
|
3834
|
+
const parentURL = new URL(".", new URL(includeConfig.path, entry.parent.tree.ctx.baseUrl)).href;
|
|
3835
|
+
const prepared = prepareProfilePatches(ctx, patches, parentURL, binName);
|
|
3836
|
+
applying = true;
|
|
3837
|
+
const retried = [...new Set([...running, ...withResolution ? [...ctx.loader.entries()].filter(importFailed) : []])];
|
|
3838
|
+
try {
|
|
3839
|
+
await entry.update({ config: {
|
|
3840
|
+
...includeConfig,
|
|
3841
|
+
patches: prepared
|
|
3842
|
+
} });
|
|
3843
|
+
} finally {
|
|
3844
|
+
await resume(ctx, retried);
|
|
3845
|
+
}
|
|
3846
|
+
const results = await Promise.allSettled(previousFibers.map(({ fiber }) => fiber.await()));
|
|
3847
|
+
await ctx.loader.await();
|
|
3848
|
+
const failures = await inactiveEntries(ctx);
|
|
3849
|
+
const introduced = failures.filter((failure) => {
|
|
3850
|
+
if (requiredIds.includes(failure.entry.options.id)) return true;
|
|
3851
|
+
if (failure.outcome.kind === "pending") return false;
|
|
3852
|
+
if (running.includes(failure.entry)) return true;
|
|
3853
|
+
return !previousFailures.some((previous) => sameFailure(previous, failure));
|
|
3854
|
+
});
|
|
3855
|
+
if (introduced.length > 0) throw new Error(activationDiagnostic(binName, introduced, false).trimEnd());
|
|
3856
|
+
for (const [index, result] of results.entries()) if (result.status === "rejected" && !previousFibers[index]?.failed) throw result.reason;
|
|
3857
|
+
ctx.emit("app-boot/config-reload");
|
|
3858
|
+
return { warnings: failures.map(reloadDiagnostic) };
|
|
3859
|
+
} finally {
|
|
3860
|
+
if (!applying && (stopped.length > 0 || running.length > 0)) try {
|
|
3861
|
+
for (const { group, options, index } of stopped.toSorted((left, right) => left.index - right.index)) {
|
|
3862
|
+
group.data.splice(index, 0, options);
|
|
3863
|
+
await group.create(options);
|
|
3864
|
+
}
|
|
3865
|
+
await resume(ctx, running);
|
|
3866
|
+
const ran = new Set(running.map((row) => row.options.id));
|
|
3867
|
+
for (const failure of await inactiveEntries(ctx)) if (ran.has(failure.entry.options.id)) ctx.logger.warn(`${binName}: ${reloadDiagnostic(failure)}`);
|
|
3868
|
+
} catch (error) {
|
|
3869
|
+
ctx.logger.warn(error);
|
|
3870
|
+
}
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
/** Whether an inactive entry is the failure recorded before: the same entry, fiber and options, and a matching diagnostic. */
|
|
3874
|
+
function sameFailure(previous, failure) {
|
|
3875
|
+
return previous.entry === failure.entry && previous.fiber === failure.entry.fiber && previous.options === JSON.stringify(failure.entry.options) && (previous.diagnostic === void 0 || previous.diagnostic === reloadDiagnostic(failure));
|
|
3876
|
+
}
|
|
3877
|
+
/** The ids of the rows a patch list inserts, including the rows of groups. */
|
|
3878
|
+
function rowIds(patches) {
|
|
3879
|
+
const ids = /* @__PURE__ */ new Set();
|
|
3880
|
+
const visit = (rows) => {
|
|
3881
|
+
for (const row of rows) {
|
|
3882
|
+
ids.add(row.id);
|
|
3883
|
+
if ((row.group === true || row.name === "cordis:group") && Array.isArray(row.config)) visit(row.config);
|
|
3884
|
+
}
|
|
3885
|
+
};
|
|
3886
|
+
visit(applyEntryPatches([], patches, () => {}));
|
|
3887
|
+
return ids;
|
|
3888
|
+
}
|
|
3889
|
+
/** Publish a generation unless it maps exactly what is published, which would only drop the package caches. */
|
|
3890
|
+
function publish(ctx, next) {
|
|
3891
|
+
const table = ({ localPackageNames, entries, linkedRoots }) => JSON.stringify([
|
|
3892
|
+
localPackageNames,
|
|
3893
|
+
entries,
|
|
3894
|
+
linkedRoots
|
|
3895
|
+
]);
|
|
3896
|
+
const packages = ctx.pluginPackages;
|
|
3897
|
+
if (table(packages.resolution) !== table(next)) packages.replace(next);
|
|
3898
|
+
}
|
|
3899
|
+
/** Whether an enabled entry below a running parent has no fiber or keeps the disposed fiber of a failed import. */
|
|
3900
|
+
function importFailed(entry) {
|
|
3901
|
+
return enabledEntry(entry) && entry.parent.ctx.fiber.uid !== null && (entry.fiber === void 0 || entry.fiber.state === FIBER_DISPOSED);
|
|
3902
|
+
}
|
|
3903
|
+
/** Whether an entry is enabled now; a throwing `disabled` expression counts as disabled. */
|
|
3904
|
+
function enabledEntry(entry) {
|
|
3905
|
+
try {
|
|
3906
|
+
return !entry.disabled;
|
|
3907
|
+
} catch (_error) {
|
|
3908
|
+
return false;
|
|
3909
|
+
}
|
|
3910
|
+
}
|
|
3911
|
+
/** Start invalidated entries the Loader still holds without a running fiber, then wait until it settles. */
|
|
3912
|
+
async function resume(ctx, invalidated) {
|
|
3913
|
+
const entries = new Set(ctx.loader.entries());
|
|
3914
|
+
for (const row of invalidated) if (entries.has(row) && !row.fiber?.uid) await row.update({}, false, true);
|
|
3592
3915
|
await ctx.loader.await();
|
|
3593
|
-
const failures = await inactiveEntries(ctx);
|
|
3594
|
-
const introduced = failures.filter((failure) => requiredIds.includes(failure.entry.options.id) || !previousFailures.some((previous) => previous.entry === failure.entry && previous.fiber === failure.entry.fiber && previous.options === JSON.stringify(failure.entry.options) && previous.diagnostic === inactiveDiagnostic(failure)));
|
|
3595
|
-
if (introduced.length > 0) throw new Error(activationDiagnostic(binName, introduced).trimEnd());
|
|
3596
|
-
for (const [index, result] of results.entries()) if (result.status === "rejected" && !previousFibers[index]?.failed) throw result.reason;
|
|
3597
|
-
ctx.emit("app-boot/config-reload");
|
|
3598
|
-
return failures.map(inactiveDiagnostic);
|
|
3599
3916
|
}
|
|
3600
3917
|
/**
|
|
3601
3918
|
* Load an optional patch-list file: a top-level YAML array of loader patch
|
|
@@ -3939,6 +4256,7 @@ const FIBER_DISPOSED = 4;
|
|
|
3939
4256
|
const requiredStartupEntryIds = new Set([
|
|
3940
4257
|
"agent-loop",
|
|
3941
4258
|
"webserver",
|
|
4259
|
+
"web-runtime",
|
|
3942
4260
|
"modules",
|
|
3943
4261
|
"connection",
|
|
3944
4262
|
"headless-runner",
|
|
@@ -3946,7 +4264,7 @@ const requiredStartupEntryIds = new Set([
|
|
|
3946
4264
|
"sdk-jsonrpc-server"
|
|
3947
4265
|
]);
|
|
3948
4266
|
/** Render plugin stacks, nested causes, and aggregate member failures once per error. */
|
|
3949
|
-
function formatActivationError(error) {
|
|
4267
|
+
function formatActivationError(error, stacks = true) {
|
|
3950
4268
|
const details = [];
|
|
3951
4269
|
const seen = /* @__PURE__ */ new Set();
|
|
3952
4270
|
function visit(value) {
|
|
@@ -3956,7 +4274,7 @@ function formatActivationError(error) {
|
|
|
3956
4274
|
}
|
|
3957
4275
|
if (seen.has(value)) return;
|
|
3958
4276
|
seen.add(value);
|
|
3959
|
-
details.push(value.stack ?? value.message);
|
|
4277
|
+
details.push(stacks ? value.stack ?? value.message : String(value));
|
|
3960
4278
|
if (value.cause !== void 0) visit(value.cause);
|
|
3961
4279
|
if (value instanceof AggregateError) value.errors.forEach(visit);
|
|
3962
4280
|
}
|
|
@@ -3982,12 +4300,23 @@ var StartupError = class extends Error {
|
|
|
3982
4300
|
});
|
|
3983
4301
|
}
|
|
3984
4302
|
};
|
|
4303
|
+
/** The error importing an entry's module raises now, which Node returns from its cache for a module that failed before. */
|
|
4304
|
+
async function importFailure(entry) {
|
|
4305
|
+
try {
|
|
4306
|
+
await entry.parent.tree.import(entry.options.name);
|
|
4307
|
+
return;
|
|
4308
|
+
} catch (error) {
|
|
4309
|
+
return error;
|
|
4310
|
+
}
|
|
4311
|
+
}
|
|
3985
4312
|
/**
|
|
3986
4313
|
* Collect Loader activation failures and disabled-expression errors. Failed
|
|
3987
4314
|
* fibers are awaited to recover their recorded rejection reason and coalesce
|
|
3988
4315
|
* duplicate Loader notifications through the next process rejection checkpoint.
|
|
4316
|
+
* An entry whose import failed reports the error importing it raises now; without
|
|
4317
|
+
* `importNow` nothing is imported and the entry reports a failed import without the import error.
|
|
3989
4318
|
*/
|
|
3990
|
-
async function inactiveEntries(ctx) {
|
|
4319
|
+
async function inactiveEntries(ctx, importNow = true) {
|
|
3991
4320
|
const failures = [];
|
|
3992
4321
|
const rejectionReasons = [];
|
|
3993
4322
|
for (const entry of ctx.loader.entries()) {
|
|
@@ -4005,12 +4334,17 @@ async function inactiveEntries(ctx) {
|
|
|
4005
4334
|
continue;
|
|
4006
4335
|
}
|
|
4007
4336
|
const fiber = entry.fiber;
|
|
4008
|
-
if (fiber === void 0) {
|
|
4337
|
+
if (fiber === void 0 || fiber.state === FIBER_DISPOSED) {
|
|
4338
|
+
const error = importNow ? await importFailure(entry) : void 0;
|
|
4009
4339
|
failures.push({
|
|
4010
4340
|
entry,
|
|
4011
|
-
outcome: {
|
|
4341
|
+
outcome: error === void 0 ? {
|
|
4342
|
+
kind: "failed",
|
|
4343
|
+
error: fiber === void 0 ? "failed to import" : `fiber state ${String(fiber.state)}`
|
|
4344
|
+
} : {
|
|
4012
4345
|
kind: "failed",
|
|
4013
|
-
error
|
|
4346
|
+
error,
|
|
4347
|
+
phase: "failed to import"
|
|
4014
4348
|
}
|
|
4015
4349
|
});
|
|
4016
4350
|
continue;
|
|
@@ -4053,17 +4387,21 @@ async function inactiveEntries(ctx) {
|
|
|
4053
4387
|
return failures;
|
|
4054
4388
|
}
|
|
4055
4389
|
/** Render one failed plugin's original error and activation phase. */
|
|
4056
|
-
function failureDetail(outcome) {
|
|
4057
|
-
return `${outcome.phase === void 0 ? "" : `${outcome.phase}: `}${formatActivationError(outcome.error)}`;
|
|
4390
|
+
function failureDetail(outcome, stacks = true) {
|
|
4391
|
+
return `${outcome.phase === void 0 ? "" : `${outcome.phase}: `}${formatActivationError(outcome.error, stacks)}`;
|
|
4058
4392
|
}
|
|
4059
4393
|
/** Render optional-only warnings without changing startup policy. */
|
|
4060
|
-
function activationDiagnostic(binName, failures) {
|
|
4394
|
+
function activationDiagnostic(binName, failures, stacks = true) {
|
|
4061
4395
|
const noun = failures.length === 1 ? "entry" : "entries";
|
|
4062
|
-
return `${binName}: warning: ${String(failures.length)} ${noun} did not activate\n${failures.map(inactiveDiagnostic).join("\n")}\n`;
|
|
4396
|
+
return `${binName}: warning: ${String(failures.length)} ${noun} did not activate\n${failures.map((failure) => inactiveDiagnostic(failure, stacks)).join("\n")}\n`;
|
|
4397
|
+
}
|
|
4398
|
+
/** Per-entry reload text, which people read through the Web UI and agents, so it carries error messages without stack frames. */
|
|
4399
|
+
function reloadDiagnostic(failure) {
|
|
4400
|
+
return inactiveDiagnostic(failure, false);
|
|
4063
4401
|
}
|
|
4064
4402
|
/** Stable per-entry text for reload comparisons and optional warnings. */
|
|
4065
|
-
function inactiveDiagnostic({ entry, outcome }) {
|
|
4066
|
-
const detail = outcome.kind === "failed" ? failureDetail(outcome) : `pending (waiting for ${outcome.missing.length === 1 ? "service" : "services"}: ${outcome.missing.join(", ") || "unknown"})`;
|
|
4403
|
+
function inactiveDiagnostic({ entry, outcome }, stacks = true) {
|
|
4404
|
+
const detail = outcome.kind === "failed" ? failureDetail(outcome, stacks) : `pending (waiting for ${outcome.missing.length === 1 ? "service" : "services"}: ${outcome.missing.join(", ") || "unknown"})`;
|
|
4067
4405
|
return `${entry.options.id} (${entry.options.name}): ${detail}`;
|
|
4068
4406
|
}
|
|
4069
4407
|
/** Group startup failures and pending services, marking every required entry. */
|
|
@@ -4204,37 +4542,11 @@ async function boot(binName, absoluteConfigPath, patches, prepare, bareModuleBas
|
|
|
4204
4542
|
seen.add(deepest);
|
|
4205
4543
|
deepest = deepest.cause;
|
|
4206
4544
|
}
|
|
4207
|
-
const stack = deepest instanceof AggregateError ? `\n${deepest.stack ?? deepest.message}\n${deepest.errors.map(formatActivationError).join("\n")}` : deepest instanceof Error && deepest !== cause ? `\n${deepest.stack ?? deepest.message}` : "";
|
|
4545
|
+
const stack = deepest instanceof AggregateError ? `\n${deepest.stack ?? deepest.message}\n${deepest.errors.map((error) => formatActivationError(error)).join("\n")}` : deepest instanceof Error && deepest !== cause ? `\n${deepest.stack ?? deepest.message}` : "";
|
|
4208
4546
|
throw new Error(`${binName}: ${stage}: ${detail}${stack}`, { cause });
|
|
4209
4547
|
} finally {
|
|
4210
4548
|
await diagnostics.fiber.dispose();
|
|
4211
4549
|
}
|
|
4212
4550
|
}
|
|
4213
|
-
/** Prompt-section name for the harness-source location line an app bin adds after boot. */
|
|
4214
|
-
const HARNESS_SOURCE_SECTION = "harness:source";
|
|
4215
|
-
/**
|
|
4216
|
-
* Add a global prompt section naming the on-disk harness source checkout while
|
|
4217
|
-
* explicitly distinguishing it from the task workspace and current working
|
|
4218
|
-
* directory. The self-referential `dsh-tool-cordis` toolset reads and edits this
|
|
4219
|
-
* checkout. Call once on the settled boot context ({@link boot}); the section
|
|
4220
|
-
* uses the shared first-party placement after reusable instructions
|
|
4221
|
-
* and before the Web surface and persona suffix. A booted tree with no
|
|
4222
|
-
* `systemPrompt` service has no prompt to augment, so this is then a no-op
|
|
4223
|
-
* that returns `undefined`. The section is
|
|
4224
|
-
* registered against the `systemPrompt` service's fiber, so a dev HMR reload of
|
|
4225
|
-
* that plugin drops it until the next boot.
|
|
4226
|
-
* @param ctx - the settled boot context whose global system prompt to augment.
|
|
4227
|
-
* @param sourceRoot - the absolute path to the harness checkout root.
|
|
4228
|
-
* @returns the section disposer, or `undefined` when no `systemPrompt` service is mounted.
|
|
4229
|
-
*/
|
|
4230
|
-
function addHarnessSourceSection(ctx, sourceRoot) {
|
|
4231
|
-
const systemPrompt = ctx.get("systemPrompt");
|
|
4232
|
-
if (systemPrompt === void 0) return void 0;
|
|
4233
|
-
return systemPrompt.section({
|
|
4234
|
-
name: HARNESS_SOURCE_SECTION,
|
|
4235
|
-
order: systemPrompt.getSectionOrder("HARNESS_SOURCE"),
|
|
4236
|
-
text: `The DeepSeek Harness implementation checkout is at ${sourceRoot}. The checkout location and current working directory are separate values and may differ; never infer the working directory from this path. Use pwd to determine the current working directory. Use this checkout only to inspect or extend DSH itself.`
|
|
4237
|
-
});
|
|
4238
|
-
}
|
|
4239
4551
|
//#endregion
|
|
4240
|
-
export { DEFAULT_PROFILE_BUNDLES, FAIL_LOUD_RELEASE_TIMEOUT_MS,
|
|
4552
|
+
export { DEFAULT_PROFILE_BUNDLES, FAIL_LOUD_RELEASE_TIMEOUT_MS, LOADER_EXPRESSION_SCHEMA, OFFICIAL_ON_DEMAND_CATALOG, ON_DEMAND_BUNDLES, OPTIONAL_BUNDLES, PROFILES_DIR, PROFILE_COMPATIBILITY_FILENAME, PROFILE_PATCH_FILENAME, PROFILE_TEMPLATES, PluginPackages, ProfileRuntimeResolution, ResolutionRestartRequired, StartupError, auditStartupEntries, boot, bundlePatchFiles, bundlePatchPaths, composeEntries, createConfigProjector, createRuntimeResolution, evaluatePluginCompatibility, generateConfigSchema, getDshRuntimeVersion, initProfile, installFailLoud, isNativeConfigSchema, loadEnv, loadLayeredEnv, loadOptionalPatches, loadOverlayPatches, loadProfile, loadProfileDirectory, mountRootInclude, pluginCompatibilityWarning, prepareProfileEntries, prepareProfilePatches, readBundlePatches, readPluginMeta, readProfileCompatibility, readProfileManifest, readProfilePatches, readProfilePlugins, readProfileVersionExemptions, recomposeProfile, reconcileProfilePatches, reconcileProfilePlugins, removeLinkProjections, renderConfigDump, reportSkippedBundles, resolveBundleDir, resolveConfigPath, resolvePluginResource, resolveProfileDir, resolveTelemetryPatch, sanitizeProfile, setProfileVersionExemption, writeProfileBundles, writeProfileManifest };
|