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:
+39
-25
@@ -3,32 +3,41 @@ import { isToolCallEventType, type ExtensionAPI, type ExtensionContext, type Ski
|
|||||||
import { detectSlashSkill, matchReadPathToSkillWhenEnabled, parseSkillBlocksFromText, userMessageText } from "./detect.js";
|
import { detectSlashSkill, matchReadPathToSkillWhenEnabled, parseSkillBlocksFromText, userMessageText } from "./detect.js";
|
||||||
import { readSettings } from "./settings.js";
|
import { readSettings } from "./settings.js";
|
||||||
import { findRegisteredSkillByName, resolveRegisteredSkills } from "./skills-registry.js";
|
import { findRegisteredSkillByName, resolveRegisteredSkills } from "./skills-registry.js";
|
||||||
import { createInitialState, trackSkill, type ExtensionState } from "./state.js";
|
import {
|
||||||
|
createInitialState,
|
||||||
function trackReadSkillPath(
|
saveState,
|
||||||
path: string,
|
trackSkill,
|
||||||
ctx: ExtensionContext,
|
type TrackSkillInput,
|
||||||
state: ExtensionState,
|
} from "./state.js";
|
||||||
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 {
|
export default function skillReinject(pi: ExtensionAPI): void {
|
||||||
const state = createInitialState();
|
const state = createInitialState();
|
||||||
let registeredSkills: Skill[] = [];
|
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) => {
|
pi.on("before_agent_start", async (event) => {
|
||||||
registeredSkills = event.systemPromptOptions.skills ?? registeredSkills;
|
registeredSkills = event.systemPromptOptions.skills ?? registeredSkills;
|
||||||
});
|
});
|
||||||
@@ -43,7 +52,7 @@ export default function skillReinject(pi: ExtensionAPI): void {
|
|||||||
const skills = resolveRegisteredSkills(ctx.cwd, registeredSkills);
|
const skills = resolveRegisteredSkills(ctx.cwd, registeredSkills);
|
||||||
const skill = findRegisteredSkillByName(skills, skillName);
|
const skill = findRegisteredSkillByName(skills, skillName);
|
||||||
if (skill) {
|
if (skill) {
|
||||||
trackSkill(state, {
|
trackSkillAndPersist({
|
||||||
name: skill.name,
|
name: skill.name,
|
||||||
filePath: skill.filePath,
|
filePath: skill.filePath,
|
||||||
baseDir: skill.baseDir,
|
baseDir: skill.baseDir,
|
||||||
@@ -60,9 +69,13 @@ export default function skillReinject(pi: ExtensionAPI): void {
|
|||||||
return;
|
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);
|
const skills = resolveRegisteredSkills(ctx.cwd, registeredSkills);
|
||||||
for (const block of parseSkillBlocksFromText(text)) {
|
for (const block of blocks) {
|
||||||
const registered = findRegisteredSkillByName(skills, block.name);
|
const registered = findRegisteredSkillByName(skills, block.name);
|
||||||
trackSkill(state, {
|
trackSkill(state, {
|
||||||
name: block.name,
|
name: block.name,
|
||||||
@@ -71,12 +84,13 @@ export default function skillReinject(pi: ExtensionAPI): void {
|
|||||||
source: "skill-block",
|
source: "skill-block",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
persistState();
|
||||||
});
|
});
|
||||||
|
|
||||||
pi.on("tool_call", async (event, ctx) => {
|
pi.on("tool_call", async (event, ctx) => {
|
||||||
if (!isToolCallEventType("read", event)) {
|
if (!isToolCallEventType("read", event)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
trackReadSkillPath(event.input.path, ctx, state, registeredSkills);
|
trackReadSkillPath(event.input.path, ctx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user