Merge pull request #4203 from code-yeongyu/fix/continuation-prompt-dispatch-20260520051014
fix(plugin): dispatch synthetic idle hooks
This commit is contained in:
@@ -37,10 +37,6 @@ export function saveInjectedRules(
|
||||
sessionID: string,
|
||||
data: { contentHashes: Set<string>; realPaths: Set<string> }
|
||||
): void {
|
||||
if (!existsSync(RULES_INJECTOR_STORAGE)) {
|
||||
mkdirSync(RULES_INJECTOR_STORAGE, { recursive: true });
|
||||
}
|
||||
|
||||
const storageData: InjectedRulesData = {
|
||||
sessionID,
|
||||
injectedHashes: [...data.contentHashes],
|
||||
@@ -48,7 +44,16 @@ export function saveInjectedRules(
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
|
||||
writeFileSync(getStoragePath(sessionID), JSON.stringify(storageData, null, 2));
|
||||
mkdirSync(RULES_INJECTOR_STORAGE, { recursive: true });
|
||||
try {
|
||||
writeFileSync(getStoragePath(sessionID), JSON.stringify(storageData, null, 2));
|
||||
} catch (error) {
|
||||
if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
|
||||
throw error;
|
||||
}
|
||||
mkdirSync(RULES_INJECTOR_STORAGE, { recursive: true });
|
||||
writeFileSync(getStoragePath(sessionID), JSON.stringify(storageData, null, 2));
|
||||
}
|
||||
}
|
||||
|
||||
export function clearInjectedRules(sessionID: string): void {
|
||||
|
||||
@@ -208,6 +208,55 @@ describe("createEventHandler - idle deduplication", () => {
|
||||
expect(onEvent.mock.calls[0]?.[0]).toEqual(idleEvent.event)
|
||||
})
|
||||
|
||||
it("#given tmux integration enabled #when session.status reports idle #then synthetic idle forwards to tmuxSessionManager.onEvent", async () => {
|
||||
//#given
|
||||
const onEvent = mock<(event: EventInput["event"]) => void>(() => {})
|
||||
const eventHandler = createEventHandler({
|
||||
ctx: asEventHandlerContext({
|
||||
directory: "/tmp",
|
||||
client: {
|
||||
session: {},
|
||||
},
|
||||
}),
|
||||
pluginConfig: asPluginConfig({
|
||||
tmux: { enabled: true },
|
||||
}),
|
||||
firstMessageVariantGate: {
|
||||
markSessionCreated: () => {},
|
||||
clear: () => {},
|
||||
},
|
||||
managers: createEventHandlerManagers({
|
||||
tmuxSessionManager: {
|
||||
onEvent,
|
||||
onSessionCreated: async () => {},
|
||||
onSessionDeleted: async () => {},
|
||||
},
|
||||
}),
|
||||
hooks: createEventHandlerHooks({}),
|
||||
})
|
||||
|
||||
//#when
|
||||
await eventHandler(asEventHandlerInput({
|
||||
event: {
|
||||
type: "session.status",
|
||||
properties: {
|
||||
sessionID: "ses_tmux_synthetic_idle",
|
||||
status: { type: "idle" },
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
//#then
|
||||
expect(onEvent).toHaveBeenCalledTimes(1)
|
||||
expect(onEvent.mock.calls[0]?.[0]).toEqual({
|
||||
type: "session.idle",
|
||||
properties: {
|
||||
sessionID: "ses_tmux_synthetic_idle",
|
||||
synthetic: true,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it("#given a readiness retry is pending #when session.idle arrives through the plugin handler #then tmux retry spawns the pane", async () => {
|
||||
//#given
|
||||
const sessionStatusData: Record<string, { type: string }> = {}
|
||||
|
||||
+10
-4
@@ -394,6 +394,12 @@ export function createEventHandler(args: {
|
||||
return hooks.sessionRecovery.handleInterruptedToolResultsOnIdle(sessionID);
|
||||
};
|
||||
|
||||
const dispatchIdleOnlyHooks = async (input: EventInput): Promise<void> => {
|
||||
managers.tmuxSessionManager?.onEvent?.(input.event);
|
||||
await runEventHookSafely("teamIdleWakeHint", teamIdleWakeHint, input);
|
||||
await runEventHookSafely("teamMemberStatusHandler", teamMemberStatusHandler, input);
|
||||
};
|
||||
|
||||
const getFallbackContinuationKeys = (fallbackContext?: FallbackContinuationContext): FallbackContinuationDedupeKeys => {
|
||||
const agentKey = fallbackContext?.agentName
|
||||
? getAgentConfigKey(fallbackContext.agentName).trim().toLowerCase()
|
||||
@@ -628,7 +634,8 @@ export function createEventHandler(args: {
|
||||
if (!shouldDispatchIdleEvent(sessionID, now)) {
|
||||
return;
|
||||
}
|
||||
await dispatchToHooks(syntheticIdle as EventInput);
|
||||
const syntheticIdleInput = syntheticIdle as EventInput;
|
||||
await dispatchToHooks(syntheticIdleInput);
|
||||
if (pluginConfig.openclaw) {
|
||||
await dispatchOpenClawEvent({
|
||||
config: pluginConfig.openclaw,
|
||||
@@ -640,6 +647,7 @@ export function createEventHandler(args: {
|
||||
},
|
||||
});
|
||||
}
|
||||
await dispatchIdleOnlyHooks(syntheticIdleInput);
|
||||
}
|
||||
|
||||
const { event } = input;
|
||||
@@ -761,9 +769,7 @@ export function createEventHandler(args: {
|
||||
}
|
||||
|
||||
if (event.type === "session.idle") {
|
||||
managers.tmuxSessionManager?.onEvent?.(event);
|
||||
await runEventHookSafely("teamIdleWakeHint", teamIdleWakeHint, input);
|
||||
await runEventHookSafely("teamMemberStatusHandler", teamMemberStatusHandler, input);
|
||||
await dispatchIdleOnlyHooks(input);
|
||||
}
|
||||
|
||||
if (event.type === "message.updated") {
|
||||
|
||||
Reference in New Issue
Block a user