import { dirname } from "node:path"; import { isToolCallEventType, type ExtensionAPI, type ExtensionContext, type Skill } from "@earendil-works/pi-coding-agent"; import { detectSlashSkill, matchReadPathToSkillWhenEnabled, parseSkillBlocksFromText, userMessageText } from "./detect.js"; import { readSettings } from "./settings.js"; import { findRegisteredSkillByName, resolveRegisteredSkills } from "./skills-registry.js"; import { createInitialState, trackSkill, type ExtensionState } from "./state.js"; function trackReadSkillPath( path: string, ctx: ExtensionContext, state: ExtensionState, registeredSkills: Skill[], ): void { const settings = readSettings(ctx); const skills = resolveRegisteredSkills(ctx.cwd, registeredSkills); const matched = matchReadPathToSkillWhenEnabled(path, skills, settings.trackReadPaths); if (!matched) { return; } trackSkill(state, { name: matched.name, filePath: matched.filePath, baseDir: matched.baseDir, source: "read", }); } export default function skillReinject(pi: ExtensionAPI): void { const state = createInitialState(); let registeredSkills: Skill[] = []; pi.on("before_agent_start", async (event) => { registeredSkills = event.systemPromptOptions.skills ?? registeredSkills; }); pi.on("input", async (event, ctx) => { if (event.source === "extension") { return { action: "continue" }; } const skillName = detectSlashSkill(event.text); if (skillName) { const skills = resolveRegisteredSkills(ctx.cwd, registeredSkills); const skill = findRegisteredSkillByName(skills, skillName); if (skill) { trackSkill(state, { name: skill.name, filePath: skill.filePath, baseDir: skill.baseDir, source: "slash", }); } } return { action: "continue" }; }); pi.on("message_end", async (event, ctx) => { if (event.message.role !== "user") { return; } const text = userMessageText(event.message.content); const skills = resolveRegisteredSkills(ctx.cwd, registeredSkills); for (const block of parseSkillBlocksFromText(text)) { const registered = findRegisteredSkillByName(skills, block.name); trackSkill(state, { name: block.name, filePath: registered?.filePath ?? block.location, baseDir: registered?.baseDir ?? dirname(block.location), source: "skill-block", }); } }); pi.on("tool_call", async (event, ctx) => { if (!isToolCallEventType("read", event)) { return; } trackReadSkillPath(event.input.path, ctx, state, registeredSkills); }); }