Files
stack/packages/mosaic/src/runtime/detector.ts
Jason Woltje b57fc317b8
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
feat(mosaic): migrate install wizard from v0 to v1
Complete port of the ~2000 LOC mosaic install wizard from v0. Migrates
all 27 source files across the prompter, config, platform, template,
runtime, skills, and stages subsystems to v1 ESM/NodeNext conventions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 19:54:09 -05:00

83 lines
1.9 KiB
TypeScript

import { execSync } from 'node:child_process';
import { platform } from 'node:os';
import type { RuntimeName } from '../types.js';
export interface RuntimeInfo {
name: RuntimeName;
label: string;
installed: boolean;
path?: string;
version?: string;
installHint: string;
}
const RUNTIME_DEFS: Record<
RuntimeName,
{ label: string; command: string; versionFlag: string; installHint: string }
> = {
claude: {
label: 'Claude Code',
command: 'claude',
versionFlag: '--version',
installHint: 'npm install -g @anthropic-ai/claude-code',
},
codex: {
label: 'Codex',
command: 'codex',
versionFlag: '--version',
installHint: 'npm install -g @openai/codex',
},
opencode: {
label: 'OpenCode',
command: 'opencode',
versionFlag: 'version',
installHint: 'See https://opencode.ai for install instructions',
},
};
export function detectRuntime(name: RuntimeName): RuntimeInfo {
const def = RUNTIME_DEFS[name];
const isWindows = platform() === 'win32';
const whichCmd = isWindows ? `where ${def.command} 2>nul` : `which ${def.command} 2>/dev/null`;
try {
const pathOutput =
execSync(whichCmd, {
encoding: 'utf-8',
timeout: 5000,
})
.trim()
.split('\n')[0] ?? '';
let version: string | undefined;
try {
version = execSync(`${def.command} ${def.versionFlag} 2>/dev/null`, {
encoding: 'utf-8',
timeout: 5000,
}).trim();
} catch {
// Version detection is optional
}
return {
name,
label: def.label,
installed: true,
path: pathOutput,
version,
installHint: def.installHint,
};
} catch {
return {
name,
label: def.label,
installed: false,
installHint: def.installHint,
};
}
}
export function getInstallInstructions(name: RuntimeName): string {
return RUNTIME_DEFS[name].installHint;
}