fix(cli): isolate Web runtime context from headless
This commit is contained in:
@@ -46,11 +46,13 @@
|
||||
# `dshClient` rows are the browser roster the modules node half scans into
|
||||
# window.__DSH_BOOT__; the modules row is simultaneously a host row.
|
||||
- insert:
|
||||
# Launcher-provided builtin: owns Web GUI orientation in the model prompt
|
||||
# and the matching managed Bash variables. Profiles with a complete prompt
|
||||
# contract disable this row instead of relying on launcher special cases.
|
||||
# Launcher-provided builtin: Headless keeps this shared row disabled, while
|
||||
# `dsh web` enables it before the later personal/--config layer. Profiles
|
||||
# with a complete prompt contract can therefore disable both Web GUI
|
||||
# orientation and its matching managed Bash variables.
|
||||
- id: web-runtime-context
|
||||
name: cordis:web-runtime-context
|
||||
disabled: true
|
||||
|
||||
- id: session-projection
|
||||
name: '@deepseek-ai/dsh-session-projection'
|
||||
|
||||
@@ -141,9 +141,15 @@ export interface AppCLIEntryOptions {
|
||||
*/
|
||||
overlayPath: string
|
||||
/**
|
||||
* Optional explicit overlay applied after {@link overlayPath} and before
|
||||
* Launcher-owned patches applied after {@link overlayPath} and before the
|
||||
* personal or explicit overlay, so user configuration can still override
|
||||
* surface activation choices.
|
||||
*/
|
||||
launcherPatches?: readonly PatchOptions[]
|
||||
/**
|
||||
* Optional explicit overlay applied after {@link launcherPatches} and before
|
||||
* this entry's own profile/flag patches. When absent, the personal
|
||||
* `$DSH_HOME/config.yaml` overlay is applied instead.
|
||||
* `$DSH_HOME/config.yaml` overlay is applied in the same position instead.
|
||||
*/
|
||||
extraOverlayPath?: string
|
||||
/** Whether to append client-bundle HMR (the Web surface's prod/dev difference). */
|
||||
@@ -261,10 +267,12 @@ export class AppCLIEntry {
|
||||
private async bootTree(): Promise<void> {
|
||||
// One include of the shared base with every overlay as a sibling patch
|
||||
// list: patches never cross an include boundary, so nesting them would
|
||||
// silently stop reaching base rows. The surface overlay applies first, then
|
||||
// this entry's profile-json and CLI-flag patches, which therefore win.
|
||||
// silently stop reaching base rows. The shared surface overlay applies
|
||||
// first, then launcher activation, user configuration, and finally this
|
||||
// entry's profile-json and CLI-flag patches.
|
||||
const compose = (overlay: PatchOptions[]): PatchOptions[] => [
|
||||
...loadOverlayPatches('dsh', this.options.overlayPath),
|
||||
...(this.options.launcherPatches ?? []),
|
||||
...overlay,
|
||||
...this.patches,
|
||||
]
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
type ConfigDumpLayer,
|
||||
} from '@deepseek-ai/dsh-app-boot'
|
||||
import { resolveDshHome } from '@deepseek-ai/dsh-paths'
|
||||
import { WEB_RUNTIME_CONTEXT_ENABLE_PATCH } from './web.ts'
|
||||
|
||||
const NAME = 'dsh'
|
||||
const BASE_CONFIG = fileURLToPath(new URL('../config/base.cordis.yml', import.meta.url))
|
||||
@@ -36,6 +37,7 @@ export function runDumpConfig(surface: 'config' | 'web', defaultOnly: boolean, c
|
||||
}
|
||||
} else {
|
||||
layers.push({ label: basename(WEB_OVERLAY), patches: loadOverlayPatches(NAME, WEB_OVERLAY) })
|
||||
layers.push({ label: 'dsh web launcher', patches: [WEB_RUNTIME_CONTEXT_ENABLE_PATCH] })
|
||||
if (!defaultOnly) {
|
||||
if (config === undefined) {
|
||||
const personal = loadPersonalPatches(NAME)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import type { Context } from 'cordis'
|
||||
import type { PatchOptions } from '@cordisjs/plugin-include'
|
||||
import { addHarnessSourceSection, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
|
||||
import type {} from '@deepseek-ai/dsh-host-webserver'
|
||||
import type {} from '@deepseek-ai/dsh-system-prompt'
|
||||
@@ -24,6 +25,12 @@ const DSH_WEB_URL = 'DSH_WEB_URL' as const
|
||||
const DSH_WEB_MODE = 'DSH_WEB_MODE' as const
|
||||
const WEB_RUNTIME_CONTEXT_BUILTIN = 'web-runtime-context' as const
|
||||
|
||||
/** Web-launcher activation applied before personal or explicit configuration. */
|
||||
export const WEB_RUNTIME_CONTEXT_ENABLE_PATCH = {
|
||||
id: WEB_RUNTIME_CONTEXT_BUILTIN,
|
||||
disabled: false,
|
||||
} as const satisfies PatchOptions
|
||||
|
||||
type WebMode = 'production' | 'development'
|
||||
|
||||
// Display-only mirror of the webserver schema's loopback host: the address the
|
||||
@@ -125,6 +132,7 @@ export async function runWeb(
|
||||
const entry = new AppCLIEntry({
|
||||
configPath: BASE_CONFIG,
|
||||
overlayPath: WEB_OVERLAY,
|
||||
launcherPatches: [WEB_RUNTIME_CONTEXT_ENABLE_PATCH],
|
||||
...config !== undefined && { extraOverlayPath: resolveConfigPath(config, undefined) },
|
||||
dev,
|
||||
prepare: (ctx) => { prepareWebRuntimeContext(ctx, SOURCE_ROOT, mode) },
|
||||
|
||||
@@ -10,6 +10,7 @@ const repoRoot = fileURLToPath(new URL('../../../', import.meta.url))
|
||||
const dshBin = join(repoRoot, 'apps/cli/lib/bin.js')
|
||||
const rawOverlay = fileURLToPath(new URL('./fixtures/raw-overlay.cordis.yml', import.meta.url))
|
||||
const rawInvalidProvider = fileURLToPath(new URL('./fixtures/raw-invalid-provider.cordis.yml', import.meta.url))
|
||||
const coreWebOverlay = fileURLToPath(new URL('../config/core-web.cordis.yml', import.meta.url))
|
||||
|
||||
async function runBuiltBin(
|
||||
args: readonly string[] = [],
|
||||
@@ -200,6 +201,17 @@ describe.skipIf(!existsSync(dshBin))('dsh BUILT bin (node lib/bin.js, no tsx)',
|
||||
expect(code).toBe(0)
|
||||
expect(stdout).toContain("name: '@deepseek-ai/dsh-host-webserver'")
|
||||
expect(stdout).toContain('provider: personal-provider')
|
||||
expect(stdout).toMatch(/- id: web-runtime-context\n name: cordis:web-runtime-context\n disabled: false/u)
|
||||
}, 30_000)
|
||||
|
||||
it('lets an explicit Web profile override launcher activation', async () => {
|
||||
const { stdout, code, stderr } = await runBuiltBin(
|
||||
['web', '--dump-config', '--config', coreWebOverlay],
|
||||
{ DSH_HOME: home },
|
||||
)
|
||||
expect(code).toBe(0)
|
||||
expect(stderr).toBe('')
|
||||
expect(stdout).toMatch(/- id: web-runtime-context\n name: cordis:web-runtime-context\n disabled: true/u)
|
||||
}, 30_000)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user