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:
+31
-3
@@ -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 {
|
export default function skillReinject(pi: ExtensionAPI): void {
|
||||||
pi.on("session_start", () => {
|
const state = createInitialState();
|
||||||
// Phase 0 shell — hooks wired in later phases
|
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" };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user