import test from "node:test"; import assert from "node:assert/strict"; import os from "node:os"; import path from "node:path"; import { mkdtemp, rm } from "node:fs/promises"; import type { Device, MasterAgentTask } from "../src/lib/boss-data"; let runtimeRoot = ""; let data: typeof import("../src/lib/boss-data"); async function setup() { if (runtimeRoot) return; runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-master-task-reliability-")); process.env.BOSS_RUNTIME_ROOT = runtimeRoot; process.env.BOSS_STATE_FILE = path.join(runtimeRoot, "boss-state.json"); data = await import("../src/lib/boss-data.ts"); } test.after(async () => { if (runtimeRoot) await rm(runtimeRoot, { recursive: true, force: true }); }); function makeQueuedTask(taskId: string, overrides: Partial = {}): MasterAgentTask { return { taskId, projectId: "master-agent", taskType: "conversation_reply", requestMessageId: `${taskId}-request`, requestText: "回复一句收到", executionPrompt: "回复一句收到", requestedBy: "Boss 测试", requestedByAccount: "krisolo", deviceId: "mac-studio", status: "queued", requestedAt: new Date().toISOString(), ...overrides, }; } test("master agent task claim, progress, and complete maintain reliability phase", async () => { await setup(); const state = await data.readState(); state.masterAgentTasks.unshift(makeQueuedTask("task-phase-normal")); await data.writeState(state); const claimed = await data.claimNextMasterAgentTask("mac-studio"); assert.equal(claimed?.taskId, "task-phase-normal"); assert.equal(claimed?.status, "running"); assert.equal(claimed?.phase, "claimed"); assert.ok(claimed?.lastProgressAt); const progressed = await data.updateMasterAgentTaskProgress({ taskId: "task-phase-normal", deviceId: "mac-studio", status: "running", phase: "awaiting_reply", }); assert.equal(progressed.status, "running"); assert.equal(progressed.phase, "awaiting_reply"); assert.ok(progressed.leaseExpiresAt); const completed = await data.completeMasterAgentTask({ taskId: "task-phase-normal", deviceId: "mac-studio", status: "completed", replyBody: "收到。", }); assert.equal(completed.status, "completed"); assert.equal(completed.phase, "completed"); assert.equal(completed.recoverable, false); }); test("expired pre-turn task is safely requeued and claimed again", async () => { await setup(); const state = await data.readState(); state.masterAgentTasks.unshift( makeQueuedTask("task-phase-retry", { status: "running", phase: "executor_starting", claimedAt: "2020-01-01T08:00:00.000Z", lastProgressAt: "2020-01-01T08:00:00.000Z", leaseExpiresAt: "2020-01-01T08:01:00.000Z", attemptCount: 1, maxAttempts: 2, }), ); await data.writeState(state); const claimed = await data.claimNextMasterAgentTask("mac-studio"); assert.equal(claimed?.taskId, "task-phase-retry"); assert.equal(claimed?.status, "running"); assert.equal(claimed?.phase, "claimed"); assert.equal(claimed?.attemptCount, 2); assert.equal(claimed?.recoverable, false); }); test("expired task after turn start is timed out instead of duplicated", async () => { await setup(); const state = await data.readState(); state.masterAgentTasks.unshift( makeQueuedTask("task-phase-no-duplicate", { status: "running", phase: "turn_started", claimedAt: "2020-01-01T08:00:00.000Z", lastProgressAt: "2020-01-01T08:00:00.000Z", leaseExpiresAt: "2020-01-01T08:01:00.000Z", attemptCount: 1, maxAttempts: 2, }), ); await data.writeState(state); const claimed = await data.claimNextMasterAgentTask("mac-studio"); assert.notEqual(claimed?.taskId, "task-phase-no-duplicate"); const nextState = await data.readState(); const task = nextState.masterAgentTasks.find((item) => item.taskId === "task-phase-no-duplicate"); assert.equal(task?.status, "timed_out"); assert.equal(task?.phase, "timed_out"); assert.equal(task?.recoverable, false); }); test("recoverable codex app-server runtime failure requeues conversation reply", async () => { await setup(); const state = await data.readState(); state.masterAgentTasks.unshift( makeQueuedTask("task-runtime-retry", { projectId: "project-juyuwan", targetProjectId: "project-juyuwan", targetThreadId: "thread-juyuwan", status: "running", phase: "awaiting_reply", claimedAt: "2026-06-07T06:05:16.000Z", lastProgressAt: "2026-06-07T06:10:00.000Z", leaseExpiresAt: "2026-06-07T06:20:16.000Z", attemptCount: 1, maxAttempts: 2, }), ); await data.writeState(state); const completed = await data.completeMasterAgentTask({ taskId: "task-runtime-retry", deviceId: "mac-studio", status: "failed", errorMessage: "CODEX_APP_SERVER_TURN_INTERRUPTED", }); assert.equal(completed.status, "queued"); assert.equal(completed.phase, "recoverable_failed"); assert.equal(completed.recoverable, true); assert.equal(completed.errorMessage, "CODEX_APP_SERVER_TURN_INTERRUPTED"); assert.equal(completed.attemptCount, 1); assert.equal(completed.completedAt, undefined); assert.equal(completed.claimedAt, undefined); assert.ok(completed.nextRetryAt); const claimed = await data.claimNextMasterAgentTask("mac-studio"); assert.equal(claimed?.taskId, "task-runtime-retry"); assert.equal(claimed?.attemptCount, 2); }); test("recoverable codex app-server runtime failure becomes terminal after max attempts", async () => { await setup(); const state = await data.readState(); state.masterAgentTasks.unshift( makeQueuedTask("task-runtime-terminal", { projectId: "project-juyuwan", targetProjectId: "project-juyuwan", targetThreadId: "thread-juyuwan", status: "running", phase: "awaiting_reply", claimedAt: "2026-06-07T06:05:16.000Z", lastProgressAt: "2026-06-07T06:10:00.000Z", leaseExpiresAt: "2026-06-07T06:20:16.000Z", attemptCount: 2, maxAttempts: 2, }), ); await data.writeState(state); const completed = await data.completeMasterAgentTask({ taskId: "task-runtime-terminal", deviceId: "mac-studio", status: "failed", errorMessage: "CODEX_APP_SERVER_TIMEOUT", }); assert.equal(completed.status, "failed"); assert.equal(completed.phase, "terminal_failed"); assert.equal(completed.recoverable, false); assert.equal(completed.errorMessage, "CODEX_APP_SERVER_TIMEOUT"); assert.equal(completed.completedAt !== undefined, true); }); test("codex app server health distinguishes available, degraded, and unavailable", async () => { await setup(); assert.equal(data.resolveCodexAppServerHealth(undefined), "unavailable"); assert.equal( data.resolveCodexAppServerHealth({ id: "device-offline", name: "离线设备", avatar: "D", account: "krisolo", source: "production", status: "offline", projects: [], quota5h: 0, quota7d: 0, lastSeenAt: "2026-06-06T08:00:00.000Z", endpoint: "", token: "", note: "", capabilities: { codexAppServer: { connected: false, lastSeenAt: "2026-06-06T08:00:00.000Z", }, }, } satisfies Device), "unavailable", ); assert.equal( data.resolveCodexAppServerHealth({ id: "device-degraded", name: "降级设备", avatar: "D", account: "krisolo", source: "production", status: "online", projects: [], quota5h: 0, quota7d: 0, lastSeenAt: new Date().toISOString(), endpoint: "", token: "", note: "", capabilities: { codexAppServer: { connected: true, lastSeenAt: new Date().toISOString(), metadata: { errors: ["thread/turns/list:STDIN_CLOSED"] }, }, }, } satisfies Device), "degraded", ); assert.equal( data.resolveCodexAppServerHealth({ id: "device-available", name: "可用设备", avatar: "D", account: "krisolo", source: "production", status: "online", projects: [], quota5h: 0, quota7d: 0, lastSeenAt: new Date().toISOString(), endpoint: "", token: "", note: "", capabilities: { codexAppServer: { connected: true, lastSeenAt: new Date().toISOString(), metadata: {}, }, }, } satisfies Device), "available", ); });