mirror of
https://github.com/hansjone/netxops.git
synced 2026-10-19 21:44:06 +08:00
54 lines
3.1 KiB
JavaScript
54 lines
3.1 KiB
JavaScript
/** Check both plugin faces against the locally installed Harness declarations. */
|
|
import { createRequire } from 'node:module'
|
|
import { existsSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs'
|
|
import { homedir, tmpdir } from 'node:os'
|
|
import { dirname, isAbsolute, join, relative, resolve } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
import { spawnSync } from 'node:child_process'
|
|
|
|
const root = dirname(dirname(fileURLToPath(import.meta.url)))
|
|
const home = process.env.DSH_HOME?.trim() || join(homedir(), '.dsh')
|
|
const anchors = [join(root, 'package.json'), ...['desktop', 'web', ''].map(profile =>
|
|
join(home, 'profiles', profile, 'node_modules', '@deepseek-ai', 'dsh-client-ui-renderer', 'package.json'))]
|
|
const requires = anchors.filter(existsSync).flatMap(path => [createRequire(path), createRequire(realpathSync(path))])
|
|
function findPackage(name) {
|
|
for (const req of requires) {
|
|
try { return req.resolve(`${name}/package.json`) } catch { /* Try another installed profile. */ }
|
|
}
|
|
throw new Error(`Missing typecheck peer ${name}; install the Harness and run link:peers.`)
|
|
}
|
|
const paths = {}
|
|
for (const spec of [
|
|
'@deepseek-ai/dsh-client-ui-slots', '@deepseek-ai/dsh-client-locale/client',
|
|
'@deepseek-ai/dsh-client-ui-renderer/client', '@deepseek-ai/dsh-api-remotes/client',
|
|
'@deepseek-ai/dsh-client-ui-settings/client',
|
|
'@deepseek-ai/dsh-client-ui-settings-plugins/client',
|
|
]) {
|
|
const parts = spec.split('/'), pkgName = parts.slice(0, 2).join('/'), subpath = parts.slice(2).join('/')
|
|
const pkgPath = findPackage(pkgName), pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
|
|
const entry = pkg.exports?.[subpath ? `./${subpath}` : '.']
|
|
const types = typeof entry === 'object' ? entry.types : pkg.types
|
|
if (!types) throw new Error(`No declarations for ${spec}`)
|
|
paths[spec] = [join(dirname(pkgPath), types)]
|
|
}
|
|
const nodeTypes = dirname(findPackage('@types/node'))
|
|
const folder = mkdtempSync(join(tmpdir(), 'netxops-typecheck-'))
|
|
try {
|
|
const configPath = join(folder, 'tsconfig.json')
|
|
writeFileSync(configPath, JSON.stringify({ compilerOptions: {
|
|
target: 'ES2022', module: 'ESNext', moduleResolution: 'Bundler', jsx: 'react-jsx',
|
|
noEmit: true, strict: true, skipLibCheck: true, allowImportingTsExtensions: true,
|
|
types: ['node', 'react'], typeRoots: [dirname(nodeTypes), join(root, 'node_modules', '@types')], paths,
|
|
}, include: [join(root, 'src', '**', '*.ts'), join(root, 'src', '**', '*.tsx')].map(path => path.replaceAll('\\', '/')) }))
|
|
const result = spawnSync(process.execPath, [join(root, 'node_modules', 'typescript', 'bin', 'tsc'), '-p', configPath],
|
|
{ cwd: root, stdio: 'inherit' })
|
|
process.exitCode = result.status ?? 1
|
|
} finally {
|
|
// The only cleanup target is the exact unique temporary directory returned above.
|
|
const target = realpathSync(folder)
|
|
const within = relative(realpathSync(tmpdir()), target)
|
|
if (!within || within.startsWith('..') || isAbsolute(within) || !target.startsWith(resolve(folder))) {
|
|
throw new Error(`Refusing cleanup outside the temporary workspace: ${target}`)
|
|
}
|
|
rmSync(target, { recursive: true, force: true })
|
|
}
|