Files
MokoCLI/mcp/src/runner.ts
T
Jonathan Miller 1d87be7d5e
Branch Policy Check / Verify merge target (pull_request) Has been cancelled
fix: standardize file headers — REPO rename, SPDX case, missing fields
- Update REPO: from MokoStandards-API to moko-platform in 125 files
- Fix wrong org path (mokoconsulting-tech → MokoConsulting) in 10 files
- Fix SPDX-LICENSE-IDENTIFIER case in 2 template files
- Add missing REPO: field to 3 files

Authored-by: Moko Consulting

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-11 17:01:17 -05:00

56 lines
1.9 KiB
TypeScript

/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
*
* This file is part of a Moko Consulting project.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* FILE INFORMATION
* DEFGROUP: mokostandards-mcp.Runner
* INGROUP: MokoStandards-API
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /mcp/src/runner.ts
* BRIEF: PHP CLI command runner for MokoStandards tools — uses execFile (no shell injection)
*/
import { execFile as nodeExecFile } from 'node:child_process';
import { resolve } from 'node:path';
import type { StandardsConfig, ExecResult } from './types.js';
const TIMEOUT_MS = 60_000;
/**
* Runs MokoStandards PHP CLI tools via execFile (safe, no shell).
* All arguments are passed as array elements — never interpolated into a shell string.
*/
export class StandardsRunner {
private readonly apiPath: string;
constructor(config: StandardsConfig) {
this.apiPath = config.apiPath;
}
async runCli(script: string, args: string[] = []): Promise<ExecResult> {
const scriptPath = resolve(this.apiPath, 'cli', script);
return this.run('php', [scriptPath, ...args]);
}
async runValidate(script: string, args: string[] = []): Promise<ExecResult> {
const scriptPath = resolve(this.apiPath, 'validate', script);
return this.run('php', [scriptPath, ...args]);
}
private run(command: string, args: string[]): Promise<ExecResult> {
return new Promise((resolvePromise) => {
// execFile is used intentionally — it does NOT spawn a shell,
// so arguments cannot be injected. This is the safe alternative to exec().
nodeExecFile(command, args, { timeout: TIMEOUT_MS, maxBuffer: 10 * 1024 * 1024 }, (err, stdout, stderr) => {
resolvePromise({
stdout: stdout?.toString() ?? '',
stderr: stderr?.toString() ?? '',
exitCode: err && 'code' in err ? (err as { code: number }).code : (err ? 1 : 0),
});
});
});
}
}