| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- /** Select and copy the local npm tarball closures that supply Desktop dsh and its private Host. */
- import { createHash } from 'node:crypto'
- import {
- constants,
- copyFileSync,
- mkdirSync,
- readFileSync,
- readdirSync,
- rmSync,
- statSync,
- writeFileSync,
- } from 'node:fs'
- import { basename, join, resolve } from 'node:path'
- import { parseArgs } from 'node:util'
- import {
- DESKTOP_HOST_PACKAGE,
- DESKTOP_HOST_RUNTIME_FILES,
- DESKTOP_PACKAGES_DIR,
- DESKTOP_PACKAGE_SET_FILE,
- parseDesktopCorePackageSet,
- type DesktopCorePackageRecord,
- } from '../src/core-package-set.ts'
- import { capture } from '../../../scripts/release/process.ts'
- import { tarballFiles } from '../../../scripts/release/tarball.ts'
- import { resolveDesktopTargetBuildPaths } from './desktop-build-paths.mjs'
- const DSH_PACKAGE = '@deepseek-ai/dsh'
- const ROOT_PACKAGES = [DSH_PACKAGE, DESKTOP_HOST_PACKAGE] as const
- const APP_ROOT = resolve(import.meta.dirname, '..')
- const REPOSITORY_ROOT = resolve(APP_ROOT, '..', '..')
- const REQUIRED_DEPENDENCY_SECTIONS = ['dependencies', 'peerDependencies'] as const
- const OPTIONAL_DEPENDENCY_SECTION = 'optionalDependencies'
- /** Packed package information needed to form the local Desktop closure. */
- export interface PackedDesktopPackage {
- readonly tarball: string
- readonly manifest: Readonly<Record<string, unknown>>
- }
- function dependencyNames(manifest: Readonly<Record<string, unknown>>, section: string): string[] {
- const value = manifest[section]
- if (value === undefined) return []
- if (value === null || typeof value !== 'object' || Array.isArray(value)) {
- throw new Error(`desktop package set: ${String(manifest.name)} has invalid ${section}`)
- }
- return Object.keys(value).sort()
- }
- /**
- * Select the complete available first-party dependency closures rooted at dsh and its private Host.
- * @param available - Packed packages indexed by package name.
- * @returns Selected packages sorted by name.
- */
- export function selectDesktopPackageClosure(
- available: ReadonlyMap<string, PackedDesktopPackage>,
- ): PackedDesktopPackage[] {
- const selected = new Map<string, PackedDesktopPackage>()
- const visit = (name: string): void => {
- if (selected.has(name)) return
- const packed = available.get(name)
- if (packed === undefined) throw new Error(`desktop package set: packed inputs omit required package ${name}`)
- selected.set(name, packed)
- for (const section of REQUIRED_DEPENDENCY_SECTIONS) {
- for (const dependency of dependencyNames(packed.manifest, section)) {
- if (available.has(dependency)) visit(dependency)
- else if (dependency.startsWith('@deepseek-ai/')) {
- throw new Error(`desktop package set: ${name} requires unpacked internal package ${dependency}`)
- }
- }
- }
- for (const dependency of dependencyNames(packed.manifest, OPTIONAL_DEPENDENCY_SECTION)) {
- if (available.has(dependency)) visit(dependency)
- }
- }
- for (const name of ROOT_PACKAGES) {
- if (!available.has(name)) throw new Error(`desktop package set: packed inputs omit ${name}`)
- visit(name)
- }
- return [...selected.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([, packed]) => packed)
- }
- function packedManifest(tarball: string): Record<string, unknown> {
- const value: unknown = JSON.parse(capture('tar', ['-xOzf', tarball, 'package/package.json']))
- if (value === null || typeof value !== 'object' || Array.isArray(value)) {
- throw new Error(`desktop package set: ${tarball} has no package manifest`)
- }
- return value as Record<string, unknown>
- }
- function packedPackages(inputs: readonly string[]): Map<string, PackedDesktopPackage> {
- const available = new Map<string, PackedDesktopPackage>()
- for (const input of inputs) {
- const tarballs = readdirSync(input).filter(file => file.endsWith('.tgz')).sort()
- if (tarballs.length === 0) throw new Error(`desktop package set: ${input} contains no tarballs`)
- for (const file of tarballs) {
- const tarball = join(input, file)
- const manifest = packedManifest(tarball)
- const name = manifest.name
- if (typeof name !== 'string' || name === '') throw new Error(`desktop package set: ${tarball} has no package name`)
- if (available.has(name)) throw new Error(`desktop package set: duplicate packed package ${name}`)
- available.set(name, { tarball, manifest })
- }
- }
- return available
- }
- /**
- * Require every private Host file used before the Desktop profile can pass its health check.
- * @param files - Tarball paths rooted at `package/`.
- * @returns Nothing.
- */
- export function assertDesktopHostPackageFiles(files: readonly string[]): void {
- const available = new Set(files)
- const missing = DESKTOP_HOST_RUNTIME_FILES
- .map(file => `package/${file}`)
- .filter(file => !available.has(file))
- if (missing.length > 0) {
- throw new Error(`desktop package set: ${DESKTOP_HOST_PACKAGE} tarball omits required file(s): ${missing.join(', ')}`)
- }
- }
- /** Prepare a package set from release tarball directories. */
- export function prepareDesktopPackageSet(inputs: readonly string[], output: string): void {
- const selected = selectDesktopPackageClosure(packedPackages(inputs))
- const host = selected.find(packed => packed.manifest.name === DESKTOP_HOST_PACKAGE)
- if (host === undefined) throw new Error(`desktop package set: selected closure omits ${DESKTOP_HOST_PACKAGE}`)
- assertDesktopHostPackageFiles(tarballFiles(host.tarball))
- rmSync(output, { recursive: true, force: true })
- const packageDir = join(output, DESKTOP_PACKAGES_DIR)
- mkdirSync(packageDir, { recursive: true })
- const records: DesktopCorePackageRecord[] = selected.map((packed) => {
- const name = packed.manifest.name
- const version = packed.manifest.version
- if (typeof name !== 'string' || typeof version !== 'string') {
- throw new Error(`desktop package set: ${packed.tarball} has no package identity`)
- }
- const file = basename(packed.tarball)
- const destination = join(packageDir, file)
- copyFileSync(packed.tarball, destination, constants.COPYFILE_EXCL)
- const body = readFileSync(destination)
- return {
- name,
- version,
- file,
- bytes: statSync(destination).size,
- integrity: `sha512-${createHash('sha512').update(body).digest('base64')}`,
- }
- })
- const packageSet = parseDesktopCorePackageSet({ schemaVersion: 1, packages: records })
- writeFileSync(join(output, DESKTOP_PACKAGE_SET_FILE), `${JSON.stringify(packageSet, undefined, 2)}\n`, { mode: 0o600 })
- }
- function main(): void {
- const buildPaths = resolveDesktopTargetBuildPaths()
- const defaultInputs = [
- buildPaths.packedDsh,
- buildPaths.packedVendor,
- buildPaths.packedLandlock,
- ]
- const { values } = parseArgs({
- options: { from: { type: 'string', multiple: true }, out: { type: 'string' } },
- allowPositionals: false,
- })
- const inputs = (values.from ?? defaultInputs).map(path => resolve(REPOSITORY_ROOT, path))
- const output = values.out === undefined ? buildPaths.packageSet : resolve(REPOSITORY_ROOT, values.out)
- prepareDesktopPackageSet(inputs, output)
- console.log(`desktop package set: prepared ${output}`)
- }
- if (import.meta.main) main()
|