Merge remote-tracking branch 'origin/master' into codex/ci-profile-stability

This commit is contained in:
Qiuner
2026-08-17 22:03:23 +08:00
3 changed files with 145 additions and 23 deletions
@@ -1,7 +1,7 @@
/** Headless artifact smoke for the Electron-backed dsh and pnpm command entries. */
import { spawnSync } from 'node:child_process'
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { cpSync, mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { fileURLToPath } from 'node:url'
@@ -10,6 +10,8 @@ import { installDesktopPnpmRuntime } from '../lib/desktop-runtime-environment.js
const packageRoot = new URL('../', import.meta.url)
const desktopCli = fileURLToPath(new URL('lib/desktop-cli.js', packageRoot))
const dshAppBootPackage = fileURLToPath(new URL('node_modules/@deepseek-ai/dsh-app-boot/', packageRoot))
const dshPackage = fileURLToPath(new URL('node_modules/@deepseek-ai/dsh/', packageRoot))
const pnpmCli = fileURLToPath(new URL('node_modules/pnpm/bin/pnpm.mjs', packageRoot))
const dshVersion = JSON.parse(readFileSync(new URL('node_modules/@deepseek-ai/dsh/package.json', packageRoot), 'utf8')).version
const pnpmVersion = JSON.parse(readFileSync(new URL('node_modules/pnpm/package.json', packageRoot), 'utf8')).version
@@ -39,25 +41,31 @@ function assertNoRunnerEnvironment(label, env) {
}
}
function verifyResult(label, result, expectedVersion) {
function verifyResult(label, result, expectedOutput) {
if (result.error !== undefined) throw result.error
if (result.status !== 0) {
throw new Error(`${label} artifact smoke exited ${String(result.status)}: ${result.stderr.trim()}`)
}
if (result.stdout.trim() !== expectedVersion) {
throw new Error(`${label} artifact smoke returned ${JSON.stringify(result.stdout.trim())} instead of ${JSON.stringify(expectedVersion)}`)
if (expectedOutput === undefined) return
const output = result.stdout.trim()
const matches = expectedOutput instanceof RegExp
? expectedOutput.test(output)
: output === expectedOutput
if (!matches) {
throw new Error(`${label} artifact smoke returned ${JSON.stringify(output)} instead of matching ${String(expectedOutput)}`)
}
}
function runElectronEntry(label, nodeArgs, entry, expectedVersion) {
function runElectronEntry(label, nodeArgs, entry, args, expectedOutput, extraEnvironment = {}) {
const env = cleanEnvironment()
Object.assign(env, extraEnvironment)
env.ELECTRON_RUN_AS_NODE = '1'
const result = spawnSync(electronPath, [...nodeArgs, entry, '--version'], {
const result = spawnSync(electronPath, [...nodeArgs, entry, ...args], {
encoding: 'utf8',
env,
shell: false,
})
verifyResult(label, result, expectedVersion)
verifyResult(label, result, expectedOutput)
}
function environmentValue(env, name) {
@@ -148,5 +156,30 @@ function runPackagedPnpmShim() {
}
}
runElectronEntry('dsh', ['--expose-internals'], desktopCli, dshVersion)
function runFlatProfileDshEntry() {
const root = mkdtempSync(join(tmpdir(), 'dsh-desktop-flat-cli-smoke-'))
const desktopPackage = join(root, 'node_modules', 'dsh-plugin-desktop')
const linkedAppBootPackage = join(root, 'node_modules', '@deepseek-ai', 'dsh-app-boot')
const linkedDshPackage = join(root, 'node_modules', '@deepseek-ai', 'dsh')
try {
mkdirSync(join(root, 'node_modules', '@deepseek-ai'), { recursive: true })
cpSync(fileURLToPath(new URL('lib/', packageRoot)), join(desktopPackage, 'lib'), { recursive: true })
cpSync(fileURLToPath(new URL('package.json', packageRoot)), join(desktopPackage, 'package.json'))
symlinkSync(dshAppBootPackage, linkedAppBootPackage, process.platform === 'win32' ? 'junction' : 'dir')
symlinkSync(dshPackage, linkedDshPackage, process.platform === 'win32' ? 'junction' : 'dir')
runElectronEntry(
'flat profile dsh plugin help',
['--expose-internals'],
join(desktopPackage, 'lib', 'desktop-cli.js'),
['plugin', '--help'],
undefined,
{ DSH_DESKTOP_DEFAULT_PROFILE: 'desktop' },
)
} finally {
rmSync(root, { recursive: true, force: true })
}
}
runElectronEntry('dsh', ['--expose-internals'], desktopCli, ['--version'], dshVersion)
runFlatProfileDshEntry()
runPackagedPnpmShim()
@@ -1,6 +1,37 @@
/** Physical-path helpers for dependencies Electron Builder removes from app.asar. */
import { fileURLToPath } from 'node:url'
import { readFileSync } from 'node:fs'
import { createRequire } from 'node:module'
import { dirname, join } from 'node:path'
function resolvePackageRoot(moduleUrl: string, packageName: string): string {
const resolve = createRequire(moduleUrl).resolve
try {
return dirname(resolve(`${packageName}/package.json`))
} catch (manifestCause) {
let directory: string
try {
directory = dirname(resolve(packageName))
} catch {
throw manifestCause
}
while (true) {
try {
const manifest: unknown = JSON.parse(readFileSync(join(directory, 'package.json'), 'utf8'))
if (manifest !== null
&& typeof manifest === 'object'
&& (manifest as { name?: unknown }).name === packageName) {
return directory
}
} catch {
// Continue toward the filesystem root until the owning package is found.
}
const parent = dirname(directory)
if (parent === directory) throw manifestCause
directory = parent
}
}
}
/**
* Map one logical ASAR path to the sibling physical unpacked tree.
@@ -12,9 +43,9 @@ export function unpackedAsarPath(filename: string): string {
}
/**
* Resolve one dependency entry beside a built desktop module.
* Resolve one dependency entry from a built desktop module.
* @param moduleUrl - URL of a module emitted below the package's `lib` directory.
* @param dependencyEntry - path below packaged `node_modules`.
* @param dependencyEntry - package subpath resolved through Node module lookup.
* @returns a physical path suitable for Node execution and profile symlinks.
*/
export function packagedDependencyPath(moduleUrl: string, dependencyEntry: string): string {
@@ -22,9 +53,15 @@ export function packagedDependencyPath(moduleUrl: string, dependencyEntry: strin
if (dependencyEntry.length === 0
|| dependencyEntry.startsWith('/')
|| dependencyEntry.includes('\\')
|| segments.some(segment => segment.length === 0 || segment === '.' || segment === '..')) {
|| segments.some(segment => segment.length === 0 || segment === '.' || segment === '..')
|| (segments[0]?.startsWith('@') === true && segments.length < 2)) {
throw new Error('dsh-plugin-desktop: packaged dependency entry must be a relative POSIX path')
}
const logicalPath = fileURLToPath(new URL(`../node_modules/${dependencyEntry}`, moduleUrl))
const packageSegments = segments[0]?.startsWith('@') === true ? 2 : 1
const packageName = segments.slice(0, packageSegments).join('/')
const logicalPath = join(
resolvePackageRoot(moduleUrl, packageName),
...segments.slice(packageSegments),
)
return unpackedAsarPath(logicalPath)
}
+62 -10
View File
@@ -1,3 +1,5 @@
import { mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { pathToFileURL } from 'node:url'
import { describe, expect, it, vi } from 'vitest'
@@ -81,17 +83,67 @@ describe('packaged dsh bootstrap', () => {
expect(unpackedAsarPath('/Applications/DSH Desktop.app/Contents/Resources/app.asar/package.json'))
.toBe('/Applications/DSH Desktop.app/Contents/Resources/app.asar.unpacked/package.json')
expect(unpackedAsarPath('/workspace/node_modules/pkg')).toBe('/workspace/node_modules/pkg')
const moduleUrl = pathToFileURL(join(process.cwd(), 'app.asar', 'lib', 'desktop-cli.js')).href
expect(packagedDependencyPath(moduleUrl, '@deepseek-ai/dsh/lib/bin.js')).toBe(join(
process.cwd(),
'app.asar.unpacked',
'node_modules',
'@deepseek-ai',
'dsh',
'lib',
'bin.js',
))
expect(() => packagedDependencyPath(import.meta.url, '../outside.js'))
.toThrow('relative POSIX path')
})
it('maps a resolved ASAR dependency to its physical unpacked path', () => {
const root = mkdtempSync(join(tmpdir(), 'dsh-desktop-asar-profile-'))
const desktopLib = join(root, 'app.asar', 'lib')
const dshPackage = join(root, 'app.asar', 'node_modules', '@deepseek-ai', 'dsh')
try {
mkdirSync(desktopLib, { recursive: true })
mkdirSync(join(dshPackage, 'lib'), { recursive: true })
writeFileSync(join(dshPackage, 'package.json'), JSON.stringify({
name: '@deepseek-ai/dsh',
type: 'module',
}))
writeFileSync(join(dshPackage, 'lib', 'bin.js'), '')
const moduleUrl = pathToFileURL(join(desktopLib, 'desktop-cli.js')).href
expect(packagedDependencyPath(moduleUrl, '@deepseek-ai/dsh/lib/bin.js')).toBe(join(
realpathSync(root),
'app.asar.unpacked',
'node_modules',
'@deepseek-ai',
'dsh',
'lib',
'bin.js',
))
} finally {
rmSync(root, { recursive: true, force: true })
}
})
it('resolves the DSH entry from a pnpm profile with flat package dependencies', () => {
const root = mkdtempSync(join(tmpdir(), 'dsh-desktop-flat-profile-'))
const desktopLib = join(root, 'node_modules', 'dsh-plugin-desktop', 'lib')
const dshPackage = join(root, 'node_modules', '@deepseek-ai', 'dsh')
const dshEntry = join(dshPackage, 'lib', 'bin.js')
const pnpmPackage = join(root, 'node_modules', 'pnpm')
const pnpmEntry = join(pnpmPackage, 'bin', 'pnpm.mjs')
try {
mkdirSync(desktopLib, { recursive: true })
mkdirSync(join(dshPackage, 'lib'), { recursive: true })
mkdirSync(join(pnpmPackage, 'bin'), { recursive: true })
writeFileSync(join(dshPackage, 'package.json'), JSON.stringify({
name: '@deepseek-ai/dsh',
type: 'module',
}))
writeFileSync(dshEntry, '')
writeFileSync(join(pnpmPackage, 'package.json'), JSON.stringify({
name: 'pnpm',
exports: { '.': './package.json' },
}))
writeFileSync(pnpmEntry, '')
const moduleUrl = pathToFileURL(join(desktopLib, 'desktop-cli.js')).href
expect(packagedDependencyPath(moduleUrl, '@deepseek-ai/dsh/lib/bin.js'))
.toBe(join(realpathSync(root), 'node_modules', '@deepseek-ai', 'dsh', 'lib', 'bin.js'))
expect(packagedDependencyPath(moduleUrl, 'pnpm/bin/pnpm.mjs'))
.toBe(join(realpathSync(root), 'node_modules', 'pnpm', 'bin', 'pnpm.mjs'))
} finally {
rmSync(root, { recursive: true, force: true })
}
})
})