@qlzt/dsh-app-boot 0.0.0-stage → 0.2.1-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,26 @@
1
+ import type { Context } from '@deepseek-ai/cordis';
2
+ import type { EntryOptions } from '@deepseek-ai/cordis-plugin-loader';
3
+ import { type PatchOptions } from '@deepseek-ai/cordis-plugin-include';
4
+ /** Prepare profile or preset rows before the owning DSH caller passes them to Loader.
5
+ * Only a compatibility conflict denies a row: an entry whose manifest cannot be resolved keeps
6
+ * the Loader's own import failure. A denied ordinary row gains `disabled`; a native Include that
7
+ * reaches a denied plugin is denied as a whole, because its file is never rewritten.
8
+ * @param ctx Context carrying launcher-owned profile facts; non-profile contexts retain their rows.
9
+ * @param entries Complete effective entry list, after patch composition.
10
+ * @param parentURL Resolution base of the tree that will import these rows.
11
+ * @param binName Diagnostic prefix for a denied row; defaults to `dsh`.
12
+ * @returns Detached rows with incompatible entries denied; reads the profile compatibility file once.
13
+ * @throws For malformed compatibility permissions or a profile composition without a resolution base.
14
+ */
15
+ export declare function prepareProfileEntries(ctx: Context, entries: readonly EntryOptions[], parentURL: string | undefined, binName?: string): EntryOptions[];
16
+ /** Apply compatibility policy to the complete patch composition over a profile's empty root.
17
+ * The caller passes every patch layer of the profile, because this returns one insertion patch for
18
+ * that empty root: a non-empty root config would lose the caller's override patches by id.
19
+ * @param ctx Profile context prepared by the launcher.
20
+ * @param patches Original ordered profile patches; these remain unchanged.
21
+ * @param parentURL Root Include's resolution base.
22
+ * @param binName Diagnostic prefix for a denied row; defaults to `dsh`.
23
+ * @returns One prepared insertion patch for profiles, or the original patches for non-profile callers.
24
+ */
25
+ export declare function prepareProfilePatches(ctx: Context, patches: PatchOptions[], parentURL: string, binName?: string): PatchOptions[];
26
+ //# sourceMappingURL=compatibility-preflight.d.ts.map
@@ -0,0 +1,16 @@
1
+ /** Boot-free inspection of declared plugin Config schemas using profile module resolution. */
2
+ import type { Profile, RuntimeResolution } from '../profile.ts';
3
+ import type { ConfigSchemaDiagnostic, ConfigSchemaDump } from './types.ts';
4
+ /**
5
+ * Generate JSON Schema from parsed entry rows and root-tree patches without applying plugins or evaluating expressions.
6
+ * Imports, Config getters, and lazy schema builders execute trusted plugin code; transform callbacks do not. Calls must not overlap
7
+ * another profile-resolution interception; module imports remain cached after the interception is released.
8
+ * @param profile - prepared profile whose directory anchors root module and include resolution.
9
+ * @param entries - unvalidated rows from profile composition; malformed rows become positioned diagnostics without losing siblings.
10
+ * @param resolution - the same immutable package resolution used for profile boot.
11
+ * @param diagnostics - existing composition diagnostics; copied into the returned catalog.
12
+ * @returns a JSON Schema document with partial-result diagnostics and Config references under `x-cordis`.
13
+ * @throws when Node's profile module resolution cannot be installed.
14
+ */
15
+ export declare function collectConfigSchemas(profile: Profile, entries: readonly unknown[], resolution: RuntimeResolution, diagnostics?: readonly ConfigSchemaDiagnostic[]): Promise<ConfigSchemaDump>;
16
+ //# sourceMappingURL=collect.d.ts.map
@@ -0,0 +1,13 @@
1
+ /** Compose Loader entry/patch structure and discovered plugin input schemas into one JSON Schema document. */
2
+ import type { CollectedConfigEntry, ConfigSchemaDiagnostic, ConfigSchemaDump } from './types.ts';
3
+ /**
4
+ * Build a schema for the composed entry list and a separately addressable root-tree patch list.
5
+ * Unknown plugin names remain open; only collected schemas supply plugin-specific constraints.
6
+ * @param profile - selected profile name.
7
+ * @param collected - declarations discovered without mounting plugins, including include descendants.
8
+ * @param targets - last-id-wins patch targets from the root tree's patch index, excluding include descendants.
9
+ * @param initialDiagnostics - composition and import diagnostics already collected.
10
+ * @returns one JSON Schema document with explicit collection and projection annotations.
11
+ */
12
+ export declare function buildConfigSchemaDocument(profile: string, collected: readonly CollectedConfigEntry[], targets: ReadonlyMap<string, CollectedConfigEntry>, initialDiagnostics: readonly ConfigSchemaDiagnostic[]): Promise<ConfigSchemaDump>;
13
+ //# sourceMappingURL=document.d.ts.map
@@ -0,0 +1,19 @@
1
+ /** Profile schema generation: composition diagnostics, runtime resolution, and boot-free discovery. */
2
+ import type { PatchOptions } from '@deepseek-ai/cordis-plugin-include';
3
+ import { type Profile } from '../profile.ts';
4
+ import type { ConfigSchemaDump } from './types.ts';
5
+ export type { ConfigSchemaDump, NativeConfigSchema } from './types.ts';
6
+ /**
7
+ * Generate JSON Schema for a prepared profile's ordered patch layers without mounting plugins or evaluating expressions.
8
+ * Imports, Config getters, and lazy builders execute trusted code. Native validators and
9
+ * transform callbacks are not executed. Calls must not overlap another profile-resolution interception; collection
10
+ * releases its interception on success or rejection, while Node retains imported modules. Supplied layers are not mutated.
11
+ * Profile preparation, layer selection, process streams, and exit policy belong to the caller.
12
+ * @param profile - prepared on-disk profile whose directory anchors root module and include resolution.
13
+ * @param layers - already parsed patch lists in application order, including caller-selected home and argv overlays.
14
+ * @param installAnchor - package manifest anchoring the installation's runtime dependencies.
15
+ * @returns a JSON Schema document with declaration references, partial results, and diagnostics under `x-cordis`.
16
+ * @throws when composition or runtime resolution cannot be prepared.
17
+ */
18
+ export declare function generateConfigSchema(profile: Profile, layers: readonly PatchOptions[][], installAnchor: string): Promise<ConfigSchemaDump>;
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,9 @@
1
+ /** Identity checks at the plugin-export and lazy-builder boundaries. */
2
+ import type { NativeConfigSchema } from './types.ts';
3
+ /**
4
+ * Recognize the native Schemastery graph protocol without invoking a validator or serialization hook.
5
+ * @param value - plugin Config export or lazy-builder result.
6
+ * @returns whether native schema fields can be inspected.
7
+ */
8
+ export declare function isNativeConfigSchema(value: unknown): value is NativeConfigSchema;
9
+ //# sourceMappingURL=native.d.ts.map
@@ -0,0 +1,8 @@
1
+ /** Conservative compatibility checks between native RegExp validation and Unicode JSON Schema patterns. */
2
+ /**
3
+ * Create a checker for patterns that can retain native acceptance under Unicode regex semantics.
4
+ * Unrecognized flagless syntax stays explicitly partial rather than becoming a misleading constraint.
5
+ * @returns the compatibility predicate; parsing never executes the regular expression against config values.
6
+ */
7
+ export declare function createPatternCheck(): Promise<(source: string, flags?: string) => boolean>;
8
+ //# sourceMappingURL=pattern.d.ts.map
@@ -0,0 +1,20 @@
1
+ /** Project native Config input constraints without executing their validators or transform callbacks. */
2
+ import type { ConfigJsonSchema, ConfigJsonSchemaObject, NativeConfigSchema } from './types.ts';
3
+ /** Definition that projected value positions reference as `#/$defs/loaderExpression`; an enclosing document must define it. */
4
+ export declare const LOADER_EXPRESSION_SCHEMA: ConfigJsonSchemaObject;
5
+ /** One Config projection; unknown omission behavior is explicit rather than an invented default. */
6
+ export interface ConfigProjection {
7
+ /** Object-form root: value positions are wrapped in `anyOf` with the loader-expression reference. */
8
+ schema: ConfigJsonSchemaObject;
9
+ definitions: Record<string, ConfigJsonSchema>;
10
+ acceptsMissing: boolean | 'unknown';
11
+ limitations: string[];
12
+ }
13
+ /**
14
+ * Create an invocation-local projector. Ajv checks only literal defaults against generated schemas;
15
+ * it does not fill defaults, coerce input, or call native plugin validators. Opaque input or metadata effects
16
+ * widen validation with explicit limitations instead of simulating native mutation.
17
+ * @returns a function projecting one trusted native Config graph into the enclosing document's definitions.
18
+ */
19
+ export declare function createConfigProjector(): Promise<(root: NativeConfigSchema, prefix: string) => ConfigProjection>;
20
+ //# sourceMappingURL=projector.d.ts.map
@@ -0,0 +1,95 @@
1
+ /** JSON Schema output and native graph inputs for boot-free configuration inspection. */
2
+ /** JSON Schema 2020-12, including annotations that standard validators may ignore. */
3
+ export type ConfigJsonSchema = boolean | ConfigJsonSchemaObject;
4
+ /** Object-form JSON Schema; vocabulary extensions are annotations, not executable validators. */
5
+ export interface ConfigJsonSchemaObject {
6
+ [keyword: string]: unknown;
7
+ $schema?: string;
8
+ $ref?: string;
9
+ $defs?: Record<string, ConfigJsonSchema>;
10
+ type?: string | string[];
11
+ properties?: Record<string, ConfigJsonSchema>;
12
+ required?: string[];
13
+ items?: ConfigJsonSchema;
14
+ prefixItems?: ConfigJsonSchema[];
15
+ additionalProperties?: ConfigJsonSchema;
16
+ propertyNames?: ConfigJsonSchema;
17
+ anyOf?: ConfigJsonSchema[];
18
+ allOf?: ConfigJsonSchema[];
19
+ not?: ConfigJsonSchema;
20
+ if?: ConfigJsonSchema;
21
+ then?: ConfigJsonSchema;
22
+ default?: unknown;
23
+ description?: string;
24
+ }
25
+ /** A collection or projection diagnostic, without independently collected config values. */
26
+ export interface ConfigSchemaDiagnostic {
27
+ level: 'warning' | 'error';
28
+ /** Structural position in the discovered entry tree, when applicable. */
29
+ path?: string;
30
+ message: string;
31
+ }
32
+ /** One declared entry and its generated Config reference; include paths describe discovery, not root JSON pointers. */
33
+ export interface ConfigSchemaEntry {
34
+ path: string;
35
+ id?: string;
36
+ /** Omitted when a malformed row has no literal plugin name. */
37
+ name?: string;
38
+ status: 'schema' | 'partial' | 'absent' | 'unsupported' | 'error';
39
+ configRef?: string;
40
+ /** Native Loader carrier, whose config is not interpolated as an ordinary plugin config. */
41
+ tree?: 'group' | 'include';
42
+ }
43
+ /** JSON Schema for a composed entry list; `$defs.patchList` describes profile overlays. */
44
+ export interface ConfigSchemaDump extends ConfigJsonSchemaObject {
45
+ $schema: 'https://json-schema.org/draft/2020-12/schema';
46
+ $defs: Record<string, ConfigJsonSchema>;
47
+ 'x-cordis': {
48
+ profile: string;
49
+ /** False for error diagnostics, partial/unsupported/error entries, or ambiguous plugin-name schemas; includes disabled declarations. */
50
+ complete: boolean;
51
+ entries: ConfigSchemaEntry[];
52
+ diagnostics: ConfigSchemaDiagnostic[];
53
+ patchSchema: '#/$defs/patchList';
54
+ };
55
+ }
56
+ /** Native Schemastery graph protocol after its identity marker has been checked. */
57
+ export interface NativeConfigSchema {
58
+ type: string;
59
+ meta: {
60
+ role?: string;
61
+ extra?: unknown;
62
+ hidden?: boolean;
63
+ disabled?: boolean;
64
+ collapse?: boolean;
65
+ link?: string;
66
+ comment?: string;
67
+ badges?: {
68
+ text: string;
69
+ type: string;
70
+ }[];
71
+ required?: boolean;
72
+ volatile?: boolean;
73
+ default?: unknown;
74
+ min?: number;
75
+ max?: number;
76
+ step?: number;
77
+ pattern?: {
78
+ source: string;
79
+ flags?: string;
80
+ };
81
+ description?: string | Record<string, string>;
82
+ loose?: boolean;
83
+ };
84
+ dict?: Record<string, NativeConfigSchema>;
85
+ inner?: NativeConfigSchema;
86
+ sKey?: NativeConfigSchema;
87
+ list?: NativeConfigSchema[];
88
+ value?: unknown;
89
+ builder?: unknown;
90
+ }
91
+ /** Collected declaration used only while constructing the JSON Schema document. */
92
+ export interface CollectedConfigEntry extends ConfigSchemaEntry {
93
+ native?: NativeConfigSchema;
94
+ }
95
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,327 @@
1
+ /**
2
+ * Shared boot glue for `dsh` profiles, including the CLI packaged by the Python runtime wheel: load the gitignored
3
+ * `.env`, install the fail-loud Loader guards, resolve the config path (snapshot-aware), load the
4
+ * optional user patch layers from the Harness home (`~/.dsh`), expose its path resolver to
5
+ * config expressions, and drive the Cordis Loader against a leaf `cordis.yml` until the tree settles.
6
+ * @module @qlzt/dsh-app-boot
7
+ */
8
+ import { Context, type FiberState } from '@deepseek-ai/cordis';
9
+ import { type Entry } from '@deepseek-ai/cordis-plugin-loader';
10
+ import { type PatchOptions } from '@deepseek-ai/cordis-plugin-include';
11
+ import { dshHomePath } from '@qlzt/dsh-home-paths';
12
+ import { type LaunchEnvironmentSnapshot } from '@qlzt/dsh-launch-environment';
13
+ export { readProfilePatches, resolveTelemetryPatch, type ProfileContext, type ProfilePnpmInvocation } from './profile-context.ts';
14
+ export { sanitizeProfile } from './profile-sanitize.ts';
15
+ export { getDshRuntimeVersion, evaluatePluginCompatibility, pluginCompatibilityWarning, type PluginCompatibility } from './plugin-compatibility.ts';
16
+ export { PROFILE_COMPATIBILITY_FILENAME, readProfileCompatibility, readProfileVersionExemptions, setProfileVersionExemption, type ProfileCompatibility, } from './profile-compatibility.ts';
17
+ export { prepareProfileEntries, prepareProfilePatches } from './compatibility-preflight.ts';
18
+ export { readPluginMeta, resolvePluginResource } from './package-meta.ts';
19
+ export { ON_DEMAND_BUNDLES, OFFICIAL_ON_DEMAND_CATALOG, type OfficialBundleCatalogEntry } from './official-bundles.ts';
20
+ export { generateConfigSchema, type ConfigSchemaDump, type NativeConfigSchema } from './config-schema/index.ts';
21
+ export { createConfigProjector, LOADER_EXPRESSION_SCHEMA, type ConfigProjection } from './config-schema/projector.ts';
22
+ export { isNativeConfigSchema } from './config-schema/native.ts';
23
+ export { readProfilePlugins, reconcileProfilePlugins, writeProfileBundles, type ProfilePluginLocation, type ProfilePluginDependency, type ProfilePluginInventory, type ProfilePluginReconciliation, } from './profile-plugins.ts';
24
+ declare module '@deepseek-ai/cordis' {
25
+ interface Context {
26
+ /** Harness-home path resolver available to Loader `!!js` config expressions. */
27
+ dshHomePath?: typeof dshHomePath;
28
+ }
29
+ interface Events {
30
+ /**
31
+ * Profile patches were reconciled into the running Loader tree: every entry update settled and no new
32
+ * inactive entry was introduced. Carries no diff; listeners re-read Loader entries.
33
+ * @mode emit
34
+ */
35
+ 'app-boot/config-reload'(): void;
36
+ }
37
+ }
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
+ export { PluginPackages, type PluginPackage, type PluginPackagesConfig, } from './profile-resolution/service.ts';
40
+ /**
41
+ * Resolve the config to boot. Replay swaps a `cordis.yml` basename for
42
+ * `cordis.snapshot.yml` in the same directory; every other mode keeps the path.
43
+ * @param configPath - the requested config path (absolute, or relative to `cwd`).
44
+ * @param snapshotMode - the bin's `$DSH_SNAPSHOT` value; only `'replay'` swaps the
45
+ * basename.
46
+ * @param cwd - the base a relative `configPath` resolves against.
47
+ * @returns the absolute path of the config to boot.
48
+ */
49
+ export declare function resolveConfigPath(configPath: string, snapshotMode: string | undefined, cwd?: string): string;
50
+ /**
51
+ * Load the optional gitignored `.env` from `dir`. Missing files fall back to the
52
+ * ambient environment; other read failures are reported through `warn`.
53
+ * @param binName - the diagnostic prefix on the warn line.
54
+ * @param dir - the directory whose `.env` to load.
55
+ * @param warn - sink for the one-line misconfiguration diagnostic.
56
+ */
57
+ export declare function loadEnv(binName: string, dir?: string, warn?: (line: string) => void): void;
58
+ /**
59
+ * Load the product CLI's inherited > invoking-directory `.env` > Harness-home
60
+ * `.env` snapshot. The Harness home resolves before either file; both files
61
+ * are checked before either is applied, and accepted values are materialized
62
+ * without replacing inherited ones. The snapshot preserves which layer supplied each value.
63
+ * @param binName - the diagnostic prefix on the diagnostics.
64
+ * @param cwd - the invoking directory whose `.env` is the project layer.
65
+ * @param warn - sink for the one-line misconfiguration diagnostics.
66
+ * @returns this run's frozen environment snapshot.
67
+ * @throws when either file declares a bootstrap-only variable, except {@link HOME_LAYER_PROXY_NAMES} in the Harness-home file.
68
+ */
69
+ export declare function loadLayeredEnv(binName: string, cwd?: string, warn?: (line: string) => void): LaunchEnvironmentSnapshot;
70
+ /** Apply one complete patch generation and wait for Loader activation diagnostics.
71
+ * @param ctx Booted root context.
72
+ * @param patches Complete ordered patch list.
73
+ * @param binName Diagnostic prefix.
74
+ * @param requiredIds Explicit enablement targets whose existing failures also reject reconciliation.
75
+ * @returns Diagnostics for unchanged pre-existing inactive entries; new or changed failures reject.
76
+ */
77
+ export declare function reconcileProfilePatches(ctx: Context, patches: PatchOptions[], binName: string, requiredIds?: readonly string[]): Promise<string[]>;
78
+ /**
79
+ * Load an optional patch-list file: a top-level YAML array of loader patch
80
+ * entries (`@deepseek-ai/cordis-plugin-include`'s `PatchOptions`): id-targeted config
81
+ * overrides and `insert` lists, with `!!js` expressions allowed. A missing
82
+ * file means "no layer"; an unreadable, unparsable, or non-array file throws —
83
+ * a present patch file that cannot apply is a misconfiguration and must fail
84
+ * loud at boot, never be silently skipped.
85
+ * @param binName - the diagnostic prefix on the thrown error.
86
+ * @param file - absolute path of the patch file.
87
+ * @returns the parsed patches, or `undefined` when the file does not exist.
88
+ */
89
+ export declare function loadOptionalPatches(binName: string, file: string): PatchOptions[] | undefined;
90
+ /**
91
+ * Load a required overlay patch list: a bundle's `cordis.patch.yml` or a
92
+ * `--patch <path>` overlay. Same file format as {@link loadOptionalPatches},
93
+ * but a missing file throws, because the caller named this file — its absence
94
+ * is a misconfiguration, not "no overlay".
95
+ * @param binName - the diagnostic prefix on the thrown error.
96
+ * @param file - absolute path of the overlay file.
97
+ * @returns the parsed patch list.
98
+ */
99
+ export declare function loadOverlayPatches(binName: string, file: string): PatchOptions[];
100
+ /** One overlay patch list with the source label printed in dump comments. */
101
+ export interface ConfigDumpLayer {
102
+ /** Source name shown in dump comments (a file basename or path). */
103
+ label: string;
104
+ /** The layer's patches, from {@link loadOverlayPatches} / {@link loadOptionalPatches}. */
105
+ patches: PatchOptions[];
106
+ }
107
+ /**
108
+ * Compose the configured entry list: parse the base config file with the
109
+ * include's entry-list dialect, apply every layer's patches as ONE flattened
110
+ * list through the include's own patch algorithm (`applyEntryPatches`) — the
111
+ * same call `boot()` makes, so even patch-visibility corner cases (a later
112
+ * layer targeting a group child a plain config replacement introduced, which
113
+ * the single-pass id index never sees) compose identically — then render the
114
+ * result as YAML in the same dialect (`!!js` expressions print verbatim,
115
+ * unevaluated). Row admission is a later stage: a plugin row the compatibility
116
+ * policy denies still appears here, while a denied bundle contributes no layer.
117
+ *
118
+ * Every run of rows from the same file and patch layers is preceded by a `# ==` comment
119
+ * naming the file that contributed the rows and any layers that patched them,
120
+ * so the output stays a loadable YAML document while showing which section
121
+ * comes from which file. The file and patch labels are derived from single-call prefix
122
+ * snapshots (base + layers 1..k), diffed positionally: the patch algorithm
123
+ * only rewrites rows in place or appends, so a top-level index identifies one
124
+ * row across snapshots, and a layer whose addition changes the row (config
125
+ * replacement, disable, group insert) is listed as having patched it.
126
+ *
127
+ * A patch that matches no row is reported through `warn` with its layer
128
+ * label, mirroring the Loader's boot-time warning. Earlier layers' patches
129
+ * see an identical preceding state in every snapshot that includes them, so
130
+ * each snapshot's warning list extends the previous one and the new tail
131
+ * belongs to the added layer.
132
+ * @param binName - the diagnostic prefix on read/parse errors.
133
+ * @param absoluteConfigPath - the base config file `boot()` would include.
134
+ * @param layers - overlay layers in application order (later wins).
135
+ * @param warn - sink for skipped-patch diagnostics; defaults to stderr.
136
+ * @returns the composed entry list rendered as a YAML document with
137
+ * source comment separators.
138
+ */
139
+ export declare function renderConfigDump(binName: string, absoluteConfigPath: string, layers: ConfigDumpLayer[], warn?: (line: string) => void): string;
140
+ /**
141
+ * Mount and remember the exact root Include entry used by app boot and user patch-layer HMR.
142
+ * @param ctx - context carrying an initialized Loader service.
143
+ * @param absoluteConfigPath - absolute YAML or JSON configuration path.
144
+ * @param patches - initial app and user patches, applied in order.
145
+ * @param bareModuleBaseUrl - optional installed-host base for bare package
146
+ * names; relative names continue to resolve beside the configuration file.
147
+ * @param binName - diagnostic prefix for a profile plugin denied by compatibility policy; defaults to `dsh`.
148
+ * @returns the created root Include entry, or `undefined` when a surface
149
+ * disposed the whole tree (taking the Loader service with it) while the
150
+ * entry creation was in flight.
151
+ */
152
+ export declare function mountRootInclude(ctx: Context, absoluteConfigPath: string, patches?: readonly PatchOptions[], bareModuleBaseUrl?: string, binName?: string): Promise<Entry | undefined>;
153
+ /** The two process events {@link installFailLoud} turns into a fatal exit. */
154
+ export type FailLoudEvent = 'unhandledRejection' | 'uncaughtException';
155
+ /**
156
+ * The slice of `process` {@link installFailLoud} needs — injectable so tests
157
+ * exercise the handler without registering on (or exiting) the real process.
158
+ */
159
+ export interface FailLoudProcess {
160
+ on(event: FailLoudEvent, handler: (err: unknown) => void): unknown;
161
+ off(event: FailLoudEvent, handler: (err: unknown) => void): unknown;
162
+ stderr: {
163
+ write(chunk: string): unknown;
164
+ };
165
+ /**
166
+ * Terminate the process. Callers treat this as the end of the run, as
167
+ * `process.exit` is; a fake that returns lets the caller continue, which only
168
+ * a test observes.
169
+ */
170
+ exit(code: number): void;
171
+ }
172
+ /**
173
+ * How long {@link installFailLoud} waits for its `release` hook before exiting
174
+ * anyway. A wedged disposer must delay the fatal exit, never cancel it.
175
+ */
176
+ export declare const FAIL_LOUD_RELEASE_TIMEOUT_MS = 2000;
177
+ /**
178
+ * Install before boot to turn an unhandled rejection or an uncaught exception,
179
+ * at any point in the process lifetime, into one labelled stderr diagnostic and
180
+ * `exit(1)`. A rejection already included by {@link auditStartupEntries} is
181
+ * ignored during its process checkpoint; every other rejection and every
182
+ * uncaught exception remains fatal. Control never returns to the failed
183
+ * operation after either: only the throw site knows which state is intact, and
184
+ * a listener that threw mid-update (a stream `'data'` handler, a half-applied
185
+ * registry write) leaves silently wrong results behind if it were resumed. The
186
+ * event loop keeps running only until the release hook settles or times out.
187
+ * Stdout remains untouched for ACP; the returned function removes both handlers.
188
+ *
189
+ * The diagnostic is `util.inspect(err)`, not `err.stack`: a `node:fs` error's
190
+ * `code`, `syscall`, and `path` and any `cause` chain are enumerable properties
191
+ * that the stack line omits, and they are what a crash report needs. Once a
192
+ * handler is installed Node prints nothing of its own, so this line is the
193
+ * only record of the failure.
194
+ *
195
+ * The Loader mounts entries concurrently, so a surface that owns the terminal
196
+ * can already hold it when a sibling entry rejects. Exiting straight from the
197
+ * handler would strand raw mode, bracketed paste, and the keyboard protocol on
198
+ * the user's shell, and leave an in-flight terminal query's reply to land as
199
+ * literal text at the next prompt. `release` is the terminal owner's chance to
200
+ * hand it back; it is awaited under {@link FAIL_LOUD_RELEASE_TIMEOUT_MS}, whose
201
+ * timer stays referenced so a never-settling disposer cannot let Node reach an
202
+ * empty event loop and exit 0 instead of failing.
203
+ *
204
+ * The diagnostic is written before the release so a hanging or failing disposer
205
+ * cannot swallow the reason. The handler stays installed while the release runs
206
+ * — removing it would let a second concurrent rejection become uncaught and kill
207
+ * the process mid-teardown, stranding exactly the terminal state this restores —
208
+ * so a latch keeps the first rejection the reported one and lets later
209
+ * rejections (including the release's own) fall through to the pending exit.
210
+ * @param binName - the diagnostic prefix on the fatal-failure line.
211
+ * @param proc - the process slice to register on; tests inject a fake.
212
+ * @param release - optional teardown awaited before exit, used by a
213
+ * terminal-owning surface to restore the terminal. Its own failure is
214
+ * swallowed because the pending fatal exit already owns the outcome.
215
+ * @returns the uninstaller that removes both handlers.
216
+ */
217
+ export declare function installFailLoud(binName: string, proc?: FailLoudProcess, release?: () => Promise<void> | void): () => void;
218
+ interface InactiveEntry {
219
+ /** Loader entry used to identify the bootstrap Include and required ids. */
220
+ entry: Entry;
221
+ /** Activation errors and missing services remain distinct for presentation. */
222
+ outcome: {
223
+ kind: 'failed';
224
+ error: unknown;
225
+ phase?: string;
226
+ } | {
227
+ kind: 'pending';
228
+ missing: string[];
229
+ };
230
+ }
231
+ /** Inactive plugin metadata without retaining its Context or Fiber. */
232
+ interface StartupEntryDiagnostic {
233
+ id: string;
234
+ module: string;
235
+ required: boolean;
236
+ fiberState: FiberState | undefined;
237
+ outcome: InactiveEntry['outcome'];
238
+ }
239
+ /** Startup warning or error arguments, including import errors with no Fiber. */
240
+ interface StartupLogRecord {
241
+ ts: number;
242
+ name: string;
243
+ type: string;
244
+ args: readonly unknown[];
245
+ }
246
+ /** Startup audit failure with non-enumerable metadata and original failures as its cause. */
247
+ export declare class StartupError extends Error {
248
+ readonly entries: readonly StartupEntryDiagnostic[];
249
+ /** Root configuration and startup logs, attached by boot after disposal. */
250
+ startup?: {
251
+ configurationPath: string;
252
+ messages: readonly StartupLogRecord[];
253
+ };
254
+ /**
255
+ * @param message - concise terminal diagnostic.
256
+ * @param entries - inactive plugin metadata and original failure values.
257
+ */
258
+ constructor(message: string, entries: readonly StartupEntryDiagnostic[]);
259
+ }
260
+ /**
261
+ * Apply DSH startup policy to a settled Loader tree.
262
+ *
263
+ * Inactive entries from the global required list reject startup. Other
264
+ * inactive entries join that failure diagnostic, or produce one warning when
265
+ * no required entry failed and leave successful siblings running.
266
+ * Required ids absent from the tree, and disabled required entries, are ignored.
267
+ * A throwing disabled expression is an entry failure, not a disabled entry.
268
+ * The bootstrap Include must activate so unreadable or invalid root config is fatal.
269
+ * @param ctx - the settled context whose Loader entries to audit.
270
+ * @param binName - the prefix on startup diagnostics.
271
+ * @param warn - sink for optional-entry warnings.
272
+ * @returns after optional warnings if required startup checks pass.
273
+ * @throws {@link StartupError} when the bootstrap Include or a required entry is inactive or its disabled expression throws;
274
+ * its message includes optional failures too.
275
+ */
276
+ export declare function auditStartupEntries(ctx: Context, binName: string, warn?: (line: string) => void): Promise<void>;
277
+ /**
278
+ * Boot the Loader against `absoluteConfigPath` and return only after the whole
279
+ * tree settles. Relative entry names resolve against the config directory;
280
+ * bare package names resolve there by default or against an explicit
281
+ * `bareModuleBaseUrl` for closed packaged runtimes. The bootstrap include
282
+ * is statically imported and mounted as the `cordis:include` builtin, loading
283
+ * through the ambient module pipeline (vite/tsx/plain ESM). The package build
284
+ * embeds Include while leaving Loader external, so the built include tree and
285
+ * host share one Loader peer. Loader settlement drains entry work without
286
+ * rejecting the whole tree. The final {@link auditStartupEntries} call rejects
287
+ * failures in the global required list and warns about other failed, missing,
288
+ * and pending entries while successful siblings remain active. Later unhandled
289
+ * rejections remain covered by {@link installFailLoud}. Built bins need the Loader's native
290
+ * helper for bare plugin specifiers; relative specifiers do not.
291
+ * @param binName - the diagnostic prefix for load-failure errors.
292
+ * @param absoluteConfigPath - the config to include; must already be absolute
293
+ * (see {@link resolveConfigPath}).
294
+ * @param patches - optional overlay patches applied over the included tree
295
+ * (see {@link loadOptionalPatches}); an empty list mounts none.
296
+ * @param prepare - optional host setup run after Loader installation and before any config-tree entry mounts.
297
+ * @param bareModuleBaseUrl - optional installed-host base for bare package
298
+ * names; use it when the host, rather than the configuration project, owns the
299
+ * complete plugin set.
300
+ * @returns the root context after the initial startup audit, or as soon as a
301
+ * surface disposed the tree while startup was still in flight.
302
+ * @throws {@link StartupError} for an inactive required entry, including all inactive plugins in its message;
303
+ * otherwise a labelled error after disposing the partial context — `host
304
+ * preparation failed` when `prepare` threw before any config-tree entry
305
+ * mounted, `plugin tree failed to load` afterwards. Cyclic causes terminate
306
+ * diagnostic traversal without replacing the original cause.
307
+ */
308
+ 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
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,4 @@
1
+ /** Package admission shared by offline catalog generation and release ordering. */
2
+ /** Public DSH release members available through the ordinary on-demand bundle installer. */
3
+ export declare const ON_DEMAND_BUNDLES: readonly string[];
4
+ //# sourceMappingURL=official-bundle-packages.d.ts.map
@@ -0,0 +1,12 @@
1
+ /** Official bundles offered without installing their provider runtimes in the DSH distribution. */
2
+ import type { PluginLocalizedMeta } from '@qlzt/dsh-package-manifest';
3
+ export { ON_DEMAND_BUNDLES } from './official-bundle-packages.ts';
4
+ /** Offline discovery metadata; installation state and the requested version belong to the running host. */
5
+ export interface OfficialBundleCatalogEntry {
6
+ /** Exact npm package name accepted by the existing bundle installer. */
7
+ readonly packageName: string;
8
+ /** Package-owned localized text and a self-contained icon, embedded without provider code. */
9
+ readonly meta: Required<Pick<PluginLocalizedMeta, 'title' | 'description' | 'icon'>>;
10
+ }
11
+ export { OFFICIAL_ON_DEMAND_CATALOG } from './official-bundles.generated.ts';
12
+ //# sourceMappingURL=official-bundles.d.ts.map
@@ -0,0 +1,5 @@
1
+ /** Generated offline Official bundle metadata. Run pnpm gen-official-bundle-catalog; do not edit. */
2
+ import type { OfficialBundleCatalogEntry } from './official-bundles.ts';
3
+ /** Official on-demand entries, independent of installed packages and registry availability. */
4
+ export declare const OFFICIAL_ON_DEMAND_CATALOG: readonly OfficialBundleCatalogEntry[];
5
+ //# sourceMappingURL=official-bundles.generated.d.ts.map
@@ -0,0 +1,29 @@
1
+ /** Read plugin display text and icons through exported resources without evaluating plugin code. */
2
+ import type { PluginLocalizedMeta } from '@qlzt/dsh-package-manifest';
3
+ /**
4
+ * Resolve a plugin resource through the active Node ESM resolver without evaluating it.
5
+ * @param specifier - plugin module or exported resource specifier.
6
+ * @param parentURL - owning module-resolution base.
7
+ * @returns the local filesystem path selected by Node and the active profile.
8
+ * @throws when the resolver is unavailable or the resource cannot resolve to a local file.
9
+ */
10
+ export declare function resolvePluginResource(specifier: string, parentURL: string): string;
11
+ /**
12
+ * Read plugin locale JSON display text and icon without evaluating JavaScript entries.
13
+ * Only a package-root specifier reads its exported package.json: `name`/`description` fill missing
14
+ * locale fields, and a declared `icon` takes priority over the `<specifier>/icon` resource.
15
+ * A subpath specifier never reads package.json; its icon comes only from `<specifier>/icon`.
16
+ * Manifest icons remain inside their declaring directory; exported icons remain inside their
17
+ * owning package after realpath resolution. Both accept SVG, PNG, JPEG, or WebP up to 256 KiB.
18
+ * Icon failures retain display text without falling back.
19
+ * Non-package specifiers are skipped without invoking the resource resolver.
20
+ * Language files share the directory containing the resolved English resource;
21
+ * each file is resolved through the complete plugin specifier before reading.
22
+ * Translation maps retain an English fallback, ultimately the full module specifier
23
+ * for titles and empty for descriptions.
24
+ * @param specifier - configured plugin module name, including any package subpath.
25
+ * @param parentURL - owning Loader tree's module-resolution base.
26
+ * @returns display fields and any resource diagnostic, or undefined for non-package specifiers or absent metadata.
27
+ */
28
+ export declare function readPluginMeta(specifier: string, parentURL: string): PluginLocalizedMeta | undefined;
29
+ //# sourceMappingURL=package-meta.d.ts.map
@@ -0,0 +1,35 @@
1
+ /** Evaluate plugin dsh peer requirements without importing plugin code. */
2
+ /** Incompatible dsh peers and the exact plugin/runtime exemption decision. */
3
+ export interface PluginCompatibility {
4
+ name: string;
5
+ version: string;
6
+ runtimeVersion: string;
7
+ /** Only peer requirements not satisfied by the running dsh version. */
8
+ peers: Record<string, string>;
9
+ exempted: boolean;
10
+ }
11
+ /**
12
+ * Read this app-boot package's version in both source and bundled installations.
13
+ * @returns the validated runtime semantic version, preserving its exact spelling.
14
+ * @throws if package.json cannot be read or its version is missing or invalid.
15
+ */
16
+ export declare function getDshRuntimeVersion(): string;
17
+ /**
18
+ * Check every @qlzt/dsh or @deepseek-ai/dsh-* peer against the runtime.
19
+ * Prereleases participate in ranges. workspace:^, workspace:~, and workspace:*
20
+ * refer to the current runtime; other invalid ranges are incompatible.
21
+ * @param manifest - parsed plugin package.json; inherited fields are ignored.
22
+ * @param exemptions - exact plugin name@version keys mapped to exact runtime versions.
23
+ * @param runtimeVersion - running dsh version, defaulting to this app-boot package.
24
+ * @returns incompatible peers and exemption status, or undefined when none are incompatible.
25
+ * @throws for malformed manifest peer fields, invalid runtime versions, or missing identity on a mismatch.
26
+ */
27
+ export declare function evaluatePluginCompatibility(manifest: object, exemptions?: Readonly<Record<string, readonly string[]>>, runtimeVersion?: string): PluginCompatibility | undefined;
28
+ /**
29
+ * Describe incompatible peers, their risk, and the exact-version remedy.
30
+ * Surfaces with their own grant mechanism or locale render the structured result themselves.
31
+ * @param issue - incompatible plugin/runtime result, including exempted mismatches.
32
+ * @returns an English diagnostic for logs and stderr.
33
+ */
34
+ export declare function pluginCompatibilityWarning(issue: PluginCompatibility): string;
35
+ //# sourceMappingURL=plugin-compatibility.d.ts.map