Merge pull request #4686 from deepseek-harness/fix/desktop-dev-runtime-target
fix(desktop): resolve the development runtime directory from the build target
This commit is contained in:
commit
c5dc0853d6
14 files changed
+135
-17
No files matched your search
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write apps/desktop/README.md
|
||||
README.md: 87b16ac8fd7ec269e8c02a34a32e6593b38aec0a
|
||||
README.zh.md: 895fdd972148c90bad00916a35b21cebff8842e8
|
||||
README.md: ec3f2f44d5e49db00bd595588a0594bcee0a1538
|
||||
README.zh.md: 50fba340a0edc114a75d4b6363b8e6c42be0c45f
|
||||
@@ -399,7 +399,7 @@ The downloaded bytes are inert, and the installation call is recorded rather tha
|
||||
|
||||
## Low-level development overrides
|
||||
|
||||
An unpackaged Electron process uses `.desktop-build/development/project` under its application directory as its development project. `DSH_DESKTOP_PNPM_ENTRY` and `DSH_DESKTOP_DSH_DIR` select explicit runtime resources. Packaged applications ignore these variables, resolve signed resources from `process.resourcesPath`, and use the managed Desktop profile.
|
||||
An unpackaged Electron process uses `.desktop-build/development/project` under its application directory as its development project. `DSH_DESKTOP_PNPM_ENTRY` and `DSH_DESKTOP_DSH_DIR` are optional overrides with application-path defaults. `DSH_DESKTOP_PRIMARY_RUNTIME_DIR` is required for every unpackaged launch: the development launchers (`dev:desktop`, `start:desktop`, and the workspace-update qualification runner) set it to the primary-runtime directory of the target they prepared, and a launch without it fails with the fatal startup dialog. The launcher must set it because the shell cannot derive that directory from `process.arch`: the build target fixes Windows to x64 while the host may be arm64. Packaged applications ignore these variables, resolve signed resources from `process.resourcesPath`, and use the managed Desktop profile.
|
||||
|
||||
## Known limitations
|
||||
|
||||
@@ -408,6 +408,7 @@ An unpackaged Electron process uses `.desktop-build/development/project` under i
|
||||
- Release signing, notarization, update hosting, and previous-version installed-artifact qualification require the production release environment.
|
||||
- Dependency lifecycle scripts follow pnpm’s build permissions; Desktop provides no separate approval dialog.
|
||||
- The desktop shell shares sessions, settings, credentials, workspaces, and storage under `$DSH_HOME` with CLI dsh, while executable packages, plugin activation, and lockfiles remain separate.
|
||||
- Unpackaged startup on an Electron win32-arm64 host now succeeds, but the payload remains x64: the architecture check in `packages/skill/tool-workspace-dependencies/src/index.ts` compares the recorded payload architecture against the host `process.arch`, so the `load_workspace_dependencies` tool can still reject the primary runtime.
|
||||
|
||||
Sign in opens the configured platform page in the system browser. The Host owns PKCE and a temporary loopback callback, saves the credential before entering the workspace, and redirects the browser to the platform completion page. Opened and copied authorization links carry the effective Desktop theme as `theme=light` or `theme=dark`; `system` resolves at the time of the action. Cancel withdraws the local attempt even if the platform page later approves it. Settings offers Account sign-out; without a separate API key, sign-out returns to the welcome window. Packaged applications register dsh://open to show the window without passing credentials. On macOS, the development launcher prepares an ad-hoc-signed `Harness Dev.app` under `.desktop-build/development`, declares `dsh` in its Info.plist, and registers it with Launch Services. It loads the current workspace and records the selected development home, browser-data path, and debug settings for cold starts. Starting this bundle makes it the default `dsh://` handler; starting the packaged application registers the packaged handler again. The generated bundle does not contain account tokens and requires the workspace and prepared runtime to remain available.
|
||||
|
||||
|
||||
@@ -399,7 +399,7 @@ node apps/desktop/node_modules/pnpm/bin/pnpm.mjs --dir apps/desktop run test:upd
|
||||
|
||||
## 底层开发覆盖项
|
||||
|
||||
未打包的 Electron 进程使用应用目录下的 `.desktop-build/development/project` 作为开发项目。`DSH_DESKTOP_PNPM_ENTRY` 和 `DSH_DESKTOP_DSH_DIR` 用于选择明确的运行时资源。打包应用会忽略这些变量,从 `process.resourcesPath` 解析签名资源,并使用受管 Desktop profile。
|
||||
未打包的 Electron 进程使用应用目录下的 `.desktop-build/development/project` 作为开发项目。`DSH_DESKTOP_PNPM_ENTRY` 和 `DSH_DESKTOP_DSH_DIR` 是带应用路径默认值的可选覆盖项。每次未打包启动都必须设置 `DSH_DESKTOP_PRIMARY_RUNTIME_DIR`:开发启动器(`dev:desktop`、`start:desktop` 及工作区更新验证运行器)会把它设置为自己已准备目标的 primary-runtime 目录;缺少该变量的启动会以致命启动对话框失败。启动器必须设置它,因为壳无法从 `process.arch` 推导该目录:构建目标将 Windows 固定为 x64,而宿主可能是 arm64。打包应用会忽略这些变量,从 `process.resourcesPath` 解析签名资源,并使用受管 Desktop profile。
|
||||
|
||||
## 已知限制
|
||||
|
||||
@@ -408,6 +408,7 @@ node apps/desktop/node_modules/pnpm/bin/pnpm.mjs --dir apps/desktop run test:upd
|
||||
- 发布签名、公证、更新托管和跨上一版本的已安装产物验证需要生产发布环境。
|
||||
- 依赖的生命周期脚本遵循 pnpm 的构建权限;Desktop 不提供单独的审批对话框。
|
||||
- 桌面壳与 CLI dsh 共享 `$DSH_HOME` 下的会话、设置、凭据、工作区和存储,但可执行包、插件激活和锁文件彼此隔离。
|
||||
- 在 Electron win32-arm64 宿主上,未打包启动现在可以成功,但载荷仍为 x64:`packages/skill/tool-workspace-dependencies/src/index.ts` 的架构校验会把载荷记录的架构与宿主 `process.arch` 比较,因此 `load_workspace_dependencies` 工具仍可能拒绝 primary runtime。
|
||||
|
||||
登录会在系统浏览器中打开配置的平台页面。Host 负责 PKCE 和临时本机回调,在进入工作区前保存凭证,再将浏览器跳转到平台完成页。打开和复制的授权链接通过 `theme=light` 或 `theme=dark` 携带当前生效的 Desktop 主题;`system` 在执行操作时解析。即使平台页面随后批准,取消仍会撤销本地尝试。设置中的账号页面提供退出;没有独立 API Key 时,退出后返回欢迎窗。打包应用注册 dsh://open,只显示窗口而不传递凭证。macOS 开发启动器在 `.desktop-build/development` 下准备经临时签名的 `Harness Dev.app`,在 Info.plist 中声明 `dsh` 并注册到 Launch Services。它加载当前工作区,并记录选定的开发 home、浏览器数据路径和调试设置,以供冷启动使用。启动此应用会将其设为 `dsh://` 默认处理程序;启动打包应用会重新注册打包版处理程序。生成的应用包不包含账号 token,依赖工作区和已准备的运行环境继续存在。
|
||||
|
||||
|
||||
@@ -36,6 +36,17 @@ export function resolveDesktopBuildTarget(
|
||||
*/
|
||||
export function desktopTargetBuildPaths(target: DesktopAutoUpdateTarget): DesktopTargetBuildPaths
|
||||
|
||||
/**
|
||||
* Return the platform and architecture of the payload one release target prepares.
|
||||
* Windows is prepared as x64 only, so this differs from the build host on an arm64 Windows machine.
|
||||
* @param target - Supported Desktop target name.
|
||||
* @returns Platform and architecture of the prepared payload.
|
||||
*/
|
||||
export function desktopTargetPlatform(target: DesktopAutoUpdateTarget): {
|
||||
readonly platform: 'darwin' | 'win32'
|
||||
readonly arch: 'arm64' | 'x64'
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the paths owned by the target selected in a packaging environment.
|
||||
* @param env - Packaging environment.
|
||||
@@ -48,3 +59,16 @@ export function resolveDesktopTargetBuildPaths(
|
||||
hostPlatform?: NodeJS.Platform,
|
||||
hostArch?: string,
|
||||
): DesktopTargetBuildPaths
|
||||
|
||||
/**
|
||||
* Resolve the primary-runtime directory an unpackaged development launch uses.
|
||||
* @param env - Packaging environment.
|
||||
* @param hostPlatform - Build-host platform used when no target override exists.
|
||||
* @param hostArch - Build-host architecture used when no target override exists.
|
||||
* @returns Primary-runtime directory prepared for the selected target.
|
||||
*/
|
||||
export function developmentRuntimeDirectory(
|
||||
env?: NodeJS.ProcessEnv,
|
||||
hostPlatform?: NodeJS.Platform,
|
||||
hostArch?: string,
|
||||
): string
|
||||
@@ -29,15 +29,19 @@ export function resolveDesktopBuildTarget(
|
||||
return /** @type {'mac-arm64' | 'mac-x64' | 'win-x64'} */ (target)
|
||||
}
|
||||
|
||||
function assertSupportedTarget(target) {
|
||||
if (!SUPPORTED_TARGETS.has(target)) {
|
||||
throw new Error(`desktop build paths: unsupported target ${String(target)}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mutable preparation and artifact directories owned by one release target.
|
||||
* @param {'mac-arm64' | 'mac-x64' | 'win-x64'} target - Supported Desktop target name.
|
||||
* @returns {{ root: string, artifacts: string, unsignedArtifacts: string, runtime: string, packageSet: string, dsh: string, dshPnpm: string, electron: string, packedDsh: string, packedVendor: string, packedLandlock: string, downloads: string }} Target paths plus the shared immutable download cache.
|
||||
*/
|
||||
export function desktopTargetBuildPaths(target) {
|
||||
if (!SUPPORTED_TARGETS.has(target)) {
|
||||
throw new Error(`desktop build paths: unsupported target ${String(target)}`)
|
||||
}
|
||||
assertSupportedTarget(target)
|
||||
const root = join(BUILD_ROOT, 'targets', target)
|
||||
const packed = join(root, 'packed')
|
||||
return {
|
||||
@@ -56,6 +60,20 @@ export function desktopTargetBuildPaths(target) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the platform and architecture of the payload one release target prepares.
|
||||
* Windows is prepared as x64 only, so this differs from the build host on an arm64 Windows machine.
|
||||
* @param {'mac-arm64' | 'mac-x64' | 'win-x64'} target - Supported Desktop target name.
|
||||
* @returns {{ platform: 'darwin' | 'win32', arch: 'arm64' | 'x64' }} Platform and architecture of the prepared payload.
|
||||
*/
|
||||
export function desktopTargetPlatform(target) {
|
||||
assertSupportedTarget(target)
|
||||
return {
|
||||
platform: /** @type {'darwin' | 'win32'} */ (target === 'win-x64' ? 'win32' : 'darwin'),
|
||||
arch: /** @type {'arm64' | 'x64'} */ (target === 'mac-arm64' ? 'arm64' : 'x64'),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the paths owned by the target selected in a packaging environment.
|
||||
* @param {NodeJS.ProcessEnv} env - Packaging environment.
|
||||
@@ -70,3 +88,20 @@ export function resolveDesktopTargetBuildPaths(
|
||||
) {
|
||||
return desktopTargetBuildPaths(resolveDesktopBuildTarget(env, hostPlatform, hostArch))
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the primary-runtime directory an unpackaged development launch uses.
|
||||
* The build target fixes Windows to x64, so the shell cannot derive this directory from
|
||||
* the architecture of the process that launched it.
|
||||
* @param {NodeJS.ProcessEnv} env - Packaging environment.
|
||||
* @param {NodeJS.Platform} hostPlatform - Build-host platform used when no target override exists.
|
||||
* @param {string} hostArch - Build-host architecture used when no target override exists.
|
||||
* @returns {string} Primary-runtime directory prepared for the selected target.
|
||||
*/
|
||||
export function developmentRuntimeDirectory(
|
||||
env = process.env,
|
||||
hostPlatform = process.platform,
|
||||
hostArch = process.arch,
|
||||
) {
|
||||
return join(resolveDesktopTargetBuildPaths(env, hostPlatform, hostArch).runtime, 'primary-runtime')
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { join, resolve } from 'node:path'
|
||||
import { parseArgs } from 'node:util'
|
||||
import { DESKTOP_HOST_PROTOCOL_VERSION } from '../src/host-protocol.ts'
|
||||
import type { DesktopRelease } from '../src/release.ts'
|
||||
import { developmentRuntimeDirectory, resolveDesktopBuildTarget } from './desktop-build-paths.mjs'
|
||||
import { prepareDevelopmentProject } from './development-project.ts'
|
||||
import { prepareDevelopmentApp } from './development-app.ts'
|
||||
import { preparePrimaryRuntime } from './prepare-primary-runtime.ts'
|
||||
@@ -67,6 +68,7 @@ async function launchElectron(): Promise<void> {
|
||||
const environment: NodeJS.ProcessEnv = {
|
||||
...process.env,
|
||||
DSH_HOME: home,
|
||||
DSH_DESKTOP_PRIMARY_RUNTIME_DIR: process.env.DSH_DESKTOP_PRIMARY_RUNTIME_DIR ?? developmentRuntimeDirectory(),
|
||||
DSH_DESKTOP_HOST_INSPECT_PORT: String(hostPort),
|
||||
DSH_DESKTOP_OPEN_DEVTOOLS: process.env.DSH_DESKTOP_OPEN_DEVTOOLS ?? '1',
|
||||
ELECTRON_ENABLE_LOGGING: process.env.ELECTRON_ENABLE_LOGGING ?? '1',
|
||||
@@ -115,6 +117,7 @@ async function main(): Promise<void> {
|
||||
hostDir: join(REPOSITORY_ROOT, 'apps', 'desktop-host'),
|
||||
dependencyDir: join(REPOSITORY_ROOT, 'node_modules', '.pnpm', 'node_modules'),
|
||||
release,
|
||||
target: resolveDesktopBuildTarget(),
|
||||
})
|
||||
await preparePrimaryRuntime()
|
||||
await launchElectron()
|
||||
|
||||
@@ -16,6 +16,8 @@ import { dirname, join } from 'node:path'
|
||||
import { createDevelopmentProjectMetadata } from '../src/project-manager.ts'
|
||||
import type { DesktopRelease } from '../src/release.ts'
|
||||
import { DESKTOP_RUNTIME_FILE, type DesktopRuntimeDescriptor } from '../src/runtime-tree.ts'
|
||||
import type { DesktopAutoUpdateTarget } from './desktop-auto-update-environment.mjs'
|
||||
import { desktopTargetPlatform } from './desktop-build-paths.mjs'
|
||||
|
||||
interface PackageManifest {
|
||||
readonly name?: string
|
||||
@@ -35,6 +37,8 @@ export interface DevelopmentProjectOptions {
|
||||
readonly dependencyDir: string
|
||||
/** Release identity written into the disposable project metadata. */
|
||||
readonly release: DesktopRelease
|
||||
/** Build target whose prepared payload the disposable project runs against. */
|
||||
readonly target: DesktopAutoUpdateTarget
|
||||
}
|
||||
|
||||
function readManifest(path: string): PackageManifest {
|
||||
@@ -115,7 +119,7 @@ function mirrorWorkspaceDependencies(roots: readonly string[], destinationRoot:
|
||||
|
||||
/**
|
||||
* Replace one disposable project with links to the current built workspace.
|
||||
* @param options - Project destination, CLI package, and release identity.
|
||||
* @param options - Project destination, CLI package, release identity, and build target.
|
||||
* @returns the absolute project directory supplied by the caller.
|
||||
*/
|
||||
export function prepareDevelopmentProject(options: DevelopmentProjectOptions): string {
|
||||
@@ -159,7 +163,7 @@ export function prepareDevelopmentProject(options: DevelopmentProjectOptions): s
|
||||
return typeof manifest.version === 'string' ? [{ name, version: manifest.version, path: `node_modules/${name}` }] : []
|
||||
})
|
||||
const runtime: DesktopRuntimeDescriptor = { schemaVersion: 1, release: options.release,
|
||||
platform: process.platform, arch: process.arch, sharedPackages, files: [] }
|
||||
...desktopTargetPlatform(options.target), sharedPackages, files: [] }
|
||||
writeFileSync(join(options.projectDir, DESKTOP_RUNTIME_FILE), `${JSON.stringify(runtime, undefined, 2)}\n`)
|
||||
return options.projectDir
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import { fileURLToPath } from 'node:url'
|
||||
import { createDevelopmentProjectMetadata, createPluginProfile } from '../src/project-manager.ts'
|
||||
import { removeOwnedDirectory } from '../src/owned-directory.ts'
|
||||
import { DESKTOP_HOST_PROTOCOL_VERSION } from '../src/host-protocol.ts'
|
||||
import { desktopTargetPlatform, developmentRuntimeDirectory, resolveDesktopBuildTarget } from './desktop-build-paths.mjs'
|
||||
|
||||
const repo = resolve(import.meta.dirname, '../../..')
|
||||
const interactive = process.argv.includes('--interactive')
|
||||
@@ -27,10 +28,11 @@ try {
|
||||
nodeVersion: execFileSync(electron, ['-p', 'process.versions.node'],
|
||||
{ encoding: 'utf8', env: { ...process.env, ELECTRON_RUN_AS_NODE: '1' }, windowsHide: true }).trim(),
|
||||
pnpmVersion: pnpm.version, hostProtocolVersion: DESKTOP_HOST_PROTOCOL_VERSION }
|
||||
const target = resolveDesktopBuildTarget()
|
||||
createDevelopmentProjectMetadata(project, release)
|
||||
createPluginProfile(profile)
|
||||
await writeFile(join(project, 'desktop-runtime.json'), JSON.stringify({
|
||||
schemaVersion: 1, release, platform: process.platform, arch: process.arch, files: [],
|
||||
schemaVersion: 1, release, ...desktopTargetPlatform(target), files: [],
|
||||
sharedPackages: ['@deepseek-ai/dsh', '@deepseek-ai/dsh-desktop-host']
|
||||
.map(name => ({ name, version: manifest.version, path: `node_modules/${name}` })),
|
||||
}))
|
||||
@@ -43,7 +45,6 @@ try {
|
||||
for (const owner of [application, project]) {
|
||||
await symlink(join(repo, 'node_modules/.pnpm/node_modules'), join(owner, 'node_modules'), process.platform === 'win32' ? 'junction' : 'dir')
|
||||
}
|
||||
const target = `${process.platform === 'darwin' ? 'mac' : 'win'}-${process.arch}`
|
||||
const targetRoot = join(application, '.desktop-build/targets', target)
|
||||
await mkdir(targetRoot, { recursive: true })
|
||||
await symlink(join(repo, 'apps/desktop/.desktop-build/targets', target, 'runtime'), join(targetRoot, 'runtime'),
|
||||
@@ -61,7 +62,7 @@ try {
|
||||
...(interactive ? ['--interactive'] : [])], {
|
||||
cwd: root, env: { ...environment, DSH_HOME: join(root, 'home'), USERPROFILE: root, HOME: root,
|
||||
TEMP: root, TMP: root, TMPDIR: root, DSH_WORKSPACE_UPDATE_ROOT: root, DSH_WORKSPACE_UPDATE_TOKEN: randomUUID(),
|
||||
DSH_DESKTOP_OPEN_DEVTOOLS: '0' },
|
||||
DSH_DESKTOP_PRIMARY_RUNTIME_DIR: developmentRuntimeDirectory(), DSH_DESKTOP_OPEN_DEVTOOLS: '0' },
|
||||
// Hiding the GUI process suppresses its first window and can suspend renderer frame callbacks.
|
||||
stdio: 'inherit', windowsHide: false,
|
||||
})
|
||||
|
||||
@@ -139,6 +139,14 @@ function runtimeResources(): RuntimeResources {
|
||||
return { node, nodeBin, pnpm, dsh }
|
||||
}
|
||||
|
||||
function developmentPrimaryRuntime(): string {
|
||||
const directory = process.env.DSH_DESKTOP_PRIMARY_RUNTIME_DIR
|
||||
if (directory === undefined || directory === '') {
|
||||
throw new Error('dsh desktop: DSH_DESKTOP_PRIMARY_RUNTIME_DIR is required for an unpackaged launch')
|
||||
}
|
||||
return directory
|
||||
}
|
||||
|
||||
function developmentHostInspectPort(enabled: boolean): number | undefined {
|
||||
const configured = process.env.DSH_DESKTOP_HOST_INSPECT_PORT
|
||||
if (!enabled || configured === undefined || configured === '') return undefined
|
||||
@@ -289,6 +297,9 @@ async function main(): Promise<void> {
|
||||
const resources = runtimeResources()
|
||||
const paths = resolveDesktopPaths()
|
||||
const development = !app.isPackaged
|
||||
const primaryRuntime = development
|
||||
? developmentPrimaryRuntime()
|
||||
: join(process.resourcesPath, 'runtime', 'primary-runtime')
|
||||
const activeProject = paths.profile
|
||||
const manager = new DesktopProjectManager(paths, resources)
|
||||
let quitting = false
|
||||
@@ -370,8 +381,7 @@ async function main(): Promise<void> {
|
||||
const hostInspectPort = developmentHostInspectPort(development)
|
||||
const host = new DesktopHostProcess(resources.node, resources.dsh, activeProject,
|
||||
hostInspectPort, process.env, onFailure,
|
||||
development ? join(app.getAppPath(), '.desktop-build', 'targets', `${process.platform === 'darwin' ? 'mac' : 'win'}-${process.arch}`, 'runtime', 'primary-runtime')
|
||||
: join(process.resourcesPath, 'runtime', 'primary-runtime'),
|
||||
primaryRuntime,
|
||||
resources, (next) => { platformView.setSession(next) })
|
||||
return {
|
||||
start: async () => {
|
||||
|
||||
@@ -2,6 +2,8 @@ import { join, sep } from 'node:path'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
desktopTargetBuildPaths,
|
||||
desktopTargetPlatform,
|
||||
developmentRuntimeDirectory,
|
||||
resolveDesktopBuildTarget,
|
||||
} from '../scripts/desktop-build-paths.mjs'
|
||||
|
||||
@@ -39,6 +41,22 @@ describe('desktop build paths', () => {
|
||||
expect(arm64.downloads).not.toContain(`${sep}targets${sep}`)
|
||||
})
|
||||
|
||||
it('resolves the development primary runtime from the build target rather than the host architecture', () => {
|
||||
expect(developmentRuntimeDirectory({}, 'darwin', 'arm64'))
|
||||
.toContain(join('targets', 'mac-arm64', 'runtime', 'primary-runtime'))
|
||||
expect(developmentRuntimeDirectory({}, 'darwin', 'x64'))
|
||||
.toContain(join('targets', 'mac-x64', 'runtime', 'primary-runtime'))
|
||||
expect(developmentRuntimeDirectory({}, 'win32', 'arm64'))
|
||||
.toContain(join('targets', 'win-x64', 'runtime', 'primary-runtime'))
|
||||
})
|
||||
|
||||
it('maps every target to the platform and architecture of the payload it prepares', () => {
|
||||
expect(desktopTargetPlatform('mac-arm64')).toEqual({ platform: 'darwin', arch: 'arm64' })
|
||||
expect(desktopTargetPlatform('mac-x64')).toEqual({ platform: 'darwin', arch: 'x64' })
|
||||
expect(desktopTargetPlatform('win-x64')).toEqual({ platform: 'win32', arch: 'x64' })
|
||||
expect(() => desktopTargetPlatform('linux-x64' as 'mac-x64')).toThrow(/unsupported target/u)
|
||||
})
|
||||
|
||||
it('resolves environment overrides and rejects unsupported targets', () => {
|
||||
expect(resolveDesktopBuildTarget({
|
||||
DSH_DESKTOP_TARGET_PLATFORM: 'darwin',
|
||||
|
||||
@@ -46,9 +46,10 @@ describe('desktop development project', () => {
|
||||
writeFileSync(join(host, 'lib/index.js'), '')
|
||||
writeFileSync(join(dependency, 'package.json'), JSON.stringify({ name: 'unhoisted', version: '1.2.3' }))
|
||||
symlinkSync(dependency, join(cli, 'node_modules/unhoisted'), process.platform === 'win32' ? 'junction' : 'dir')
|
||||
const project = prepareDevelopmentProject({ projectDir: join(root, 'runtime'), cliDir: cli, hostDir: host, dependencyDir: hoisted, release: release() })
|
||||
const project = prepareDevelopmentProject({ projectDir: join(root, 'runtime'), cliDir: cli, hostDir: host, dependencyDir: hoisted, release: release(), target: 'mac-arm64' })
|
||||
expect(realpathSync(join(project, 'node_modules/unhoisted'))).toBe(realpathSync(dependency))
|
||||
const descriptor = JSON.parse(readFileSync(join(project, 'desktop-runtime.json'), 'utf8')) as { sharedPackages: unknown[] }
|
||||
const descriptor = JSON.parse(readFileSync(join(project, 'desktop-runtime.json'), 'utf8')) as { platform: string; arch: string; sharedPackages: unknown[] }
|
||||
expect(descriptor).toMatchObject({ platform: 'darwin', arch: 'arm64' })
|
||||
expect(descriptor.sharedPackages).toContainEqual({ name: 'unhoisted', version: '1.2.3', path: 'node_modules/unhoisted' })
|
||||
})
|
||||
|
||||
@@ -76,6 +77,7 @@ describe('desktop development project', () => {
|
||||
hostDir: host,
|
||||
dependencyDir: dependencies,
|
||||
release: release(),
|
||||
target: 'win-x64',
|
||||
})
|
||||
expect(realpathSync(join(project, 'node_modules', '@deepseek-ai', 'dsh'))).toBe(realpathSync(cli))
|
||||
expect(realpathSync(join(project, 'node_modules', '@deepseek-ai', 'dsh-desktop-host'))).toBe(realpathSync(host))
|
||||
@@ -88,6 +90,8 @@ describe('desktop development project', () => {
|
||||
}
|
||||
expect(manifest.dependencies['@deepseek-ai/dsh']).toBe('1.2.3')
|
||||
expect(manifest.dependencies['@deepseek-ai/dsh-desktop-host']).toBe('1.2.3')
|
||||
const descriptor = JSON.parse(readFileSync(join(project, 'desktop-runtime.json'), 'utf8')) as { platform: string; arch: string }
|
||||
expect(descriptor).toMatchObject({ platform: 'win32', arch: 'x64' })
|
||||
const manager = new DesktopProjectManager(resolveDesktopPaths(join(root, 'home')), {
|
||||
dsh: project,
|
||||
})
|
||||
@@ -115,6 +119,7 @@ describe('desktop development project', () => {
|
||||
hostDir: host,
|
||||
dependencyDir: dependencies,
|
||||
release: release(),
|
||||
target: 'mac-x64',
|
||||
})).toThrow(/must be @deepseek-ai\/dsh@1\.2\.3/u)
|
||||
})
|
||||
})
|
||||
@@ -333,6 +333,7 @@ beforeEach(() => {
|
||||
vi.spyOn(console, 'info').mockImplementation(() => {})
|
||||
vi.stubEnv('DSH_DESKTOP_PNPM_ENTRY', 'test-pnpm')
|
||||
vi.stubEnv('DSH_DESKTOP_DSH_DIR', 'test-runtime')
|
||||
vi.stubEnv('DSH_DESKTOP_PRIMARY_RUNTIME_DIR', 'test-primary-runtime')
|
||||
vi.stubGlobal('process', { ...process, platform: 'win32', arch: 'x64', resourcesPath: 'desktop-test-resources' })
|
||||
vi.stubEnv('DSH_DESKTOP_HOST_INSPECT_PORT', undefined)
|
||||
vi.stubEnv('DSH_DESKTOP_DEV_PROJECT_DIR', undefined)
|
||||
@@ -1621,13 +1622,24 @@ describe('desktop main startup', () => {
|
||||
harness.prepared.resolve()
|
||||
await harness.hostStarted.promise
|
||||
const project = join(harness.app.getAppPath(), '.desktop-build', 'development', 'project')
|
||||
expect(harness.hosts[0]).toMatchObject({ node: process.execPath, runtime: project, profile: 'desktop-test-profile' })
|
||||
expect(harness.hosts[0]).toMatchObject({ node: process.execPath, runtime: project,
|
||||
primaryRuntime: 'test-primary-runtime', profile: 'desktop-test-profile' })
|
||||
expect(harness.applyRelease).toHaveBeenCalledOnce()
|
||||
harness.hosts[0]!.ready.resolve()
|
||||
await harness.navigated.promise
|
||||
expect(harness.dialog.showErrorBox).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('fails an unpackaged launch that receives no primary runtime directory', async () => {
|
||||
harness.app.isPackaged = false
|
||||
vi.stubEnv('DSH_DESKTOP_PRIMARY_RUNTIME_DIR', undefined)
|
||||
await import('../src/main.ts')
|
||||
await harness.dialogShown.promise
|
||||
const options = harness.dialog.showMessageBox.mock.calls[0]![0] as MessageBoxOptions
|
||||
expect(options.detail).toContain('DSH_DESKTOP_PRIMARY_RUNTIME_DIR is required for an unpackaged launch')
|
||||
expect(harness.hosts).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('keeps startup errors in the existing window without a retry handler', async () => {
|
||||
await import('../src/main.ts')
|
||||
await harness.preparing.promise
|
||||
|
||||
@@ -98,6 +98,9 @@ describe.skipIf(!existsSync(builtHost))('built Desktop welcome flow', () => {
|
||||
nodeVersion: process.versions.node,
|
||||
hostProtocolVersion: DESKTOP_HOST_PROTOCOL_VERSION,
|
||||
},
|
||||
// This suite assembles a synthetic project on hosts that prepare no Desktop target, and
|
||||
// nothing it exercises compares the descriptor's platform/arch outside packaging.
|
||||
target: 'mac-x64',
|
||||
})
|
||||
cpSync(join(repository, 'packages/skill/skill-office/assets'), join(root, 'runtime/office-skills'), { recursive: true })
|
||||
const nodeBin = join(root, 'runtime/primary-runtime/dependencies/node/bin')
|
||||
|
||||
@@ -148,6 +148,7 @@ it('starts the Host for welcome onboarding and opens the workspace on skip witho
|
||||
vi.stubEnv('DSH_DESKTOP_NODE_BINARY', '/runtime/node')
|
||||
vi.stubEnv('DSH_DESKTOP_PNPM_ENTRY', '/runtime/pnpm')
|
||||
vi.stubEnv('DSH_DESKTOP_DSH_DIR', '/runtime/dsh')
|
||||
vi.stubEnv('DSH_DESKTOP_PRIMARY_RUNTIME_DIR', '/runtime/primary-runtime')
|
||||
vi.stubEnv('DSH_DESKTOP_HOST_INSPECT_PORT', undefined)
|
||||
vi.stubEnv('DSH_DESKTOP_OPEN_DEVTOOLS', '0')
|
||||
vi.stubEnv('DSH_DESKTOP_MANDATORY_UPDATE_CONFIG', undefined)
|
||||
|
||||
Reference in new issue
Block a user