edc01d1079
Match read tool paths against registered skills when trackReadPaths is enabled and upsert with source read. Co-authored-by: Cursor <cursoragent@cursor.com>
83 lines
2.5 KiB
TypeScript
83 lines
2.5 KiB
TypeScript
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);
|
|
});
|
|
}
|