86 lines
4.2 KiB
TypeScript
86 lines
4.2 KiB
TypeScript
/** Launch the Desktop profile through the Web application and report its URL to Electron. */
|
|
|
|
import { delimiter, join } from 'node:path'
|
|
import { loadLayeredEnv, loadProfileDirectory } from '@deepseek-ai/dsh-app-boot'
|
|
import { runProfile } from '@deepseek-ai/dsh/profile-boot'
|
|
import type {} from '@deepseek-ai/dsh-client-connection'
|
|
import type {} from '@deepseek-ai/dsh-host-webserver'
|
|
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths'
|
|
import * as desktopOffice from './office.ts'
|
|
|
|
import { installDesktopUpdateTaskControl } from './update-tasks.ts'
|
|
|
|
async function main(): Promise<void> {
|
|
const runtimeDir = process.argv[2] as string
|
|
const projectDir = process.argv[3] as string
|
|
const installAnchor = join(runtimeDir, 'node_modules', '@deepseek-ai', 'dsh', 'package.json')
|
|
const profile = loadProfileDirectory('dsh', projectDir, installAnchor)
|
|
const application = runProfile({
|
|
environment: loadLayeredEnv('dsh'),
|
|
profile: 'desktop',
|
|
resolutionMode: process.argv[5] === 'runtime' ? 'runtime' : 'link',
|
|
resolvedProfile: { profile, installAnchor },
|
|
patchFiles: [],
|
|
args: ['--no-open', '--port', '19387'],
|
|
...(process.argv[6] === undefined ? {} : {
|
|
packageManager: {
|
|
command: process.execPath,
|
|
args: ['--expose-internals', process.argv[6]],
|
|
env: {
|
|
ELECTRON_RUN_AS_NODE: '1',
|
|
DSH_DESKTOP_NODE_EXECUTABLE: process.execPath,
|
|
PATH: `${process.argv[7] ?? ''}${delimiter}${process.env.PATH ?? ''}`,
|
|
},
|
|
},
|
|
}),
|
|
})
|
|
let stopping: Promise<void> | undefined
|
|
const control: { updateTasks?: ReturnType<typeof installDesktopUpdateTaskControl> } = {}
|
|
const send = (message: object): Promise<void> => new Promise((resolve, reject) => {
|
|
if (!process.connected || process.send === undefined) { resolve(); return }
|
|
process.send(message, (error) => { if (error === null) resolve(); else reject(error) })
|
|
})
|
|
const stop = (): Promise<void> => stopping ??= (async () => {
|
|
// Startup failure is reported by main; shutdown only owns a tree that booted.
|
|
const running = await application.catch(() => undefined)
|
|
await running?.shutdown.shutdown(0)
|
|
await send({ type: 'shutdown-complete' })
|
|
if (process.connected) process.disconnect()
|
|
})()
|
|
process.on('message', (message: unknown) => {
|
|
if (typeof message !== 'object' || message === null || !('type' in message)) return
|
|
if (message.type === 'shutdown') { void stop(); return }
|
|
if (message.type !== 'update-tasks' || !('requestId' in message) || !Number.isSafeInteger(message.requestId)
|
|
|| !('action' in message) || !['inspect', 'lock', 'unlock'].includes(String(message.action))) return
|
|
void (async () => {
|
|
try {
|
|
if (stopping !== undefined || control.updateTasks === undefined) throw new Error('desktop update: Host is unavailable')
|
|
const active = await control.updateTasks(message.action as 'inspect' | 'lock' | 'unlock')
|
|
await send({ type: 'update-tasks', requestId: message.requestId, active })
|
|
} catch (error) {
|
|
await send({ type: 'update-tasks', requestId: message.requestId, active: true,
|
|
error: error instanceof Error ? error.message : String(error) })
|
|
}
|
|
})().catch((error: unknown) => { console.error(error) })
|
|
})
|
|
process.once('disconnect', () => { void stop() })
|
|
const { ctx } = await application
|
|
control.updateTasks = installDesktopUpdateTaskControl(ctx)
|
|
await ctx.plugin(desktopOffice, {
|
|
source: process.argv[4] ?? join(runtimeDir, '..', 'runtime', 'primary-runtime'),
|
|
root: join(resolveDshHome(), 'dsh-runtimes', 'dsh-primary-runtime'),
|
|
})
|
|
const url = ctx.connection.authenticatedUrl(`http://127.0.0.1:${String(ctx.webServer.port)}`)
|
|
if (process.connected) process.send?.({ type: 'ready', url, injections: ctx.webServer.collectIndexInjections() }, (error) => { if (error !== null) console.error(error) })
|
|
}
|
|
|
|
if (import.meta.main) {
|
|
main().catch((error: unknown) => {
|
|
const message = error instanceof Error ? error.message : String(error)
|
|
if (process.connected) process.send?.({ type: 'fatal', message }, (error) => { if (error !== null) console.error(error) })
|
|
console.error(error)
|
|
process.exitCode = 1
|
|
if (process.connected) process.disconnect()
|
|
})
|
|
}
|