From f5eae0765732006cc035587f39f660888923342d Mon Sep 17 00:00:00 2001 From: Eyejoker Date: Mon, 23 Mar 2026 07:18:47 +0900 Subject: [PATCH] fix: use resolved ipc dirs for recovery flow --- src/group-folder.test.ts | 4 +++- src/group-folder.ts | 11 +++++++++-- src/group-queue.test.ts | 7 +++---- src/index.ts | 7 +++++-- src/message-runtime.ts | 15 ++++++++++++--- src/task-scheduler.test.ts | 4 +++- 6 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/group-folder.test.ts b/src/group-folder.test.ts index 9e4bcd5..76be5ba 100644 --- a/src/group-folder.test.ts +++ b/src/group-folder.test.ts @@ -53,7 +53,9 @@ describe('group folder validation', () => { it('throws for unsafe folder names', () => { expect(() => resolveGroupFolderPath('../../etc')).toThrow(); expect(() => resolveGroupIpcPath('/tmp')).toThrow(); - expect(() => resolveTaskRuntimeIpcPath('family-chat', '../../etc')).toThrow(); + expect(() => + resolveTaskRuntimeIpcPath('family-chat', '../../etc'), + ).toThrow(); expect(() => resolveTaskSessionsPath('family-chat', '/tmp')).toThrow(); }); }); diff --git a/src/group-folder.ts b/src/group-folder.ts index 1788c98..52c646d 100644 --- a/src/group-folder.ts +++ b/src/group-folder.ts @@ -29,7 +29,11 @@ function assertValidRuntimeSegment(segment: string, label: string): void { if (!RUNTIME_SEGMENT_PATTERN.test(segment)) { throw new Error(`Invalid ${label} "${segment}"`); } - if (segment.includes('/') || segment.includes('\\') || segment.includes('..')) { + if ( + segment.includes('/') || + segment.includes('\\') || + segment.includes('..') + ) { throw new Error(`Invalid ${label} "${segment}"`); } } @@ -76,7 +80,10 @@ export function resolveTaskRuntimeIpcPath( return ipcPath; } -export function resolveTaskSessionsPath(folder: string, taskId: string): string { +export function resolveTaskSessionsPath( + folder: string, + taskId: string, +): string { assertValidGroupFolder(folder); assertValidRuntimeSegment(taskId, 'task ID'); const sessionsBaseDir = path.resolve(DATA_DIR, 'sessions'); diff --git a/src/group-queue.test.ts b/src/group-queue.test.ts index 3cc7e3a..6201110 100644 --- a/src/group-queue.test.ts +++ b/src/group-queue.test.ts @@ -77,10 +77,9 @@ describe('GroupQueue', () => { await vi.advanceTimersByTimeAsync(10); expect(queue.sendMessage('group1@g.us', '후속 메시지')).toBe(true); - expect(fs.mkdirSync).toHaveBeenCalledWith( - `${ipcDir}/input`, - { recursive: true }, - ); + expect(fs.mkdirSync).toHaveBeenCalledWith(`${ipcDir}/input`, { + recursive: true, + }); expect(fs.writeFileSync).toHaveBeenCalled(); expect(fs.renameSync).toHaveBeenCalled(); diff --git a/src/index.ts b/src/index.ts index 588eabb..0b36845 100644 --- a/src/index.ts +++ b/src/index.ts @@ -39,7 +39,7 @@ import { } from './db.js'; import { composeDashboardContent } from './dashboard-render.js'; import { GroupQueue } from './group-queue.js'; -import { resolveGroupFolderPath } from './group-folder.js'; +import { resolveGroupFolderPath, resolveGroupIpcPath } from './group-folder.js'; import { startIpcWatcher } from './ipc.js'; import { findChannel, formatOutbound } from './router.js'; import { @@ -428,7 +428,10 @@ async function main(): Promise { restartContext, registeredGroups, )) { - queue.enqueueMessageCheck(candidate.chatJid, candidate.groupFolder); + queue.enqueueMessageCheck( + candidate.chatJid, + resolveGroupIpcPath(candidate.groupFolder), + ); logger.info( { chatJid: candidate.chatJid, diff --git a/src/message-runtime.ts b/src/message-runtime.ts index 2969e28..8339632 100644 --- a/src/message-runtime.ts +++ b/src/message-runtime.ts @@ -533,7 +533,10 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): { continue; } - deps.queue.enqueueMessageCheck(chatJid, resolveGroupIpcPath(group.folder)); + deps.queue.enqueueMessageCheck( + chatJid, + resolveGroupIpcPath(group.folder), + ); } } } catch (err) { @@ -555,7 +558,10 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): { { chatJid, group: group.name, workItemId: openWorkItem.id }, 'Recovery: found open work item awaiting delivery', ); - deps.queue.enqueueMessageCheck(chatJid, resolveGroupIpcPath(group.folder)); + deps.queue.enqueueMessageCheck( + chatJid, + resolveGroupIpcPath(group.folder), + ); continue; } @@ -576,7 +582,10 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): { { group: group.name, pendingCount: pending.length }, 'Recovery: found unprocessed messages', ); - deps.queue.enqueueMessageCheck(chatJid, resolveGroupIpcPath(group.folder)); + deps.queue.enqueueMessageCheck( + chatJid, + resolveGroupIpcPath(group.folder), + ); } else if (rawPending.length > 0) { const endSeq = rawPending[rawPending.length - 1].seq; if (endSeq != null) { diff --git a/src/task-scheduler.test.ts b/src/task-scheduler.test.ts index 511d85a..19993a3 100644 --- a/src/task-scheduler.test.ts +++ b/src/task-scheduler.test.ts @@ -10,7 +10,9 @@ const { runAgentProcessMock, writeTasksSnapshotMock } = vi.hoisted(() => ({ vi.mock('./agent-runner.js', async () => { const actual = - await vi.importActual('./agent-runner.js'); + await vi.importActual( + './agent-runner.js', + ); return { ...actual, runAgentProcess: runAgentProcessMock,