fix: use resolved ipc dirs for recovery flow
This commit is contained in:
@@ -53,7 +53,9 @@ describe('group folder validation', () => {
|
|||||||
it('throws for unsafe folder names', () => {
|
it('throws for unsafe folder names', () => {
|
||||||
expect(() => resolveGroupFolderPath('../../etc')).toThrow();
|
expect(() => resolveGroupFolderPath('../../etc')).toThrow();
|
||||||
expect(() => resolveGroupIpcPath('/tmp')).toThrow();
|
expect(() => resolveGroupIpcPath('/tmp')).toThrow();
|
||||||
expect(() => resolveTaskRuntimeIpcPath('family-chat', '../../etc')).toThrow();
|
expect(() =>
|
||||||
|
resolveTaskRuntimeIpcPath('family-chat', '../../etc'),
|
||||||
|
).toThrow();
|
||||||
expect(() => resolveTaskSessionsPath('family-chat', '/tmp')).toThrow();
|
expect(() => resolveTaskSessionsPath('family-chat', '/tmp')).toThrow();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -29,7 +29,11 @@ function assertValidRuntimeSegment(segment: string, label: string): void {
|
|||||||
if (!RUNTIME_SEGMENT_PATTERN.test(segment)) {
|
if (!RUNTIME_SEGMENT_PATTERN.test(segment)) {
|
||||||
throw new Error(`Invalid ${label} "${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}"`);
|
throw new Error(`Invalid ${label} "${segment}"`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,7 +80,10 @@ export function resolveTaskRuntimeIpcPath(
|
|||||||
return ipcPath;
|
return ipcPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveTaskSessionsPath(folder: string, taskId: string): string {
|
export function resolveTaskSessionsPath(
|
||||||
|
folder: string,
|
||||||
|
taskId: string,
|
||||||
|
): string {
|
||||||
assertValidGroupFolder(folder);
|
assertValidGroupFolder(folder);
|
||||||
assertValidRuntimeSegment(taskId, 'task ID');
|
assertValidRuntimeSegment(taskId, 'task ID');
|
||||||
const sessionsBaseDir = path.resolve(DATA_DIR, 'sessions');
|
const sessionsBaseDir = path.resolve(DATA_DIR, 'sessions');
|
||||||
|
|||||||
@@ -77,10 +77,9 @@ describe('GroupQueue', () => {
|
|||||||
await vi.advanceTimersByTimeAsync(10);
|
await vi.advanceTimersByTimeAsync(10);
|
||||||
|
|
||||||
expect(queue.sendMessage('group1@g.us', '후속 메시지')).toBe(true);
|
expect(queue.sendMessage('group1@g.us', '후속 메시지')).toBe(true);
|
||||||
expect(fs.mkdirSync).toHaveBeenCalledWith(
|
expect(fs.mkdirSync).toHaveBeenCalledWith(`${ipcDir}/input`, {
|
||||||
`${ipcDir}/input`,
|
recursive: true,
|
||||||
{ recursive: true },
|
});
|
||||||
);
|
|
||||||
expect(fs.writeFileSync).toHaveBeenCalled();
|
expect(fs.writeFileSync).toHaveBeenCalled();
|
||||||
expect(fs.renameSync).toHaveBeenCalled();
|
expect(fs.renameSync).toHaveBeenCalled();
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import {
|
|||||||
} from './db.js';
|
} from './db.js';
|
||||||
import { composeDashboardContent } from './dashboard-render.js';
|
import { composeDashboardContent } from './dashboard-render.js';
|
||||||
import { GroupQueue } from './group-queue.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 { startIpcWatcher } from './ipc.js';
|
||||||
import { findChannel, formatOutbound } from './router.js';
|
import { findChannel, formatOutbound } from './router.js';
|
||||||
import {
|
import {
|
||||||
@@ -428,7 +428,10 @@ async function main(): Promise<void> {
|
|||||||
restartContext,
|
restartContext,
|
||||||
registeredGroups,
|
registeredGroups,
|
||||||
)) {
|
)) {
|
||||||
queue.enqueueMessageCheck(candidate.chatJid, candidate.groupFolder);
|
queue.enqueueMessageCheck(
|
||||||
|
candidate.chatJid,
|
||||||
|
resolveGroupIpcPath(candidate.groupFolder),
|
||||||
|
);
|
||||||
logger.info(
|
logger.info(
|
||||||
{
|
{
|
||||||
chatJid: candidate.chatJid,
|
chatJid: candidate.chatJid,
|
||||||
|
|||||||
@@ -533,7 +533,10 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
deps.queue.enqueueMessageCheck(chatJid, resolveGroupIpcPath(group.folder));
|
deps.queue.enqueueMessageCheck(
|
||||||
|
chatJid,
|
||||||
|
resolveGroupIpcPath(group.folder),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -555,7 +558,10 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): {
|
|||||||
{ chatJid, group: group.name, workItemId: openWorkItem.id },
|
{ chatJid, group: group.name, workItemId: openWorkItem.id },
|
||||||
'Recovery: found open work item awaiting delivery',
|
'Recovery: found open work item awaiting delivery',
|
||||||
);
|
);
|
||||||
deps.queue.enqueueMessageCheck(chatJid, resolveGroupIpcPath(group.folder));
|
deps.queue.enqueueMessageCheck(
|
||||||
|
chatJid,
|
||||||
|
resolveGroupIpcPath(group.folder),
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -576,7 +582,10 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): {
|
|||||||
{ group: group.name, pendingCount: pending.length },
|
{ group: group.name, pendingCount: pending.length },
|
||||||
'Recovery: found unprocessed messages',
|
'Recovery: found unprocessed messages',
|
||||||
);
|
);
|
||||||
deps.queue.enqueueMessageCheck(chatJid, resolveGroupIpcPath(group.folder));
|
deps.queue.enqueueMessageCheck(
|
||||||
|
chatJid,
|
||||||
|
resolveGroupIpcPath(group.folder),
|
||||||
|
);
|
||||||
} else if (rawPending.length > 0) {
|
} else if (rawPending.length > 0) {
|
||||||
const endSeq = rawPending[rawPending.length - 1].seq;
|
const endSeq = rawPending[rawPending.length - 1].seq;
|
||||||
if (endSeq != null) {
|
if (endSeq != null) {
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ const { runAgentProcessMock, writeTasksSnapshotMock } = vi.hoisted(() => ({
|
|||||||
|
|
||||||
vi.mock('./agent-runner.js', async () => {
|
vi.mock('./agent-runner.js', async () => {
|
||||||
const actual =
|
const actual =
|
||||||
await vi.importActual<typeof import('./agent-runner.js')>('./agent-runner.js');
|
await vi.importActual<typeof import('./agent-runner.js')>(
|
||||||
|
'./agent-runner.js',
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
...actual,
|
...actual,
|
||||||
runAgentProcess: runAgentProcessMock,
|
runAgentProcess: runAgentProcessMock,
|
||||||
|
|||||||
Reference in New Issue
Block a user