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 applyProjectConflictDecision: (typeof import("../src/lib/boss-data"))["applyProjectConflictDecision"]; let getDeviceWorkspaceView: (typeof import("../src/lib/boss-projections"))["getDeviceWorkspaceView"]; let buildDeviceWorkspaceDetailCards: (typeof import("../src/components/app-ui"))["buildDeviceWorkspaceDetailCards"]; async function setup() { if (runtimeRoot) return; runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-device-detail-route-")); process.env.BOSS_RUNTIME_ROOT = runtimeRoot; process.env.BOSS_STATE_FILE = path.join(runtimeRoot, "boss-state.json"); const [data, projections, ui] = await Promise.all([ import("../src/lib/boss-data.ts"), import("../src/lib/boss-projections.ts"), import("../src/components/app-ui.tsx"), ]); readState = data.readState; writeState = data.writeState; applyProjectConflictDecision = data.applyProjectConflictDecision; getDeviceWorkspaceView = projections.getDeviceWorkspaceView; buildDeviceWorkspaceDetailCards = ui.buildDeviceWorkspaceDetailCards; } test.after(async () => { if (runtimeRoot) { await rm(runtimeRoot, { recursive: true, force: true }); } }); test("device detail exposes gui cli capability state and preferred execution mode", async () => { await setup(); const state = await readState(); const workspace = getDeviceWorkspaceView(state, "mac-studio"); const cards = buildDeviceWorkspaceDetailCards(workspace); assert.equal(cards.capabilities.title, "执行能力"); assert.equal(cards.capabilities.items.gui, "GUI:已连接"); assert.equal(cards.capabilities.items.cli, "CLI:已连接"); assert.equal(cards.capabilities.items.preferredExecutionMode, "默认执行模式:CLI"); }); test("device detail exposes Codex App Server discovered model and extension summary", async () => { await setup(); const state = await readState(); const device = state.devices.find((item) => item.id === "mac-studio"); assert.ok(device); device!.capabilities = { ...(device!.capabilities ?? {}), codexAppServer: { connected: true, lastSeenAt: "2026-05-31T10:00:00.000Z", lastActiveProjectId: "", metadata: { models: [ { id: "gpt-5.4", displayName: "GPT-5.4" }, { id: "gpt-5.4-mini", displayName: "GPT-5.4 mini" }, ], defaultModelId: "gpt-5.4", fastModelId: "gpt-5.4-mini", deepModelId: "gpt-5.4", skills: [{ name: "image2-ui-prototype" }], plugins: [{ id: "github" }], apps: [{ id: "canva" }], experimentalFeatures: [ { name: "multi_agent", stage: "stable", enabled: true }, { name: "apps", stage: "beta", enabled: false }, ], collaborationModes: [{ id: "solo" }, { id: "plan" }], permissionProfiles: [{ id: ":workspace" }], mcpServers: [ { name: "github", toolCount: 2, authStatus: "oAuth" }, { name: "figma", toolCount: 0, authStatus: "notLoggedIn" }, ], accountSummary: { signedIn: true, authMode: "chatgpt", planType: "pro", requiresOpenaiAuth: true }, rateLimitSummary: { bucketCount: 2, maxUsedPercent: 42, reached: false }, appConfigSummary: { appCount: 2, enabledAppCount: 1, defaultEnabled: true, destructiveEnabled: false, openWorldEnabled: false, }, configRequirements: { managed: true, requirementCount: 2, warningCount: 1 }, externalAgentMigration: { itemCount: 3, homeItemCount: 1, projectItemCount: 2, itemTypes: ["AGENTS_MD", "MCP_SERVER_CONFIG", "SKILLS"], }, skillExtraRootsSummary: { configured: true, status: "applied", rootCount: 2, rootLabels: ["boss-shared-skills", "team-skills"], }, hookSummary: { workspaceCount: 1, hookCount: 2, enabledHookCount: 1, managedHookCount: 1, trustedHookCount: 1, modifiedHookCount: 1, untrustedHookCount: 0, warningCount: 1, errorCount: 1, eventNames: ["PreToolUse", "SessionStart"], handlerTypes: ["command", "prompt"], }, threadSummary: { threadCount: 3, loadedThreadCount: 2, activeThreadCount: 1, archivedThreadCount: 1, latestUpdatedAt: "2026-06-03T08:20:00.000Z", sourceKinds: ["app", "cli"], visibleThreads: [ { id: "thr-active", name: "Boss App Server rollout", sourceKind: "app", status: "active", archived: false, loaded: true, updatedAt: "2026-06-03T08:20:00.000Z", }, ], }, threadTurnSummary: { threadCount: 2, totalTurnCount: 3, runningTurnCount: 1, completedTurnCount: 2, latestUpdatedAt: "2026-06-03T08:21:00.000Z", threads: [ { threadId: "thr-active", turnCount: 2, runningTurnCount: 1, completedTurnCount: 1, latestTurnStatus: "running", latestTurnUpdatedAt: "2026-06-03T08:21:00.000Z", }, ], }, threadActionSummary: { actionCount: 11, lifecycleActionCount: 5, metadataActionCount: 2, liveTurnActionCount: 2, shellActionAvailable: true, userInitiatedOnly: true, labels: ["归档", "恢复", "分叉", "压缩", "回滚", "改名", "元数据", "活跃干预", "中断", "Shell", "取消订阅"], }, threadCollaborationSummary: { bossBrokerAvailable: true, collabToolCallHandlerAvailable: true, directThreadChatSupported: false, collaborationModeCount: 2, userInitiatedOnly: true, labels: ["源线程读取", "上下文注入", "目标线程执行", "协作事件"], }, protocolDriftSummary: { driftLevel: "compatible", compatibilityMode: "runtime-probe", failedProbeCount: 0, runtimeFailureMethods: [], docFollowupCount: 3, docFollowupItems: ["collaborationMode/list", "thread/turns/list", "ThreadItem.collabToolCall"], fallbackStrategy: "Boss Broker + App Server 注入/执行", userInitiatedOnly: true, labels: ["运行时探测", "官方文档跟进", "Boss Broker 兜底"], }, pluginGovernanceSummary: { actionCount: 9, lifecycleActionCount: 2, shareActionCount: 4, readActionCount: 3, skillReadAvailable: true, userInitiatedOnly: true, labels: ["安装", "卸载", "读取", "Skill 读取", "共享保存", "共享拉取", "共享删除", "共享目标", "共享列表"], }, accountGovernanceSummary: { actionCount: 6, loginActionCount: 3, sessionActionCount: 1, tokenRefreshAvailable: true, billingNudgeAvailable: true, userInitiatedOnly: true, labels: ["登录开始", "登录取消", "登录完成", "退出登录", "刷新令牌", "额度提醒"], }, configGovernanceSummary: { actionCount: 5, writeActionCount: 3, reloadActionCount: 1, readActionAvailable: true, userInitiatedOnly: true, labels: ["配置读取", "单项写入", "批量写入", "MCP 重载", "Skill 配置"], }, fileSystemGovernanceSummary: { actionCount: 9, readActionCount: 3, writeActionCount: 3, destructiveActionCount: 1, watchActionCount: 2, userInitiatedOnly: true, labels: ["读取文件", "读取目录", "元数据", "写入文件", "创建目录", "复制", "删除", "监听", "取消监听"], }, commandSessionSummary: { actionCount: 5, controlActionCount: 3, streamAvailable: true, terminationAvailable: true, sandboxedCommandAvailable: true, userInitiatedOnly: true, labels: ["执行命令", "写入 stdin", "调整 PTY", "终止命令", "输出流"], }, externalAgentGovernanceSummary: { actionCount: 3, importActionCount: 1, notificationActionCount: 1, detectActionAvailable: true, userInitiatedOnly: true, labels: ["迁移检测", "迁移导入", "导入完成"], }, marketplaceGovernanceSummary: { actionCount: 3, writeActionCount: 3, upgradeAvailable: true, userInitiatedOnly: true, labels: ["添加市场", "移除市场", "升级市场"], }, experimentalFeatureGovernanceSummary: { actionCount: 2, writeActionCount: 1, listAvailable: true, userInitiatedOnly: true, labels: ["实验列表", "启用设置"], }, reviewGovernanceSummary: { actionCount: 1, reviewStartAvailable: true, userInitiatedOnly: true, labels: ["启动审查"], }, windowsSandboxGovernanceSummary: { actionCount: 3, setupActionCount: 1, readinessAvailable: true, notificationAvailable: true, userInitiatedOnly: true, labels: ["准备检查", "启动设置", "设置完成"], }, fuzzyFileSearchSummary: { eventCount: 2, completedEventAvailable: true, notificationOnly: true, labels: ["搜索更新", "搜索完成"], }, mcpGovernanceSummary: { actionCount: 5, oauthActionCount: 2, resourceActionCount: 1, toolActionCount: 1, elicitationAvailable: true, userInitiatedOnly: true, labels: ["OAuth 登录", "OAuth 完成", "资源读取", "工具调用", "交互请求"], }, userInteractionGovernanceSummary: { actionCount: 1, requestUserInputAvailable: true, userInitiatedOnly: true, labels: ["请求用户输入"], }, guardianGovernanceSummary: { actionCount: 2, approvalActionCount: 1, permissionRequestEventAvailable: true, userInitiatedOnly: true, labels: ["Guardian 放行", "权限请求"], }, runtimeEventSummary: { eventCount: 3, processEventCount: 2, rawResponseEventAvailable: true, notificationOnly: true, labels: ["进程输出", "进程退出", "原始响应完成"], }, extensionEventSummary: { eventCount: 2, skillChangeEventAvailable: true, pluginInstallEventAvailable: true, notificationOnly: true, labels: ["Skill 变更", "插件安装"], }, threadLifecycleEventSummary: { eventCount: 5, archiveEventCount: 2, nameEventAvailable: true, closeEventAvailable: true, notificationOnly: true, labels: ["线程启动", "线程关闭", "已归档", "已恢复", "改名完成"], }, streamDeltaEventSummary: { eventCount: 9, reasoningDeltaEventCount: 3, commandStreamEventCount: 2, toolProgressEventAvailable: true, fileChangeOutputEventAvailable: true, notificationOnly: true, labels: ["Agent 增量", "计划增量", "思考新增", "思考文本", "原始思考", "MCP 进度", "命令输出", "终端交互", "文件输出"], }, }, }, }; await writeState(state); const workspace = getDeviceWorkspaceView(await readState(), "mac-studio"); const cards = buildDeviceWorkspaceDetailCards(workspace); assert.equal(cards.capabilities.items.codexAppServer, "Codex App Server:已连接"); assert.equal(cards.capabilities.items.codexModels, "模型:2 个 · 默认 gpt-5.4 · 快速 gpt-5.4-mini · 深度 gpt-5.4"); assert.equal(cards.capabilities.items.codexExtensions, "扩展:Skill 1 个 · Plugin 1 个 · App 1 个"); assert.equal(cards.capabilities.items.codexGovernance, "治理:实验特性 2 个 · 协作模式 2 个 · MCP 2 个 · 权限 1 个"); assert.equal(cards.capabilities.items.codexAccount, "账号:chatgpt · 套餐 pro · 额度 42%"); assert.equal(cards.capabilities.items.codexConfig, "配置:App 2 个 · 已启用 1 个 · 托管要求 2 个 · 外部迁移 3 项"); assert.equal(cards.capabilities.items.codexSkillRoots, "共享 Skill 根:2 个 · 已下发"); assert.equal(cards.capabilities.items.codexHooks, "Hook:2 个 · 启用 1 个 · 警告 1 个"); assert.equal(cards.capabilities.items.codexThreads, "线程:3 个 · 已加载 2 个 · 活跃 1 个 · 最新 2026-06-03 16:20"); assert.equal(cards.capabilities.items.codexTurns, "轮次:3 个 · 运行中 1 个 · 完成 2 个 · 最新 2026-06-03 16:21"); assert.equal(cards.capabilities.items.codexThreadActions, "线程操作:11 项 · 生命周期 5 项 · 活跃干预 2 项 · Shell 可用"); assert.equal(cards.capabilities.items.codexThreadCollaboration, "线程协作:Boss Broker 可用 · 协作事件可处理 · 2 种模式 · 非原生私聊"); assert.equal(cards.capabilities.items.codexProtocolDrift, "协议漂移:兼容 · 失败探针 0 个 · 文档跟进 3 项 · Boss Broker 兜底"); assert.equal(cards.capabilities.items.codexPluginGovernance, "插件治理:9 项 · 安装/卸载 2 项 · 共享 4 项 · Skill 读取可用"); assert.equal(cards.capabilities.items.codexAccountGovernance, "账号治理:6 项 · 登录 3 项 · 令牌刷新可用 · 额度提醒可用"); assert.equal(cards.capabilities.items.codexConfigGovernance, "配置治理:5 项 · 写入 3 项 · 重载 1 项 · 读取可用"); assert.equal(cards.capabilities.items.codexFileSystemGovernance, "文件治理:9 项 · 读 3 项 · 写 3 项 · 监听 2 项"); assert.equal(cards.capabilities.items.codexCommandSession, "命令会话:5 项 · 控制 3 项 · 输出流可用 · 可终止"); assert.equal(cards.capabilities.items.codexExternalAgentGovernance, "迁移治理:3 项 · 导入 1 项 · 检测可用"); assert.equal(cards.capabilities.items.codexMarketplaceGovernance, "市场治理:3 项 · 写入 3 项 · 升级可用"); assert.equal(cards.capabilities.items.codexExperimentalFeatureGovernance, "实验特性治理:2 项 · 写入 1 项 · 列表可用"); assert.equal(cards.capabilities.items.codexReviewGovernance, "审查治理:1 项 · 审查可启动"); assert.equal(cards.capabilities.items.codexWindowsSandboxGovernance, "Windows 沙箱:3 项 · 设置 1 项 · 准备检查可用"); assert.equal(cards.capabilities.items.codexFuzzyFileSearch, "文件搜索事件:2 项 · 完成事件可用"); assert.equal(cards.capabilities.items.codexMcpGovernance, "MCP 治理:5 项 · OAuth 2 项 · 工具 1 项 · 交互可用"); assert.equal(cards.capabilities.items.codexUserInteractionGovernance, "用户交互:1 项 · 输入请求可用"); assert.equal(cards.capabilities.items.codexGuardianGovernance, "Guardian 治理:2 项 · 审批 1 项 · 权限事件可用"); assert.equal(cards.capabilities.items.codexRuntimeEvents, "运行事件:3 项 · 进程 2 项 · 原始响应可用"); assert.equal(cards.capabilities.items.codexExtensionEvents, "扩展事件:2 项 · Skill 变更可用 · 插件安装可用"); assert.equal(cards.capabilities.items.codexThreadLifecycleEvents, "线程生命周期:5 项 · 归档 2 项 · 改名可用 · 关闭可用"); assert.equal(cards.capabilities.items.codexStreamDeltaEvents, "流式增量:9 项 · 思考 3 项 · 命令 2 项 · MCP 进度可用 · 文件输出可用"); }); test("device detail exposes folder and project conflict skeleton from workspace policy", async () => { await setup(); const state = await readState(); state.projectExecutionPolicies = [ { deviceId: "mac-studio", folderKey: "mac-studio:boss", projectId: "thread-ui", allowPolicy: "allow_always", conflictState: "warning", updatedAt: "2026-04-06T12:00:00.000Z", }, ]; await writeState(state); const workspace = getDeviceWorkspaceView(await readState(), "mac-studio"); const cards = buildDeviceWorkspaceDetailCards(workspace); assert.equal(cards.conflicts.title, "异常项目 / 文件夹冲突"); assert.equal(cards.conflicts.headerHint, "已接入,可直接调整"); assert.equal(cards.conflicts.items.device, "设备:Mac Studio"); assert.equal(cards.conflicts.items.folderKey, "文件夹:mac-studio:boss"); assert.equal(cards.conflicts.items.projectId, "项目:thread-ui"); assert.equal(cards.conflicts.items.allowPolicy, "当前策略:永久放行"); assert.equal(cards.conflicts.items.conflictState, "冲突态:存在并行风险"); }); test("device detail conflict card keeps project-scoped actions on the active folder only", async () => { await setup(); await applyProjectConflictDecision({ deviceId: "mac-studio", folderKey: "mac-studio:boss", projectId: "thread-ui", decision: "allow_once", }); const workspace = getDeviceWorkspaceView(await readState(), "mac-studio"); const cards = buildDeviceWorkspaceDetailCards(workspace); assert.equal(cards.conflicts.headerHint, "已接入,可直接调整"); assert.equal(cards.conflicts.items.allowPolicy, "当前策略:允许本次"); assert.equal(cards.conflicts.items.conflictState, "冲突态:存在并行风险"); assert.deepEqual(cards.conflicts.actions, ["禁止", "允许本次", "永久放行"]); assert.equal(cards.conflicts.scopeLabel, "仅作用于当前异常项目 / 文件夹"); });