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

356 lines
15 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 放行", "权限请求"],
},
},
},
};
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 项 · 权限事件可用");
});
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, "仅作用于当前异常项目 / 文件夹");
});