Files
boss/tests/device-detail-capabilities-route.test.ts

244 lines
9.9 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 读取", "共享保存", "共享拉取", "共享删除", "共享目标", "共享列表"],
},
},
},
};
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 读取可用");
});
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, "仅作用于当前异常项目 / 文件夹");
});