opencode and native tasks

This commit is contained in:
2026-02-16 20:20:09 +00:00
parent 9ab0940ca4
commit dca4743e8b
3 changed files with 31 additions and 4 deletions
+29 -2
View File
@@ -2,7 +2,8 @@ import type { ServerWebSocket } from 'bun';
import { mkdir, rename } from 'node:fs/promises';
import { join } from 'node:path';
import type { ClientMessage, ServerMessage, ImageData, TaskInfo } from '@@/api/chat-types';
import { getTmpAttachmentsDir, getAttachmentsDir } from '@@/data-path';
import { getTmpAttachmentsDir, getAttachmentsDir, getNativeSkillsDir, getGlobalSkillsDir, getUserSkillsDir } from '@@/data-path';
import { readSkillDirs, parseFrontmatter } from '@@/api/skills/skills';
import { createTaskLog, appendToLog, finalizeLog } from '@@/api/task-logger';
const OPENCODE_PORT = process.env.OPENCODE_PORT ?? '10006';
@@ -303,6 +304,29 @@ function handleSSEEvent(ws: ServerWebSocket<WSData>, event: string, data: any) {
}
}
async function buildSkillsPrompt(email: string): Promise<string> {
const nativeSkills = await readSkillDirs(getNativeSkillsDir());
const globalSkills = await readSkillDirs(getGlobalSkillsDir());
const userSkills = await readSkillDirs(getUserSkillsDir(email));
const merged = new Map(nativeSkills);
for (const [name, path] of globalSkills) merged.set(name, path);
for (const [name, path] of userSkills) merged.set(name, path);
if (merged.size === 0) return '';
const lines = await Promise.all(
Array.from(merged.entries()).map(async ([dirName, filePath]) => {
const raw = await Bun.file(filePath).text();
const { frontmatter } = parseFrontmatter(raw);
const name = frontmatter.name || dirName;
return `- ${name}: ${frontmatter.description} (read ${filePath} for full instructions)`;
}),
);
return `\n\nYou have access to the following skills. When a user's request matches a skill, read its SKILL.md file for detailed instructions before proceeding.\n\nAvailable skills:\n${lines.join('\n')}`;
}
type HandleChatParams = {
ws: ServerWebSocket<WSData>;
prompt: string;
@@ -368,6 +392,9 @@ async function handleChat({ ws, prompt, sessionId, model, attachmentIds, images,
}
}
const skillsAppend = await buildSkillsPrompt(ws.data.email);
const fullPrompt = skillsAppend ? `${skillsAppend}\n\n${prompt}` : prompt;
const parts: Record<string, unknown>[] = [];
if (images?.length) {
for (const img of images) {
@@ -378,7 +405,7 @@ async function handleChat({ ws, prompt, sessionId, model, attachmentIds, images,
});
}
}
parts.push({ type: 'text', text: prompt });
parts.push({ type: 'text', text: fullPrompt });
const promptBody: Record<string, unknown> = { parts };
if (modelSelection.modelId) {