refactor: relocate outbox I/O to session-manager + dead-code sweep
## Outbox extraction (delivery.ts → session-manager.ts) File I/O for outbound attachments now lives in session-manager.ts alongside the symmetric inbound extractAttachmentFiles. delivery.ts no longer touches the filesystem — it hands buffers to the adapter and calls clearOutbox on success. - New `readOutboxFiles(agentGroupId, sessionId, messageId, filenames)` and `clearOutbox(agentGroupId, sessionId, messageId)` in session-manager.ts. - deliverMessage in delivery.ts loses ~35 lines of fs/path code and its `fs`/`path` imports. ## Dead-code sweep TypeScript's --noUnusedLocals surfaced several cruft imports. Fixed: - src/container-runner.ts: drop unused `markContainerIdle` import; drop unused `session` parameter from `buildContainerArgs` signature. - src/delivery.ts: drop unused `getSession`, `writeSessionMessage`, `wakeContainer` imports. - src/host-sweep.ts: drop unused `updateSession`, `outboundDbPath` imports. - container/agent-runner/src/poll-loop.ts: drop unused `config`, `processingIds` params from `processQuery`. - Test files: drop unused imports in channel-registry.test, db-v2.test, host-core.test. Skipped: `conversations` state in chat-sdk-bridge.ts (never read but tangled with public `updateConversations` method; cleaning it risks a merge conflict with the channels branch at the next sync). ## Validation - `pnpm run build` clean - `pnpm test` — 137 host tests pass - `bun test` in container/agent-runner — 17 tests pass - Service boots (`NanoClaw running`, `OneCLI approval handler started`) and shuts down cleanly on SIGTERM Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ import type Database from 'better-sqlite3';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import type { OutboundFile } from './channels/adapter.js';
|
||||
import { DATA_DIR } from './config.js';
|
||||
import { getMessagingGroup } from './db/messaging-groups.js';
|
||||
import { createSession, findSession, findSessionByAgentGroup, getSession, updateSession } from './db/sessions.js';
|
||||
@@ -289,6 +290,53 @@ export function writeSystemResponse(
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load outbox attachments for a delivered message.
|
||||
*
|
||||
* Symmetric with `extractAttachmentFiles` on the inbound side: the container
|
||||
* writes files into the session's `outbox/<messageId>/` directory alongside
|
||||
* its `messages_out` row, and the host reads them back at delivery time.
|
||||
*
|
||||
* Returns undefined when the outbox dir is missing or no declared file was
|
||||
* actually on disk — delivery continues without attachments rather than
|
||||
* failing the whole message.
|
||||
*/
|
||||
export function readOutboxFiles(
|
||||
agentGroupId: string,
|
||||
sessionId: string,
|
||||
messageId: string,
|
||||
filenames: string[],
|
||||
): OutboundFile[] | undefined {
|
||||
const outboxDir = path.join(sessionDir(agentGroupId, sessionId), 'outbox', messageId);
|
||||
if (!fs.existsSync(outboxDir)) return undefined;
|
||||
const files: OutboundFile[] = [];
|
||||
for (const filename of filenames) {
|
||||
const filePath = path.join(outboxDir, filename);
|
||||
if (fs.existsSync(filePath)) {
|
||||
files.push({ filename, data: fs.readFileSync(filePath) });
|
||||
} else {
|
||||
log.warn('Outbox file not found', { messageId, filename });
|
||||
}
|
||||
}
|
||||
return files.length > 0 ? files : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a message's outbox directory after successful delivery. Best-effort:
|
||||
* failures log and swallow. A cleanup failure must NOT propagate to the
|
||||
* delivery caller — the message is already on the user's screen, and a
|
||||
* thrown error would trigger the delivery retry path and deliver twice.
|
||||
*/
|
||||
export function clearOutbox(agentGroupId: string, sessionId: string, messageId: string): void {
|
||||
const outboxDir = path.join(sessionDir(agentGroupId, sessionId), 'outbox', messageId);
|
||||
if (!fs.existsSync(outboxDir)) return;
|
||||
try {
|
||||
fs.rmSync(outboxDir, { recursive: true, force: true });
|
||||
} catch (err) {
|
||||
log.warn('Outbox cleanup failed (message already delivered)', { messageId, err });
|
||||
}
|
||||
}
|
||||
|
||||
/** Mark a container as running for a session. */
|
||||
export function markContainerRunning(sessionId: string): void {
|
||||
updateSession(sessionId, { container_status: 'running', last_active: new Date().toISOString() });
|
||||
|
||||
Reference in New Issue
Block a user