Require the tracked FreeBSD 15.x line during install and environment checks, and align docs and skill compatibility metadata with 15.x only. --- Build: pass Tests: pass — 37 passed (2 files) --- Build: pass | Tests: pass — 2363 passed (701 files)
126 lines
3.2 KiB
TypeScript
126 lines
3.2 KiB
TypeScript
/**
|
|
* FreeBSD-focused detection utilities for Clawdie setup.
|
|
*/
|
|
import { execSync } from 'child_process';
|
|
import os from 'os';
|
|
import path from 'path';
|
|
|
|
export type Platform = 'freebsd' | 'unknown';
|
|
export type ServiceManager = 'freebsd-rc' | 'none';
|
|
|
|
export const SUPPORTED_FREEBSD_MAJOR = 15;
|
|
export const SUPPORTED_FREEBSD_LINE = 'FreeBSD 15.x';
|
|
|
|
export interface FreeBSDVersionSupport {
|
|
ok: boolean;
|
|
detected: string;
|
|
major: number | null;
|
|
required: string;
|
|
}
|
|
|
|
export function getPlatform(): Platform {
|
|
return os.platform() === 'freebsd' ? 'freebsd' : 'unknown';
|
|
}
|
|
|
|
export function isRoot(): boolean {
|
|
return process.getuid?.() === 0;
|
|
}
|
|
|
|
/**
|
|
* Open a URL or file path in the default browser.
|
|
* FreeBSD commonly exposes xdg-open from desktop utilities.
|
|
*/
|
|
export function openBrowser(target: string): boolean {
|
|
if (!commandExists('xdg-open')) return false;
|
|
try {
|
|
execSync(`xdg-open ${JSON.stringify(target)}`, { stdio: 'ignore' });
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export function getServiceManager(): ServiceManager {
|
|
return getPlatform() === 'freebsd' ? 'freebsd-rc' : 'none';
|
|
}
|
|
|
|
export function parseFreeBSDMajorVersion(raw: string): number | null {
|
|
const match = raw.trim().match(/^(\d+)(?:[.-]|$)/u);
|
|
if (!match) return null;
|
|
const major = parseInt(match[1], 10);
|
|
return Number.isNaN(major) ? null : major;
|
|
}
|
|
|
|
export function checkFreeBSDVersionSupport(raw: string): FreeBSDVersionSupport {
|
|
const detected = raw.trim();
|
|
const major = parseFreeBSDMajorVersion(detected);
|
|
return {
|
|
ok: major === SUPPORTED_FREEBSD_MAJOR,
|
|
detected: detected || 'unknown',
|
|
major,
|
|
required: SUPPORTED_FREEBSD_LINE,
|
|
};
|
|
}
|
|
|
|
export function readFreeBSDUserlandVersion(): string {
|
|
return execSync('freebsd-version -u', { encoding: 'utf-8' }).trim();
|
|
}
|
|
|
|
export function getFreeBSDVersionSupport(): FreeBSDVersionSupport {
|
|
try {
|
|
return checkFreeBSDVersionSupport(readFreeBSDUserlandVersion());
|
|
} catch {
|
|
return {
|
|
ok: false,
|
|
detected: 'unknown',
|
|
major: null,
|
|
required: SUPPORTED_FREEBSD_LINE,
|
|
};
|
|
}
|
|
}
|
|
|
|
export function getNodePath(): string {
|
|
try {
|
|
return execSync('command -v node', { encoding: 'utf-8' }).trim();
|
|
} catch {
|
|
return process.execPath;
|
|
}
|
|
}
|
|
|
|
export function getNpmPath(): string {
|
|
try {
|
|
return execSync('command -v npm', { encoding: 'utf-8' }).trim();
|
|
} catch {
|
|
// Fallback: npm lives alongside node on FreeBSD (same bin dir)
|
|
return `${path.dirname(getNodePath())}/npm`;
|
|
}
|
|
}
|
|
|
|
export function commandExists(name: string): boolean {
|
|
try {
|
|
execSync(`command -v ${name}`, { stdio: 'ignore' });
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export function getNodeVersion(): string | null {
|
|
try {
|
|
const version = execSync('node --version', { encoding: 'utf-8' }).trim();
|
|
return version.replace(/^v/, '');
|
|
} catch {
|
|
return process.version ? process.version.replace(/^v/, '') : null;
|
|
}
|
|
}
|
|
|
|
export function getNodeMajorVersion(): number | null {
|
|
const version = getNodeVersion();
|
|
if (!version) return null;
|
|
const major = parseInt(version.split('.')[0], 10);
|
|
return isNaN(major) ? null : major;
|
|
}
|
|
|
|
export function hasBrowser(): boolean {
|
|
return ['xdg-open', 'firefox', 'chromium', 'chrome'].some(commandExists);
|
|
}
|