import { z } from 'zod'; import { config } from '../../config.js'; import { runCommand } from '../../lib/runCommand.js'; import { errorResult, jsonResult, toErrorMessage } from '../shared.js'; import { requireLaravel } from './requireLaravel.js'; /** * Heuristic: treat an expression as a write if it contains common Eloquent / * DB mutation method names. Read-only inspections (find, get, all, count, * toArray, …) do not require confirm. */ const WRITE_PATTERN = /\b(save|create|update|delete|destroy|forceDelete|insert|upsert|truncate|updateOrCreate|firstOrCreate|push|attach|detach|sync|restore|increment|decrement)\s*\(/i; export function registerTinkerEvalTool(server) { server.registerTool('laravel_tinker_eval', { title: 'Laravel Tinker Eval', description: 'Evaluate a short PHP expression/snippet via `php artisan tinker --execute` for quick data/model inspection. ' + 'Read-only by convention. Expressions that appear to mutate data (save/create/update/delete/…) require confirm: true.', inputSchema: { code: z .string() .min(1) .max(4000) .describe('PHP expression to evaluate, e.g. "\\\\App\\\\Models\\\\User::count()" or "config(\'app.name\')".'), confirm: z .boolean() .optional() .describe('Required as true when the expression appears to perform a write/mutation.'), }, }, async ({ code, confirm }) => { try { if (WRITE_PATTERN.test(code) && confirm !== true) { return errorResult('This expression looks like it mutates data (save/create/update/delete/…). ' + 'Re-run with confirm: true if you intentionally want to write.'); } const laravel = requireLaravel(); // --execute runs the snippet non-interactively and prints the result. const result = await runCommand('php', ['artisan', 'tinker', `--execute=${code}`], { cwd: laravel.root, timeoutMs: config.defaultCommandTimeoutMs, }); return jsonResult({ code, writeDetected: WRITE_PATTERN.test(code), ...result }); } catch (error) { return errorResult(toErrorMessage(error)); } }); } //# sourceMappingURL=tinkerEval.js.map