Files
deepseek-harness/apps/cli/tests/windows-shell.spec.ts
T
Huanqi Cao 8ff75622c6 feat(bundle): default Windows hosts to the pwsh shell stack
win32 hosts booting a shipped profile now get pwsh-local as the ctx.bash
executor and tool-pwsh as the shell tool through the base bundle's new
windows.cordis.patch.yml platform layer, injected by the launcher between
the bundle layers and the user layers on win32. bash-sandbox, tool-bash,
permission, and ui-permission are disabled there: the POSIX-only executor
cannot run on Windows, and dsh-permission requires a confining executor.
Overriding the default is a composition decision through the user's
cordis.patch.yml; there is no environment override channel.

apps/cli and dsh-base re-declare dsh-pwsh-local/dsh-tool-pwsh so the
profile module fallback links them for cold starts (the profiles rework
had dropped them from the CLI closure).

Promotes the windows-pwsh-default Agent Note from proposed to implemented
and documents the platform layer in the base bundle README.
2026-08-07 00:37:33 +08:00

65 lines
2.4 KiB
TypeScript

import { afterEach, describe, expect, it } from 'vitest'
import { mkdtempSync, writeFileSync, rmSync, mkdirSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import type { ProfileLayer } from '@deepseek-ai/dsh-app-boot'
import {
BASE_BUNDLE,
resolveWindowsShellLayer,
WINDOWS_SHELL_PATCH_FILENAME,
} from '../src/windows-shell.ts'
const WINDOWS_PATCH = `- id: bash-sandbox
disabled: true
- insert:
- id: pwsh-local
name: '@deepseek-ai/dsh-pwsh-local'
`
/** One fake bundle layer rooted in a temp directory. */
function fakeLayer(packageName: string, dir: string): ProfileLayer {
return { packageName, packageDir: dir, patchPath: join(dir, 'cordis.patch.yml'), patches: [] }
}
/** A base bundle layer whose package carries the Windows shell patch. */
function baseLayerWithPatch(dir: string): ProfileLayer {
writeFileSync(join(dir, WINDOWS_SHELL_PATCH_FILENAME), WINDOWS_PATCH)
return fakeLayer(BASE_BUNDLE, dir)
}
describe('resolveWindowsShellLayer', () => {
let base: string
afterEach(() => { if (base !== undefined) rmSync(base, { recursive: true, force: true }) })
const tempBase = (): string => {
base = mkdtempSync(join(tmpdir(), 'dsh-windows-shell-'))
return base
}
it('never applies on POSIX hosts', () => {
expect(resolveWindowsShellLayer('linux', [baseLayerWithPatch(tempBase())], 'dsh')).toBeUndefined()
expect(resolveWindowsShellLayer('darwin', [baseLayerWithPatch(tempBase())], 'dsh')).toBeUndefined()
})
it('defaults Windows hosts to the pwsh platform layer', () => {
const layer = resolveWindowsShellLayer('win32', [baseLayerWithPatch(tempBase())], 'dsh')
expect(layer).toBeDefined()
expect(layer?.label.endsWith(WINDOWS_SHELL_PATCH_FILENAME)).toBe(true)
expect(layer?.patches).toEqual([
{ id: 'bash-sandbox', disabled: true },
{ insert: [{ id: 'pwsh-local', name: '@deepseek-ai/dsh-pwsh-local' }] },
])
})
it('skips custom profiles without a base bundle', () => {
const other = fakeLayer('@deepseek-ai/dsh-custom', tempBase())
expect(resolveWindowsShellLayer('win32', [other], 'dsh')).toBeUndefined()
})
it('fails loud when the base bundle ships no Windows shell patch', () => {
const base = tempBase()
mkdirSync(base, { recursive: true })
expect(() => resolveWindowsShellLayer('win32', [fakeLayer(BASE_BUNDLE, base)], 'dsh'))
.toThrow(/@deepseek-ai\/dsh-base ships no windows\.cordis\.patch\.yml/)
})
})