From 446a18643147ce1d3e0a1abbc92e62dfb7b95d96 Mon Sep 17 00:00:00 2001 From: GRayHook Date: Wed, 17 Jun 2026 11:58:15 +0700 Subject: [PATCH] =?UTF-8?q?Phase=207:=20add=20sendImmediateReinjectIdle=20?= =?UTF-8?q?=E2=80=94=20first=20skill=20triggers=20turn,=20rest=20as=20foll?= =?UTF-8?q?owUp.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extracts buildReinjectBlocks for shared expand logic; immediate delivery when the agent is idle uses sendUserMessage without deliverAs for the first block only. Co-authored-by: Cursor --- src/reinject.ts | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/reinject.ts b/src/reinject.ts index 67761eb..fdec78a 100644 --- a/src/reinject.ts +++ b/src/reinject.ts @@ -1,5 +1,6 @@ import type { BeforeAgentStartEventResult, + ExtensionAPI, ExtensionContext, SessionCompactEvent, Skill, @@ -59,16 +60,16 @@ export function enqueueDeferredReinjectFromCompact( ); } -/** Combined skill-block user text for pending names in queue order (SPEC §5.3). */ -export function buildDeferredReinjectContent( - pendingNames: readonly string[], +/** Expanded skill-block messages in queue order (SPEC §5.3). */ +export function buildReinjectBlocks( + skillNames: readonly string[], state: ExtensionState, settings: SkillReinjectSettings, registeredSkills: readonly Pick[], -): string { +): string[] { const registeredByName = new Map(registeredSkills.map((skill) => [skill.name, skill])); const blocks: string[] = []; - for (const name of pendingNames) { + for (const name of skillNames) { const tracked = state.skills.find((skill) => skill.name === name); const registered = registeredByName.get(name); if (!tracked || !registered) { @@ -85,7 +86,31 @@ export function buildDeferredReinjectContent( ), ); } - return blocks.join("\n\n"); + return blocks; +} + +/** Combined skill-block user text for pending names in queue order (SPEC §5.3). */ +export function buildDeferredReinjectContent( + pendingNames: readonly string[], + state: ExtensionState, + settings: SkillReinjectSettings, + registeredSkills: readonly Pick[], +): string { + return buildReinjectBlocks(pendingNames, state, settings, registeredSkills).join("\n\n"); +} + +/** Immediate path when agent is idle: first block triggers turn, rest queue as followUp (SPEC §6.5.2). */ +export function sendImmediateReinjectIdle( + pi: ExtensionAPI, + skillNames: readonly string[], + state: ExtensionState, + settings: SkillReinjectSettings, + registeredSkills: readonly Pick[], +): void { + const blocks = buildReinjectBlocks(skillNames, state, settings, registeredSkills); + blocks.forEach((block, index) => { + pi.sendUserMessage(block, index === 0 ? undefined : { deliverAs: "followUp" }); + }); } /**