import { kody } from 'kody:runtime' import { getCommandRecord } from './commands-store.ts' export type RunInput = { /** Run a stored command by id. */ commandId?: string /** Ad-hoc ESM module (same shape as MCP execute). Ignored when commandId is set. */ code?: string /** Passed to the module default export. */ params?: Record idempotencyKey?: string } function isPlainObject(value: unknown): value is Record { return Boolean(value) && typeof value === 'object' && !Array.isArray(value) } /** * Minted `run` URLs are sometimes also registered on a GitHub repo via * `webhookUrlApply` so a local machine can read them with `gh api` without * pasting secrets. GitHub then POSTs real hook events at those URLs. Those * payloads must not throw (5xx → retries + Activity noise). * * Catch more than repo-scoped deliveries: installation/meta/org/advisory shapes * often omit top-level `repository` and would otherwise fall through to the * commandId/code throw. */ function isGithubWebhookNoise(input: Record): boolean { if (typeof input.commandId === 'string' && input.commandId.trim()) return false if (typeof input.code === 'string' && input.code.trim()) return false if (typeof input.zen === 'string') return true if ('hook_id' in input || isPlainObject(input.hook)) return true if (isPlainObject(input.installation)) return true if ( 'repositories_added' in input || 'repositories_removed' in input || 'repository_selection' in input ) { return true } if (isPlainObject(input.organization) && isPlainObject(input.sender)) return true if ( isPlainObject(input.security_advisory) || isPlainObject(input.marketplace_purchase) || isPlainObject(input.sponsorship) ) { return true } if (isPlainObject(input.repository)) return true const sender = input.sender if ( isPlainObject(sender) && typeof sender.login === 'string' && typeof input.action === 'string' ) { return true } return false } /** * Run a stored Raycast command or ad-hoc execute code via `kody.execute`. * HTTP callers use the minted `run` webhook; agents can import this export too. * * @param input.commandId - Stored command id * @param input.code - Ad-hoc ESM when not using commandId * @param input.params - Params for the default export * @returns The execute result payload (ok, result, error, logs, …) * * @example * import run from 'kody:@kody/raycast/run' * const out = await run({ * code: `export default async function main() { return { ok: true } }`, * }) */ export default async function run(input: RunInput = {}) { const record = input as Record if (isGithubWebhookNoise(record)) { return { ok: true, ignored: true, reason: 'github-webhook-event', commandId: null, title: null, } } const commandId = typeof input.commandId === 'string' ? input.commandId.trim() : '' let code = typeof input.code === 'string' ? input.code : '' let title: string | null = null if (commandId) { const command = await getCommandRecord(commandId) if (!command) { throw new Error(`Unknown Raycast command id: ${commandId}`) } code = command.code title = command.title } if (!code.trim()) { throw new Error('Provide commandId or code (ESM with export default).') } const executed = await kody.execute({ code, params: input.params ?? {}, idempotencyKey: input.idempotencyKey, }) return { commandId: commandId || null, title, ...executed, } }