diff --git a/scripts/check-doc-coverage.sh b/scripts/check-doc-coverage.sh index 76830e1f..9174721f 100755 --- a/scripts/check-doc-coverage.sh +++ b/scripts/check-doc-coverage.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# check-doc-coverage.sh — Verify every adapter in src/clis/ has a doc page. +# check-doc-coverage.sh — Verify every adapter in clis/ has a doc page. # # Exit codes: # 0 — all adapters have docs @@ -19,7 +19,7 @@ fi SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -SRC_DIR="$ROOT_DIR/src/clis" +SRC_DIR="$ROOT_DIR/clis" DOCS_DIR="$ROOT_DIR/docs/adapters" missing=() diff --git a/scripts/fetch-adapters.js b/scripts/fetch-adapters.js index 0d03f425..6d119e9c 100644 --- a/scripts/fetch-adapters.js +++ b/scripts/fetch-adapters.js @@ -87,8 +87,9 @@ export function fetchAdapters() { const currentVersion = getPackageVersion(); const oldManifest = readManifest(); - // Skip if already installed at the same version - if (currentVersion !== 'unknown' && oldManifest?.version === currentVersion) { + // Skip if already installed at the same version (unless forced via OPENCLI_FETCH=1) + const isForced = process.env.OPENCLI_FETCH === '1'; + if (!isForced && currentVersion !== 'unknown' && oldManifest?.version === currentVersion) { log(`Adapters already up to date (v${currentVersion})`); return; } diff --git a/src/discovery.ts b/src/discovery.ts index b572b434..e5bf3ca9 100644 --- a/src/discovery.ts +++ b/src/discovery.ts @@ -37,6 +37,19 @@ function parseStrategy(rawStrategy: string | undefined, fallback: Strategy = Str import { isRecord } from './utils.js'; +/** + * Find the package root (directory containing package.json). + * Dev: import.meta.url is in src/ → one level up. + * Prod: import.meta.url is in dist/src/ → two levels up. + */ +function findPackageRoot(): string { + let dir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); + if (!fs.existsSync(path.join(dir, 'package.json'))) { + dir = path.resolve(dir, '..'); + } + return dir; +} + function resolveHostRuntimeModulePath(moduleName: string): string { const runtimeDir = path.dirname(fileURLToPath(import.meta.url)); for (const ext of ['.js', '.ts']) { @@ -119,7 +132,7 @@ export async function ensureUserCliCompatShims(baseDir: string = USER_OPENCLI_DI // Create node_modules/@jackwener/opencli symlink so user TS CLIs can import // from '@jackwener/opencli/registry' (the package export). // This is needed because ~/.opencli/clis/ is outside opencli's node_modules tree. - const opencliRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); + const opencliRoot = findPackageRoot(); const symlinkDir = path.join(baseDir, 'node_modules', '@jackwener'); const symlinkPath = path.join(symlinkDir, 'opencli'); try { @@ -162,10 +175,10 @@ export async function ensureUserAdapters(): Promise { // Dir doesn't exist — needs fetch } - log.info('First run detected — fetching adapters...'); + log.info('First run detected — copying adapters (one-time setup)...'); try { const { execFileSync } = await import('node:child_process'); - const scriptPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', 'scripts', 'fetch-adapters.js'); + const scriptPath = path.join(findPackageRoot(), 'scripts', 'fetch-adapters.js'); execFileSync(process.execPath, [scriptPath], { stdio: 'inherit', env: { ...process.env, _OPENCLI_FIRST_RUN: '1' },