Phase 9: track slash /skill:name on input hook — SPEC §6.2 #1.

Wire input handler to detect slash skills and upsert into session state using registered skill metadata from before_agent_start cache or loadSkills fallback.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-17 12:28:22 +07:00
parent eb911ab7e3
commit 86c6837351
2 changed files with 58 additions and 3 deletions
+31 -3
View File
@@ -1,7 +1,35 @@
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import type { ExtensionAPI, Skill } from "@earendil-works/pi-coding-agent";
import { detectSlashSkill } from "./detect.js";
import { findRegisteredSkillByName, resolveRegisteredSkills } from "./skills-registry.js";
import { createInitialState, trackSkill } from "./state.js";
export default function skillReinject(pi: ExtensionAPI): void {
pi.on("session_start", () => {
// Phase 0 shell — hooks wired in later phases
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" };
});
}
+27
View File
@@ -0,0 +1,27 @@
import { getAgentDir, loadSkills, type Skill } from "@earendil-works/pi-coding-agent";
/** First match on name collision (SPEC §11). */
export function findRegisteredSkillByName(
skills: readonly Skill[],
name: string,
): Skill | undefined {
return skills.find((skill) => skill.name === name);
}
/** Mirror resourceLoader skill list when cache is empty (e.g. first user input). */
export function loadRegisteredSkills(cwd: string): Skill[] {
return loadSkills({
cwd,
agentDir: getAgentDir(),
skillPaths: [],
includeDefaults: true,
}).skills;
}
/** Prefer live skills from before_agent_start; fall back to loadSkills (SPEC §6.2). */
export function resolveRegisteredSkills(cwd: string, cached: readonly Skill[]): Skill[] {
if (cached.length > 0) {
return [...cached];
}
return loadRegisteredSkills(cwd);
}