fix(agent-teams): move team existence check under lock
This commit is contained in:
parent
f4e4fdb2e4
commit
0ec6afcd9e
@ -22,12 +22,21 @@ import {
|
|||||||
TeamTeammateMember,
|
TeamTeammateMember,
|
||||||
isTeammateMember,
|
isTeammateMember,
|
||||||
} from "./types"
|
} from "./types"
|
||||||
|
import { validateTeamName } from "./name-validation"
|
||||||
|
|
||||||
function nowMs(): number {
|
function nowMs(): number {
|
||||||
return Date.now()
|
return Date.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function assertValidTeamName(teamName: string): void {
|
||||||
|
const validationError = validateTeamName(teamName)
|
||||||
|
if (validationError) {
|
||||||
|
throw new Error(validationError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function withTeamLock<T>(teamName: string, operation: () => T): T {
|
function withTeamLock<T>(teamName: string, operation: () => T): T {
|
||||||
|
assertValidTeamName(teamName)
|
||||||
const teamDir = getTeamDir(teamName)
|
const teamDir = getTeamDir(teamName)
|
||||||
ensureDir(teamDir)
|
ensureDir(teamDir)
|
||||||
const lock = acquireLock(teamDir)
|
const lock = acquireLock(teamDir)
|
||||||
@ -55,6 +64,7 @@ function createLeadMember(teamName: string, leadSessionId: string, cwd: string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function ensureTeamStorageDirs(teamName: string): void {
|
export function ensureTeamStorageDirs(teamName: string): void {
|
||||||
|
assertValidTeamName(teamName)
|
||||||
ensureDir(getTeamsRootDir())
|
ensureDir(getTeamsRootDir())
|
||||||
ensureDir(getTeamTasksRootDir())
|
ensureDir(getTeamTasksRootDir())
|
||||||
ensureDir(getTeamDir(teamName))
|
ensureDir(getTeamDir(teamName))
|
||||||
@ -63,6 +73,7 @@ export function ensureTeamStorageDirs(teamName: string): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function teamExists(teamName: string): boolean {
|
export function teamExists(teamName: string): boolean {
|
||||||
|
assertValidTeamName(teamName)
|
||||||
return existsSync(getTeamConfigPath(teamName))
|
return existsSync(getTeamConfigPath(teamName))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,10 +86,6 @@ export function createTeamConfig(
|
|||||||
): TeamConfig {
|
): TeamConfig {
|
||||||
ensureTeamStorageDirs(teamName)
|
ensureTeamStorageDirs(teamName)
|
||||||
|
|
||||||
if (teamExists(teamName)) {
|
|
||||||
throw new Error("team_already_exists")
|
|
||||||
}
|
|
||||||
|
|
||||||
const leadAgentId = `team-lead@${teamName}`
|
const leadAgentId = `team-lead@${teamName}`
|
||||||
const config: TeamConfig = {
|
const config: TeamConfig = {
|
||||||
name: teamName,
|
name: teamName,
|
||||||
@ -90,12 +97,16 @@ export function createTeamConfig(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return withTeamLock(teamName, () => {
|
return withTeamLock(teamName, () => {
|
||||||
|
if (teamExists(teamName)) {
|
||||||
|
throw new Error("team_already_exists")
|
||||||
|
}
|
||||||
writeJsonAtomic(getTeamConfigPath(teamName), TeamConfigSchema.parse(config))
|
writeJsonAtomic(getTeamConfigPath(teamName), TeamConfigSchema.parse(config))
|
||||||
return config
|
return config
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function readTeamConfig(teamName: string): TeamConfig | null {
|
export function readTeamConfig(teamName: string): TeamConfig | null {
|
||||||
|
assertValidTeamName(teamName)
|
||||||
return readJsonSafe(getTeamConfigPath(teamName), TeamConfigSchema)
|
return readJsonSafe(getTeamConfigPath(teamName), TeamConfigSchema)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,6 +119,7 @@ export function readTeamConfigOrThrow(teamName: string): TeamConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function writeTeamConfig(teamName: string, config: TeamConfig): TeamConfig {
|
export function writeTeamConfig(teamName: string, config: TeamConfig): TeamConfig {
|
||||||
|
assertValidTeamName(teamName)
|
||||||
return withTeamLock(teamName, () => {
|
return withTeamLock(teamName, () => {
|
||||||
const validated = TeamConfigSchema.parse(config)
|
const validated = TeamConfigSchema.parse(config)
|
||||||
writeJsonAtomic(getTeamConfigPath(teamName), validated)
|
writeJsonAtomic(getTeamConfigPath(teamName), validated)
|
||||||
@ -146,6 +158,7 @@ export function assignNextColor(config: TeamConfig): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function deleteTeamData(teamName: string): void {
|
export function deleteTeamData(teamName: string): void {
|
||||||
|
assertValidTeamName(teamName)
|
||||||
const teamDir = getTeamDir(teamName)
|
const teamDir = getTeamDir(teamName)
|
||||||
const taskDir = getTeamTaskDir(teamName)
|
const taskDir = getTeamTaskDir(teamName)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user