Files
boss/tests/device-detail-capabilities-route.test.ts
2026-06-03 12:37:23 +08:00

391 lines
17 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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", "取消订阅"],
},
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, "Hook2 个 · 启用 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.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, "仅作用于当前异常项目 / 文件夹");
});