mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-03 22:19:42 +02:00
Environment-aware dependency probe (linux|darwin|win32|wsl) with a static registry, an injectable ProbeHost seam for testing, grouped table + `--json` output, and a non-zero exit when a required dependency is missing/outdated. Node and tmux are the only hard-required tools; the agent CLIs and document converters (LibreOffice / MS Office via WSL interop) are optional. CI-safe unit tests (no tmux, injected host).
76 lines
3.0 KiB
TypeScript
76 lines
3.0 KiB
TypeScript
/**
|
|
* @fileoverview Renders ToolResult[] from the dependency checker into a
|
|
* human-readable grouped table or JSON, and computes the process exit code.
|
|
* Plain text only (no color) so output is stable and snapshot-friendly; the
|
|
* CLI layer may colorize.
|
|
*
|
|
* @module utils/dependency-report
|
|
*/
|
|
|
|
import type { ProbeEnvironment, ToolCategory } from '../config/dependency-registry.js';
|
|
import type { ToolResult, ToolStatus } from './dependency-checker.js';
|
|
|
|
const CATEGORY_ORDER: ToolCategory[] = ['core', 'office', 'other'];
|
|
|
|
function glyph(r: ToolResult): string {
|
|
if (r.status === 'ok') return '✓';
|
|
if (r.status === 'skipped') return '○';
|
|
return r.required ? '✗' : '○';
|
|
}
|
|
|
|
function statusText(r: ToolResult): string {
|
|
if (r.status === 'ok') return r.version ?? 'installed';
|
|
if (r.status === 'outdated') return `${r.version ?? '?'} (below minimum)`;
|
|
if (r.status === 'skipped') return 'n/a';
|
|
if (r.status === 'error') return 'version error';
|
|
return 'not found';
|
|
}
|
|
|
|
export function computeExitCode(results: ToolResult[]): number {
|
|
const failed = results.some(
|
|
(r) => r.required && (r.status === 'missing' || r.status === 'outdated' || r.status === 'error')
|
|
);
|
|
return failed ? 1 : 0;
|
|
}
|
|
|
|
export function renderTable(results: ToolResult[], environment: ProbeEnvironment): string {
|
|
const lines: string[] = [`Codeman dependency check — ${environment}`, ''];
|
|
for (const category of CATEGORY_ORDER) {
|
|
const rows = results.filter((r) => r.category === category);
|
|
if (rows.length === 0) continue;
|
|
lines.push(category.toUpperCase());
|
|
for (const r of rows) {
|
|
const detail = r.path ? ` ${r.path}` : '';
|
|
lines.push(` ${glyph(r)} ${r.label.padEnd(14)} ${statusText(r).padEnd(22)}${detail}`);
|
|
if (r.usedBy.length) lines.push(` used by: ${r.usedBy.join(', ')}`);
|
|
if (r.installHint) lines.push(` install: ${r.installHint}`);
|
|
}
|
|
lines.push('');
|
|
}
|
|
const ok = results.filter((r) => r.status === 'ok').length;
|
|
const requiredMissing = results.filter((r) => r.required && r.status !== 'ok' && r.status !== 'skipped').length;
|
|
const optionalMissing = results.filter((r) => !r.required && r.status === 'missing').length;
|
|
lines.push(`Summary: ${ok} ok · ${requiredMissing} required missing · ${optionalMissing} optional missing`);
|
|
return lines.join('\n');
|
|
}
|
|
|
|
export interface DependencyReportJson {
|
|
platform: { environment: ProbeEnvironment };
|
|
summary: { ok: number; requiredMissing: number; optionalMissing: number; exitCode: number };
|
|
tools: ToolResult[];
|
|
}
|
|
|
|
export function renderJson(results: ToolResult[], environment: ProbeEnvironment): DependencyReportJson {
|
|
const byStatus = (s: ToolStatus) => results.filter((r) => r.status === s).length;
|
|
return {
|
|
platform: { environment },
|
|
summary: {
|
|
ok: byStatus('ok'),
|
|
requiredMissing: results.filter((r) => r.required && r.status !== 'ok' && r.status !== 'skipped').length,
|
|
optionalMissing: results.filter((r) => !r.required && r.status === 'missing').length,
|
|
exitCode: computeExitCode(results),
|
|
},
|
|
tools: results,
|
|
};
|
|
}
|