From e1fdc475522c7b7c0be8c927300950a7a923f036 Mon Sep 17 00:00:00 2001 From: Eyejoker Date: Sat, 28 Mar 2026 05:41:16 +0900 Subject: [PATCH] style: sync pre-commit formatting fallout --- src/agent-error-detection.test.ts | 2 - src/agent-runner-environment.test.ts | 3 +- src/agent-runner-environment.ts | 5 +- src/config.ts | 6 +- src/db.ts | 12 +- src/duplicate-suppression.test.ts | 237 ++++++++++++++++----------- src/group-folder.ts | 7 +- src/index.ts | 16 +- src/message-agent-executor.test.ts | 6 +- src/message-agent-executor.ts | 26 +-- src/message-runtime.test.ts | 3 +- src/message-runtime.ts | 32 +++- src/output-suppression.ts | 8 +- src/router.ts | 5 +- src/service-routing.ts | 13 +- src/task-scheduler.test.ts | 52 +++--- src/task-scheduler.ts | 3 +- 17 files changed, 261 insertions(+), 175 deletions(-) diff --git a/src/agent-error-detection.test.ts b/src/agent-error-detection.test.ts index fba55c8..0e33261 100644 --- a/src/agent-error-detection.test.ts +++ b/src/agent-error-detection.test.ts @@ -5,7 +5,6 @@ import { classifyClaudeAuthError, detectClaudeProviderFailureMessage, isClaudeOrgAccessDeniedMessage, - shouldRotateClaudeToken, } from './agent-error-detection.js'; @@ -64,5 +63,4 @@ describe('agent-error-detection', () => { expect(shouldRotateClaudeToken('overloaded')).toBe(false); expect(shouldRotateClaudeToken('success-null-result')).toBe(false); }); - }); diff --git a/src/agent-runner-environment.test.ts b/src/agent-runner-environment.test.ts index 0ead3fb..164927d 100644 --- a/src/agent-runner-environment.test.ts +++ b/src/agent-runner-environment.test.ts @@ -63,7 +63,8 @@ vi.mock('./group-folder.js', () => ({ folder: string, serviceId: string, taskId: string, - ) => `${process.env.EJ_TEST_ROOT}/task-sessions/${folder}/${serviceId}/${taskId}`, + ) => + `${process.env.EJ_TEST_ROOT}/task-sessions/${folder}/${serviceId}/${taskId}`, })); vi.mock('os', async () => { diff --git a/src/agent-runner-environment.ts b/src/agent-runner-environment.ts index 94bd260..d8c6a6e 100644 --- a/src/agent-runner-environment.ts +++ b/src/agent-runner-environment.ts @@ -273,7 +273,10 @@ function prepareCodexSessionEnvironment(args: { : [ readPlatformPrompt('codex', args.projectRoot), isReviewService(SERVICE_ID) - ? readOptionalPromptFile(args.projectRoot, 'codex-review-platform.md') + ? readOptionalPromptFile( + args.projectRoot, + 'codex-review-platform.md', + ) : undefined, args.isPairedRoom ? readPairedRoomPrompt('codex', args.projectRoot) diff --git a/src/config.ts b/src/config.ts index 374989a..8794ce2 100644 --- a/src/config.ts +++ b/src/config.ts @@ -137,12 +137,10 @@ export function isSessionCommandSenderAllowed(sender: string): boolean { } // Delta handoff: cross-provider session continuity with probe + fallback -export const DELTA_HANDOFF_ENABLED = - getEnv('DELTA_HANDOFF_ENABLED') === 'true'; +export const DELTA_HANDOFF_ENABLED = getEnv('DELTA_HANDOFF_ENABLED') === 'true'; // Comma-separated list of group folders for canary testing -const rawDeltaHandoffCanaryGroups = - getEnv('DELTA_HANDOFF_CANARY_GROUPS') || ''; +const rawDeltaHandoffCanaryGroups = getEnv('DELTA_HANDOFF_CANARY_GROUPS') || ''; export const DELTA_HANDOFF_CANARY_GROUPS = new Set( rawDeltaHandoffCanaryGroups .split(',') diff --git a/src/db.ts b/src/db.ts index 6af768b..5ea0026 100644 --- a/src/db.ts +++ b/src/db.ts @@ -361,7 +361,9 @@ function createSchema(database: Database.Database): void { } try { - database.exec(`ALTER TABLE work_items ADD COLUMN service_id TEXT DEFAULT ''`); + database.exec( + `ALTER TABLE work_items ADD COLUMN service_id TEXT DEFAULT ''`, + ); } catch { /* column already exists */ } @@ -884,9 +886,7 @@ export function getRecentChatMessages( LIMIT ? ) ORDER BY timestamp `; - const rows = db - .prepare(sql) - .all(chatJid, limit) as Array< + const rows = db.prepare(sql).all(chatJid, limit) as Array< NewMessage & { is_from_me?: boolean | number; is_bot_message?: boolean | number; @@ -1834,7 +1834,9 @@ function parseLastAgentSeqState( } if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { - throw new Error(`Invalid last_agent_seq JSON for ${serviceId}: not an object`); + throw new Error( + `Invalid last_agent_seq JSON for ${serviceId}: not an object`, + ); } const cursors: Record = {}; diff --git a/src/duplicate-suppression.test.ts b/src/duplicate-suppression.test.ts index 8ad016e..3fe2379 100644 --- a/src/duplicate-suppression.test.ts +++ b/src/duplicate-suppression.test.ts @@ -19,16 +19,18 @@ beforeEach(() => { }); // Helper to create a message -const createMessage = (overrides: Partial<{ - id: string; - chat_jid: string; - sender: string; - sender_name: string; - content: string; - timestamp: string; - is_from_me: boolean; - is_bot_message: boolean; -}> = {}) => ({ +const createMessage = ( + overrides: Partial<{ + id: string; + chat_jid: string; + sender: string; + sender_name: string; + content: string; + timestamp: string; + is_from_me: boolean; + is_bot_message: boolean; + }> = {}, +) => ({ id: overrides.id ?? 'msg-1', chat_jid: overrides.chat_jid ?? 'dc:test-room', sender: overrides.sender ?? 'user1', @@ -41,7 +43,13 @@ const createMessage = (overrides: Partial<{ // Helper to setup chat metadata const setupChat = (jid: string) => { - storeChatMetadata(jid, new Date().toISOString(), 'Test Chat', 'discord', true); + storeChatMetadata( + jid, + new Date().toISOString(), + 'Test Chat', + 'discord', + true, + ); }; describe('isPairedRoomJid', () => { @@ -103,34 +111,40 @@ describe('getLastBotFinalMessage', () => { setupChat(jid); // Store older bot message (from any bot) - storeMessage(createMessage({ - id: 'msg-1', - chat_jid: jid, - content: 'First bot message', - timestamp: new Date(now.getTime() - 1000).toISOString(), - is_from_me: true, - is_bot_message: true, - })); + storeMessage( + createMessage({ + id: 'msg-1', + chat_jid: jid, + content: 'First bot message', + timestamp: new Date(now.getTime() - 1000).toISOString(), + is_from_me: true, + is_bot_message: true, + }), + ); // Store newer bot message (from different bot - is_from_me=0 but is_bot_message=1) - storeMessage(createMessage({ - id: 'msg-2', - chat_jid: jid, - content: 'Second bot message', - timestamp: now.toISOString(), - is_from_me: false, // Different bot - is_bot_message: true, - })); + storeMessage( + createMessage({ + id: 'msg-2', + chat_jid: jid, + content: 'Second bot message', + timestamp: now.toISOString(), + is_from_me: false, // Different bot + is_bot_message: true, + }), + ); // Store human message (should not be returned) - storeMessage(createMessage({ - id: 'msg-3', - chat_jid: jid, - content: 'Human message', - timestamp: new Date(now.getTime() + 1000).toISOString(), - is_from_me: false, - is_bot_message: false, - })); + storeMessage( + createMessage({ + id: 'msg-3', + chat_jid: jid, + content: 'Human message', + timestamp: new Date(now.getTime() + 1000).toISOString(), + is_from_me: false, + is_bot_message: false, + }), + ); const lastMessages = getLastBotFinalMessage(jid, 'claude-code', 1); expect(lastMessages).toHaveLength(1); @@ -183,21 +197,27 @@ describe('isDuplicateOfLastBotFinal (runtime function)', () => { }); // Store a bot message (from any bot) - storeMessage(createMessage({ - id: 'msg-1', - chat_jid: jid, - content: 'DONE — Task completed successfully', - timestamp: new Date().toISOString(), - is_from_me: false, // Different bot - is_bot_message: true, - })); + storeMessage( + createMessage({ + id: 'msg-1', + chat_jid: jid, + content: 'DONE — Task completed successfully', + timestamp: new Date().toISOString(), + is_from_me: false, // Different bot + is_bot_message: true, + }), + ); // Verify it's a paired room expect(isPairedRoomJid(jid)).toBe(true); // Verify duplicate detection works via the actual runtime function - expect(isDuplicateOfLastBotFinal(jid, 'DONE — Task completed successfully')).toBe(true); - expect(isDuplicateOfLastBotFinal(jid, 'done — task completed successfully')).toBe(true); // Normalized match + expect( + isDuplicateOfLastBotFinal(jid, 'DONE — Task completed successfully'), + ).toBe(true); + expect( + isDuplicateOfLastBotFinal(jid, 'done — task completed successfully'), + ).toBe(true); // Normalized match }); it('non-paired room: duplicate check is bypassed', () => { @@ -214,14 +234,16 @@ describe('isDuplicateOfLastBotFinal (runtime function)', () => { }); // Store a bot message - storeMessage(createMessage({ - id: 'msg-1', - chat_jid: jid, - content: 'DONE — Task completed', - timestamp: new Date().toISOString(), - is_from_me: true, - is_bot_message: true, - })); + storeMessage( + createMessage({ + id: 'msg-1', + chat_jid: jid, + content: 'DONE — Task completed', + timestamp: new Date().toISOString(), + is_from_me: true, + is_bot_message: true, + }), + ); // Verify it's NOT a paired room expect(isPairedRoomJid(jid)).toBe(false); @@ -252,17 +274,21 @@ describe('isDuplicateOfLastBotFinal (runtime function)', () => { }); // Store a bot message - storeMessage(createMessage({ - id: 'msg-1', - chat_jid: jid, - content: 'First message content', - timestamp: new Date().toISOString(), - is_from_me: true, - is_bot_message: true, - })); + storeMessage( + createMessage({ + id: 'msg-1', + chat_jid: jid, + content: 'First message content', + timestamp: new Date().toISOString(), + is_from_me: true, + is_bot_message: true, + }), + ); // Verify different content is not a duplicate - expect(isDuplicateOfLastBotFinal(jid, 'Different message content')).toBe(false); + expect(isDuplicateOfLastBotFinal(jid, 'Different message content')).toBe( + false, + ); expect(isDuplicateOfLastBotFinal(jid, 'First message content')).toBe(true); }); @@ -288,17 +314,21 @@ describe('isDuplicateOfLastBotFinal (runtime function)', () => { }); // Store a bot message from "codex" (is_from_me=0) - storeMessage(createMessage({ - id: 'msg-1', - chat_jid: jid, - content: 'DONE — Analysis complete', - timestamp: new Date().toISOString(), - is_from_me: false, // Other bot - is_bot_message: true, - })); + storeMessage( + createMessage({ + id: 'msg-1', + chat_jid: jid, + content: 'DONE — Analysis complete', + timestamp: new Date().toISOString(), + is_from_me: false, // Other bot + is_bot_message: true, + }), + ); // Verify claude service detects this as duplicate (cross-bot detection) - expect(isDuplicateOfLastBotFinal(jid, 'DONE — Analysis complete')).toBe(true); + expect(isDuplicateOfLastBotFinal(jid, 'DONE — Analysis complete')).toBe( + true, + ); }); it('normalization handles whitespace and case differences', () => { @@ -323,18 +353,27 @@ describe('isDuplicateOfLastBotFinal (runtime function)', () => { }); // Store a bot message with specific formatting - storeMessage(createMessage({ - id: 'msg-1', - chat_jid: jid, - content: 'DONE — Task completed\n\nSuccessfully', - timestamp: new Date().toISOString(), - is_from_me: true, - is_bot_message: true, - })); + storeMessage( + createMessage({ + id: 'msg-1', + chat_jid: jid, + content: 'DONE — Task completed\n\nSuccessfully', + timestamp: new Date().toISOString(), + is_from_me: true, + is_bot_message: true, + }), + ); // Same content with different whitespace should be detected as duplicate - expect(isDuplicateOfLastBotFinal(jid, 'done — task completed successfully')).toBe(true); - expect(isDuplicateOfLastBotFinal(jid, ' DONE — Task completed Successfully ')).toBe(true); + expect( + isDuplicateOfLastBotFinal(jid, 'done — task completed successfully'), + ).toBe(true); + expect( + isDuplicateOfLastBotFinal( + jid, + ' DONE — Task completed Successfully ', + ), + ).toBe(true); // Different content should not be duplicate expect(isDuplicateOfLastBotFinal(jid, 'FAILED — Task failed')).toBe(false); @@ -362,14 +401,16 @@ describe('isDuplicateOfLastBotFinal (runtime function)', () => { }); // Store a bot message (simulating previous delivery) - storeMessage(createMessage({ - id: 'msg-1', - chat_jid: jid, - content: 'DONE — Task completed successfully', - timestamp: new Date().toISOString(), - is_from_me: true, - is_bot_message: true, - })); + storeMessage( + createMessage({ + id: 'msg-1', + chat_jid: jid, + content: 'DONE — Task completed successfully', + timestamp: new Date().toISOString(), + is_from_me: true, + is_bot_message: true, + }), + ); // Create a work item with the same content (duplicate) const workItem = createProducedWorkItem({ @@ -416,14 +457,16 @@ describe('isDuplicateOfLastBotFinal (runtime function)', () => { }); // Store a bot message - storeMessage(createMessage({ - id: 'msg-1', - chat_jid: jid, - content: 'First message', - timestamp: new Date().toISOString(), - is_from_me: true, - is_bot_message: true, - })); + storeMessage( + createMessage({ + id: 'msg-1', + chat_jid: jid, + content: 'First message', + timestamp: new Date().toISOString(), + is_from_me: true, + is_bot_message: true, + }), + ); // Create a work item with DIFFERENT content (non-duplicate) const workItem = createProducedWorkItem({ diff --git a/src/group-folder.ts b/src/group-folder.ts index d429945..51fffcf 100644 --- a/src/group-folder.ts +++ b/src/group-folder.ts @@ -75,7 +75,12 @@ export function resolveServiceGroupSessionsPath( assertValidGroupFolder(folder); assertValidRuntimeSegment(serviceId, 'service ID'); const sessionsBaseDir = path.resolve(DATA_DIR, 'sessions'); - const sessionsPath = path.resolve(sessionsBaseDir, folder, 'services', serviceId); + const sessionsPath = path.resolve( + sessionsBaseDir, + folder, + 'services', + serviceId, + ); ensureWithinBase(sessionsBaseDir, sessionsPath); return sessionsPath; } diff --git a/src/index.ts b/src/index.ts index 2358282..d678029 100644 --- a/src/index.ts +++ b/src/index.ts @@ -71,7 +71,10 @@ import { Channel, NewMessage, RegisteredGroup } from './types.js'; import { logger } from './logger.js'; import { normalizeStoredSeqCursor } from './message-cursor.js'; import { initCodexTokenRotation } from './codex-token-rotation.js'; -import { hasAvailableClaudeToken, initTokenRotation } from './token-rotation.js'; +import { + hasAvailableClaudeToken, + initTokenRotation, +} from './token-rotation.js'; import { shouldStartTokenRefreshLoop, startTokenRefreshLoop, @@ -442,7 +445,10 @@ async function main(): Promise { editFormattedTrackedChannelMessage(channels, jid, messageId, rawText), }); } else { - logger.info({ serviceId: SERVICE_ID }, 'Skipping scheduler for review service'); + logger.info( + { serviceId: SERVICE_ID }, + 'Skipping scheduler for review service', + ); } startIpcWatcher({ sendMessage: (jid, text) => { @@ -536,7 +542,11 @@ async function main(): Promise { } restoreDefaultChannelLease(lease.chatJid); logger.info( - { chatJid: lease.chatJid, serviceId: SERVICE_ID, elapsedMin: Math.round(elapsed / 60_000) }, + { + chatJid: lease.chatJid, + serviceId: SERVICE_ID, + elapsedMin: Math.round(elapsed / 60_000), + }, 'Claude token available and failover hold period elapsed, restored default channel lease', ); } diff --git a/src/message-agent-executor.test.ts b/src/message-agent-executor.test.ts index 76895dd..03ded9b 100644 --- a/src/message-agent-executor.test.ts +++ b/src/message-agent-executor.test.ts @@ -44,7 +44,8 @@ vi.mock('./logger.js', () => ({ })); vi.mock('./agent-error-detection.js', async (importOriginal) => { - const actual = await importOriginal(); + const actual = + await importOriginal(); return { ...actual, classifyRotationTrigger: vi.fn((error?: string | null) => { @@ -528,7 +529,8 @@ describe('runAgentForGroup Claude rotation', () => { await onOutput?.({ status: 'success', phase: 'final', - result: 'You\u2019re out of extra usage \u00b7 resets 4am (Asia/Seoul)', + result: + 'You\u2019re out of extra usage \u00b7 resets 4am (Asia/Seoul)', }); return { status: 'success', diff --git a/src/message-agent-executor.ts b/src/message-agent-executor.ts index 78a65a8..ffec1e3 100644 --- a/src/message-agent-executor.ts +++ b/src/message-agent-executor.ts @@ -20,12 +20,19 @@ import { shouldResetSessionOnAgentFailure, shouldRetryFreshSessionOnAgentFailure, } from './session-recovery.js'; -import { CODEX_MAIN_SERVICE_ID, CODEX_REVIEW_SERVICE_ID, SERVICE_SESSION_SCOPE } from './config.js'; +import { + CODEX_MAIN_SERVICE_ID, + CODEX_REVIEW_SERVICE_ID, + SERVICE_SESSION_SCOPE, +} from './config.js'; import { buildSuppressTokenPrompt, classifySuppressTokenOutput, } from './output-suppression.js'; -import { activateCodexFailover, getEffectiveChannelLease } from './service-routing.js'; +import { + activateCodexFailover, + getEffectiveChannelLease, +} from './service-routing.js'; import { evaluateStreamedOutput, type StreamedOutputState, @@ -111,7 +118,8 @@ export async function runAgentForGroup( const canRotateToken = isClaudeCodeAgent && getTokenCount() > 1; const currentLease = getEffectiveChannelLease(chatJid); - const reviewerMode = currentLease.reviewer_service_id === SERVICE_SESSION_SCOPE; + const reviewerMode = + currentLease.reviewer_service_id === SERVICE_SESSION_SCOPE; const effectivePrompt = buildSuppressTokenPrompt(prompt, suppressToken, { reviewerMode, }); @@ -569,11 +577,7 @@ export async function runAgentForGroup( } if (primaryAttempt.error) { - if ( - canRotateToken && - provider === 'claude' && - !primaryAttempt.sawOutput - ) { + if (canRotateToken && provider === 'claude' && !primaryAttempt.sawOutput) { const errMsg = getErrorMessage(primaryAttempt.error); const trigger = primaryAttempt.streamedTriggerReason ? { @@ -666,11 +670,7 @@ export async function runAgentForGroup( } if (output.status === 'error') { - if ( - canRotateToken && - provider === 'claude' && - !primaryAttempt.sawOutput - ) { + if (canRotateToken && provider === 'claude' && !primaryAttempt.sawOutput) { const trigger = primaryAttempt.streamedTriggerReason ? { shouldRetry: true, diff --git a/src/message-runtime.test.ts b/src/message-runtime.test.ts index e93c479..4c0ea11 100644 --- a/src/message-runtime.test.ts +++ b/src/message-runtime.test.ts @@ -12,7 +12,8 @@ vi.mock('./agent-runner.js', () => ({ })); vi.mock('./output-suppression.js', async (importOriginal) => { - const actual = await importOriginal(); + const actual = + await importOriginal(); return { ...actual, createSuppressToken: vi.fn(() => '__TEST_SUPPRESS__'), diff --git a/src/message-runtime.ts b/src/message-runtime.ts index 597a14e..b0f8200 100644 --- a/src/message-runtime.ts +++ b/src/message-runtime.ts @@ -24,7 +24,11 @@ import { SERVICE_ID, } from './config.js'; import { GroupQueue, GroupRunContext } from './group-queue.js'; -import { findChannel, formatMessages, normalizeMessageForDedupe } from './router.js'; +import { + findChannel, + formatMessages, + normalizeMessageForDedupe, +} from './router.js'; import { isTriggerAllowed, loadSenderAllowlist } from './sender-allowlist.js'; import { advanceLastAgentCursor, @@ -52,7 +56,10 @@ import { shouldServiceProcessChat } from './service-routing.js'; * Check if a message is a duplicate of the last bot final message in a paired room. * Exported for testing purposes. */ -export function isDuplicateOfLastBotFinal(chatJid: string, text: string): boolean { +export function isDuplicateOfLastBotFinal( + chatJid: string, + text: string, +): boolean { // Only check in paired rooms (both claude and codex registered) if (!isPairedRoomJid(chatJid)) { return false; @@ -115,7 +122,10 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): { * Check if a message is a duplicate of the last bot final message in a paired room. * Returns true if duplicate (should be suppressed). */ - const checkDuplicateOfLastBotFinal = (chatJid: string, text: string): boolean => { + const checkDuplicateOfLastBotFinal = ( + chatJid: string, + text: string, + ): boolean => { return isDuplicateOfLastBotFinal(chatJid, text); }; @@ -129,7 +139,10 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): { const replaceMessageId = options?.replaceMessageId ?? null; // Check for duplicate in paired rooms before attempting delivery - const isDuplicate = checkDuplicateOfLastBotFinal(item.chat_jid, item.result_payload); + const isDuplicate = checkDuplicateOfLastBotFinal( + item.chat_jid, + item.result_payload, + ); if (isDuplicate) { // Mark as delivered without sending, and don't open continuation @@ -263,7 +276,9 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): { const isClaudeCodeAgent = (group.agentType || 'claude-code') === 'claude-code'; const suppressToken = - isClaudeService() || isReviewService() ? createSuppressToken() : undefined; + isClaudeService() || isReviewService() + ? createSuppressToken() + : undefined; const deferTypingUntilVisible = Boolean(suppressToken) && isClaudeService(); const turnController = new MessageTurnController({ @@ -277,7 +292,8 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): { deferTypingUntilVisible, suppressToken, clearSession: () => deps.clearSession(group.folder), - requestClose: (reason) => deps.queue.closeStdin(chatJid, { runId, reason }), + requestClose: (reason) => + deps.queue.closeStdin(chatJid, { runId, reason }), deliverFinalText: async (text) => { try { const workItem = createProducedWorkItem({ @@ -352,7 +368,9 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): { } }; - const processClaimedHandoff = async (handoff: ServiceHandoff): Promise => { + const processClaimedHandoff = async ( + handoff: ServiceHandoff, + ): Promise => { const group = deps.getRegisteredGroups()[handoff.chat_jid]; if (!group) { failServiceHandoff(handoff.id, 'Group not registered on target service'); diff --git a/src/output-suppression.ts b/src/output-suppression.ts index a68c60e..c9e5d08 100644 --- a/src/output-suppression.ts +++ b/src/output-suppression.ts @@ -19,8 +19,7 @@ export function shouldEnableSuppressOutputForService( if (!serviceId) return false; const normalized = normalizeServiceId(serviceId); return ( - normalized === CLAUDE_SERVICE_ID || - normalized === CODEX_REVIEW_SERVICE_ID + normalized === CLAUDE_SERVICE_ID || normalized === CODEX_REVIEW_SERVICE_ID ); } @@ -29,7 +28,10 @@ export function classifySuppressTokenOutput( suppressToken: string | undefined, ): 'exact' | 'mixed' | 'none' { const trimmed = rawText.trim(); - if ((suppressToken && trimmed === suppressToken) || EXACT_ANY_SUPPRESS_TOKEN_PATTERN.test(trimmed)) { + if ( + (suppressToken && trimmed === suppressToken) || + EXACT_ANY_SUPPRESS_TOKEN_PATTERN.test(trimmed) + ) { return 'exact'; } if (suppressToken && rawText.includes(suppressToken)) { diff --git a/src/router.ts b/src/router.ts index 83a3233..20e9bda 100644 --- a/src/router.ts +++ b/src/router.ts @@ -99,8 +99,5 @@ export function findChannel( * - Collapse consecutive whitespace/newlines into single space */ export function normalizeMessageForDedupe(text: string): string { - return text - .trim() - .replace(/\s+/g, ' ') - .toLowerCase(); + return text.trim().replace(/\s+/g, ' ').toLowerCase(); } diff --git a/src/service-routing.ts b/src/service-routing.ts index 8059ad8..f491af9 100644 --- a/src/service-routing.ts +++ b/src/service-routing.ts @@ -85,7 +85,9 @@ function getDefaultLease(chatJid: string): EffectiveChannelLease { return { chat_jid: chatJid, owner_service_id: - SERVICE_AGENT_TYPE === 'codex' ? CODEX_MAIN_SERVICE_ID : CLAUDE_SERVICE_ID, + SERVICE_AGENT_TYPE === 'codex' + ? CODEX_MAIN_SERVICE_ID + : CLAUDE_SERVICE_ID, reviewer_service_id: null, activated_at: null, reason: null, @@ -106,7 +108,9 @@ export function refreshChannelOwnerCache(force = false): void { lastLeaseRefreshAt = now; } -export function getEffectiveChannelLease(chatJid: string): EffectiveChannelLease { +export function getEffectiveChannelLease( + chatJid: string, +): EffectiveChannelLease { refreshChannelOwnerCache(); const row = leaseCache.get(chatJid); if (row) { @@ -180,7 +184,10 @@ export function getActiveCodexFailoverLeases(): ActiveFailoverLease[] { normalizeServiceId(row.reviewer_service_id || '') === CODEX_MAIN_SERVICE_ID, ) - .map((row) => ({ chatJid: row.chat_jid, activatedAt: row.activated_at ?? null })); + .map((row) => ({ + chatJid: row.chat_jid, + activatedAt: row.activated_at ?? null, + })); } /** @deprecated Use getActiveCodexFailoverLeases() instead */ diff --git a/src/task-scheduler.test.ts b/src/task-scheduler.test.ts index a20c7f8..f262ac6 100644 --- a/src/task-scheduler.test.ts +++ b/src/task-scheduler.test.ts @@ -25,7 +25,8 @@ const { })); vi.mock('./agent-error-detection.js', async (importOriginal) => { - const actual = await importOriginal(); + const actual = + await importOriginal(); return { ...actual, classifyRotationTrigger: vi.fn((error?: string | null) => { @@ -566,31 +567,30 @@ Check the run. created_at: '2026-02-22T00:00:00.000Z', }); - (runAgentProcessMock as any) - .mockImplementationOnce( - async ( - _group: unknown, - _input: unknown, - _onProcess: unknown, - onOutput?: (output: Record) => Promise, - ) => { - await onOutput?.({ - status: 'success', - phase: 'intermediate', - result: - 'API Error: 502 502 Bad Gateway

502 Bad Gateway


cloudflare
', - }); - await onOutput?.({ - status: 'success', - result: - 'API Error: 502 502 Bad Gateway

502 Bad Gateway


cloudflare
', - }); - return { - status: 'success', - result: null, - }; - }, - ); + (runAgentProcessMock as any).mockImplementationOnce( + async ( + _group: unknown, + _input: unknown, + _onProcess: unknown, + onOutput?: (output: Record) => Promise, + ) => { + await onOutput?.({ + status: 'success', + phase: 'intermediate', + result: + 'API Error: 502 502 Bad Gateway

502 Bad Gateway


cloudflare
', + }); + await onOutput?.({ + status: 'success', + result: + 'API Error: 502 502 Bad Gateway

502 Bad Gateway


cloudflare
', + }); + return { + status: 'success', + result: null, + }; + }, + ); const enqueueTask = vi.fn( (_groupJid: string, _taskId: string, fn: () => Promise) => { diff --git a/src/task-scheduler.ts b/src/task-scheduler.ts index 7695be7..c534fc0 100644 --- a/src/task-scheduler.ts +++ b/src/task-scheduler.ts @@ -535,8 +535,7 @@ async function runTask( } }; - const provider = - context.taskAgentType === 'codex' ? 'codex' : 'claude'; + const provider = context.taskAgentType === 'codex' ? 'codex' : 'claude'; { const attempt = await runTaskAttempt(provider);