From 7ad60cbedb275ba22b2a04d6d65875b7103dbc64 Mon Sep 17 00:00:00 2001 From: Nguyen Khac Trung Kien Date: Sun, 8 Feb 2026 08:54:52 +0700 Subject: [PATCH] fix(agent-teams): atomically write inbox files --- src/tools/agent-teams/inbox-store.ts | 32 ++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/tools/agent-teams/inbox-store.ts b/src/tools/agent-teams/inbox-store.ts index b351db1c..6d9dcb1e 100644 --- a/src/tools/agent-teams/inbox-store.ts +++ b/src/tools/agent-teams/inbox-store.ts @@ -1,7 +1,8 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs" import { z } from "zod" -import { acquireLock, ensureDir } from "../../features/claude-tasks/storage" +import { acquireLock, ensureDir, writeJsonAtomic } from "../../features/claude-tasks/storage" import { getTeamInboxDir, getTeamInboxPath } from "./paths" +import { validateAgentNameOrLead, validateTeamName } from "./name-validation" import { TeamInboxMessage, TeamInboxMessageSchema } from "./types" const TeamInboxListSchema = z.array(TeamInboxMessageSchema) @@ -10,7 +11,22 @@ function nowIso(): string { return new Date().toISOString() } +function assertValidTeamName(teamName: string): void { + const validationError = validateTeamName(teamName) + if (validationError) { + throw new Error(validationError) + } +} + +function assertValidInboxAgentName(agentName: string): void { + const validationError = validateAgentNameOrLead(agentName) + if (validationError) { + throw new Error(validationError) + } +} + function withInboxLock(teamName: string, operation: () => T): T { + assertValidTeamName(teamName) const inboxDir = getTeamInboxDir(teamName) ensureDir(inboxDir) const lock = acquireLock(inboxDir) @@ -36,6 +52,8 @@ function parseInboxFile(content: string): TeamInboxMessage[] { } function readInboxMessages(teamName: string, agentName: string): TeamInboxMessage[] { + assertValidTeamName(teamName) + assertValidInboxAgentName(agentName) const path = getTeamInboxPath(teamName, agentName) if (!existsSync(path)) { return [] @@ -44,24 +62,30 @@ function readInboxMessages(teamName: string, agentName: string): TeamInboxMessag } function writeInboxMessages(teamName: string, agentName: string, messages: TeamInboxMessage[]): void { + assertValidTeamName(teamName) + assertValidInboxAgentName(agentName) const path = getTeamInboxPath(teamName, agentName) - writeFileSync(path, JSON.stringify(messages), "utf-8") + writeJsonAtomic(path, messages) } export function ensureInbox(teamName: string, agentName: string): void { + assertValidTeamName(teamName) + assertValidInboxAgentName(agentName) withInboxLock(teamName, () => { const path = getTeamInboxPath(teamName, agentName) if (!existsSync(path)) { - writeFileSync(path, "[]", "utf-8") + writeJsonAtomic(path, []) } }) } export function appendInboxMessage(teamName: string, agentName: string, message: TeamInboxMessage): void { + assertValidTeamName(teamName) + assertValidInboxAgentName(agentName) withInboxLock(teamName, () => { const path = getTeamInboxPath(teamName, agentName) if (!existsSync(path)) { - writeFileSync(path, "[]", "utf-8") + writeJsonAtomic(path, []) } const messages = readInboxMessages(teamName, agentName) messages.push(TeamInboxMessageSchema.parse(message))