import { tool } from "@opencode-ai/plugin" import { researchSave } from "../lib/runtime/research" export default tool({ description: "Save a research findings file to the workspace researches/ directory. " + "Creates researches/{topic}/{filename}.md with YAML frontmatter. " + "Each research axis gets its own file (e.g. 'market-data', 'catl-profile'). " + "Content should use structured blocks such as ## Finding: , ## Synthesis: , ## Analysis: , " + "## Implementation Note: , ## Asset Lead: , and ## Gaps.", args: { topic: tool.schema .string() .describe( "Topic key in kebab-case, e.g. 'ev-battery-market' or 'saas-competitive-analysis'. " + "All files for the same presentation share the same topic key.", ), filename: tool.schema .string() .describe( "Axis name without extension, e.g. 'market-data', 'catl-profile', 'tech-trends'. " + "Each parallel research agent uses a unique axis name.", ), content: tool.schema .string() .describe( "Structured markdown findings. Prefer stable cards:\n" + "## Finding: — evidence with Source, URL/path, Quote/Snippet, Supports, Evidence boundary, Strength, Deck use, and optional Display note\n" + "## Synthesis: — interpretation across findings with Basis, Interpretation, So what, Decision implication, Confidence, Alternative reading, Evidence boundary, Deck use, and optional Display note\n" + "## Analysis: — LLM/user analytical frameworks; not external factual proof\n" + "## Implementation Note: — render/data/API contracts; not market evidence\n" + "## Asset Lead: — image/logo/media leads with source, license/attribution status, alt text, and deck use\n" + "## Gaps — topics not found or insufficiently covered", ), sources: tool.schema .array(tool.schema.string()) .optional() .describe("Source URLs or filenames for YAML frontmatter, e.g. ['https://example.com/report', 'data.xlsx']"), }, async execute(args, context) { try { return JSON.stringify(researchSave({ topic: args.topic, filename: args.filename, content: args.content, sources: args.sources, workspaceRoot: context.directory ?? process.cwd(), })) } catch (e: any) { return JSON.stringify({ error: e.message || String(e) }) } }, })