fix(agent-teams): atomically write inbox files
This commit is contained in:
parent
1a5030d359
commit
7ad60cbedb
@ -1,7 +1,8 @@
|
|||||||
import { existsSync, readFileSync, writeFileSync } from "node:fs"
|
import { existsSync, readFileSync, writeFileSync } from "node:fs"
|
||||||
import { z } from "zod"
|
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 { getTeamInboxDir, getTeamInboxPath } from "./paths"
|
||||||
|
import { validateAgentNameOrLead, validateTeamName } from "./name-validation"
|
||||||
import { TeamInboxMessage, TeamInboxMessageSchema } from "./types"
|
import { TeamInboxMessage, TeamInboxMessageSchema } from "./types"
|
||||||
|
|
||||||
const TeamInboxListSchema = z.array(TeamInboxMessageSchema)
|
const TeamInboxListSchema = z.array(TeamInboxMessageSchema)
|
||||||
@ -10,7 +11,22 @@ function nowIso(): string {
|
|||||||
return new Date().toISOString()
|
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<T>(teamName: string, operation: () => T): T {
|
function withInboxLock<T>(teamName: string, operation: () => T): T {
|
||||||
|
assertValidTeamName(teamName)
|
||||||
const inboxDir = getTeamInboxDir(teamName)
|
const inboxDir = getTeamInboxDir(teamName)
|
||||||
ensureDir(inboxDir)
|
ensureDir(inboxDir)
|
||||||
const lock = acquireLock(inboxDir)
|
const lock = acquireLock(inboxDir)
|
||||||
@ -36,6 +52,8 @@ function parseInboxFile(content: string): TeamInboxMessage[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function readInboxMessages(teamName: string, agentName: string): TeamInboxMessage[] {
|
function readInboxMessages(teamName: string, agentName: string): TeamInboxMessage[] {
|
||||||
|
assertValidTeamName(teamName)
|
||||||
|
assertValidInboxAgentName(agentName)
|
||||||
const path = getTeamInboxPath(teamName, agentName)
|
const path = getTeamInboxPath(teamName, agentName)
|
||||||
if (!existsSync(path)) {
|
if (!existsSync(path)) {
|
||||||
return []
|
return []
|
||||||
@ -44,24 +62,30 @@ function readInboxMessages(teamName: string, agentName: string): TeamInboxMessag
|
|||||||
}
|
}
|
||||||
|
|
||||||
function writeInboxMessages(teamName: string, agentName: string, messages: TeamInboxMessage[]): void {
|
function writeInboxMessages(teamName: string, agentName: string, messages: TeamInboxMessage[]): void {
|
||||||
|
assertValidTeamName(teamName)
|
||||||
|
assertValidInboxAgentName(agentName)
|
||||||
const path = getTeamInboxPath(teamName, agentName)
|
const path = getTeamInboxPath(teamName, agentName)
|
||||||
writeFileSync(path, JSON.stringify(messages), "utf-8")
|
writeJsonAtomic(path, messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ensureInbox(teamName: string, agentName: string): void {
|
export function ensureInbox(teamName: string, agentName: string): void {
|
||||||
|
assertValidTeamName(teamName)
|
||||||
|
assertValidInboxAgentName(agentName)
|
||||||
withInboxLock(teamName, () => {
|
withInboxLock(teamName, () => {
|
||||||
const path = getTeamInboxPath(teamName, agentName)
|
const path = getTeamInboxPath(teamName, agentName)
|
||||||
if (!existsSync(path)) {
|
if (!existsSync(path)) {
|
||||||
writeFileSync(path, "[]", "utf-8")
|
writeJsonAtomic(path, [])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function appendInboxMessage(teamName: string, agentName: string, message: TeamInboxMessage): void {
|
export function appendInboxMessage(teamName: string, agentName: string, message: TeamInboxMessage): void {
|
||||||
|
assertValidTeamName(teamName)
|
||||||
|
assertValidInboxAgentName(agentName)
|
||||||
withInboxLock(teamName, () => {
|
withInboxLock(teamName, () => {
|
||||||
const path = getTeamInboxPath(teamName, agentName)
|
const path = getTeamInboxPath(teamName, agentName)
|
||||||
if (!existsSync(path)) {
|
if (!existsSync(path)) {
|
||||||
writeFileSync(path, "[]", "utf-8")
|
writeJsonAtomic(path, [])
|
||||||
}
|
}
|
||||||
const messages = readInboxMessages(teamName, agentName)
|
const messages = readInboxMessages(teamName, agentName)
|
||||||
messages.push(TeamInboxMessageSchema.parse(message))
|
messages.push(TeamInboxMessageSchema.parse(message))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user