import { z } from 'zod'; import { config } from '../../config.js'; import { processManager } from '../../lib/processManager.js'; import { runCommand } from '../../lib/runCommand.js'; import { errorResult, jsonResult, toErrorMessage } from '../shared.js'; import { ARTISAN_ALLOWED, ARTISAN_BACKGROUND, ARTISAN_DESTRUCTIVE, isAllowedArtisanCommand, } from './artisanAllowList.js'; import { requireLaravel } from './requireLaravel.js'; export function registerArtisanTool(server) { server.registerTool('artisan', { title: 'Run Artisan Command', description: 'Run a whitelisted `php artisan` subcommand in the detected Laravel project and return stdout/stderr. ' + `Allowed commands: ${ARTISAN_ALLOWED.join(', ')}. ` + 'Destructive commands (migrate:fresh, migrate:refresh, migrate:reset, db:wipe) require confirm: true. ' + 'Long-running commands (queue:work, queue:listen) are started as tracked background processes.', inputSchema: { command: z .string() .min(1) .describe('Artisan subcommand, e.g. "make:controller" or "migrate".'), args: z .array(z.string()) .optional() .default([]) .describe('Arguments forwarded after the subcommand, e.g. ["PostController", "--api"].'), confirm: z .boolean() .optional() .describe('Required as true for destructive commands (migrate:fresh/refresh/reset, db:wipe).'), }, }, async ({ command, args, confirm }) => { try { if (!isAllowedArtisanCommand(command)) { return errorResult(`Artisan command "${command}" is not on the allow-list. Allowed: ${ARTISAN_ALLOWED.join(', ')}.`); } if (ARTISAN_DESTRUCTIVE.has(command) && confirm !== true) { return errorResult(`Artisan command "${command}" is destructive and requires confirm: true.`); } const laravel = requireLaravel(); const phpArgs = ['artisan', command, ...(args ?? [])]; if (ARTISAN_BACKGROUND.has(command)) { const info = processManager.start({ label: `artisan:${command}`, command: 'php', args: phpArgs, cwd: laravel.root, }); return jsonResult({ background: true, processId: info.id, artisanCommand: command, artisanArgs: args ?? [], pid: info.pid, status: info.status, startedAt: info.startedAt, cwd: info.cwd, hint: 'Use get_process_logs / stop_process to manage this background artisan process.', }); } const result = await runCommand('php', phpArgs, { cwd: laravel.root, timeoutMs: config.scaffoldCommandTimeoutMs, }); return jsonResult({ background: false, artisanCommand: command, artisanArgs: args ?? [], exitCode: result.exitCode, timedOut: result.timedOut, failed: result.failed, output: result.output, cwd: result.cwd, }); } catch (error) { return errorResult(toErrorMessage(error)); } }); } //# sourceMappingURL=artisan.js.map