fix: make sessionExists() async with SDK verification on SQLite

sessionExists() previously returned unconditional true on SQLite,
preventing ralph-loop orphaned-session cleanup from triggering.
Now uses sdkClient.session.messages() to verify session actually
exists. Callers updated to await the async result.

Addresses Cubic review feedback on PR #1837.
This commit is contained in:
YeonGyu-Kim
2026-02-15 19:23:05 +09:00
parent 3bbe0cbb1d
commit 11586445cf
4 changed files with 16 additions and 8 deletions

View File

@@ -122,7 +122,7 @@ export function createSessionHooks(args: {
? safeHook("ralph-loop", () =>
createRalphLoopHook(ctx, {
config: pluginConfig.ralph_loop,
checkSessionExists: async (sessionId) => sessionExists(sessionId),
checkSessionExists: async (sessionId) => await sessionExists(sessionId),
}))
: null

View File

@@ -78,15 +78,15 @@ describe("session-manager storage", () => {
expect(result).toBe(sessionPath)
})
test("sessionExists returns false for non-existent session", () => {
test("sessionExists returns false for non-existent session", async () => {
// when
const exists = sessionExists("ses_nonexistent")
const exists = await sessionExists("ses_nonexistent")
// then
expect(exists).toBe(false)
})
test("sessionExists returns true for existing session", () => {
test("sessionExists returns true for existing session", async () => {
// given
const sessionID = "ses_exists"
const sessionPath = join(TEST_MESSAGE_STORAGE, sessionID)
@@ -94,7 +94,7 @@ describe("session-manager storage", () => {
writeFileSync(join(sessionPath, "msg_001.json"), JSON.stringify({ id: "msg_001" }))
// when
const exists = sessionExists(sessionID)
const exists = await sessionExists(sessionID)
// then
expect(exists).toBe(true)

View File

@@ -138,8 +138,16 @@ export function getMessageDir(sessionID: string): string | null {
return null
}
export function sessionExists(sessionID: string): boolean {
if (isSqliteBackend()) return true
export async function sessionExists(sessionID: string): Promise<boolean> {
if (isSqliteBackend() && sdkClient) {
try {
const response = await sdkClient.session.messages({ path: { id: sessionID } })
const messages = response.data as unknown[] | undefined
return Array.isArray(messages) && messages.length > 0
} catch {
return false
}
}
return getMessageDir(sessionID) !== null
}

View File

@@ -70,7 +70,7 @@ export function createSessionManagerTools(ctx: PluginInput): Record<string, Tool
},
execute: async (args: SessionReadArgs, _context) => {
try {
if (!sessionExists(args.session_id)) {
if (!(await sessionExists(args.session_id))) {
return `Session not found: ${args.session_id}`
}