@deepseek-ai/dsh-app-boot 0.2.1-alpha.2 → 0.2.1-alpha.4
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 +16 -19
- package/README.md +11 -15
- package/README.zh.md +11 -15
- package/lib/index.js +379 -106
- package/lib/types/index.d.ts +41 -20
- package/lib/types/plugin-compatibility.d.ts +11 -10
- package/lib/types/profile-context.d.ts +7 -0
- package/lib/types/profile-resolution/resolver.d.ts +14 -6
- package/lib/types/profile-resolution/service.d.ts +3 -1
- package/lib/types/profile.d.ts +2 -2
- package/lib/worker/profile-resolution-bootstrap.js +133 -11
- package/package.json +18 -19
package/lib/types/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { type Entry } from '@deepseek-ai/cordis-plugin-loader';
|
|
|
10
10
|
import { type PatchOptions } from '@deepseek-ai/cordis-plugin-include';
|
|
11
11
|
import { dshHomePath } from '@deepseek-ai/dsh-home-paths';
|
|
12
12
|
import { type LaunchEnvironmentSnapshot } from '@deepseek-ai/dsh-launch-environment';
|
|
13
|
-
export { readProfilePatches, resolveTelemetryPatch, type ProfileContext, type ProfilePnpmInvocation } from './profile-context.ts';
|
|
13
|
+
export { readBundlePatches, readProfilePatches, resolveTelemetryPatch, type ProfileContext, type ProfilePnpmInvocation } from './profile-context.ts';
|
|
14
14
|
export { sanitizeProfile } from './profile-sanitize.ts';
|
|
15
15
|
export { getDshRuntimeVersion, evaluatePluginCompatibility, pluginCompatibilityWarning, type PluginCompatibility } from './plugin-compatibility.ts';
|
|
16
16
|
export { PROFILE_COMPATIBILITY_FILENAME, readProfileCompatibility, readProfileVersionExemptions, setProfileVersionExemption, type ProfileCompatibility, } from './profile-compatibility.ts';
|
|
@@ -37,6 +37,7 @@ declare module '@deepseek-ai/cordis' {
|
|
|
37
37
|
}
|
|
38
38
|
export { composeEntries, createRuntimeResolution, ProfileRuntimeResolution, DEFAULT_PROFILE_BUNDLES, OPTIONAL_BUNDLES, bundlePatchFiles, bundlePatchPaths, initProfile, removeLinkProjections, loadProfile, loadProfileDirectory, PROFILE_PATCH_FILENAME, PROFILE_TEMPLATES, PROFILES_DIR, readProfileManifest, reportSkippedBundles, resolveBundleDir, resolveProfileDir, writeProfileManifest, type Profile, type ProfileLayer, type SkippedBundle, type ProfileManifest, type LinkedRoot, type RuntimeResolutionOptions, type RuntimeResolutionEntry, type RuntimeResolution, type ProfileTemplate, } from './profile.ts';
|
|
39
39
|
export { PluginPackages, type PluginPackage, type PluginPackagesConfig, } from './profile-resolution/service.ts';
|
|
40
|
+
export { ResolutionRestartRequired } from './profile-resolution/resolver.ts';
|
|
40
41
|
/**
|
|
41
42
|
* Resolve the config to boot. Replay swaps a `cordis.yml` basename for
|
|
42
43
|
* `cordis.snapshot.yml` in the same directory; every other mode keeps the path.
|
|
@@ -67,7 +68,45 @@ export declare function loadEnv(binName: string, dir?: string, warn?: (line: str
|
|
|
67
68
|
* @throws when either file declares a bootstrap-only variable, except {@link HOME_LAYER_PROXY_NAMES} in the Harness-home file.
|
|
68
69
|
*/
|
|
69
70
|
export declare function loadLayeredEnv(binName: string, cwd?: string, warn?: (line: string) => void): LaunchEnvironmentSnapshot;
|
|
70
|
-
/**
|
|
71
|
+
/** What a caller of {@link recomposeProfile} already did and requires. */
|
|
72
|
+
export interface ProfileRecompositionOptions {
|
|
73
|
+
/** Explicit enablement targets whose existing failures also reject the recomposition. */
|
|
74
|
+
readonly requiredIds?: readonly string[];
|
|
75
|
+
/**
|
|
76
|
+
* Loader entries that ran before the caller stopped some of them. Each that no longer runs starts again, and each that
|
|
77
|
+
* failed afterwards counts as a new failure.
|
|
78
|
+
*/
|
|
79
|
+
readonly running?: readonly Entry[];
|
|
80
|
+
}
|
|
81
|
+
/** The outcome of a {@link recomposeProfile} that applied or kept the composition. */
|
|
82
|
+
export interface ProfileRecomposition {
|
|
83
|
+
/** Diagnostics for unchanged pre-existing inactive entries. */
|
|
84
|
+
warnings: string[];
|
|
85
|
+
/** Present when the runtime resolution could not publish a moved package or a changed installation mapping. */
|
|
86
|
+
restartReason?: 'package-moved';
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Recompose the profile from its complete patch list, together with its runtime resolution. The rows the generation no
|
|
90
|
+
* longer lists are removed first and their disposal finishes while their packages are still mapped; the latest
|
|
91
|
+
* generation of an installed, recomputable resolution is published; the compatibility preflight reads the published
|
|
92
|
+
* packages; the generation is applied to the root Include; entries that ran, and enabled entries whose import failed,
|
|
93
|
+
* start afterwards when the update left them without a running fiber; and activation is judged. A failure before the generation applies,
|
|
94
|
+
* including a publication the resolution rejects, which reports `package-moved`, puts the removed rows back at their
|
|
95
|
+
* places, starting them again, and starts the entries that ran again. An entry waiting for a service is reported as a
|
|
96
|
+
* warning unless it is required. Patches are copied with `structuredClone`, so they hold no functions.
|
|
97
|
+
* @param ctx Booted root context.
|
|
98
|
+
* @param patches Complete ordered patch list.
|
|
99
|
+
* @param binName Diagnostic prefix.
|
|
100
|
+
* @param options What the caller already did and requires.
|
|
101
|
+
* @returns Diagnostics for unchanged pre-existing inactive entries, and the restart reason of a rejected publication.
|
|
102
|
+
* @throws When the root Include is missing; the latest resolution cannot be read or published; preparation or the
|
|
103
|
+
* Loader update rejects; or for a new or changed failure, an inactive required entry, a failed entry that ran, or a
|
|
104
|
+
* healthy fiber whose disposal rejected.
|
|
105
|
+
*/
|
|
106
|
+
export declare function recomposeProfile(ctx: Context, patches: PatchOptions[], binName: string, options?: ProfileRecompositionOptions): Promise<ProfileRecomposition>;
|
|
107
|
+
/**
|
|
108
|
+
* Apply a complete patch list to the root Include and judge activation, leaving the runtime resolution and entries
|
|
109
|
+
* whose import failed as they are.
|
|
71
110
|
* @param ctx Booted root context.
|
|
72
111
|
* @param patches Complete ordered patch list.
|
|
73
112
|
* @param binName Diagnostic prefix.
|
|
@@ -306,22 +345,4 @@ export declare function auditStartupEntries(ctx: Context, binName: string, warn?
|
|
|
306
345
|
* diagnostic traversal without replacing the original cause.
|
|
307
346
|
*/
|
|
308
347
|
export declare function boot(binName: string, absoluteConfigPath: string, patches?: PatchOptions[], prepare?: (ctx: Context) => Promise<void> | void, bareModuleBaseUrl?: string): Promise<Context>;
|
|
309
|
-
/** Prompt-section name for the harness-source location line an app bin adds after boot. */
|
|
310
|
-
export declare const HARNESS_SOURCE_SECTION = "harness:source";
|
|
311
|
-
/**
|
|
312
|
-
* Add a global prompt section naming the on-disk harness source checkout while
|
|
313
|
-
* explicitly distinguishing it from the task workspace and current working
|
|
314
|
-
* directory. The self-referential `dsh-tool-cordis` toolset reads and edits this
|
|
315
|
-
* checkout. Call once on the settled boot context ({@link boot}); the section
|
|
316
|
-
* uses the shared first-party placement after reusable instructions
|
|
317
|
-
* and before the Web surface and persona suffix. A booted tree with no
|
|
318
|
-
* `systemPrompt` service has no prompt to augment, so this is then a no-op
|
|
319
|
-
* that returns `undefined`. The section is
|
|
320
|
-
* registered against the `systemPrompt` service's fiber, so a dev HMR reload of
|
|
321
|
-
* that plugin drops it until the next boot.
|
|
322
|
-
* @param ctx - the settled boot context whose global system prompt to augment.
|
|
323
|
-
* @param sourceRoot - the absolute path to the harness checkout root.
|
|
324
|
-
* @returns the section disposer, or `undefined` when no `systemPrompt` service is mounted.
|
|
325
|
-
*/
|
|
326
|
-
export declare function addHarnessSourceSection(ctx: Context, sourceRoot: string): (() => void) | undefined;
|
|
327
348
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
/** Evaluate plugin dsh
|
|
2
|
-
/**
|
|
1
|
+
/** Evaluate plugin dsh requirements (`engines.dsh`, else dsh peers) without importing plugin code. */
|
|
2
|
+
/** Unmet dsh requirements and the exact plugin/runtime exemption decision. */
|
|
3
3
|
export interface PluginCompatibility {
|
|
4
4
|
name: string;
|
|
5
5
|
version: string;
|
|
6
6
|
runtimeVersion: string;
|
|
7
|
-
/** Only
|
|
8
|
-
|
|
7
|
+
/** Only requirements the running dsh version does not satisfy: `engines.dsh`, or dsh peer package names. */
|
|
8
|
+
requirements: Record<string, string>;
|
|
9
9
|
exempted: boolean;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
@@ -15,18 +15,19 @@ export interface PluginCompatibility {
|
|
|
15
15
|
*/
|
|
16
16
|
export declare function getDshRuntimeVersion(): string;
|
|
17
17
|
/**
|
|
18
|
-
* Check
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* Check the plugin's dsh requirements against the runtime. An own `engines.dsh` range decides alone and
|
|
19
|
+
* peerDependencies are ignored; otherwise every @deepseek-ai/dsh or @deepseek-ai/dsh-* peer must match.
|
|
20
|
+
* Prereleases participate in ranges. For peers only, workspace:^, workspace:~, and workspace:* refer to
|
|
21
|
+
* the current runtime; other empty or invalid ranges, including any workspace: `engines.dsh`, are unmet.
|
|
21
22
|
* @param manifest - parsed plugin package.json; inherited fields are ignored.
|
|
22
23
|
* @param exemptions - exact plugin name@version keys mapped to exact runtime versions.
|
|
23
24
|
* @param runtimeVersion - running dsh version, defaulting to this app-boot package.
|
|
24
|
-
* @returns
|
|
25
|
-
* @throws for malformed manifest peer fields, invalid runtime versions, or missing identity on a mismatch.
|
|
25
|
+
* @returns unmet requirements and exemption status, or undefined when every requirement is met.
|
|
26
|
+
* @throws for malformed manifest engines or peer fields, invalid runtime versions, or missing identity on a mismatch.
|
|
26
27
|
*/
|
|
27
28
|
export declare function evaluatePluginCompatibility(manifest: object, exemptions?: Readonly<Record<string, readonly string[]>>, runtimeVersion?: string): PluginCompatibility | undefined;
|
|
28
29
|
/**
|
|
29
|
-
* Describe
|
|
30
|
+
* Describe unmet requirements, their risk, and the exact-version remedy.
|
|
30
31
|
* Surfaces with their own grant mechanism or locale render the structured result themselves.
|
|
31
32
|
* @param issue - incompatible plugin/runtime result, including exempted mismatches.
|
|
32
33
|
* @returns an English diagnostic for logs and stderr.
|
|
@@ -41,6 +41,13 @@ declare module '@deepseek-ai/cordis' {
|
|
|
41
41
|
* @returns the disable patch, or `undefined` when no hard-disable patch is required.
|
|
42
42
|
*/
|
|
43
43
|
export declare function resolveTelemetryPatch(disabledEnv: string | undefined, hasRow: boolean): PatchOptions | undefined;
|
|
44
|
+
/** Read the selected bundles' patches, which apply before the profile patch file.
|
|
45
|
+
* @param binName Diagnostic prefix for malformed or missing configuration.
|
|
46
|
+
* @param context Data supplied by the profile launcher.
|
|
47
|
+
* @param initialProfile Already loaded startup profile; omitted reads the current files.
|
|
48
|
+
* @returns Bundle patches in application order.
|
|
49
|
+
*/
|
|
50
|
+
export declare function readBundlePatches(binName: string, context: ProfileContext, initialProfile?: Profile): PatchOptions[];
|
|
44
51
|
/** Read current bundle and user layers with the launch-time overlays.
|
|
45
52
|
* @param binName Diagnostic prefix for malformed or missing configuration.
|
|
46
53
|
* @param context Data supplied by the profile launcher.
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
/** In-memory profile package routing for Node's default ESM and CommonJS loaders. */
|
|
2
2
|
import type { RuntimeResolution } from '../profile.ts';
|
|
3
|
+
/** A successor resolution the running process cannot adopt, such as a retained mapping in another directory; it waits for a restart. */
|
|
4
|
+
export declare class ResolutionRestartRequired extends Error {
|
|
5
|
+
/** @param message Diagnostic naming the rejected changes. */
|
|
6
|
+
constructor(message: string);
|
|
7
|
+
}
|
|
3
8
|
/** Active interception in one Node isolate. */
|
|
4
9
|
export interface RuntimeInterception {
|
|
5
10
|
/**
|
|
@@ -12,13 +17,16 @@ export interface RuntimeInterception {
|
|
|
12
17
|
packageDir(specifier: string, parentURL: string): string | undefined;
|
|
13
18
|
/**
|
|
14
19
|
* Atomically publish a complete successor and fresh caches. Profile-scoped mappings, local names, and linked
|
|
15
|
-
* roots may be removed; removed roots stop intercepting uncovered directories.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
20
|
+
* roots may be removed; removed roots stop intercepting uncovered directories. A retained profile mapping may
|
|
21
|
+
* change its version and declarer when its normalized directory and scope stay unchanged, as when a package is
|
|
22
|
+
* upgraded in place. Existing modules and Node caches remain intact: callers remove a package only after its
|
|
23
|
+
* plugins stop, and replace the loaded modules of a package upgraded in place separately.
|
|
24
|
+
* A previously published link name may point to another real directory; callers stop the plugins of its previous
|
|
25
|
+
* target first, as removing and installing the package again does.
|
|
18
26
|
* @param successor - fully constructed generation retaining the installation mappings.
|
|
19
|
-
* @throws when the profile scope
|
|
20
|
-
*
|
|
21
|
-
*
|
|
27
|
+
* @throws when the profile scope changes; and `ResolutionRestartRequired` when a retained profile mapping's real
|
|
28
|
+
* directory or scope, or an installation version or declarer changes; an installation mapping is removed; or a new
|
|
29
|
+
* local name overrides an existing mapping.
|
|
22
30
|
*/
|
|
23
31
|
replace(successor: RuntimeResolution): void;
|
|
24
32
|
/** Restore the native resolver methods. Interceptions dispose in reverse order. */
|
|
@@ -33,10 +33,12 @@ export declare class PluginPackages extends Service {
|
|
|
33
33
|
private disposeWorkerResolution;
|
|
34
34
|
private current;
|
|
35
35
|
constructor(ctx: Context, config?: PluginPackagesConfig);
|
|
36
|
+
/** The published runtime resolution, or `undefined` when Node resolves packages alone. */
|
|
37
|
+
get resolution(): RuntimeResolution | undefined;
|
|
36
38
|
/**
|
|
37
39
|
* Publish a complete successor generation for this process and subsequently created Workers.
|
|
38
40
|
* Profile mappings and local package names may be removed after their plugins stop; linked roots may also be removed.
|
|
39
|
-
* Retained profile mappings may change their declarer, but not their normalized directory
|
|
41
|
+
* Retained profile mappings may change their declarer and version, but not their normalized directory or scope;
|
|
40
42
|
* installation mappings must remain unchanged. Publication does not unload modules or clear Node caches.
|
|
41
43
|
* @param successor - fully constructed generation accepted by {@link RuntimeInterception.replace}.
|
|
42
44
|
*/
|
package/lib/types/profile.d.ts
CHANGED
|
@@ -76,7 +76,7 @@ export interface Profile {
|
|
|
76
76
|
/** Selected bundles that contributed no layer, in `dsh.profile.bundles` order, with why. */
|
|
77
77
|
skippedBundles: SkippedBundle[];
|
|
78
78
|
}
|
|
79
|
-
/** A selected bundle the profile could not load, or whose own DSH
|
|
79
|
+
/** A selected bundle the profile could not load, or whose own DSH requirements the profile does not exempt. */
|
|
80
80
|
export interface SkippedBundle {
|
|
81
81
|
/** The bundle's package name from `dsh.profile.bundles`. */
|
|
82
82
|
packageName: string;
|
|
@@ -237,7 +237,7 @@ export declare function resolveBundleDir(binName: string, packageName: string, i
|
|
|
237
237
|
* the shared Harness home. This is used by application-owned profiles whose
|
|
238
238
|
* package project and lifecycle belong to that application.
|
|
239
239
|
* Retired bundles are removed from the stored bundle list first, rewriting the
|
|
240
|
-
* manifest when it listed one. Unreadable bundles, and bundles whose own dsh
|
|
240
|
+
* manifest when it listed one. Unreadable bundles, and bundles whose own dsh requirements the profile does not exempt, are skipped
|
|
241
241
|
* without changing the manifest and listed in `skippedBundles`; nothing is printed.
|
|
242
242
|
* @param binName - the diagnostic prefix on thrown errors.
|
|
243
243
|
* @param dir - absolute profile package directory.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire, isBuiltin } from "node:module";
|
|
2
2
|
import { getEnvironmentData } from "node:worker_threads";
|
|
3
3
|
import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
4
|
-
import { basename, dirname, join, resolve, sep } from "node:path";
|
|
4
|
+
import { basename, dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
6
|
//#region ../../../node_modules/.pnpm/resolve.exports@2.0.3/node_modules/resolve.exports/dist/index.mjs
|
|
7
7
|
function e(e, n, r) {
|
|
@@ -44,6 +44,14 @@ function f(e, r, t) {
|
|
|
44
44
|
//#region lib/types/profile-resolution/resolver.js
|
|
45
45
|
/** In-memory profile package routing for Node's default ESM and CommonJS loaders. */
|
|
46
46
|
const EMPTY_ATTRIBUTES = Object.freeze({});
|
|
47
|
+
/** A successor resolution the running process cannot adopt, such as a retained mapping in another directory; it waits for a restart. */
|
|
48
|
+
var ResolutionRestartRequired = class extends Error {
|
|
49
|
+
/** @param message Diagnostic naming the rejected changes. */
|
|
50
|
+
constructor(message) {
|
|
51
|
+
super(message);
|
|
52
|
+
this.name = "ResolutionRestartRequired";
|
|
53
|
+
}
|
|
54
|
+
};
|
|
47
55
|
/**
|
|
48
56
|
* Split a bare request into its package name without allocating path segments.
|
|
49
57
|
* @param request - module specifier to classify.
|
|
@@ -57,6 +65,15 @@ function barePackageName(request) {
|
|
|
57
65
|
const second = request.indexOf("/", first + 1);
|
|
58
66
|
return second < 0 ? request : request.slice(0, second);
|
|
59
67
|
}
|
|
68
|
+
/** The JavaScript and native real paths of an existing directory; none for a directory that no longer exists. */
|
|
69
|
+
function realSpellings(path) {
|
|
70
|
+
try {
|
|
71
|
+
const native = Reflect.get(realpathSync, "native");
|
|
72
|
+
return [realpathSync(path), ...typeof native === "function" ? [String(Reflect.apply(native, realpathSync, [path]))] : []];
|
|
73
|
+
} catch (_error) {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
60
77
|
function canonicalPath(path) {
|
|
61
78
|
try {
|
|
62
79
|
return realpathSync(path);
|
|
@@ -71,7 +88,10 @@ function prefixes(path) {
|
|
|
71
88
|
}
|
|
72
89
|
function compileResolution(resolution) {
|
|
73
90
|
return {
|
|
74
|
-
entries: new Map(resolution.entries.map((entry) => [entry.name,
|
|
91
|
+
entries: new Map(resolution.entries.map((entry) => [entry.name, {
|
|
92
|
+
...entry,
|
|
93
|
+
realDir: canonicalPath(entry.packageDir)
|
|
94
|
+
}])),
|
|
75
95
|
profilesDir: resolution.profilesDir,
|
|
76
96
|
profileDir: resolution.profileDir,
|
|
77
97
|
profilePaths: prefixes(resolution.profilesDir),
|
|
@@ -234,11 +254,65 @@ function sameResolution(left, right) {
|
|
|
234
254
|
if (left === right) return true;
|
|
235
255
|
return canonicalPath(left) === canonicalPath(right);
|
|
236
256
|
}
|
|
257
|
+
/** A directory as given and in its JavaScript and native real paths, each with a trailing separator. */
|
|
258
|
+
function spellings(dir) {
|
|
259
|
+
const result = new Set([dir + sep]);
|
|
260
|
+
for (const real of realSpellings(dir)) result.add(real + sep);
|
|
261
|
+
return [...result];
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* The previous real directories of packages that moved, each mapped to the current one. Node keeps the real path of
|
|
265
|
+
* every link it resolved through and never refreshes it, so a lookup through a link that now points elsewhere still
|
|
266
|
+
* selects a file below the target Node saw first; {@link MovedDirectories.relocate} selects the same file below the
|
|
267
|
+
* current target instead.
|
|
268
|
+
*/
|
|
269
|
+
var MovedDirectories = class {
|
|
270
|
+
/** Previous directory to current directory, both with a trailing separator. */
|
|
271
|
+
targets = /* @__PURE__ */ new Map();
|
|
272
|
+
/**
|
|
273
|
+
* Record that a package moved from one directory to another. Every spelling of the previous directory leads to the
|
|
274
|
+
* current one. A directory that an earlier move led to the previous one now leads to the current one as well, since
|
|
275
|
+
* Node still selects files below the earliest target.
|
|
276
|
+
* @param from Previous real directory.
|
|
277
|
+
* @param to Current real directory.
|
|
278
|
+
*/
|
|
279
|
+
record(from, to) {
|
|
280
|
+
const previous = spellings(from);
|
|
281
|
+
const current = to + sep;
|
|
282
|
+
for (const [key, value] of this.targets) if (previous.includes(value)) this.targets.set(key, current);
|
|
283
|
+
for (const key of previous) this.targets.set(key, current);
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Forget the previous directories that are current again, in any spelling, and records that lead to themselves.
|
|
287
|
+
* @param current The real directories the published resolution maps.
|
|
288
|
+
*/
|
|
289
|
+
forget(current) {
|
|
290
|
+
const active = /* @__PURE__ */ new Set();
|
|
291
|
+
for (const dir of current) for (const spelling of spellings(dir)) active.add(spelling);
|
|
292
|
+
for (const [key, value] of [...this.targets]) if (active.has(key) || key === value) this.targets.delete(key);
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* The same file below the current directory when it exists, for a file below a previous directory that an importer
|
|
296
|
+
* outside that directory selected. An importer inside the previous directory keeps its own package's files. The
|
|
297
|
+
* innermost previous directory decides.
|
|
298
|
+
* @param filename Selected file.
|
|
299
|
+
* @param parent Importer path.
|
|
300
|
+
* @returns The file to load.
|
|
301
|
+
*/
|
|
302
|
+
relocate(filename, parent) {
|
|
303
|
+
let from = "";
|
|
304
|
+
for (const dir of this.targets.keys()) if (filename.startsWith(dir) && dir.length > from.length) from = dir;
|
|
305
|
+
if (from === "" || parent?.startsWith(from) === true) return filename;
|
|
306
|
+
const relocated = this.targets.get(from) + filename.slice(from.length);
|
|
307
|
+
return existsSync(relocated) ? relocated : filename;
|
|
308
|
+
}
|
|
309
|
+
};
|
|
237
310
|
/** One mutable pointer to the immutable runtime resolution. */
|
|
238
311
|
var ResolutionRouter = class {
|
|
239
312
|
nodeModulePaths;
|
|
240
313
|
current;
|
|
241
314
|
linkedTargets;
|
|
315
|
+
moved = new MovedDirectories();
|
|
242
316
|
constructor(resolution, nodeModulePaths) {
|
|
243
317
|
this.nodeModulePaths = nodeModulePaths;
|
|
244
318
|
this.current = compileResolution(resolution);
|
|
@@ -247,21 +321,49 @@ var ResolutionRouter = class {
|
|
|
247
321
|
replace(successor) {
|
|
248
322
|
const entries = new Map(successor.entries.map((entry) => [entry.name, entry]));
|
|
249
323
|
if (successor.profilesDir !== this.current.profilesDir || successor.profileDir !== this.current.profileDir) throw new Error("profile resolution: a successor cannot change its profile scope");
|
|
324
|
+
const rejected = [];
|
|
325
|
+
const moves = [];
|
|
250
326
|
for (const [name, current] of this.current.entries) {
|
|
251
327
|
const next = entries.get(name);
|
|
252
328
|
if (next === void 0 && current.scope === "profile") continue;
|
|
253
|
-
if (next
|
|
329
|
+
if (next !== void 0 && current.scope === "profile" && next.scope === "profile") {
|
|
330
|
+
if (current.realDir === canonicalPath(next.packageDir)) continue;
|
|
331
|
+
rejected.push(`profile resolution: replacing ${JSON.stringify(name)} requires a process restart`);
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
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`);
|
|
254
335
|
}
|
|
255
336
|
const localPackageNames = new Set(successor.localPackageNames);
|
|
256
|
-
for (const name of localPackageNames) if (!this.current.localPackageNames.has(name) && this.current.entries.has(name))
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
337
|
+
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`);
|
|
338
|
+
const targets = new Map(this.linkedTargets);
|
|
339
|
+
for (const [name, previous] of this.linkedTargets) {
|
|
340
|
+
const root = successor.linkedRoots.find((candidate) => candidate.name === name);
|
|
341
|
+
const entry = entries.get(name);
|
|
342
|
+
const target = root?.realPath ?? (entry?.scope === "profile" ? canonicalPath(entry.packageDir) : void 0);
|
|
343
|
+
if (target === void 0 || sameResolution(previous, target)) continue;
|
|
344
|
+
moves.push([previous, target]);
|
|
345
|
+
targets.set(name, target);
|
|
260
346
|
}
|
|
347
|
+
if (rejected.length > 0) throw new ResolutionRestartRequired(rejected.join("; "));
|
|
261
348
|
const next = compileResolution(successor);
|
|
262
|
-
for (const { name, realPath } of successor.linkedRoots)
|
|
349
|
+
for (const { name, realPath } of successor.linkedRoots) targets.set(name, realPath);
|
|
350
|
+
this.linkedTargets = targets;
|
|
351
|
+
for (const [from, to] of moves) this.moved.record(from, to);
|
|
352
|
+
const current = [];
|
|
353
|
+
for (const entry of next.entries.values()) current.push(entry.realDir);
|
|
354
|
+
for (const root of successor.linkedRoots) current.push(root.realPath);
|
|
355
|
+
this.moved.forget(current);
|
|
263
356
|
this.current = next;
|
|
264
357
|
}
|
|
358
|
+
/**
|
|
359
|
+
* The file to load instead of one Node selected through a link that has moved since; see {@link MovedDirectories}.
|
|
360
|
+
* @param filename Selected file.
|
|
361
|
+
* @param parent Importer path.
|
|
362
|
+
* @returns The file to load.
|
|
363
|
+
*/
|
|
364
|
+
relocate(filename, parent) {
|
|
365
|
+
return this.moved.relocate(filename, parent);
|
|
366
|
+
}
|
|
265
367
|
/** Whether a module path has an interception layer: it lies in the profiles tree, the active profile, or a linked root. */
|
|
266
368
|
hasInterceptionLayerForPath(path) {
|
|
267
369
|
return findInterceptionLayer(path, this.current) !== void 0;
|
|
@@ -580,7 +682,23 @@ function installRuntimeInterception(resolution) {
|
|
|
580
682
|
delegatedEsm = previous;
|
|
581
683
|
}
|
|
582
684
|
};
|
|
583
|
-
|
|
685
|
+
const relocate = (result, parent) => {
|
|
686
|
+
if (!result.url.startsWith("file:")) return result;
|
|
687
|
+
const url = new URL(result.url);
|
|
688
|
+
const filename = fileURLToPath(url);
|
|
689
|
+
const relocated = router.relocate(filename, parent?.startsWith("file:") === true ? fileURLToPath(parent) : void 0);
|
|
690
|
+
if (relocated === filename) return result;
|
|
691
|
+
url.pathname = pathToFileURL(relocated).pathname;
|
|
692
|
+
return {
|
|
693
|
+
...result,
|
|
694
|
+
url: url.href
|
|
695
|
+
};
|
|
696
|
+
};
|
|
697
|
+
return (request, parent, attributes) => {
|
|
698
|
+
const result = adapted(request, parent, attributes);
|
|
699
|
+
/* v8 ignore next -- Node 24+ resolves synchronously; the Node 22 matrix covers its Promise result */
|
|
700
|
+
return result instanceof Promise ? result.then((resolved) => relocate(resolved, parent)) : relocate(result, parent);
|
|
701
|
+
};
|
|
584
702
|
};
|
|
585
703
|
let restoreEsm;
|
|
586
704
|
/* v8 ignore else -- CI coverage runs Node 24 v2; the Node 22 matrix exercises the v1 adapter */
|
|
@@ -704,7 +822,11 @@ function installRuntimeInterception(resolution) {
|
|
|
704
822
|
delegatedCjs--;
|
|
705
823
|
}
|
|
706
824
|
};
|
|
707
|
-
|
|
825
|
+
const relocatedFilename = (request, parent, main, options) => {
|
|
826
|
+
const filename = wrappedFilename(request, parent, main, options);
|
|
827
|
+
return isAbsolute(filename) ? router.relocate(filename, parent?.filename ?? void 0) : filename;
|
|
828
|
+
};
|
|
829
|
+
cjs._resolveFilename = relocatedFilename;
|
|
708
830
|
return {
|
|
709
831
|
packageDir(specifier, parentURL) {
|
|
710
832
|
return router.packageDir(specifier, parentURL);
|
|
@@ -714,7 +836,7 @@ function installRuntimeInterception(resolution) {
|
|
|
714
836
|
},
|
|
715
837
|
dispose() {
|
|
716
838
|
/* v8 ignore else -- interceptions are disposed in reverse installation order */
|
|
717
|
-
if (cjs._resolveFilename ===
|
|
839
|
+
if (cjs._resolveFilename === relocatedFilename) cjs._resolveFilename = originalFilename;
|
|
718
840
|
restoreEsm();
|
|
719
841
|
}
|
|
720
842
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-app-boot",
|
|
3
3
|
"description": "Shared boot glue for the app bins: .env loading, fail-loud Loader guards, snapshot-aware config resolution, and the Loader boot sequence",
|
|
4
|
-
"version": "0.2.1-alpha.
|
|
4
|
+
"version": "0.2.1-alpha.4",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
],
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@deepseek-ai/dsh-atomic-write": "0.2.1-alpha.
|
|
36
|
-
"@deepseek-ai/dsh-package-manifest": "0.2.1-alpha.
|
|
35
|
+
"@deepseek-ai/dsh-atomic-write": "0.2.1-alpha.4",
|
|
36
|
+
"@deepseek-ai/dsh-package-manifest": "0.2.1-alpha.4",
|
|
37
37
|
"@eslint-community/regexpp": "^4.12.2",
|
|
38
38
|
"ajv": "^8.20.0",
|
|
39
39
|
"js-yaml": "^4.3.2",
|
|
@@ -42,25 +42,24 @@
|
|
|
42
42
|
"semver": "^7.8.5"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@deepseek-ai/cordis-plugin-group": "~1.0.5-alpha.
|
|
46
|
-
"@deepseek-ai/cordis-plugin-include": "~1.0.10-alpha.
|
|
47
|
-
"@deepseek-ai/cordis-plugin-loader": "~1.0.6-alpha.
|
|
48
|
-
"@deepseek-ai/dsh-launch-environment": "0.2.1-alpha.
|
|
49
|
-
"@deepseek-ai/dsh-home-paths": "0.2.1-alpha.
|
|
50
|
-
"@deepseek-ai/
|
|
51
|
-
"@deepseek-ai/cordis": "~4.0.5-alpha.1"
|
|
45
|
+
"@deepseek-ai/cordis-plugin-group": "~1.0.5-alpha.2",
|
|
46
|
+
"@deepseek-ai/cordis-plugin-include": "~1.0.10-alpha.2",
|
|
47
|
+
"@deepseek-ai/cordis-plugin-loader": "~1.0.6-alpha.2",
|
|
48
|
+
"@deepseek-ai/dsh-launch-environment": "0.2.1-alpha.4",
|
|
49
|
+
"@deepseek-ai/dsh-home-paths": "0.2.1-alpha.4",
|
|
50
|
+
"@deepseek-ai/cordis": "~4.0.5-alpha.2"
|
|
52
51
|
},
|
|
53
52
|
"devDependencies": {
|
|
54
|
-
"@deepseek-ai/schemastery": "~3.18.5-alpha.
|
|
55
|
-
"@deepseek-ai/cordis-plugin-group": "~1.0.5-alpha.
|
|
56
|
-
"@deepseek-ai/cordis-plugin-include": "~1.0.10-alpha.
|
|
57
|
-
"@deepseek-ai/cordis-plugin-loader": "~1.0.6-alpha.
|
|
58
|
-
"@deepseek-ai/cordis-plugin-timer": "~1.1.7-alpha.
|
|
59
|
-
"@deepseek-ai/dsh-launch-environment": "0.2.1-alpha.
|
|
60
|
-
"@deepseek-ai/dsh-home-paths": "0.2.1-alpha.
|
|
61
|
-
"@deepseek-ai/dsh-system-prompt": "0.2.1-alpha.
|
|
53
|
+
"@deepseek-ai/schemastery": "~3.18.5-alpha.2",
|
|
54
|
+
"@deepseek-ai/cordis-plugin-group": "~1.0.5-alpha.2",
|
|
55
|
+
"@deepseek-ai/cordis-plugin-include": "~1.0.10-alpha.2",
|
|
56
|
+
"@deepseek-ai/cordis-plugin-loader": "~1.0.6-alpha.2",
|
|
57
|
+
"@deepseek-ai/cordis-plugin-timer": "~1.1.7-alpha.2",
|
|
58
|
+
"@deepseek-ai/dsh-launch-environment": "0.2.1-alpha.4",
|
|
59
|
+
"@deepseek-ai/dsh-home-paths": "0.2.1-alpha.4",
|
|
60
|
+
"@deepseek-ai/dsh-system-prompt": "0.2.1-alpha.4",
|
|
62
61
|
"@types/js-yaml": "^4.0.9",
|
|
63
62
|
"@types/semver": "^7.8.0",
|
|
64
|
-
"@deepseek-ai/cordis": "~4.0.5-alpha.
|
|
63
|
+
"@deepseek-ai/cordis": "~4.0.5-alpha.2"
|
|
65
64
|
}
|
|
66
65
|
}
|