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.
65 lines
2.4 KiB
TypeScript
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/)
|
|
})
|
|
})
|