Files
sveltejs-ai-tools/scripts/sync-opencode-plugin.ts
2026-04-29 11:34:57 +02:00

114 lines
3.3 KiB
TypeScript

import fs from 'node:fs/promises';
import path from 'node:path';
const OPENCODE_PKG_DIR = './packages/opencode';
const TOOLS_DIR = './tools';
const DOCS_AGENTS_DIR = './documentation/docs/20-instructions/.generated';
/**
* Sync skills from tools/ to opencode package (direct copy)
*/
async function sync_skills() {
const source = path.join(TOOLS_DIR, 'skills');
const dest = path.join(OPENCODE_PKG_DIR, 'skills');
await fs.rm(dest, { recursive: true, force: true });
await fs.cp(source, dest, { recursive: true });
console.log('Synced skills to opencode package');
}
/**
* Sync AGENTS.md from tools/ to opencode package and documentation site
*/
async function sync_agents_md() {
const source = path.join(TOOLS_DIR, 'instructions', 'AGENTS.md');
const opencode_dest = path.join(OPENCODE_PKG_DIR, 'instructions', 'opencode-agents.md');
const docs_dest = path.join(DOCS_AGENTS_DIR, 'agents.md');
await fs.mkdir(path.dirname(opencode_dest), { recursive: true });
await fs.mkdir(DOCS_AGENTS_DIR, { recursive: true });
const content = await fs.readFile(source, 'utf-8');
await fs.writeFile(opencode_dest, content);
await fs.writeFile(docs_dest, content);
console.log('Synced AGENTS.md to opencode package and documentation');
}
interface AgentData {
name: string;
description: string;
prompt: string;
}
/**
* Parse a markdown agent file with frontmatter (name, description) and body (prompt)
*/
function parse_agent_md(content: string, file_path: string): AgentData | null {
const frontmatter_match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
if (!frontmatter_match) {
console.warn(`Skipping ${file_path}: no frontmatter found`);
return null;
}
const frontmatter = frontmatter_match[1] ?? '';
const body = (frontmatter_match[2] ?? '').trim();
const name = frontmatter.match(/^name:\s*(.+)$/m)?.[1]?.trim();
const description = frontmatter.match(/^description:\s*(.+)$/m)?.[1]?.trim();
if (!name || !description) {
console.warn(`Skipping ${file_path}: missing name or description in frontmatter`);
return null;
}
return { name, description, prompt: body };
}
/**
* Generate agents.ts module from tools/agents/*.md files
*/
async function sync_agents() {
const agents_dir = path.join(TOOLS_DIR, 'agents');
const entries = await fs.readdir(agents_dir, { withFileTypes: true });
const md_files = entries.filter((e) => e.isFile() && e.name.endsWith('.md'));
const agents: AgentData[] = [];
for (const file of md_files) {
const file_path = path.join(agents_dir, file.name);
const content = await fs.readFile(file_path, 'utf-8');
const agent = parse_agent_md(content, file_path);
if (agent) {
agents.push(agent);
}
}
const output = [
'// This file is auto-generated by scripts/sync-opencode-plugin.ts',
'// Do not edit manually — edit the markdown files in tools/agents/ instead.',
'',
`export const agents = ${JSON.stringify(
Object.fromEntries(
agents.map((a) => [a.name, { description: a.description, prompt: a.prompt }]),
),
null,
'\t',
)} as const;`,
'',
].join('\n');
const dest = path.join(OPENCODE_PKG_DIR, 'agents.ts');
await fs.writeFile(dest, output);
console.log(`Generated agents.ts with ${agents.length} agent(s)`);
}
await sync_skills();
await sync_agents_md();
await sync_agents();
console.log('OpenCode plugin sync complete');