Public Access
1d87be7d5e
Branch Policy Check / Verify merge target (pull_request) Has been cancelled
- 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>
56 lines
1.9 KiB
TypeScript
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),
|
|
});
|
|
});
|
|
});
|
|
}
|
|
}
|