#!/usr/bin/env node /** * Link the harness's own packages into this checkout so `npm test` can import * them, the way a plugin resolves them once installed into a profile. * * ## Why this exists * * The plugin imports `@deepseek-ai/dsh-tools` and `@deepseek-ai/schemastery`. * Once installed into a profile those resolve from the profile's own * `node_modules`, which is where the harness lives — but a bare checkout has no * such tree, so the tests cannot even load the module under test. * * The alternative is declaring them as dependencies, and for `@deepseek-ai/cordis` * that would be a genuine bug rather than untidiness: a second copy of Cordis * means a second `Context` class, two service registries in one process, and a * plugin whose services are invisible to the harness that loaded it. So the * packages are linked, not installed. * * Idempotent, and safe to re-run after the harness is upgraded. */ import { existsSync, mkdirSync, readdirSync, rmSync, symlinkSync } from 'node:fs' import { dirname, join, resolve } from 'node:path' import { fileURLToPath } from 'node:url' /** Packages this checkout imports at runtime, and which the harness must supply. */ const NEEDED = ['cordis', 'schemastery', 'dsh-tools'] const here = dirname(fileURLToPath(import.meta.url)) const packageRoot = resolve(here, '..') /** Where a dsh installation keeps the scope, newest layout first. */ function findHarnessScope() { const candidates = [ process.env.DSH_HARNESS_NODE_MODULES, resolve(process.env.DSH_HOME ?? join(process.env.HOME ?? '', '.dsh'), 'profiles', 'node_modules'), '/usr/local/lib/node_modules/@deepseek-ai/dsh/node_modules', ] for (const candidate of candidates) { if (typeof candidate === 'string' && existsSync(join(candidate, '@deepseek-ai', 'cordis'))) return candidate } return undefined } const scope = findHarnessScope() if (scope === undefined) { console.error('dev-links: no dsh installation found. Set DSH_HARNESS_NODE_MODULES to its node_modules directory.') process.exit(1) } const target = join(packageRoot, 'node_modules') mkdirSync(join(target, '@deepseek-ai'), { recursive: true }) let linked = 0 for (const name of NEEDED) { const source = join(scope, '@deepseek-ai', name) if (!existsSync(source)) { console.error(`dev-links: ${name} is not in ${scope}; skipping`) continue } const link = join(target, '@deepseek-ai', name) if (existsSync(link)) rmSync(link, { recursive: true, force: true }) symlinkSync(source, link, 'dir') linked += 1 } const scopeLabel = readdirSync(join(scope, '@deepseek-ai')).length console.log(`dev-links: linked ${linked}/${NEEDED.length} packages from ${scope} (${scopeLabel} available)`)