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"; let runtimeRoot = ""; let readState: (typeof import("../src/lib/boss-data"))["readState"]; let writeState: (typeof import("../src/lib/boss-data"))["writeState"]; let appendAppLog: (typeof import("../src/lib/boss-data"))["appendAppLog"]; const leakedPrompt = [ "管理员全局主提示词:", "你是 Boss 控制台的主 Agent。", "默认只说和当前问题直接相关的判断、动作和风险。", "", "用户私有主提示词:", "默认中文回复。", "", "当前对话附加提示词:", "同步项目目标和版本记录后记得告诉我。", "", "当前消息:", "同步完成记得要和我说,以后也是这样。", ].join("\n"); async function setup() { if (runtimeRoot) { return; } runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-runtime-leak-redaction-")); process.env.BOSS_RUNTIME_ROOT = runtimeRoot; process.env.BOSS_STATE_FILE = path.join(runtimeRoot, "boss-state.json"); const data = await import("../src/lib/boss-data.ts"); readState = data.readState; writeState = data.writeState; appendAppLog = data.appendAppLog; } test.after(async () => { if (runtimeRoot) { await rm(runtimeRoot, { recursive: true, force: true }); } }); test("读取已有状态时会清洗历史提示词泄漏内容", async () => { await setup(); const state = await readState(); const masterProject = state.projects.find((project) => project.id === "master-agent"); assert.ok(masterProject, "expected a master-agent project"); masterProject.messages.push({ id: "msg-leak-1", sender: "ops", senderLabel: "主 Agent Relay", body: `Master Codex Node 执行失败:\n${leakedPrompt}`, sentAt: "2026-04-19T08:35:01.079Z", kind: "text", }); masterProject.preview = leakedPrompt; state.masterAgentTasks.unshift({ taskId: "task-leak-1", projectId: "master-agent", taskType: "conversation_reply", requestMessageId: "msg-user-1", requestText: "同步完成记得要和我说,以后也是这样。", executionPrompt: leakedPrompt, requestedBy: "Boss 超级管理员", requestedByAccount: "krisolo", deviceId: "mac-studio", status: "failed", requestedAt: "2026-04-19T08:35:01.079Z", errorMessage: leakedPrompt, }); state.appLogs.unshift({ logId: "log-leak-1", deviceId: "mac-studio", projectId: "master-agent", level: "error", source: "local_agent", category: "local_agent.master_agent_task_failed", message: "Master Codex Node 执行主 Agent 任务失败:task-leak-1", detail: leakedPrompt, mirroredToProject: true, createdAt: "2026-04-19T08:35:01.079Z", }); await writeState(state); const nextState = await readState(); const nextMasterProject = nextState.projects.find((project) => project.id === "master-agent"); assert.ok(nextMasterProject, "expected a reloaded master-agent project"); const leakedMessage = nextMasterProject.messages.find((message) => message.id === "msg-leak-1"); assert.ok(leakedMessage, "expected the historical message to remain"); assert.equal( /管理员全局主提示词:|用户私有主提示词:|当前对话附加提示词:/.test(leakedMessage.body), false, ); assert.match(leakedMessage.body, /已拦截内部执行日志|原始内容已隐藏/); assert.equal( /管理员全局主提示词:|用户私有主提示词:|当前对话附加提示词:/.test( nextMasterProject.preview ?? "", ), false, ); const sanitizedTask = nextState.masterAgentTasks.find((task) => task.taskId === "task-leak-1"); assert.equal(sanitizedTask?.errorMessage, "MASTER_CODEX_NODE_OUTPUT_LEAKED"); const sanitizedLog = nextState.appLogs.find((log) => log.logId === "log-leak-1"); assert.ok(sanitizedLog, "expected the historical app log to remain"); assert.equal( /管理员全局主提示词:|用户私有主提示词:|当前对话附加提示词:/.test( sanitizedLog?.detail ?? "", ), false, ); assert.match(sanitizedLog?.detail ?? "", /已拦截内部执行日志|原始内容不再展示/); }); test("local agent infrastructure failures stay out of master agent chat", async () => { await setup(); const state = await readState(); const device = state.devices[0]; assert.ok(device, "expected a seeded device"); const masterProject = state.projects.find((project) => project.id === "master-agent"); assert.ok(masterProject, "expected a master-agent project"); const beforeMessageCount = masterProject.messages.length; await writeState(state); const entry = await appendAppLog({ deviceId: device.id, level: "error", source: "local_agent", category: "local_agent.master_agent_task_failed", message: "Master Codex Node 执行失败:task-demo", detail: "Permission denied", mirrorToMaster: true, }); assert.equal(entry.mirroredToProject, false); const nextState = await readState(); const nextMasterProject = nextState.projects.find((project) => project.id === "master-agent"); assert.ok(nextMasterProject, "expected a reloaded master-agent project"); assert.equal(nextMasterProject.messages.length, beforeMessageCount); assert.ok( nextState.appLogs.some((log) => log.logId === entry.logId && log.category === "local_agent.master_agent_task_failed"), "expected the operational log to remain available outside chat", ); }); test("读取已有状态时会把历史 Codex App Server 错误码转成人类可读说明", async () => { await setup(); const state = await readState(); state.projects.push({ id: "project-runtime-error-redaction", name: "juyuwan", pinned: false, systemPinned: false, deviceIds: ["mac-studio"], preview: "juyuwan 执行失败:CODEX_APP_SERVER_TURN_INTERRUPTED", updatedAt: "2026-06-07T14:20:00+08:00", lastMessageAt: "2026-06-07T14:20:00+08:00", isGroup: false, threadMeta: { projectId: "project-runtime-error-redaction", threadId: "thread-runtime-error-redaction", threadDisplayName: "juyuwan", folderName: "juyuwan", activityIconCount: 0, updatedAt: "2026-06-07T14:20:00+08:00", codexThreadRef: "019e9b84-decc-7510-b84f-57c5a27de0e3", codexFolderRef: "juyuwan", }, groupMembers: [], createdByAgent: true, collaborationMode: "development", approvalState: "not_required", unreadCount: 1, riskLevel: "low", messages: [ { id: "msg-runtime-error-redaction", sender: "ops", senderLabel: "juyuwan", body: "juyuwan 执行失败:CODEX_APP_SERVER_TURN_INTERRUPTED", sentAt: "2026-06-07T14:20:00+08:00", kind: "text", }, ], goals: [], versions: [], }); await writeState(state); const nextState = await readState(); const project = nextState.projects.find((item) => item.id === "project-runtime-error-redaction"); assert.ok(project, "expected a reloaded project"); const message = project.messages.find((item) => item.id === "msg-runtime-error-redaction"); assert.ok(message, "expected the historical message to remain"); assert.equal(message.body.includes("CODEX_APP_SERVER_TURN_INTERRUPTED"), false); assert.equal(project.preview.includes("CODEX_APP_SERVER_TURN_INTERRUPTED"), false); assert.match(message.body, /Codex 桌面线程本轮被中断/); assert.match(project.preview, /Codex 桌面线程本轮被中断/); });