import { describe, it, expect } from "vitest"; import { manualExportProvider } from "../../src/providers/manual-export.js"; // --- Basic structure --- describe("basic structure", () => { it("exports a provider with send method", () => { expect(manualExportProvider).toBeDefined(); expect(typeof manualExportProvider.send).toBe("function"); }); it("returns { content: string } shape on success", async () => { const result = await manualExportProvider.send( { prompt: "test prompt" }, {}, ); expect(result).toHaveProperty("content"); expect(typeof result.content).toBe("string"); }); it("returns non-empty content for valid prompt", async () => { const result = await manualExportProvider.send( { prompt: "test prompt" }, {}, ); expect(result.content.length).toBeGreaterThan(0); }); it("is deterministic — same input produces same output", async () => { const input = { prompt: "deterministic test", input: { question: "hi" } }; const r1 = await manualExportProvider.send(input, {}); const r2 = await manualExportProvider.send(input, {}); expect(r1.content).toBe(r2.content); }); it("does not modify the request object", async () => { const req = { prompt: "test", input: { question: "hi" } }; const original = JSON.stringify(req); await manualExportProvider.send(req, {}); expect(JSON.stringify(req)).toBe(original); }); it("does not modify the config object", async () => { const config = { openaiApiKey: "sk-test" }; await manualExportProvider.send({ prompt: "test" }, config); expect(config.openaiApiKey).toBe("sk-test"); }); }); // --- Copy-ready structure --- describe("copy-ready structure", () => { it("includes MANUAL EXPORT header with tool name", async () => { const result = await manualExportProvider.send( { prompt: "test", input: { question: "hi" } }, {}, ); expect(result.content).toContain("MANUAL EXPORT"); }); it("includes COPY box with top-left corner delimiters (┌)", async () => { const result = await manualExportProvider.send( { prompt: "test", input: { question: "hi" } }, {}, ); expect(result.content).toContain("┌"); }); it("includes COPY box with bottom-right corner delimiters (┐ and ┘)", async () => { const result = await manualExportProvider.send( { prompt: "test", input: { question: "hi" } }, {}, ); expect(result.content).toContain("┐"); expect(result.content).toContain("└"); expect(result.content).toContain("┘"); }); it("includes instructions section with numbered steps", async () => { const result = await manualExportProvider.send( { prompt: "test", input: { question: "hi" } }, {}, ); expect(result.content).toContain("📝 INSTRUCTIONS:"); expect(result.content).toContain("1."); expect(result.content).toContain("2."); expect(result.content).toContain("3."); }); it("includes metadata section", async () => { const result = await manualExportProvider.send( { prompt: "test", input: { question: "hi" } }, {}, ); expect(result.content).toContain("📊 METADATA:"); }); it("includes provider info in metadata", async () => { const result = await manualExportProvider.send( { prompt: "test", input: { question: "hi" } }, {}, ); expect(result.content).toContain("Manual Export"); }); it("includes tool name in metadata", async () => { const result = await manualExportProvider.send( { prompt: "test", input: { question: "hi" } }, {}, ); expect(result.content).toMatch(/Tool: \w+/); }); it("includes prompt length in metadata with formatted thousands separator", async () => { const longPrompt = "x".repeat(12345); const result = await manualExportProvider.send( { prompt: longPrompt, input: { question: "hi" } }, {}, ); expect(result.content).toContain("Prompt Length:"); expect(result.content).toContain("12,345 characters"); }); it("includes advisory footer", async () => { const result = await manualExportProvider.send( { prompt: "test", input: { question: "hi" } }, {}, ); expect(result.content).toContain("advisory output only"); }); it("wraps each line of prompt in box with │ delimiter", async () => { const multiLine = "line one\nline two\nline three"; const result = await manualExportProvider.send( { prompt: multiLine, input: { question: "hi" } }, {}, ); expect(result.content).toContain("│ line one"); expect(result.content).toContain("│ line two"); expect(result.content).toContain("│ line three"); }); }); // --- Per-tool detection --- describe("tool name detection", () => { it("detects debug_issue when input has logs", async () => { const result = await manualExportProvider.send( { prompt: "test", input: { logs: "Error: boom" } }, {}, ); expect(result.content).toContain("Tool: debug_issue"); }); it("detects review_code when input has relevantFiles with paths", async () => { const result = await manualExportProvider.send( { prompt: "test", input: { relevantFiles: [{ path: "src/foo.js" }] } }, {}, ); expect(result.content).toContain("Tool: review_code"); }); it("detects architecture_review when context includes 'architecture'", async () => { const result = await manualExportProvider.send( { prompt: "test", input: { context: "Architecture decision here" } }, {}, ); expect(result.content).toContain("Tool: architecture_review"); }); it("detects review_plan when input has projectSummary", async () => { const result = await manualExportProvider.send( { prompt: "test", input: { projectSummary: "Project scope" } }, {}, ); expect(result.content).toContain("Tool: review_plan"); }); it("defaults to ask_chatgpt when no hints available", async () => { const result = await manualExportProvider.send( { prompt: "test", input: { question: "hi" } }, {}, ); expect(result.content).toContain("Tool: ask_chatgpt"); }); it("uses 'unknown' when input is absent in request", async () => { const result = await manualExportProvider.send( { prompt: "test" }, {}, ); expect(result.content).toContain("Tool: unknown"); }); }); // --- Long prompt handling --- describe("long prompt handling", () => { it("adds warning banner for prompts over 30k characters", async () => { const longPrompt = "x".repeat(31_000); const result = await manualExportProvider.send({ prompt: longPrompt, input: {} }, {}); expect(result.content).toContain("⚠️ NOTE"); }); it("does NOT add warning for prompts under 30k characters", async () => { const validPrompt = "x".repeat(29_999); const result = await manualExportProvider.send({ prompt: validPrompt, input: {} }, {}); expect(result.content).not.toContain("⚠️ NOTE"); }); it("still returns valid output for very long prompts (>50k chars)", async () => { const veryLongPrompt = "x".repeat(50_000); const result = await manualExportProvider.send({ prompt: veryLongPrompt, input: {} }, {}); expect(result.content).toContain("MANUAL EXPORT"); expect(result.content.length).toBeGreaterThan(0); }); it("shows correct character count in metadata for long prompts", async () => { const length = 50_000; const result = await manualExportProvider.send({ prompt: "x".repeat(length), input: {} }, {}); expect(result.content).toContain(`${length.toLocaleString()} characters`); }); it("handles prompts at exactly the 30k boundary", async () => { const exactPrompt = "x".repeat(30_000); const result = await manualExportProvider.send({ prompt: exactPrompt, input: {} }, {}); expect(result.content).not.toContain("⚠️ NOTE"); // not over 30k, exactly at it }); }); // --- Unicode and special characters --- describe("unicode and special characters", () => { it("preserves Japanese characters in prompt", async () => { const result = await manualExportProvider.send( { prompt: "こんにちは世界", input: {} }, {}, ); expect(result.content).toContain("こんにちは世界"); }); it("preserves emoji in prompt", async () => { const result = await manualExportProvider.send( { prompt: "🚀 Launch plan 🎯", input: {} }, {}, ); expect(result.content).toContain("🚀"); expect(result.content).toContain("🎯"); }); it("preserves markdown code blocks in prompt", async () => { const codePrompt = "```js\nconst x = 1;\n```"; const result = await manualExportProvider.send( { prompt: codePrompt, input: {} }, {}, ); expect(result.content).toContain("```js"); expect(result.content).toContain("const x = 1;"); }); it("preserves JSON in prompt", async () => { const jsonPrompt = '{"key": "value", "nested": {"a": 1}}'; const result = await manualExportProvider.send( { prompt: jsonPrompt, input: {} }, {}, ); expect(result.content).toContain('"key"'); expect(result.content).toContain('"value"'); }); it("preserves special HTML-like characters", async () => { const htmlPrompt = ''; const result = await manualExportProvider.send( { prompt: htmlPrompt, input: {} }, {}, ); expect(result.content).toContain('