ci/woodpecker/push/publish Pipeline was canceled
Co-authored-by: orch-01 <[email protected]>
68 lines
2.3 KiB
TypeScript
68 lines
2.3 KiB
TypeScript
import { spawnSync } from 'node:child_process';
|
|
import { accessSync, constants } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
|
|
import { resolveBrainHome } from '../fleet/brain-home.js';
|
|
|
|
/**
|
|
* Shared brain-tool dispatch (fleet CLI integration, Jason ruling
|
|
* 2026-08-28): the npm package embeds the COMMAND SURFACE; operator-owned
|
|
* implementations stay in the brain (tools/). Commands resolve the brain
|
|
* home (MOSAIC_BRAIN_HOME wins — see brain-home.ts) and exec the tool
|
|
* there. Nothing operator-specific ships inside the package.
|
|
*
|
|
* Pass-through contract: arguments, stdout/stderr, and the exit code belong
|
|
* to the tool. The CLI adds nothing on success; absent tools fail loudly
|
|
* with the resolved path (127) instead of guessing.
|
|
*/
|
|
|
|
/** Absolute path of a brain-relative tool. */
|
|
export function resolveBrainTool(mosaicHome: string, relPath: string): string {
|
|
return join(resolveBrainHome(mosaicHome), ...relPath.split('/'));
|
|
}
|
|
|
|
/** Map a spawnSync result + tool existence to the CLI exit status. */
|
|
export function exitStatusFor(
|
|
result: { status: number | null; error?: NodeJS.ErrnoException },
|
|
toolExists: boolean,
|
|
): number {
|
|
if (!toolExists) return 127;
|
|
if (result.status !== null) return result.status;
|
|
return 125; // killed by signal / could not run
|
|
}
|
|
|
|
export function brainToolExists(tool: string): boolean {
|
|
try {
|
|
accessSync(tool, constants.X_OK);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Exec a brain tool with full pass-through. `interpreter` runs the tool
|
|
* through e.g. python3 (renderers); omit it for executable scripts.
|
|
* Returns the process exit status; callers assign it to process.exitCode.
|
|
*/
|
|
export function execBrainTool(
|
|
mosaicHome: string,
|
|
relPath: string,
|
|
args: string[],
|
|
interpreter?: string,
|
|
): number {
|
|
const tool = resolveBrainTool(mosaicHome, relPath);
|
|
if (!brainToolExists(tool)) {
|
|
console.error(
|
|
`mosaic: brain tool not found (expected ${tool}). ` +
|
|
'Tool suites live in the brain tree under tools/; ' +
|
|
'check MOSAIC_BRAIN_HOME or the brain checkout.',
|
|
);
|
|
return 127;
|
|
}
|
|
const result = interpreter
|
|
? spawnSync(interpreter, [tool, ...args], { stdio: 'inherit', env: process.env })
|
|
: spawnSync(tool, args, { stdio: 'inherit', env: process.env });
|
|
return exitStatusFor(result, true);
|
|
}
|