diff --git a/app/src/adapt.js b/app/src/adapt.js
index bf4b21c..66d03e5 100644
--- a/app/src/adapt.js
+++ b/app/src/adapt.js
@@ -25,7 +25,7 @@ export function adaptProject(p) {
return {
id: p.id, name: p.name, path: shortPath(p.repoPath), branch: p.defaultBranch,
autonomy: p.autonomy, concurrency: p.concurrency, hue: hueFor(p.name),
- state, pending: s.attention || 0, agents: s.executing || 0,
+ state, pending: s.attention || 0, agents: s.executing || 0, blocked: s.blocked || 0,
// 透传给 ConfigPanel 用的原始字段
model: p.model, verifyCmd: p.verifyCmd, maxRetries: p.maxRetries, repoPath: p.repoPath,
logo: p.logo, budgetUsd: p.budgetUsd ?? null, budgetPeriod: p.budgetPeriod ?? 'month',
diff --git a/design/ui_kits/console/Sidebar.jsx b/design/ui_kits/console/Sidebar.jsx
index a6cbec3..a33e2a2 100644
--- a/design/ui_kits/console/Sidebar.jsx
+++ b/design/ui_kits/console/Sidebar.jsx
@@ -48,6 +48,17 @@ function projStateMeta(state, t) {
})[state] || { color: 'var(--muted)', pulse: false, label: t.projIdle };
}
+// 项目计数徽标:按优先级展示「需人工 / 运行中 / 被阻塞」,仅非零显示
+function CountBadge({ value, color, title }) {
+ return (
+ {value}
+ );
+}
+
function ProjStatusDot({ meta, size = 7 }) {
return (
onSelect(p.id)} title={p.name + ' · ' + meta.label + (p.pending ? ' · ' + t.projPendingTip.replace('{n}', p.pending) : '')}
+ onSelect(p.id)} title={p.name + ' · ' + meta.label
+ + (p.pending ? ' · ' + t.projPendingTip.replace('{n}', p.pending) : '')
+ + (p.agents ? ' · ' + t.projAgentsTip.replace('{n}', p.agents) : '')
+ + (p.blocked ? ' · ' + t.projBlockedTip.replace('{n}', p.blocked) : '')}
draggable={!collapsed}
onDragStart={(e) => { setDragId(p.id); e.dataTransfer.effectAllowed = 'move'; }}
onDragOver={(e) => { if (dragId) { e.preventDefault(); if (p.id !== dragId && overId !== p.id) setOverId(p.id); } }}
@@ -536,20 +550,16 @@ function Sidebar({ projects, currentId, onSelect, onNewProject, collapsed, onTog
{p.name}
{p.path}
-
- {p.pending > 0 ? (
- {p.pending}
- ) : null}
+
+ {p.pending > 0 ? : null}
+ {p.agents > 0 ? : null}
+ {p.blocked > 0 ? : null}
) : (
- 0 ? 8 : 6} />
+ 0 ? 8 : 6} />
)}
diff --git a/design/ui_kits/console/data.js b/design/ui_kits/console/data.js
index cac40b1..04b1ed1 100644
--- a/design/ui_kits/console/data.js
+++ b/design/ui_kits/console/data.js
@@ -1,9 +1,9 @@
// MAESTRO 调度台 · UI kit 假数据(与 src/model 状态机对齐)
window.MAESTRO_MOCK = {
projects: [
- { id: 'p1', name: 'maestro', path: '~/dev/maestro', branch: 'main', autonomy: 'auto-easy', concurrency: 2, hue: 140, state: 'running', pending: 1, agents: 1 },
- { id: 'p2', name: 'blog-engine', path: '~/dev/blog-engine', branch: 'main', autonomy: 'manual', concurrency: 1, hue: 38, state: 'paused', pending: 0, agents: 0 },
- { id: 'p3', name: 'dotfiles', path: '~/.dotfiles', branch: 'master', autonomy: 'auto-approved', concurrency: 1, hue: 265, state: 'blocked', pending: 0, agents: 0 },
+ { id: 'p1', name: 'maestro', path: '~/dev/maestro', branch: 'main', autonomy: 'auto-easy', concurrency: 2, hue: 140, state: 'running', pending: 1, agents: 1, blocked: 0 },
+ { id: 'p2', name: 'blog-engine', path: '~/dev/blog-engine', branch: 'main', autonomy: 'manual', concurrency: 1, hue: 38, state: 'paused', pending: 0, agents: 0, blocked: 0 },
+ { id: 'p3', name: 'dotfiles', path: '~/.dotfiles', branch: 'master', autonomy: 'auto-approved', concurrency: 1, hue: 265, state: 'blocked', pending: 2, agents: 0, blocked: 2 },
],
agents: [
{ id: 'r1', project: 'maestro', title: '把轮询改为 WS 推送', kind: 'EXECUTOR', time: '06:12', meta: 'wt-127 · claude-sonnet' },
diff --git a/design/ui_kits/console/i18n.js b/design/ui_kits/console/i18n.js
index d62eb8a..82259d1 100644
--- a/design/ui_kits/console/i18n.js
+++ b/design/ui_kits/console/i18n.js
@@ -22,6 +22,8 @@ window.MAESTRO_I18N = {
agentSection: 'Agent 执行', agentEmpty: '无运行中的 agent', running: 'RUNNING', since: '起',
projRunning: '运行中', projPaused: '暂停', projBlocked: '阻塞', projIdle: '空闲',
projPendingTip: '{n} 项待你审批',
+ projAgentsTip: '{n} 个 agent 运行中',
+ projBlockedTip: '{n} 项被阻塞',
gAgents: '全局 Agent', gAgentsDetail: '{p}/{P} 个项目运行 · {a} 个 agent',
apActive: '运行', apRuns: '次运行', apTokens: 'token', apWeek: '本周', apCost: '花费', apTotal: '所有项目', apPerProj: '按项目', apIdle: '空闲', apMore: '展开其余 {n} 个', apCollapse: '收起',
apDetail: '详情', apDetailTitle: '用量详情', apByDay: '按天', apByWeek: '按周', apByMonth: '按月', apColProject: '项目', apColTasks: '任务数', apColModels: '模型', apEmpty: '暂无用量数据',
@@ -74,6 +76,8 @@ window.MAESTRO_I18N = {
agentSection: 'Agent runs', agentEmpty: 'No running agents', running: 'RUNNING', since: '',
projRunning: 'Running', projPaused: 'Paused', projBlocked: 'Blocked', projIdle: 'Idle',
projPendingTip: '{n} awaiting your review',
+ projAgentsTip: '{n} agents running',
+ projBlockedTip: '{n} blocked',
gAgents: 'Agents', gAgentsDetail: '{p}/{P} projects · {a} agents',
apActive: 'active', apRuns: 'runs', apTokens: 'tokens', apWeek: 'this week', apCost: 'cost', apTotal: 'All projects', apPerProj: 'BY PROJECT', apIdle: 'idle', apMore: '+{n} more', apCollapse: 'Collapse',
apDetail: 'Details', apDetailTitle: 'Usage detail', apByDay: 'By day', apByWeek: 'By week', apByMonth: 'By month', apColProject: 'Project', apColTasks: 'Tasks', apColModels: 'Models', apEmpty: 'No usage data yet',
@@ -126,6 +130,8 @@ window.MAESTRO_I18N = {
agentSection: 'Ejecución de agents', agentEmpty: 'Sin agents en ejecución', running: 'RUNNING', since: '',
projRunning: 'En curso', projPaused: 'Pausado', projBlocked: 'Bloqueado', projIdle: 'Inactivo',
projPendingTip: '{n} esperan tu revisión',
+ projAgentsTip: '{n} agentes en curso',
+ projBlockedTip: '{n} bloqueadas',
gAgents: 'Agents globales', gAgentsDetail: '{p}/{P} proyectos · {a} agents',
apActive: 'activos', apRuns: 'ejecuciones', apTokens: 'tokens', apWeek: 'esta semana', apCost: 'coste', apTotal: 'Todos los proyectos', apPerProj: 'POR PROYECTO', apIdle: 'inactivo', apMore: '+{n} más', apCollapse: 'Contraer',
apDetail: 'Detalles', apDetailTitle: 'Detalle de uso', apByDay: 'Por día', apByWeek: 'Por semana', apByMonth: 'Por mes', apColProject: 'Proyecto', apColTasks: 'Tareas', apColModels: 'Modelos', apEmpty: 'Sin datos de uso',
@@ -178,6 +184,8 @@ window.MAESTRO_I18N = {
agentSection: 'Agent 実行', agentEmpty: '実行中の agent はありません', running: 'RUNNING', since: '開始',
projRunning: '実行中', projPaused: '一時停止', projBlocked: 'ブロック', projIdle: 'アイドル',
projPendingTip: '{n} 件があなたの承認待ち',
+ projAgentsTip: '{n} 件のエージェント実行中',
+ projBlockedTip: '{n} 件ブロック中',
gAgents: 'グローバル Agent', gAgentsDetail: '{p}/{P} プロジェクト · {a} 個の agent',
apActive: '実行中', apRuns: '回実行', apTokens: 'token', apWeek: '今週', apCost: 'コスト', apTotal: '全プロジェクト', apPerProj: 'プロジェクト別', apIdle: 'アイドル', apMore: '他 {n} 件', apCollapse: '折りたたむ',
apDetail: '詳細', apDetailTitle: '使用量の詳細', apByDay: '日別', apByWeek: '週別', apByMonth: '月別', apColProject: 'プロジェクト', apColTasks: 'タスク数', apColModels: 'モデル', apEmpty: '使用量データなし',
@@ -230,6 +238,8 @@ window.MAESTRO_I18N = {
agentSection: 'Exécutions agent', agentEmpty: 'Aucun agent en cours', running: 'RUNNING', since: '',
projRunning: 'En cours', projPaused: 'En pause', projBlocked: 'Bloqué', projIdle: 'Inactif',
projPendingTip: '{n} en attente de votre revue',
+ projAgentsTip: '{n} agents en cours',
+ projBlockedTip: '{n} bloquées',
gAgents: 'Agents globaux', gAgentsDetail: '{p}/{P} projets · {a} agents',
apActive: 'actifs', apRuns: 'exécutions', apTokens: 'tokens', apWeek: 'cette semaine', apCost: 'coût', apTotal: 'Tous les projets', apPerProj: 'PAR PROJET', apIdle: 'inactif', apMore: '+{n} de plus', apCollapse: 'Réduire',
apDetail: 'Détails', apDetailTitle: "Détail d'usage", apByDay: 'Par jour', apByWeek: 'Par semaine', apByMonth: 'Par mois', apColProject: 'Projet', apColTasks: 'Tâches', apColModels: 'Modèles', apEmpty: "Aucune donnée d'usage",