style: prettier formatting fixes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -15,12 +15,7 @@ import { getAgentGroup } from './db/agent-groups.js';
|
||||
import { getMessagingGroup } from './db/messaging-groups.js';
|
||||
import { log } from './log.js';
|
||||
import { validateAdditionalMounts } from './mount-security.js';
|
||||
import {
|
||||
markContainerIdle,
|
||||
markContainerRunning,
|
||||
markContainerStopped,
|
||||
sessionDir,
|
||||
} from './session-manager.js';
|
||||
import { markContainerIdle, markContainerRunning, markContainerStopped, sessionDir } from './session-manager.js';
|
||||
import type { AgentGroup, Session } from './types.js';
|
||||
|
||||
const onecli = new OneCLI({ url: ONECLI_URL });
|
||||
|
||||
@@ -100,10 +100,10 @@ describe('cleanupOrphans', () => {
|
||||
expect(mockExecSync).toHaveBeenNthCalledWith(3, `${CONTAINER_RUNTIME_BIN} stop -t 1 nanoclaw-group2-222`, {
|
||||
stdio: 'pipe',
|
||||
});
|
||||
expect(log.info).toHaveBeenCalledWith(
|
||||
'Stopped orphaned containers',
|
||||
{ count: 2, names: ['nanoclaw-group1-111', 'nanoclaw-group2-222'] },
|
||||
);
|
||||
expect(log.info).toHaveBeenCalledWith('Stopped orphaned containers', {
|
||||
count: 2,
|
||||
names: ['nanoclaw-group1-111', 'nanoclaw-group2-222'],
|
||||
});
|
||||
});
|
||||
|
||||
it('does nothing when no orphans exist', () => {
|
||||
@@ -140,9 +140,9 @@ describe('cleanupOrphans', () => {
|
||||
cleanupOrphans(); // should not throw
|
||||
|
||||
expect(mockExecSync).toHaveBeenCalledTimes(3);
|
||||
expect(log.info).toHaveBeenCalledWith(
|
||||
'Stopped orphaned containers',
|
||||
{ count: 2, names: ['nanoclaw-a-1', 'nanoclaw-b-2'] },
|
||||
);
|
||||
expect(log.info).toHaveBeenCalledWith('Stopped orphaned containers', {
|
||||
count: 2,
|
||||
names: ['nanoclaw-a-1', 'nanoclaw-b-2'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -131,9 +131,9 @@ async function deliverSessionMessages(session: Session): Promise<void> {
|
||||
try {
|
||||
await deliverMessage(msg, session, inDb);
|
||||
// Track delivery in inbound.db (host-owned) — not outbound.db
|
||||
inDb.prepare("INSERT OR IGNORE INTO delivered (message_out_id, delivered_at) VALUES (?, datetime('now'))").run(
|
||||
msg.id,
|
||||
);
|
||||
inDb
|
||||
.prepare("INSERT OR IGNORE INTO delivered (message_out_id, delivered_at) VALUES (?, datetime('now'))")
|
||||
.run(msg.id);
|
||||
resetContainerIdleTimer(session.id);
|
||||
} catch (err) {
|
||||
log.error('Failed to deliver message', { messageId: msg.id, sessionId: session.id, err });
|
||||
@@ -249,9 +249,7 @@ async function handleSystemAction(
|
||||
const recurrence = (content.recurrence as string) || null;
|
||||
|
||||
// Compute next even seq for host-owned inbound.db
|
||||
const maxSeq = (
|
||||
inDb.prepare('SELECT COALESCE(MAX(seq), 0) AS m FROM messages_in').get() as { m: number }
|
||||
).m;
|
||||
const maxSeq = (inDb.prepare('SELECT COALESCE(MAX(seq), 0) AS m FROM messages_in').get() as { m: number }).m;
|
||||
const nextSeq = maxSeq < 2 ? 2 : maxSeq + 2 - (maxSeq % 2);
|
||||
|
||||
inDb
|
||||
@@ -276,7 +274,9 @@ async function handleSystemAction(
|
||||
case 'cancel_task': {
|
||||
const taskId = content.taskId as string;
|
||||
inDb
|
||||
.prepare("UPDATE messages_in SET status = 'completed' WHERE id = ? AND kind = 'task' AND status IN ('pending', 'paused')")
|
||||
.prepare(
|
||||
"UPDATE messages_in SET status = 'completed' WHERE id = ? AND kind = 'task' AND status IN ('pending', 'paused')",
|
||||
)
|
||||
.run(taskId);
|
||||
log.info('Task cancelled', { taskId });
|
||||
break;
|
||||
|
||||
@@ -104,7 +104,9 @@ describe('session manager', () => {
|
||||
const outPath = outboundDbPath('ag-1', 'sess-test');
|
||||
expect(fs.existsSync(outPath)).toBe(true);
|
||||
const outDb = new Database(outPath);
|
||||
const outTables = outDb.prepare("SELECT name FROM sqlite_master WHERE type='table'").all() as Array<{ name: string }>;
|
||||
const outTables = outDb.prepare("SELECT name FROM sqlite_master WHERE type='table'").all() as Array<{
|
||||
name: string;
|
||||
}>;
|
||||
expect(outTables.map((t) => t.name)).toContain('messages_out');
|
||||
expect(outTables.map((t) => t.name)).toContain('processing_ack');
|
||||
outDb.close();
|
||||
|
||||
@@ -115,9 +115,7 @@ function syncProcessingAcks(inDb: Database.Database, outDb: Database.Database):
|
||||
if (completed.length === 0) return;
|
||||
|
||||
// Batch-update messages_in status for completed/failed messages
|
||||
const updateStmt = inDb.prepare(
|
||||
"UPDATE messages_in SET status = 'completed' WHERE id = ? AND status != 'completed'",
|
||||
);
|
||||
const updateStmt = inDb.prepare("UPDATE messages_in SET status = 'completed' WHERE id = ? AND status != 'completed'");
|
||||
inDb.transaction(() => {
|
||||
for (const { message_id } of completed) {
|
||||
updateStmt.run(message_id);
|
||||
@@ -148,9 +146,9 @@ function detectStaleContainers(
|
||||
if (heartbeatAge < STALE_THRESHOLD_MS) return; // Container is alive
|
||||
|
||||
// Heartbeat is stale — check for stuck processing entries
|
||||
const processing = outDb
|
||||
.prepare("SELECT message_id FROM processing_ack WHERE status = 'processing'")
|
||||
.all() as Array<{ message_id: string }>;
|
||||
const processing = outDb.prepare("SELECT message_id FROM processing_ack WHERE status = 'processing'").all() as Array<{
|
||||
message_id: string;
|
||||
}>;
|
||||
|
||||
if (processing.length === 0) return;
|
||||
|
||||
@@ -200,9 +198,7 @@ async function handleRecurrence(inDb: Database.Database, session: Session): Prom
|
||||
const newId = `msg-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
||||
|
||||
// Host uses even seq numbers
|
||||
const maxSeq = (
|
||||
inDb.prepare('SELECT COALESCE(MAX(seq), 0) AS m FROM messages_in').get() as { m: number }
|
||||
).m;
|
||||
const maxSeq = (inDb.prepare('SELECT COALESCE(MAX(seq), 0) AS m FROM messages_in').get() as { m: number }).m;
|
||||
const nextSeq = maxSeq < 2 ? 2 : maxSeq + 2 - (maxSeq % 2);
|
||||
|
||||
inDb
|
||||
@@ -210,7 +206,17 @@ async function handleRecurrence(inDb: Database.Database, session: Session): Prom
|
||||
`INSERT INTO messages_in (id, seq, kind, timestamp, status, process_after, recurrence, platform_id, channel_type, thread_id, content)
|
||||
VALUES (?, ?, ?, datetime('now'), 'pending', ?, ?, ?, ?, ?, ?)`,
|
||||
)
|
||||
.run(newId, nextSeq, msg.kind, nextRun, msg.recurrence, msg.platform_id, msg.channel_type, msg.thread_id, msg.content);
|
||||
.run(
|
||||
newId,
|
||||
nextSeq,
|
||||
msg.kind,
|
||||
nextRun,
|
||||
msg.recurrence,
|
||||
msg.platform_id,
|
||||
msg.channel_type,
|
||||
msg.thread_id,
|
||||
msg.content,
|
||||
);
|
||||
|
||||
// Remove recurrence from the completed message so it doesn't spawn again
|
||||
inDb.prepare('UPDATE messages_in SET recurrence = NULL WHERE id = ?').run(msg.id);
|
||||
|
||||
@@ -76,7 +76,10 @@ export function loadMountAllowlist(): MountAllowlist | null {
|
||||
if (!fs.existsSync(MOUNT_ALLOWLIST_PATH)) {
|
||||
// Do NOT cache this as an error — file may be created later without restart.
|
||||
// Only parse/structural errors are permanently cached.
|
||||
log.warn('Mount allowlist not found - additional mounts will be BLOCKED. Create the file to enable additional mounts.', { path: MOUNT_ALLOWLIST_PATH });
|
||||
log.warn(
|
||||
'Mount allowlist not found - additional mounts will be BLOCKED. Create the file to enable additional mounts.',
|
||||
{ path: MOUNT_ALLOWLIST_PATH },
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -101,12 +104,19 @@ export function loadMountAllowlist(): MountAllowlist | null {
|
||||
allowlist.blockedPatterns = mergedBlockedPatterns;
|
||||
|
||||
cachedAllowlist = allowlist;
|
||||
log.info('Mount allowlist loaded successfully', { path: MOUNT_ALLOWLIST_PATH, allowedRoots: allowlist.allowedRoots.length, blockedPatterns: allowlist.blockedPatterns.length });
|
||||
log.info('Mount allowlist loaded successfully', {
|
||||
path: MOUNT_ALLOWLIST_PATH,
|
||||
allowedRoots: allowlist.allowedRoots.length,
|
||||
blockedPatterns: allowlist.blockedPatterns.length,
|
||||
});
|
||||
|
||||
return cachedAllowlist;
|
||||
} catch (err) {
|
||||
allowlistLoadError = err instanceof Error ? err.message : String(err);
|
||||
log.error('Failed to load mount allowlist - additional mounts will be BLOCKED', { path: MOUNT_ALLOWLIST_PATH, error: allowlistLoadError });
|
||||
log.error('Failed to load mount allowlist - additional mounts will be BLOCKED', {
|
||||
path: MOUNT_ALLOWLIST_PATH,
|
||||
error: allowlistLoadError,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -287,7 +297,10 @@ export function validateMount(mount: AdditionalMount, isMain: boolean): MountVal
|
||||
} else if (!allowedRoot.allowReadWrite) {
|
||||
// Root doesn't allow read-write
|
||||
effectiveReadonly = true;
|
||||
log.info('Mount forced to read-only - root does not allow read-write', { mount: mount.hostPath, root: allowedRoot.path });
|
||||
log.info('Mount forced to read-only - root does not allow read-write', {
|
||||
mount: mount.hostPath,
|
||||
root: allowedRoot.path,
|
||||
});
|
||||
} else {
|
||||
// Read-write allowed
|
||||
effectiveReadonly = false;
|
||||
@@ -333,9 +346,20 @@ export function validateAdditionalMounts(
|
||||
readonly: result.effectiveReadonly!,
|
||||
});
|
||||
|
||||
log.debug('Mount validated successfully', { group: groupName, hostPath: result.realHostPath, containerPath: result.resolvedContainerPath, readonly: result.effectiveReadonly, reason: result.reason });
|
||||
log.debug('Mount validated successfully', {
|
||||
group: groupName,
|
||||
hostPath: result.realHostPath,
|
||||
containerPath: result.resolvedContainerPath,
|
||||
readonly: result.effectiveReadonly,
|
||||
reason: result.reason,
|
||||
});
|
||||
} else {
|
||||
log.warn('Additional mount REJECTED', { group: groupName, requestedPath: mount.hostPath, containerPath: mount.containerPath, reason: result.reason });
|
||||
log.warn('Additional mount REJECTED', {
|
||||
group: groupName,
|
||||
requestedPath: mount.hostPath,
|
||||
containerPath: mount.containerPath,
|
||||
reason: result.reason,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -139,9 +139,7 @@ export function writeSessionMessage(
|
||||
try {
|
||||
// Host uses even seq numbers, container uses odd — prevents collisions
|
||||
// across the two-DB boundary without cross-DB coordination.
|
||||
const maxSeq = (
|
||||
db.prepare('SELECT COALESCE(MAX(seq), 0) AS m FROM messages_in').get() as { m: number }
|
||||
).m;
|
||||
const maxSeq = (db.prepare('SELECT COALESCE(MAX(seq), 0) AS m FROM messages_in').get() as { m: number }).m;
|
||||
const nextSeq = maxSeq < 2 ? 2 : maxSeq + 2 - (maxSeq % 2); // next even
|
||||
|
||||
db.prepare(
|
||||
|
||||
Reference in New Issue
Block a user