UNPKG

@meldscience/meld

Version:

pipeable one-shot prompt scripting toolkit

191 lines (158 loc) 5.17 kB
import { spawn } from 'child_process'; import { join } from 'path'; import { writeFileSync, unlinkSync, existsSync } from 'fs'; import { beforeEach, afterEach, describe, it, expect } from 'vitest'; import { vi } from 'vitest'; const CLI_PATH = join(__dirname, '../../bin/oneshotcat.ts'); const TEST_PROMPT = 'test-prompt.meld.md'; const TEST_OUTPUT = 'test-output.md'; const TEST_EXPANDED = 'test-expanded.md'; const TEST_SYSTEM = 'test-system.md'; const TEST_VARIATIONS_JSON = 'test-variations.json'; const TEST_VARIATIONS_YAML = 'test-variations.yaml'; // Mock environment variables process.env.ANTHROPIC_API_KEY = 'test-anthropic-key'; process.env.OPENAI_API_KEY = 'test-openai-key'; describe('oneshotcat CLI', () => { beforeEach(() => { // Create test files writeFileSync(TEST_PROMPT, `# Test Prompt Here's what's in my directory: @cmd[ls -la] And here's my Node.js version: @cmd[node --version]`); writeFileSync(TEST_SYSTEM, 'You are a helpful assistant.'); writeFileSync(TEST_VARIATIONS_JSON, JSON.stringify(['Perspective 1', 'Perspective 2'])); writeFileSync(TEST_VARIATIONS_YAML, 'architect: "Review as architect"\ndeveloper: "Review as developer"'); }); afterEach(() => { // Cleanup test files [ TEST_PROMPT, TEST_OUTPUT, TEST_EXPANDED, TEST_SYSTEM, TEST_VARIATIONS_JSON, TEST_VARIATIONS_YAML ].forEach(file => { if (existsSync(file)) unlinkSync(file); }); }); it('should process a prompt script and send to Claude', (done) => { const oneshotcat = spawn('ts-node', [CLI_PATH, 'claude-3', TEST_PROMPT]); let output = ''; oneshotcat.stdout.on('data', (data) => { output += data.toString(); }); oneshotcat.stderr.on('data', (data) => { console.error(`stderr: ${data}`); }); oneshotcat.on('close', (code) => { expect(code).toBe(0); expect(output).toContain('🔄 Processing prompt script'); expect(output).toContain('🤖 Sending prompt to claude-3'); done(); }); }); it('should support saving expanded prompt', (done) => { const oneshotcat = spawn('ts-node', [ CLI_PATH, 'claude-3', TEST_PROMPT, '--meld-outfile', TEST_EXPANDED ]); let output = ''; oneshotcat.stdout.on('data', (data) => { output += data.toString(); }); oneshotcat.on('close', (code) => { expect(code).toBe(0); expect(existsSync(TEST_EXPANDED)).toBe(true); expect(output).toContain('📝 Expanded prompt written to'); done(); }); }); it('should support saving final response', (done) => { const oneshotcat = spawn('ts-node', [ CLI_PATH, 'claude-3', TEST_PROMPT, '-o', TEST_OUTPUT ]); let output = ''; oneshotcat.stdout.on('data', (data) => { output += data.toString(); }); oneshotcat.on('close', (code) => { expect(code).toBe(0); expect(existsSync(TEST_OUTPUT)).toBe(true); expect(output).toContain('📝 Response written to'); done(); }); }); it('should support system prompts and variations', (done) => { const oneshotcat = spawn('ts-node', [ CLI_PATH, 'claude-3', TEST_PROMPT, '--system-file', TEST_SYSTEM, '--variations-file', TEST_VARIATIONS_YAML ]); let output = ''; oneshotcat.stdout.on('data', (data) => { output += data.toString(); }); oneshotcat.on('close', (code) => { expect(code).toBe(0); expect(output).toContain('🔄 Processing prompt script'); expect(output).toContain('🤖 Sending prompt to claude-3'); done(); }); }); it('should handle command execution errors gracefully', (done) => { writeFileSync(TEST_PROMPT, `# Test\n\n@cmd[invalid-command]`); const oneshotcat = spawn('ts-node', [CLI_PATH, 'claude-3', TEST_PROMPT]); let stderr = ''; oneshotcat.stderr.on('data', (data) => { stderr += data.toString(); }); oneshotcat.on('close', (code) => { expect(code).toBe(1); expect(stderr).toContain('Error'); done(); }); }); it('should handle missing prompt file error', (done) => { const oneshotcat = spawn('ts-node', [CLI_PATH, 'claude-3', 'nonexistent.md']); let stderr = ''; oneshotcat.stderr.on('data', (data) => { stderr += data.toString(); }); oneshotcat.on('close', (code) => { expect(code).toBe(1); expect(stderr).toContain('ENOENT'); done(); }); }); it('should handle missing API key error', (done) => { // Temporarily unset API key const oldKey = process.env.ANTHROPIC_API_KEY; delete process.env.ANTHROPIC_API_KEY; const oneshotcat = spawn('ts-node', [CLI_PATH, 'claude-3', TEST_PROMPT]); let stderr = ''; oneshotcat.stderr.on('data', (data) => { stderr += data.toString(); }); oneshotcat.on('close', (code) => { // Restore API key process.env.ANTHROPIC_API_KEY = oldKey; expect(code).toBe(1); expect(stderr).toContain('Anthropic API key is required'); done(); }); }); });