Phase 9: persist state after tracked skill changes — SPEC §6.1.

Call saveState via appendEntry after slash, skill-block, and read-path tracking so session state survives resume.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-17 12:31:36 +07:00
parent edc01d1079
commit 0d274881dd
+39 -25
View File
@@ -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);
});
}