import { mkdir, mkdtemp, readFile, rename, rm, symlink, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { dirname, join } from 'node:path' import { pathToFileURL } from 'node:url' import { afterEach, expect, it } from 'vitest' import { Context } from '@deepseek-ai/cordis' import Loader from '@deepseek-ai/cordis-plugin-loader' import Include from '@deepseek-ai/cordis-plugin-include' import AgentRegistry from '@deepseek-ai/dsh-agent' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' import ToolRuntime from '@deepseek-ai/dsh-tools' import { ToolCallId } from '@deepseek-ai/dsh-llm' import { installPrimaryRuntime, readPrimaryRuntime, workspaceDependencyPaths, type PrimaryRuntimeManifest } from '../src/primary-runtime.ts' import * as workspaceDependencies from '../src/workspace-dependencies.ts' const roots: string[] = [] afterEach(async () => { await Promise.all(roots.splice(0).map(root => rm(root, { recursive: true, force: true }))) }) async function fixture() { const directory = await mkdtemp(join(tmpdir(), 'dsh-primary-runtime-')) roots.push(directory) const source = join(directory, 'resources') const root = join(directory, 'home', 'dsh-runtimes', 'dsh-primary-runtime') const manifest: PrimaryRuntimeManifest = { desktopVersion: '1.0.0', platform: process.platform === 'win32' ? 'win32' : 'darwin', arch: process.arch, components: { python: '3.12.14', node: '24.21.0', pnpm: '11.7.0', numpy: '2.3.5', pandas: '3.0.1' }, pythonPackages: { 'python-docx': '1.2.0', 'python-pptx': '1.0.2', openpyxl: '3.1.5' }, } const paths = workspaceDependencyPaths(source, manifest) for (const path of [paths.python, paths.node, paths.pnpm]) { await mkdir(dirname(path), { recursive: true }) await writeFile(path, 'interpreter') } await mkdir(paths.pythonPackages, { recursive: true }) await mkdir(paths.nodePackages, { recursive: true }) await writeFile(join(source, 'runtime.json'), JSON.stringify(manifest)) return { source, root, manifest, directory } } it.each(['win32', 'darwin'])('returns %s interpreter and package paths', (platform) => { const manifest: PrimaryRuntimeManifest = { desktopVersion: '1', platform, arch: 'x64', components: { python: '3.12.14', node: '24.21.0', pnpm: '11.7.0', numpy: '2.3.5', pandas: '3.0.1' } } const paths = workspaceDependencyPaths('/runtime', manifest) expect(paths.pythonDistributions).toEqual({}) expect(paths.python).toBe(join('/runtime', 'dependencies', 'python', ...(platform === 'win32' ? ['python.exe'] : ['bin', 'python3']))) expect(paths.pythonPackages).toBe(join('/runtime', 'dependencies', 'python', ...(platform === 'win32' ? ['Lib'] : ['lib', 'python3.12']), 'site-packages')) }) it.skipIf(process.platform === 'linux')('installs offline, reuses the same release, and leaves environment and user packages unchanged', async () => { const { source, root, manifest } = await fixture() const environment = { ...process.env } const installed = await installPrimaryRuntime(source, root) await writeFile(join(installed.pythonPackages, 'user-package.py'), 'user content') expect(await installPrimaryRuntime(source, root)).toEqual(installed) expect(installed.pythonDistributions).toEqual(manifest.pythonPackages) expect(await readFile(join(installed.pythonPackages, 'user-package.py'), 'utf8')).toBe('user content') expect(process.env).toEqual(environment) }) it.skipIf(process.platform === 'linux')('replaces release components and recovers an interrupted directory swap', async () => { const { source, root, manifest } = await fixture() await installPrimaryRuntime(source, root) await rename(root, `${root}.previous`) await writeFile(join(source, 'runtime.json'), JSON.stringify({ ...manifest, desktopVersion: '2.0.0' })) await installPrimaryRuntime(source, root) expect((await readPrimaryRuntime(root)).desktopVersion).toBe('2.0.0') }) it.skipIf(process.platform === 'linux')('replaces dependencies when the locked payload changes without a Desktop version change', async () => { const { source, root, manifest } = await fixture() const first = { ...manifest, payloadDigest: 'a'.repeat(64), pythonPackages: { 'python-docx': '1.1.2' } } await writeFile(join(source, 'runtime.json'), JSON.stringify(first)) const installed = await installPrimaryRuntime(source, root) await writeFile(join(installed.pythonPackages, 'old-package.py'), 'old dependency') const next = { ...first, payloadDigest: 'b'.repeat(64), pythonPackages: { 'python-docx': '1.2.0' } } await writeFile(join(source, 'runtime.json'), JSON.stringify(next)) await writeFile(join(workspaceDependencyPaths(source, next).pythonPackages, 'new-package.py'), 'new dependency') await installPrimaryRuntime(source, root) expect(await readPrimaryRuntime(root)).toEqual(next) expect(await readFile(join(installed.pythonPackages, 'new-package.py'), 'utf8')).toBe('new dependency') await expect(readFile(join(installed.pythonPackages, 'old-package.py'))).rejects.toMatchObject({ code: 'ENOENT' }) }) it.skipIf(process.platform === 'linux')('upgrades a release manifest without a payload digest', async () => { const { source, root, manifest } = await fixture() await installPrimaryRuntime(source, root) await writeFile(join(source, 'runtime.json'), JSON.stringify({ ...manifest, payloadDigest: 'a'.repeat(64), pythonPackages: { 'python-docx': '1.2.0' } })) await installPrimaryRuntime(source, root) expect((await readPrimaryRuntime(root)).payloadDigest).toBe('a'.repeat(64)) }) it.skipIf(process.platform === 'linux')('replaces changed payload bytes when only the digest changes', async () => { const { source, root, manifest } = await fixture() const first = { ...manifest, payloadDigest: 'a'.repeat(64), pythonPackages: { 'python-docx': '1.2.0' } } const sourceFile = join(workspaceDependencyPaths(source, first).pythonPackages, 'library.py') await writeFile(join(source, 'runtime.json'), JSON.stringify(first)) await writeFile(sourceFile, 'first wheel bytes') const installed = await installPrimaryRuntime(source, root) await writeFile(join(source, 'runtime.json'), JSON.stringify({ ...first, payloadDigest: 'b'.repeat(64) })) await writeFile(sourceFile, 'repacked wheel bytes') await installPrimaryRuntime(source, root) expect(await readFile(join(installed.pythonPackages, 'library.py'), 'utf8')).toBe('repacked wheel bytes') expect((await readPrimaryRuntime(root)).pythonPackages).toEqual(first.pythonPackages) }) it.skipIf(process.platform === 'linux')('keeps the installed release when the replacement payload is incomplete', async () => { const { source, root, manifest } = await fixture() await installPrimaryRuntime(source, root) await writeFile(join(source, 'runtime.json'), JSON.stringify({ ...manifest, desktopVersion: '2.0.0' })) await rm(workspaceDependencyPaths(source, manifest).python) await expect(installPrimaryRuntime(source, root)).rejects.toThrow() expect((await readPrimaryRuntime(root)).desktopVersion).toBe('1.0.0') }) it.skipIf(process.platform === 'linux')('refuses linked installation directories without modifying their targets', async () => { const { source, root, directory } = await fixture() const outside = join(directory, 'outside') await mkdir(outside) await writeFile(join(outside, 'keep'), 'untouched') await mkdir(dirname(root), { recursive: true }) await symlink(outside, root, process.platform === 'win32' ? 'junction' : 'dir') await expect(installPrimaryRuntime(source, root)).rejects.toThrow('filesystem link') expect(await readFile(join(outside, 'keep'), 'utf8')).toBe('untouched') }) it('rejects malformed metadata and incompatible targets', async () => { const { source, root, manifest } = await fixture() await writeFile(join(source, 'runtime.json'), JSON.stringify({ ...manifest, arch: process.arch === 'x64' ? 'arm64' : 'x64' })) await expect(installPrimaryRuntime(source, root)).rejects.toThrow('incompatible') await writeFile(join(source, 'runtime.json'), JSON.stringify({ ...manifest, components: { ...manifest.components, python: '../escape' } })) await expect(readPrimaryRuntime(source)).rejects.toThrow('invalid metadata') }) it.each([['numpy', 'numpy'], ['pandas', 'pandas'], ['Numpy', 'numpy'], ['PANDAS', 'pandas']] as const)('rejects conflicting %s component and distribution versions', async (distribution, name) => { const { source, manifest } = await fixture() await writeFile(join(source, 'runtime.json'), JSON.stringify({ ...manifest, pythonPackages: { [distribution]: '0.0.1' } })) await expect(readPrimaryRuntime(source)).rejects.toThrow(`conflicting ${name} distribution version`) const consistent = { ...manifest, pythonPackages: { [distribution]: manifest.components[name] } } await writeFile(join(source, 'runtime.json'), JSON.stringify(consistent)) expect(await readPrimaryRuntime(source)).toEqual(consistent) }) it.each([ { payloadDigest: 'invalid' }, { pythonPackages: ['python-docx'] }, { pythonPackages: { 'python-docx': '../escape' } }, { pythonPackages: { '../escape': '1.2.0' } }, { pythonPackages: { numpy: '2.3.5', Numpy: '2.3.5' } }, { pythonPackages: { Pillow: '12.3.0', pillow: '12.3.0' } }, { pythonPackages: { typing_extensions: '4.16.0', 'typing.extensions': '4.16.0' } }, ])('rejects invalid locked payload metadata: %j', async (invalid) => { const { source, manifest } = await fixture() await writeFile(join(source, 'runtime.json'), JSON.stringify({ ...manifest, ...invalid })) await expect(readPrimaryRuntime(source)).rejects.toThrow('invalid metadata') }) it.skipIf(process.platform === 'linux')('loads the real tool through Cordis, exposes installed paths, and unregisters on disposal', async () => { const { source, root, manifest, directory } = await fixture() const ctx = new Context() try { ctx.baseUrl = pathToFileURL(directory).href + '/' await ctx.plugin(Loader) ctx.loader.builtins.include = Include const modules = new Map([ ['agents', AgentRegistry], ['systemPrompt', SystemPrompt], ['tools', ToolRuntime], ['dependencies', workspaceDependencies], ]) ctx.loader.internal = { version: 'v2', async import(specifier: string) { if (!modules.has(specifier)) throw new Error(`unexpected plugin ${specifier}`) return modules.get(specifier) }, } as unknown as NonNullable const config = join(directory, 'cordis.yml') await writeFile(config, `- name: agents\n- name: systemPrompt\n- name: tools\n- name: dependencies\n config:\n source: ${JSON.stringify(source)}\n root: ${JSON.stringify(root)}\n`) await ctx.loader.create({ name: 'cordis:include', config: { path: pathToFileURL(config).href } }) await ctx.loader.await() for (const entry of ctx.loader.entries()) await entry.fiber?.await() const environment = { ...process.env } const request = { signal: new AbortController().signal, name: 'load_workspace_dependencies', arguments: {} } const results = await Promise.all(['first', 'second'].map(id => ctx.tools.execute({ ...request, callId: ToolCallId(id) }))) for (const result of results) { expect(result.isError).toBe(false) expect(result.content).toEqual([{ type: 'text', text: JSON.stringify(workspaceDependencyPaths(root, manifest), undefined, 2) }]) } expect(process.env).toEqual(environment) const entry = [...ctx.loader.entries()].find(entry => entry.options.name === 'dependencies') expect(entry).toBeDefined() await entry?.fiber?.dispose() expect(ctx.tools.schemas().some(tool => tool.name === 'load_workspace_dependencies')).toBe(false) } finally { await ctx.fiber.dispose() } })