chore: checkpoint Boss app v2.5.11
This commit is contained in:
@@ -5,6 +5,7 @@ import { BOSS_PERMISSION_TEMPLATES } from "@/lib/boss-access-templates";
|
||||
import { buildAdminOverview } from "@/lib/boss-admin-overview";
|
||||
import { readState, type BossState } from "@/lib/boss-data";
|
||||
import { getBossStateBackupStatus, type BossStateBackupStatus } from "@/lib/boss-state-backups";
|
||||
import { buildMasterAgentTaskSlaRows, type MasterAgentTaskSlaLevel } from "@/lib/master-agent-task-sla";
|
||||
|
||||
const PLATFORM_MENU_TREE = [
|
||||
{ key: "platform-overview", label: "平台总览" },
|
||||
@@ -286,35 +287,28 @@ function canRecoverActiveTask(task: BossState["masterAgentTasks"][number]) {
|
||||
function buildTaskRiskSummary(state: BossState) {
|
||||
const activeStatuses = new Set(["queued", "running", "needs_user_action"]);
|
||||
const activeTasks = state.masterAgentTasks.filter((task) => activeStatuses.has(task.status));
|
||||
const rows = activeTasks
|
||||
.map((task) => {
|
||||
const activeAt = task.lastProgressAt ?? task.claimedAt ?? task.requestedAt;
|
||||
const ageMinutes = minutesSince(activeAt);
|
||||
const stale = ageMinutes !== null && ageMinutes > 10;
|
||||
const recoverable = canRecoverActiveTask(task);
|
||||
return {
|
||||
taskId: task.taskId,
|
||||
projectId: task.projectId,
|
||||
deviceId: task.deviceId,
|
||||
status: task.status,
|
||||
phase: task.phase ?? task.status,
|
||||
stale,
|
||||
recoverable,
|
||||
lastProgressAt: task.lastProgressAt ?? "",
|
||||
summary: task.requestText || task.errorMessage || task.taskType,
|
||||
};
|
||||
})
|
||||
.sort((left, right) => Number(right.stale) - Number(left.stale) || right.taskId.localeCompare(left.taskId))
|
||||
const rows = buildMasterAgentTaskSlaRows(state)
|
||||
.filter((row) => activeStatuses.has(row.status))
|
||||
.map((row) => ({
|
||||
taskId: row.taskId,
|
||||
projectId: row.projectId,
|
||||
deviceId: row.deviceId,
|
||||
status: row.status,
|
||||
phase: row.phase,
|
||||
stale: row.stale,
|
||||
recoverable: row.recoverable || canRecoverActiveTask(state.masterAgentTasks.find((task) => task.taskId === row.taskId)!),
|
||||
lastProgressAt: row.lastProgressAt,
|
||||
summary: row.summary,
|
||||
slaLevel: row.slaLevel,
|
||||
slaDueAt: row.slaDueAt,
|
||||
recommendedAction: row.recommendedAction,
|
||||
}))
|
||||
.slice(0, 20);
|
||||
|
||||
return {
|
||||
counts: {
|
||||
active: activeTasks.length,
|
||||
stale: activeTasks.filter((task) => {
|
||||
const activeAt = task.lastProgressAt ?? task.claimedAt ?? task.requestedAt;
|
||||
const ageMinutes = minutesSince(activeAt);
|
||||
return ageMinutes !== null && ageMinutes > 10;
|
||||
}).length,
|
||||
stale: rows.filter((row) => row.stale).length,
|
||||
recoverable: activeTasks.filter(canRecoverActiveTask).length,
|
||||
needsUserAction: activeTasks.filter((task) => task.status === "needs_user_action" || task.phase === "needs_user_action").length,
|
||||
},
|
||||
@@ -322,6 +316,25 @@ function buildTaskRiskSummary(state: BossState) {
|
||||
};
|
||||
}
|
||||
|
||||
function buildTaskSlaPanel(state: BossState) {
|
||||
const rows = buildMasterAgentTaskSlaRows(state).slice(0, 50);
|
||||
const countByLevel = (level: MasterAgentTaskSlaLevel) => rows.filter((row) => row.slaLevel === level).length;
|
||||
return {
|
||||
generatedAt: new Date().toISOString(),
|
||||
summary: {
|
||||
total: rows.length,
|
||||
active: rows.filter((row) => row.status === "queued" || row.status === "running" || row.status === "needs_user_action").length,
|
||||
ok: countByLevel("ok"),
|
||||
watch: countByLevel("watch"),
|
||||
breached: countByLevel("breached"),
|
||||
recoverable: countByLevel("recoverable"),
|
||||
terminal: countByLevel("terminal"),
|
||||
autoRecoverable: rows.filter((row) => row.autoRecoverable).length,
|
||||
},
|
||||
rows,
|
||||
};
|
||||
}
|
||||
|
||||
function buildBackofficeInsights(state: BossState, options: { surface: BackofficeSurface; backupStatus: BossStateBackupStatus }) {
|
||||
const overview = buildAdminOverview(state);
|
||||
const devices = state.devices;
|
||||
@@ -378,6 +391,10 @@ function buildBackofficeInsights(state: BossState, options: { surface: Backoffic
|
||||
label: "主 Agent 执行失败",
|
||||
value: riskAggregateValue(overview.risks, (risk) => risk.kind === "master_agent_task_failed"),
|
||||
},
|
||||
{
|
||||
label: "任务 SLA 告警",
|
||||
value: riskAggregateValue(overview.risks, (risk) => risk.kind === "master_agent_task_sla"),
|
||||
},
|
||||
{
|
||||
label: "Computer Use 权限缺失",
|
||||
value: riskAggregateValue(overview.risks, (risk) => /Computer Use|权限/.test(risk.title)),
|
||||
@@ -434,6 +451,7 @@ function buildBackofficeInsights(state: BossState, options: { surface: Backoffic
|
||||
},
|
||||
dataSafetySummary: buildDataSafetySummary(options.backupStatus),
|
||||
taskRiskSummary: buildTaskRiskSummary(state),
|
||||
taskSlaPanel: buildTaskSlaPanel(state),
|
||||
capabilitySummary: {
|
||||
guiReady,
|
||||
cliReady,
|
||||
|
||||
Reference in New Issue
Block a user