From 0d274881dde2a11ee7fb7aa00ff56b19c0db3d65 Mon Sep 17 00:00:00 2001 From: GRayHook Date: Wed, 17 Jun 2026 12:31:36 +0700 Subject: [PATCH] =?UTF-8?q?Phase=209:=20persist=20state=20after=20tracked?= =?UTF-8?q?=20skill=20changes=20=E2=80=94=20SPEC=20=C2=A76.1.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Call saveState via appendEntry after slash, skill-block, and read-path tracking so session state survives resume. Co-authored-by: Cursor --- src/index.ts | 64 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/src/index.ts b/src/index.ts index 8808d14..ad2dc7e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,32 +3,41 @@ import { isToolCallEventType, type ExtensionAPI, type ExtensionContext, type Ski 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", - }); -} +import { + createInitialState, + saveState, + trackSkill, + type TrackSkillInput, +} from "./state.js"; export default function skillReinject(pi: ExtensionAPI): void { const state = createInitialState(); let registeredSkills: Skill[] = []; + function persistState(): void { + saveState(pi, state); + } + + function trackSkillAndPersist(input: TrackSkillInput): void { + trackSkill(state, input); + persistState(); + } + + function trackReadSkillPath(path: string, ctx: ExtensionContext): void { + const settings = readSettings(ctx); + const skills = resolveRegisteredSkills(ctx.cwd, registeredSkills); + const matched = matchReadPathToSkillWhenEnabled(path, skills, settings.trackReadPaths); + if (!matched) { + return; + } + trackSkillAndPersist({ + name: matched.name, + filePath: matched.filePath, + baseDir: matched.baseDir, + source: "read", + }); + } + pi.on("before_agent_start", async (event) => { registeredSkills = event.systemPromptOptions.skills ?? registeredSkills; }); @@ -43,7 +52,7 @@ export default function skillReinject(pi: ExtensionAPI): void { const skills = resolveRegisteredSkills(ctx.cwd, registeredSkills); const skill = findRegisteredSkillByName(skills, skillName); if (skill) { - trackSkill(state, { + trackSkillAndPersist({ name: skill.name, filePath: skill.filePath, baseDir: skill.baseDir, @@ -60,9 +69,13 @@ export default function skillReinject(pi: ExtensionAPI): void { return; } - const text = userMessageText(event.message.content); + const blocks = parseSkillBlocksFromText(userMessageText(event.message.content)); + if (blocks.length === 0) { + return; + } + const skills = resolveRegisteredSkills(ctx.cwd, registeredSkills); - for (const block of parseSkillBlocksFromText(text)) { + for (const block of blocks) { const registered = findRegisteredSkillByName(skills, block.name); trackSkill(state, { name: block.name, @@ -71,12 +84,13 @@ export default function skillReinject(pi: ExtensionAPI): void { source: "skill-block", }); } + persistState(); }); pi.on("tool_call", async (event, ctx) => { if (!isToolCallEventType("read", event)) { return; } - trackReadSkillPath(event.input.path, ctx, state, registeredSkills); + trackReadSkillPath(event.input.path, ctx); }); }