dsh --dump-config and dsh web --dump-config compose the shipped base, the surface overlay, and the --config or personal overlay — exactly the layers that surface boots — and print the entry list as YAML without booting; --dump-default-config stops at the surface overlay so the two outputs diff to precisely the user layer's effect. The dump shares the mounting code: the vendored include exports its patch algorithm as applyEntryPatches() and its !!js dialect as entryListSchema (logged in vendor/README.md), dsh-app-boot's renderConfigDump() composes and renders through both (and now imports the dialect instead of duplicating it), and the CLI adds a thin dump-config mode. !!js expressions print verbatim; unmatched patches warn on stderr; boot-only flags are rejected alongside the dump flags. (cherry picked from commit 1fdbebfa8a5dc7df840d53666320064a7e3dae59)
62 lines
2.6 KiB
TypeScript
62 lines
2.6 KiB
TypeScript
/**
|
|
* `dsh --dump-config` / `dsh web --dump-config` — print the composed config
|
|
* tree without booting: the shipped base, the surface overlay, and (unless
|
|
* `--dump-default-config`) the `--config` or personal overlay, composed
|
|
* through the include's own patch algorithm so the printed tree is exactly
|
|
* what that surface would mount. `!!js` expressions print verbatim,
|
|
* unevaluated — the dump shows composition, not one process's environment.
|
|
* Launcher-provided boot-context values (session identity, CLI-flag patches)
|
|
* are per-invocation facts outside the config tree and do not appear.
|
|
* @module @deepseek-ai/dsh/dump-config
|
|
*/
|
|
|
|
import { basename, join } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
import {
|
|
loadOverlayPatches,
|
|
loadPersonalPatches,
|
|
PERSONAL_CONFIG_FILENAME,
|
|
renderConfigDump,
|
|
type ConfigDumpLayer,
|
|
} from '@deepseek-ai/dsh-app-boot'
|
|
import { resolveDshHome } from '@deepseek-ai/dsh-paths'
|
|
|
|
const NAME = 'dsh'
|
|
|
|
const BASE_CONFIG = fileURLToPath(new URL('../config/base.cordis.yml', import.meta.url))
|
|
const SURFACE_OVERLAYS = {
|
|
tui: fileURLToPath(new URL('../config/tui.cordis.yml', import.meta.url)),
|
|
web: fileURLToPath(new URL('../config/web.cordis.yml', import.meta.url)),
|
|
} as const
|
|
|
|
/* v8 ignore start -- composition over the unit-tested renderConfigDump; the
|
|
built-bin e2e drives this path end to end */
|
|
/**
|
|
* Print one surface's composed config tree to stdout, with a comment
|
|
* separator naming the file each section of rows comes from (and the layers
|
|
* that patched it).
|
|
* @param surface - which surface overlay to compose over the shared base.
|
|
* @param defaultOnly - stop at the surface overlay (no `--config`/personal layer).
|
|
* @param config - the `--config` overlay path composed instead of the personal
|
|
* one, or `undefined` to use `$DSH_HOME/config.yaml`.
|
|
*/
|
|
export function runDumpConfig(surface: 'tui' | 'web', defaultOnly: boolean, config?: string): void {
|
|
const overlay = SURFACE_OVERLAYS[surface]
|
|
const layers: ConfigDumpLayer[] = [
|
|
{ label: basename(overlay), patches: loadOverlayPatches(NAME, overlay) },
|
|
]
|
|
if (!defaultOnly) {
|
|
if (config === undefined) {
|
|
const personal = loadPersonalPatches(NAME)
|
|
// The personal file may be absent; the shipped layers still print.
|
|
if (personal !== undefined) {
|
|
layers.push({ label: join(resolveDshHome(), PERSONAL_CONFIG_FILENAME), patches: personal })
|
|
}
|
|
} else {
|
|
layers.push({ label: config, patches: loadOverlayPatches(NAME, config) })
|
|
}
|
|
}
|
|
process.stdout.write(renderConfigDump(NAME, BASE_CONFIG, layers))
|
|
}
|
|
/* v8 ignore stop */
|