codingbuddy 4.2.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/cli/cli.d.ts +2 -2
- package/dist/src/cli/cli.js +4 -2
- package/dist/src/cli/cli.js.map +1 -1
- package/dist/src/cli/cli.types.d.ts +3 -0
- package/dist/src/cli/init/prompts/agent-prompt.d.ts +1 -1
- package/dist/src/cli/restart-tui.d.ts +9 -0
- package/dist/src/cli/restart-tui.js +30 -0
- package/dist/src/cli/restart-tui.js.map +1 -0
- package/dist/src/cli/run-tui.d.ts +3 -1
- package/dist/src/cli/run-tui.js +13 -1
- package/dist/src/cli/run-tui.js.map +1 -1
- package/dist/src/keyword/keyword.types.d.ts +3 -3
- package/dist/src/keyword/keyword.types.js +31 -1
- package/dist/src/keyword/keyword.types.js.map +1 -1
- package/dist/src/keyword/patterns/backend.patterns.js +10 -0
- package/dist/src/keyword/patterns/backend.patterns.js.map +1 -1
- package/dist/src/keyword/patterns/context.patterns.js +1 -1
- package/dist/src/keyword/patterns/data-science.patterns.d.ts +2 -0
- package/dist/src/keyword/patterns/data-science.patterns.js +71 -0
- package/dist/src/keyword/patterns/data-science.patterns.js.map +1 -0
- package/dist/src/keyword/patterns/index.d.ts +3 -0
- package/dist/src/keyword/patterns/index.js +7 -1
- package/dist/src/keyword/patterns/index.js.map +1 -1
- package/dist/src/keyword/patterns/intent-pattern-checks.js +24 -0
- package/dist/src/keyword/patterns/intent-pattern-checks.js.map +1 -1
- package/dist/src/keyword/patterns/security.patterns.d.ts +2 -0
- package/dist/src/keyword/patterns/security.patterns.js +106 -0
- package/dist/src/keyword/patterns/security.patterns.js.map +1 -0
- package/dist/src/keyword/patterns/systems.patterns.d.ts +2 -0
- package/dist/src/keyword/patterns/systems.patterns.js +101 -0
- package/dist/src/keyword/patterns/systems.patterns.js.map +1 -0
- package/dist/src/keyword/patterns/test.patterns.d.ts +2 -0
- package/dist/src/keyword/patterns/test.patterns.js +71 -0
- package/dist/src/keyword/patterns/test.patterns.js.map +1 -0
- package/dist/src/keyword/strategies/__tests__/strategy-test.utils.d.ts +1 -1
- package/dist/src/keyword/strategies/__tests__/strategy-test.utils.js +4 -0
- package/dist/src/keyword/strategies/__tests__/strategy-test.utils.js.map +1 -1
- package/dist/src/keyword/strategies/act-agent.strategy.js +2 -2
- package/dist/src/keyword/strategies/act-agent.strategy.js.map +1 -1
- package/dist/src/mcp/handlers/index.d.ts +1 -0
- package/dist/src/mcp/handlers/index.js +3 -1
- package/dist/src/mcp/handlers/index.js.map +1 -1
- package/dist/src/mcp/handlers/mode.handler.js +15 -1
- package/dist/src/mcp/handlers/mode.handler.js.map +1 -1
- package/dist/src/mcp/handlers/tui.handler.d.ts +8 -0
- package/dist/src/mcp/handlers/tui.handler.js +50 -0
- package/dist/src/mcp/handlers/tui.handler.js.map +1 -0
- package/dist/src/mcp/mcp.module.js +1 -0
- package/dist/src/mcp/mcp.module.js.map +1 -1
- package/dist/src/shared/version.d.ts +1 -0
- package/dist/src/shared/version.js +5 -0
- package/dist/src/shared/version.js.map +1 -0
- package/dist/src/shared/version.utils.js +2 -14
- package/dist/src/shared/version.utils.js.map +1 -1
- package/dist/src/tui/__perf__/rendering-performance.spec.js +4 -4
- package/dist/src/tui/__perf__/rendering-performance.spec.js.map +1 -1
- package/dist/src/tui/components/ActivityVisualizer.d.ts +7 -3
- package/dist/src/tui/components/ActivityVisualizer.js +8 -9
- package/dist/src/tui/components/ActivityVisualizer.js.map +1 -1
- package/dist/src/tui/components/ActivityVisualizer.spec.js +73 -27
- package/dist/src/tui/components/ActivityVisualizer.spec.js.map +1 -1
- package/dist/src/tui/components/ChecklistPanel.d.ts +10 -0
- package/dist/src/tui/components/ChecklistPanel.js +19 -0
- package/dist/src/tui/components/ChecklistPanel.js.map +1 -0
- package/dist/src/tui/components/ChecklistPanel.spec.d.ts +1 -0
- package/dist/src/tui/components/ChecklistPanel.spec.js +45 -0
- package/dist/src/tui/components/ChecklistPanel.spec.js.map +1 -0
- package/dist/src/tui/components/FocusedAgentPanel.d.ts +2 -8
- package/dist/src/tui/components/FocusedAgentPanel.js +1 -14
- package/dist/src/tui/components/FocusedAgentPanel.js.map +1 -1
- package/dist/src/tui/components/FocusedAgentPanel.spec.js +20 -51
- package/dist/src/tui/components/FocusedAgentPanel.spec.js.map +1 -1
- package/dist/src/tui/components/HeaderBar.d.ts +1 -2
- package/dist/src/tui/components/HeaderBar.js +3 -7
- package/dist/src/tui/components/HeaderBar.js.map +1 -1
- package/dist/src/tui/components/HeaderBar.spec.js +13 -13
- package/dist/src/tui/components/HeaderBar.spec.js.map +1 -1
- package/dist/src/tui/components/StageHealthBar.d.ts +3 -1
- package/dist/src/tui/components/StageHealthBar.js +10 -4
- package/dist/src/tui/components/StageHealthBar.js.map +1 -1
- package/dist/src/tui/components/StageHealthBar.spec.js +21 -7
- package/dist/src/tui/components/StageHealthBar.spec.js.map +1 -1
- package/dist/src/tui/components/activity-visualizer.pure.d.ts +3 -8
- package/dist/src/tui/components/activity-visualizer.pure.js +113 -50
- package/dist/src/tui/components/activity-visualizer.pure.js.map +1 -1
- package/dist/src/tui/components/checklist-panel.pure.d.ts +2 -0
- package/dist/src/tui/components/checklist-panel.pure.js +18 -0
- package/dist/src/tui/components/checklist-panel.pure.js.map +1 -0
- package/dist/src/tui/components/flow-map.pure.d.ts +2 -2
- package/dist/src/tui/components/flow-map.pure.js +120 -29
- package/dist/src/tui/components/flow-map.pure.js.map +1 -1
- package/dist/src/tui/components/focused-agent.pure.d.ts +0 -14
- package/dist/src/tui/components/focused-agent.pure.js +0 -45
- package/dist/src/tui/components/focused-agent.pure.js.map +1 -1
- package/dist/src/tui/components/grid-layout.pure.js +26 -4
- package/dist/src/tui/components/grid-layout.pure.js.map +1 -1
- package/dist/src/tui/components/index.d.ts +4 -2
- package/dist/src/tui/components/index.js +7 -7
- package/dist/src/tui/components/index.js.map +1 -1
- package/dist/src/tui/components/stage-health.pure.d.ts +1 -0
- package/dist/src/tui/components/stage-health.pure.js +4 -0
- package/dist/src/tui/components/stage-health.pure.js.map +1 -1
- package/dist/src/tui/dashboard-app.d.ts +2 -1
- package/dist/src/tui/dashboard-app.js +12 -15
- package/dist/src/tui/dashboard-app.js.map +1 -1
- package/dist/src/tui/dashboard-app.spec.js +11 -3
- package/dist/src/tui/dashboard-app.spec.js.map +1 -1
- package/dist/src/tui/dashboard-types.d.ts +6 -0
- package/dist/src/tui/dashboard-types.js +1 -0
- package/dist/src/tui/dashboard-types.js.map +1 -1
- package/dist/src/tui/eventbus-ui.integration.spec.js +1 -0
- package/dist/src/tui/eventbus-ui.integration.spec.js.map +1 -1
- package/dist/src/tui/events/parse-agent.js +0 -26
- package/dist/src/tui/events/parse-agent.js.map +1 -1
- package/dist/src/tui/events/response-event-extractor.js +33 -7
- package/dist/src/tui/events/response-event-extractor.js.map +1 -1
- package/dist/src/tui/hooks/use-dashboard-state.d.ts +6 -0
- package/dist/src/tui/hooks/use-dashboard-state.js +68 -18
- package/dist/src/tui/hooks/use-dashboard-state.js.map +1 -1
- package/dist/src/tui/multi-session-app.js +6 -1
- package/dist/src/tui/multi-session-app.js.map +1 -1
- package/dist/src/tui-bundle.mjs +615 -333
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +3 -3
package/dist/src/tui-bundle.mjs
CHANGED
|
@@ -1371,12 +1371,12 @@ var require_eventemitter2 = __commonJS({
|
|
|
1371
1371
|
});
|
|
1372
1372
|
|
|
1373
1373
|
// src/tui/index.tsx
|
|
1374
|
-
import
|
|
1374
|
+
import React11 from "react";
|
|
1375
1375
|
import { render } from "ink";
|
|
1376
1376
|
|
|
1377
1377
|
// src/tui/dashboard-app.tsx
|
|
1378
|
-
import
|
|
1379
|
-
import { Box as
|
|
1378
|
+
import React8, { useMemo as useMemo3 } from "react";
|
|
1379
|
+
import { Box as Box8 } from "ink";
|
|
1380
1380
|
|
|
1381
1381
|
// src/tui/hooks/use-terminal-size.ts
|
|
1382
1382
|
import { useState, useEffect } from "react";
|
|
@@ -1400,6 +1400,7 @@ function createDefaultDashboardNode(params) {
|
|
|
1400
1400
|
status: "idle",
|
|
1401
1401
|
isPrimary: false,
|
|
1402
1402
|
progress: 0,
|
|
1403
|
+
isParallel: false,
|
|
1403
1404
|
...params
|
|
1404
1405
|
};
|
|
1405
1406
|
}
|
|
@@ -1492,23 +1493,6 @@ var MODE_KEYWORD_TO_AGENT = {
|
|
|
1492
1493
|
EVAL: "eval-mode",
|
|
1493
1494
|
AUTO: "auto-mode"
|
|
1494
1495
|
};
|
|
1495
|
-
var TOOL_AGENT_MAP = {
|
|
1496
|
-
search_rules: "query",
|
|
1497
|
-
get_agent_details: "query",
|
|
1498
|
-
get_project_config: "config",
|
|
1499
|
-
set_project_root: "config",
|
|
1500
|
-
suggest_config_updates: "config",
|
|
1501
|
-
recommend_skills: "skill",
|
|
1502
|
-
get_skill: "skill",
|
|
1503
|
-
list_skills: "skill",
|
|
1504
|
-
analyze_task: "analysis",
|
|
1505
|
-
generate_checklist: "checklist",
|
|
1506
|
-
read_context: "context",
|
|
1507
|
-
update_context: "context",
|
|
1508
|
-
cleanup_context: "context",
|
|
1509
|
-
get_code_conventions: "conventions",
|
|
1510
|
-
dispatch_agents: "orchestrator"
|
|
1511
|
-
};
|
|
1512
1496
|
function parseAgentFromToolName(toolName, args) {
|
|
1513
1497
|
if (toolName === "get_agent_system_prompt") {
|
|
1514
1498
|
return parseGetAgentSystemPrompt(args);
|
|
@@ -1519,15 +1503,6 @@ function parseAgentFromToolName(toolName, args) {
|
|
|
1519
1503
|
if (toolName === "prepare_parallel_agents") {
|
|
1520
1504
|
return parseParallelAgents(args);
|
|
1521
1505
|
}
|
|
1522
|
-
const role = TOOL_AGENT_MAP[toolName];
|
|
1523
|
-
if (role) {
|
|
1524
|
-
return {
|
|
1525
|
-
agentId: toolName,
|
|
1526
|
-
name: toolName,
|
|
1527
|
-
role,
|
|
1528
|
-
isPrimary: false
|
|
1529
|
-
};
|
|
1530
|
-
}
|
|
1531
1506
|
return null;
|
|
1532
1507
|
}
|
|
1533
1508
|
function parseGetAgentSystemPrompt(args) {
|
|
@@ -1664,13 +1639,24 @@ function extractFromParseMode(json) {
|
|
|
1664
1639
|
if (Array.isArray(par.specialists) && par.specialists.length > 0) {
|
|
1665
1640
|
const specialists = par.specialists.filter((s) => typeof s === "string");
|
|
1666
1641
|
if (specialists.length > 0) {
|
|
1642
|
+
const parallelMode = typeof json.mode === "string" && VALID_MODES.has(json.mode) ? json.mode : "PLAN";
|
|
1667
1643
|
events.push({
|
|
1668
1644
|
event: TUI_EVENTS.PARALLEL_STARTED,
|
|
1669
|
-
payload: {
|
|
1670
|
-
specialists,
|
|
1671
|
-
mode: typeof json.mode === "string" && VALID_MODES.has(json.mode) ? json.mode : "PLAN"
|
|
1672
|
-
}
|
|
1645
|
+
payload: { specialists, mode: parallelMode }
|
|
1673
1646
|
});
|
|
1647
|
+
if (delegateName) {
|
|
1648
|
+
for (const name of specialists) {
|
|
1649
|
+
events.push({
|
|
1650
|
+
event: TUI_EVENTS.AGENT_RELATIONSHIP,
|
|
1651
|
+
payload: {
|
|
1652
|
+
from: `primary:${delegateName}`,
|
|
1653
|
+
to: `specialist:${name}`,
|
|
1654
|
+
label: "parallel",
|
|
1655
|
+
type: "delegation"
|
|
1656
|
+
}
|
|
1657
|
+
});
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1674
1660
|
}
|
|
1675
1661
|
}
|
|
1676
1662
|
}
|
|
@@ -1694,12 +1680,27 @@ function extractFromPrepareParallelAgents(json) {
|
|
|
1694
1680
|
}).filter((name) => name !== null);
|
|
1695
1681
|
if (specialists.length === 0) return [];
|
|
1696
1682
|
const mode = typeof json.mode === "string" && VALID_MODES.has(json.mode) ? json.mode : "PLAN";
|
|
1697
|
-
|
|
1683
|
+
const primaryAgentId = typeof json.primaryAgentId === "string" ? json.primaryAgentId : null;
|
|
1684
|
+
const events = [
|
|
1698
1685
|
{
|
|
1699
1686
|
event: TUI_EVENTS.PARALLEL_STARTED,
|
|
1700
1687
|
payload: { specialists, mode }
|
|
1701
1688
|
}
|
|
1702
1689
|
];
|
|
1690
|
+
if (primaryAgentId) {
|
|
1691
|
+
for (const name of specialists) {
|
|
1692
|
+
events.push({
|
|
1693
|
+
event: TUI_EVENTS.AGENT_RELATIONSHIP,
|
|
1694
|
+
payload: {
|
|
1695
|
+
from: primaryAgentId,
|
|
1696
|
+
to: `specialist:${name}`,
|
|
1697
|
+
label: "parallel",
|
|
1698
|
+
type: "delegation"
|
|
1699
|
+
}
|
|
1700
|
+
});
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
return events;
|
|
1703
1704
|
}
|
|
1704
1705
|
function extractFromDispatchAgents(json) {
|
|
1705
1706
|
const events = [];
|
|
@@ -2086,12 +2087,24 @@ var ACT_PRIMARY_AGENTS = [
|
|
|
2086
2087
|
// IaC, Kubernetes, multi-cloud specialist - high priority for infra tasks
|
|
2087
2088
|
"data-engineer",
|
|
2088
2089
|
// Database/schema specialist - high priority for data tasks
|
|
2090
|
+
"data-scientist",
|
|
2091
|
+
// EDA, statistical analysis, ML modeling, visualization, Jupyter notebooks
|
|
2092
|
+
"ai-ml-engineer",
|
|
2093
|
+
// ML frameworks, LLM integration, embeddings, fine-tuning
|
|
2089
2094
|
"mobile-developer",
|
|
2090
2095
|
// Mobile app specialist - detected by project files
|
|
2091
2096
|
"frontend-developer",
|
|
2092
2097
|
"backend-developer",
|
|
2093
2098
|
"devops-engineer",
|
|
2094
|
-
"agent-architect"
|
|
2099
|
+
"agent-architect",
|
|
2100
|
+
"test-engineer",
|
|
2101
|
+
// TDD, unit/integration/e2e test specialist
|
|
2102
|
+
"security-engineer",
|
|
2103
|
+
// Security features implementation & vulnerability remediation (intent priority: 5th)
|
|
2104
|
+
"systems-developer",
|
|
2105
|
+
// Rust, C, C++, FFI, WASM, embedded, low-level optimization (intent priority: 6th)
|
|
2106
|
+
"software-engineer"
|
|
2107
|
+
// fallback default — no intent patterns, language-agnostic generalist
|
|
2095
2108
|
];
|
|
2096
2109
|
var EVAL_PRIMARY_AGENT = "code-reviewer";
|
|
2097
2110
|
var ALL_PRIMARY_AGENTS = [
|
|
@@ -3933,6 +3946,7 @@ function selectFocusedAgent(agents, currentFocusId) {
|
|
|
3933
3946
|
var EVENT_LOG_MAX = 100;
|
|
3934
3947
|
var EDGE_MAX = 200;
|
|
3935
3948
|
var TOOL_CALLS_MAX = 200;
|
|
3949
|
+
var EXPECTED_AGENT_DURATION_MS = 12e4;
|
|
3936
3950
|
function createInitialDashboardState() {
|
|
3937
3951
|
return {
|
|
3938
3952
|
workspace: process.cwd(),
|
|
@@ -3948,6 +3962,8 @@ function createInitialDashboardState() {
|
|
|
3948
3962
|
objectives: [],
|
|
3949
3963
|
activeSkills: [],
|
|
3950
3964
|
toolInvokeCount: 0,
|
|
3965
|
+
agentActivateCount: 0,
|
|
3966
|
+
skillInvokeCount: 0,
|
|
3951
3967
|
outputStats: { files: 0, commits: 0 },
|
|
3952
3968
|
contextDecisions: [],
|
|
3953
3969
|
contextNotes: [],
|
|
@@ -3969,11 +3985,20 @@ function dashboardReducer(state, action) {
|
|
|
3969
3985
|
stage: state.currentMode ?? "PLAN",
|
|
3970
3986
|
status: "running",
|
|
3971
3987
|
isPrimary,
|
|
3972
|
-
progress: 0
|
|
3988
|
+
progress: 0,
|
|
3989
|
+
isParallel: false,
|
|
3990
|
+
// AGENT_ACTIVATED는 항상 단일 에이전트
|
|
3991
|
+
startedAt: Date.now()
|
|
3973
3992
|
});
|
|
3974
3993
|
const globalState = "RUNNING";
|
|
3975
3994
|
const focusedAgentId = selectFocusedAgent(agents, state.focusedAgentId);
|
|
3976
|
-
return {
|
|
3995
|
+
return {
|
|
3996
|
+
...state,
|
|
3997
|
+
agents,
|
|
3998
|
+
globalState,
|
|
3999
|
+
focusedAgentId,
|
|
4000
|
+
agentActivateCount: state.agentActivateCount + 1
|
|
4001
|
+
};
|
|
3977
4002
|
}
|
|
3978
4003
|
case "AGENT_DEACTIVATED": {
|
|
3979
4004
|
const { agentId, reason } = action.payload;
|
|
@@ -3983,7 +4008,8 @@ function dashboardReducer(state, action) {
|
|
|
3983
4008
|
agents.set(agentId, {
|
|
3984
4009
|
...existing,
|
|
3985
4010
|
status: reason === "error" ? "error" : "done",
|
|
3986
|
-
progress: reason === "error" ? existing.progress : 100
|
|
4011
|
+
progress: reason === "error" ? existing.progress : 100,
|
|
4012
|
+
completedAt: Date.now()
|
|
3987
4013
|
});
|
|
3988
4014
|
}
|
|
3989
4015
|
let anyRunning = false;
|
|
@@ -3998,24 +4024,19 @@ function dashboardReducer(state, action) {
|
|
|
3998
4024
|
return { ...state, agents, globalState, focusedAgentId };
|
|
3999
4025
|
}
|
|
4000
4026
|
case "MODE_CHANGED": {
|
|
4001
|
-
const newMode = action.payload
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
break;
|
|
4027
|
+
const { from, to: newMode } = action.payload;
|
|
4028
|
+
const agents = cloneAgents(state.agents);
|
|
4029
|
+
for (const [id, a] of agents) {
|
|
4030
|
+
if (from !== null && a.stage === from && (a.status === "done" || a.status === "idle" && a.isParallel)) {
|
|
4031
|
+
agents.delete(id);
|
|
4032
|
+
continue;
|
|
4008
4033
|
}
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
agents = cloneAgents(state.agents);
|
|
4012
|
-
for (const [id, a] of agents) {
|
|
4013
|
-
if (a.status === "running") {
|
|
4014
|
-
agents.set(id, { ...a, stage: newMode });
|
|
4015
|
-
}
|
|
4034
|
+
if (a.status === "running") {
|
|
4035
|
+
agents.set(id, { ...a, stage: newMode });
|
|
4016
4036
|
}
|
|
4017
4037
|
}
|
|
4018
|
-
|
|
4038
|
+
const focusedAgentId = selectFocusedAgent(agents, state.focusedAgentId);
|
|
4039
|
+
return { ...state, currentMode: newMode, agents, activeSkills: [], focusedAgentId };
|
|
4019
4040
|
}
|
|
4020
4041
|
case "AGENT_RELATIONSHIP": {
|
|
4021
4042
|
const edge = {
|
|
@@ -4049,10 +4070,15 @@ function dashboardReducer(state, action) {
|
|
|
4049
4070
|
targetAgent = state.agents.get(state.focusedAgentId) ?? null;
|
|
4050
4071
|
}
|
|
4051
4072
|
if (targetAgent && targetAgent.status === "running") {
|
|
4073
|
+
const now = Date.now();
|
|
4074
|
+
const elapsed = targetAgent.startedAt !== void 0 ? now - targetAgent.startedAt : 0;
|
|
4075
|
+
const timeBased = Math.min(90, elapsed / EXPECTED_AGENT_DURATION_MS * 100);
|
|
4076
|
+
const toolBased = Math.min(95, targetAgent.progress + 3);
|
|
4077
|
+
const newProgress = Math.round(Math.max(timeBased, toolBased));
|
|
4052
4078
|
agents = cloneAgents(state.agents);
|
|
4053
4079
|
agents.set(targetAgent.id, {
|
|
4054
4080
|
...targetAgent,
|
|
4055
|
-
progress:
|
|
4081
|
+
progress: newProgress
|
|
4056
4082
|
});
|
|
4057
4083
|
}
|
|
4058
4084
|
const toolCall = {
|
|
@@ -4075,7 +4101,11 @@ function dashboardReducer(state, action) {
|
|
|
4075
4101
|
case "SKILL_RECOMMENDED": {
|
|
4076
4102
|
const { skillName } = action.payload;
|
|
4077
4103
|
if (state.activeSkills.includes(skillName)) return state;
|
|
4078
|
-
return {
|
|
4104
|
+
return {
|
|
4105
|
+
...state,
|
|
4106
|
+
activeSkills: [...state.activeSkills, skillName],
|
|
4107
|
+
skillInvokeCount: state.skillInvokeCount + 1
|
|
4108
|
+
};
|
|
4079
4109
|
}
|
|
4080
4110
|
case "PARALLEL_STARTED": {
|
|
4081
4111
|
const { specialists, mode } = action.payload;
|
|
@@ -4089,7 +4119,10 @@ function dashboardReducer(state, action) {
|
|
|
4089
4119
|
stage: mode,
|
|
4090
4120
|
status: "idle",
|
|
4091
4121
|
isPrimary: false,
|
|
4092
|
-
progress: 0
|
|
4122
|
+
progress: 0,
|
|
4123
|
+
isParallel: true,
|
|
4124
|
+
// parallel dispatch로 등록된 에이전트
|
|
4125
|
+
startedAt: Date.now()
|
|
4093
4126
|
});
|
|
4094
4127
|
}
|
|
4095
4128
|
return { ...state, agents };
|
|
@@ -4106,6 +4139,21 @@ function dashboardReducer(state, action) {
|
|
|
4106
4139
|
}
|
|
4107
4140
|
case "SESSION_RESET":
|
|
4108
4141
|
return createInitialDashboardState();
|
|
4142
|
+
case "CLEANUP_STALE_AGENTS": {
|
|
4143
|
+
const { now, ttlMs } = action.payload;
|
|
4144
|
+
let changed = false;
|
|
4145
|
+
const agents = cloneAgents(state.agents);
|
|
4146
|
+
for (const [id, a] of agents) {
|
|
4147
|
+
if (a.status === "running") continue;
|
|
4148
|
+
if (a.status === "done" && a.completedAt !== void 0 && now - a.completedAt > ttlMs || a.status === "error" && a.completedAt !== void 0 && now - a.completedAt > ttlMs * 2 || a.status === "idle" && a.isParallel && a.startedAt !== void 0 && now - a.startedAt > ttlMs) {
|
|
4149
|
+
agents.delete(id);
|
|
4150
|
+
changed = true;
|
|
4151
|
+
}
|
|
4152
|
+
}
|
|
4153
|
+
if (!changed) return state;
|
|
4154
|
+
const focusedAgentId = selectFocusedAgent(agents, state.focusedAgentId);
|
|
4155
|
+
return { ...state, agents, focusedAgentId };
|
|
4156
|
+
}
|
|
4109
4157
|
// Reserved: no emitter currently produces PARALLEL_COMPLETED. Subscription kept for forward compatibility.
|
|
4110
4158
|
case "PARALLEL_COMPLETED":
|
|
4111
4159
|
case "AGENTS_LOADED":
|
|
@@ -4162,6 +4210,12 @@ function useDashboardState(eventBus) {
|
|
|
4162
4210
|
eventBus.off(TUI_EVENTS.CONTEXT_UPDATED, onContextUpdated);
|
|
4163
4211
|
};
|
|
4164
4212
|
}, [eventBus]);
|
|
4213
|
+
useEffect2(() => {
|
|
4214
|
+
const cleanupInterval = setInterval(() => {
|
|
4215
|
+
dispatch({ type: "CLEANUP_STALE_AGENTS", payload: { now: Date.now(), ttlMs: 3e4 } });
|
|
4216
|
+
}, 1e4);
|
|
4217
|
+
return () => clearInterval(cleanupInterval);
|
|
4218
|
+
}, []);
|
|
4165
4219
|
return state;
|
|
4166
4220
|
}
|
|
4167
4221
|
|
|
@@ -4296,7 +4350,6 @@ function StateIndicator({ globalState }) {
|
|
|
4296
4350
|
}
|
|
4297
4351
|
function HeaderBar({
|
|
4298
4352
|
workspace,
|
|
4299
|
-
sessionId,
|
|
4300
4353
|
currentMode,
|
|
4301
4354
|
globalState,
|
|
4302
4355
|
layoutMode,
|
|
@@ -4319,7 +4372,6 @@ function HeaderBar({
|
|
|
4319
4372
|
/* @__PURE__ */ React.createElement(StateIndicator, { globalState })
|
|
4320
4373
|
);
|
|
4321
4374
|
}
|
|
4322
|
-
const sessDisplay = sessionId.length > 8 ? sessionId.slice(0, 8) : sessionId;
|
|
4323
4375
|
return /* @__PURE__ */ React.createElement(
|
|
4324
4376
|
Box,
|
|
4325
4377
|
{
|
|
@@ -4329,9 +4381,9 @@ function HeaderBar({
|
|
|
4329
4381
|
overflowX: "hidden",
|
|
4330
4382
|
flexDirection: "row"
|
|
4331
4383
|
},
|
|
4332
|
-
/* @__PURE__ */ React.createElement(Box, { gap: 2, flexShrink: 0 }, /* @__PURE__ */ React.createElement(Text, { color: "cyan", bold: true }, "\u27E8\u27E9 CODINGBUDDY AGENT DASHBOARD"), /* @__PURE__ */ React.createElement(ModeFlow, { currentMode }), /* @__PURE__ */ React.createElement(StateIndicator, { globalState })),
|
|
4384
|
+
/* @__PURE__ */ React.createElement(Box, { gap: 2, flexShrink: 1, minWidth: 0 }, /* @__PURE__ */ React.createElement(Text, { color: "cyan", bold: true }, "\u27E8\u27E9 CODINGBUDDY AGENT DASHBOARD"), /* @__PURE__ */ React.createElement(ModeFlow, { currentMode }), /* @__PURE__ */ React.createElement(StateIndicator, { globalState })),
|
|
4333
4385
|
/* @__PURE__ */ React.createElement(Box, { flexGrow: 1 }),
|
|
4334
|
-
/* @__PURE__ */ React.createElement(Box, { flexShrink: 1, overflowX: "hidden" }, /* @__PURE__ */ React.createElement(Text, { dimColor: true, wrap: "truncate" }, workspace
|
|
4386
|
+
/* @__PURE__ */ React.createElement(Box, { flexShrink: 1, overflowX: "hidden" }, /* @__PURE__ */ React.createElement(Text, { dimColor: true, wrap: "truncate" }, workspace))
|
|
4335
4387
|
);
|
|
4336
4388
|
}
|
|
4337
4389
|
|
|
@@ -4491,9 +4543,16 @@ function computeLabelPosition(path9, label) {
|
|
|
4491
4543
|
// src/tui/components/flow-map.pure.ts
|
|
4492
4544
|
var NODE_WIDTH = 17;
|
|
4493
4545
|
var NODE_HEIGHT = 4;
|
|
4546
|
+
var PARALLEL_STYLES = {
|
|
4547
|
+
parallel: { fg: "cyan" }
|
|
4548
|
+
// 파랑 — 병렬 실행
|
|
4549
|
+
};
|
|
4550
|
+
var TREE_CONNECTOR_STYLE = { fg: "cyan", dim: true };
|
|
4494
4551
|
var STAGE_ORDER = ["PLAN", "ACT", "EVAL", "AUTO"];
|
|
4495
|
-
var STAGE_SLOT_WIDTH =
|
|
4552
|
+
var STAGE_SLOT_WIDTH = 18;
|
|
4496
4553
|
var PIPELINE_RIGHT_MARGIN = 10;
|
|
4554
|
+
var DIMMED_STYLE = { dim: true };
|
|
4555
|
+
var WAITING_STYLE = { fg: "gray", dim: true };
|
|
4497
4556
|
function groupByStage(agents) {
|
|
4498
4557
|
const byStage = /* @__PURE__ */ new Map();
|
|
4499
4558
|
for (const agent of agents.values()) {
|
|
@@ -4503,9 +4562,15 @@ function groupByStage(agents) {
|
|
|
4503
4562
|
}
|
|
4504
4563
|
return byStage;
|
|
4505
4564
|
}
|
|
4565
|
+
function isBoxAgent(agent) {
|
|
4566
|
+
return agent.isPrimary || agent.isParallel;
|
|
4567
|
+
}
|
|
4506
4568
|
function sortAgents(agents) {
|
|
4507
4569
|
return [...agents].sort((a, b) => {
|
|
4508
4570
|
if (a.isPrimary !== b.isPrimary) return a.isPrimary ? -1 : 1;
|
|
4571
|
+
if (!a.isPrimary && !b.isPrimary) {
|
|
4572
|
+
if (a.isParallel !== b.isParallel) return a.isParallel ? -1 : 1;
|
|
4573
|
+
}
|
|
4509
4574
|
return a.name.localeCompare(b.name);
|
|
4510
4575
|
});
|
|
4511
4576
|
}
|
|
@@ -4539,14 +4604,18 @@ function layoutAgentNodes(agents, columns) {
|
|
|
4539
4604
|
if (!col) continue;
|
|
4540
4605
|
const sorted = sortAgents(stageAgents);
|
|
4541
4606
|
const startY = 3;
|
|
4542
|
-
|
|
4607
|
+
let currentY = startY;
|
|
4608
|
+
for (const agent of sorted) {
|
|
4609
|
+
const boxAgent = isBoxAgent(agent);
|
|
4610
|
+
const height = boxAgent ? NODE_HEIGHT : 1;
|
|
4543
4611
|
positions.set(agent.id, {
|
|
4544
4612
|
x: col.startX + Math.floor((col.width - NODE_WIDTH) / 2),
|
|
4545
|
-
y:
|
|
4613
|
+
y: currentY,
|
|
4546
4614
|
width: NODE_WIDTH,
|
|
4547
|
-
height
|
|
4615
|
+
height
|
|
4548
4616
|
});
|
|
4549
|
-
|
|
4617
|
+
currentY += boxAgent ? height + 1 : height;
|
|
4618
|
+
}
|
|
4550
4619
|
}
|
|
4551
4620
|
return positions;
|
|
4552
4621
|
}
|
|
@@ -4554,8 +4623,27 @@ function getNodeTextStyle(status) {
|
|
|
4554
4623
|
if (status === "running") return { fg: "white", bold: true };
|
|
4555
4624
|
return { dim: true };
|
|
4556
4625
|
}
|
|
4557
|
-
function
|
|
4558
|
-
const
|
|
4626
|
+
function drawTreeConnector(buf, x, y, agent, isLast, dimmed = false) {
|
|
4627
|
+
const connector = isLast ? "\u2514\u2500" : "\u251C\u2500";
|
|
4628
|
+
const icon = STATUS_ICONS[agent.status];
|
|
4629
|
+
const maxNameLen = Math.max(1, NODE_WIDTH - connector.length - icon.length - 3);
|
|
4630
|
+
const nameStr = agent.name.length > maxNameLen ? agent.name.slice(0, maxNameLen - 3) + "..." : agent.name;
|
|
4631
|
+
buf.writeText(x, y, connector, dimmed ? DIMMED_STYLE : TREE_CONNECTOR_STYLE);
|
|
4632
|
+
buf.writeText(
|
|
4633
|
+
x + connector.length + 1,
|
|
4634
|
+
y,
|
|
4635
|
+
icon,
|
|
4636
|
+
dimmed ? DIMMED_STYLE : STATUS_STYLES[agent.status]
|
|
4637
|
+
);
|
|
4638
|
+
buf.writeText(
|
|
4639
|
+
x + connector.length + 1 + icon.length + 1,
|
|
4640
|
+
y,
|
|
4641
|
+
nameStr,
|
|
4642
|
+
dimmed ? DIMMED_STYLE : getNodeTextStyle(agent.status)
|
|
4643
|
+
);
|
|
4644
|
+
}
|
|
4645
|
+
function drawAgentNode(buf, x, y, boxW, agent, dimmed = false) {
|
|
4646
|
+
const borderStyle = dimmed ? DIMMED_STYLE : getStatusStyle(agent.status);
|
|
4559
4647
|
if (agent.isPrimary) {
|
|
4560
4648
|
buf.drawDoubleBox(x, y, boxW, NODE_HEIGHT, borderStyle);
|
|
4561
4649
|
} else {
|
|
@@ -4564,15 +4652,26 @@ function drawAgentNode(buf, x, y, boxW, agent) {
|
|
|
4564
4652
|
const icon = STATUS_ICONS[agent.status];
|
|
4565
4653
|
const maxNameLen = Math.max(1, boxW - 5);
|
|
4566
4654
|
const nameStr = agent.name.length > maxNameLen ? agent.name.slice(0, maxNameLen - 3) + "..." : agent.name;
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4655
|
+
const textStyle = dimmed ? DIMMED_STYLE : getNodeTextStyle(agent.status);
|
|
4656
|
+
const iconStyle = dimmed ? DIMMED_STYLE : STATUS_STYLES[agent.status];
|
|
4657
|
+
buf.writeText(x + 2, y + 1, nameStr, textStyle);
|
|
4658
|
+
buf.writeText(x + 2 + nameStr.length + 1, y + 1, icon, iconStyle);
|
|
4659
|
+
if (agent.isPrimary) {
|
|
4660
|
+
const barWidth = Math.max(1, boxW - 8);
|
|
4661
|
+
const bar = buildProgressBar(agent.progress, barWidth);
|
|
4662
|
+
const filledStr = PROGRESS_BAR_CHARS.filled.repeat(bar.filled);
|
|
4663
|
+
const emptyStr = PROGRESS_BAR_CHARS.empty.repeat(bar.empty);
|
|
4664
|
+
const filledStyle = dimmed ? DIMMED_STYLE : PROGRESS_BAR_STYLES.filled;
|
|
4665
|
+
const emptyStyle = dimmed ? DIMMED_STYLE : PROGRESS_BAR_STYLES.empty;
|
|
4666
|
+
buf.writeText(x + 2, y + 2, filledStr, filledStyle);
|
|
4667
|
+
if (bar.empty > 0) {
|
|
4668
|
+
buf.writeText(x + 2 + bar.filled, y + 2, emptyStr, emptyStyle);
|
|
4669
|
+
}
|
|
4670
|
+
buf.writeText(x + 2 + barWidth + 1, y + 2, bar.label, dimmed ? DIMMED_STYLE : WAITING_STYLE);
|
|
4671
|
+
} else if (agent.status === "idle") {
|
|
4672
|
+
buf.writeText(x + 2, y + 2, "\u231B waiting...", dimmed ? DIMMED_STYLE : WAITING_STYLE);
|
|
4673
|
+
} else if (agent.isParallel) {
|
|
4674
|
+
buf.writeText(x + 2, y + 2, "\u2AF8 parallel", dimmed ? DIMMED_STYLE : PARALLEL_STYLES.parallel);
|
|
4576
4675
|
}
|
|
4577
4676
|
}
|
|
4578
4677
|
function buildProgressBar(value, barWidth) {
|
|
@@ -4607,7 +4706,17 @@ function countByStatus(agents) {
|
|
|
4607
4706
|
}
|
|
4608
4707
|
return counts;
|
|
4609
4708
|
}
|
|
4610
|
-
function
|
|
4709
|
+
function countStageRunningDone(agents, stage) {
|
|
4710
|
+
let running = 0;
|
|
4711
|
+
let done = 0;
|
|
4712
|
+
for (const agent of agents.values()) {
|
|
4713
|
+
if (agent.stage !== stage) continue;
|
|
4714
|
+
if (agent.status === "running") running++;
|
|
4715
|
+
else if (agent.status === "done") done++;
|
|
4716
|
+
}
|
|
4717
|
+
return { running, done };
|
|
4718
|
+
}
|
|
4719
|
+
function renderPipelineHeader(buf, width, activeStage, hasAutoAgents = false, agents) {
|
|
4611
4720
|
const stages = hasAutoAgents ? STAGE_ORDER : STAGE_ORDER.filter((s) => s !== "AUTO");
|
|
4612
4721
|
let x = 1;
|
|
4613
4722
|
for (let i = 0; i < stages.length; i++) {
|
|
@@ -4618,6 +4727,17 @@ function renderPipelineHeader(buf, width, activeStage, hasAutoAgents = false) {
|
|
|
4618
4727
|
x += 2;
|
|
4619
4728
|
buf.writeText(x, 0, stage, stageStyle);
|
|
4620
4729
|
x += stage.length;
|
|
4730
|
+
if (agents && agents.size > 0) {
|
|
4731
|
+
const { running, done } = countStageRunningDone(agents, stage);
|
|
4732
|
+
if (running > 0 || done > 0) {
|
|
4733
|
+
const parts = [];
|
|
4734
|
+
if (running > 0) parts.push(`${running}\u2191`);
|
|
4735
|
+
if (done > 0) parts.push(`${done}\u2713`);
|
|
4736
|
+
const statsStr = ` (${parts.join(" ")})`;
|
|
4737
|
+
buf.writeText(x, 0, statsStr, { fg: "gray", dim: !isActive });
|
|
4738
|
+
x += statsStr.length;
|
|
4739
|
+
}
|
|
4740
|
+
}
|
|
4621
4741
|
if (i < stages.length - 1) {
|
|
4622
4742
|
x += 1;
|
|
4623
4743
|
const connLen = Math.max(
|
|
@@ -4644,20 +4764,36 @@ function renderFlowMap(agents, edges, width, height, activeStage = null) {
|
|
|
4644
4764
|
const buf = new ColorBuffer(width, height);
|
|
4645
4765
|
const columns = layoutStageColumns(width, hasAutoAgents);
|
|
4646
4766
|
const positions = layoutAgentNodes(agents, columns);
|
|
4647
|
-
renderPipelineHeader(buf, width, activeStage, hasAutoAgents);
|
|
4767
|
+
renderPipelineHeader(buf, width, activeStage, hasAutoAgents, agents);
|
|
4768
|
+
const inactiveIds = activeStage !== null ? new Set([...agents.values()].filter((a) => a.stage !== activeStage).map((a) => a.id)) : /* @__PURE__ */ new Set();
|
|
4648
4769
|
for (const [id, pos] of positions) {
|
|
4649
4770
|
const agent = agents.get(id);
|
|
4650
4771
|
if (!agent) continue;
|
|
4651
|
-
if (agent.status === "running" && agent.isPrimary) {
|
|
4772
|
+
if (agent.status === "running" && agent.isPrimary && !inactiveIds.has(id)) {
|
|
4652
4773
|
drawGlow(buf, pos.x, pos.y, pos.width, pos.height, GLOW_STYLE);
|
|
4653
4774
|
}
|
|
4654
4775
|
}
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4776
|
+
const byStage = groupByStage(agents);
|
|
4777
|
+
for (const [, stageAgents] of byStage) {
|
|
4778
|
+
const sorted = sortAgents(stageAgents);
|
|
4779
|
+
const connectorAgents = sorted.filter((a) => !isBoxAgent(a));
|
|
4780
|
+
const connectorLastIdx = connectorAgents.length - 1;
|
|
4781
|
+
const connectorIndexMap = new Map(connectorAgents.map((a, i) => [a.id, i]));
|
|
4782
|
+
for (const agent of sorted) {
|
|
4783
|
+
const pos = positions.get(agent.id);
|
|
4784
|
+
if (!pos) continue;
|
|
4785
|
+
if (isBoxAgent(agent)) {
|
|
4786
|
+
drawAgentNode(buf, pos.x, pos.y, pos.width, agent, inactiveIds.has(agent.id));
|
|
4787
|
+
} else {
|
|
4788
|
+
const isLast = connectorIndexMap.get(agent.id) === connectorLastIdx;
|
|
4789
|
+
drawTreeConnector(buf, pos.x, pos.y, agent, isLast, inactiveIds.has(agent.id));
|
|
4790
|
+
}
|
|
4791
|
+
}
|
|
4659
4792
|
}
|
|
4660
4793
|
for (const edge of edges) {
|
|
4794
|
+
const fromAgent = agents.get(edge.from);
|
|
4795
|
+
const toAgent = agents.get(edge.to);
|
|
4796
|
+
if (fromAgent && toAgent && fromAgent.stage === toAgent.stage) continue;
|
|
4661
4797
|
const fromPos = positions.get(edge.from);
|
|
4662
4798
|
const toPos = positions.get(edge.to);
|
|
4663
4799
|
if (!fromPos || !toPos) continue;
|
|
@@ -4670,13 +4806,20 @@ function renderFlowMap(agents, edges, width, height, activeStage = null) {
|
|
|
4670
4806
|
y: toPos.y + Math.floor(toPos.height / 2)
|
|
4671
4807
|
};
|
|
4672
4808
|
const path9 = computeEdgePath(fromPoint, toPoint);
|
|
4809
|
+
const edgeDimmed = inactiveIds.has(edge.from) && inactiveIds.has(edge.to);
|
|
4673
4810
|
for (const seg of path9) {
|
|
4674
4811
|
const isArrow = seg.char === "\u25B8" || seg.char === "\u25C2" || seg.char === "\u25BE" || seg.char === "\u25B4";
|
|
4675
|
-
|
|
4812
|
+
const segStyle = edgeDimmed ? DIMMED_STYLE : isArrow ? EDGE_STYLES.arrow : EDGE_STYLES.path;
|
|
4813
|
+
buf.setChar(seg.x, seg.y, seg.char, segStyle);
|
|
4676
4814
|
}
|
|
4677
4815
|
const labelPos = computeLabelPosition(path9, edge.label);
|
|
4678
4816
|
if (labelPos) {
|
|
4679
|
-
buf.writeText(
|
|
4817
|
+
buf.writeText(
|
|
4818
|
+
labelPos.x,
|
|
4819
|
+
labelPos.y - 1,
|
|
4820
|
+
edge.label,
|
|
4821
|
+
edgeDimmed ? DIMMED_STYLE : EDGE_STYLES.label
|
|
4822
|
+
);
|
|
4680
4823
|
}
|
|
4681
4824
|
}
|
|
4682
4825
|
const counts = countByStatus(agents);
|
|
@@ -4695,20 +4838,22 @@ function renderFlowMap(agents, edges, width, height, activeStage = null) {
|
|
|
4695
4838
|
}
|
|
4696
4839
|
return buf;
|
|
4697
4840
|
}
|
|
4698
|
-
function renderFlowMapSimplified(agents, width, height) {
|
|
4841
|
+
function renderFlowMapSimplified(agents, width, height, activeStage = null) {
|
|
4699
4842
|
const buf = new ColorBuffer(width, height);
|
|
4700
4843
|
const byStage = groupByStage(agents);
|
|
4701
4844
|
let y = 0;
|
|
4702
4845
|
for (const stage of STAGE_ORDER) {
|
|
4703
4846
|
const stageAgents = byStage.get(stage);
|
|
4704
4847
|
if (!stageAgents || stageAgents.length === 0) continue;
|
|
4705
|
-
|
|
4848
|
+
const isInactiveStage = activeStage !== null && stage !== activeStage;
|
|
4849
|
+
const stageLabelStyle = isInactiveStage ? { fg: STAGE_LABEL_STYLES[stage].fg, dim: true } : STAGE_LABEL_STYLES[stage];
|
|
4850
|
+
buf.writeText(1, y, stage, stageLabelStyle);
|
|
4706
4851
|
y++;
|
|
4707
4852
|
const sorted = sortAgents(stageAgents);
|
|
4708
4853
|
for (const agent of sorted) {
|
|
4709
4854
|
if (y >= height - 1) break;
|
|
4710
4855
|
const boxW = Math.min(width - 2, NODE_WIDTH);
|
|
4711
|
-
drawAgentNode(buf, 1, y, boxW, agent);
|
|
4856
|
+
drawAgentNode(buf, 1, y, boxW, agent, isInactiveStage);
|
|
4712
4857
|
y += NODE_HEIGHT + 1;
|
|
4713
4858
|
}
|
|
4714
4859
|
}
|
|
@@ -4821,15 +4966,6 @@ function formatObjective(objectives, maxLines = 3) {
|
|
|
4821
4966
|
}
|
|
4822
4967
|
return lines.join("\n");
|
|
4823
4968
|
}
|
|
4824
|
-
function formatToolIO(tools, inputs, outputs) {
|
|
4825
|
-
const toolLine = `Tools: ${tools.join(" / ") || "none"}`;
|
|
4826
|
-
const inLine = `IN : ${inputs.join(", ") || "none"}`;
|
|
4827
|
-
const outParts = Object.entries(outputs).filter(([, v]) => v !== void 0 && v > 0).map(([k, v]) => `${k}(${v})`);
|
|
4828
|
-
const outLine = `OUT: ${outParts.join(" / ") || "none"}`;
|
|
4829
|
-
return `${toolLine}
|
|
4830
|
-
${inLine}
|
|
4831
|
-
${outLine}`;
|
|
4832
|
-
}
|
|
4833
4969
|
function formatLogTail(events, maxLines = 10) {
|
|
4834
4970
|
const tail = events.slice(-maxLines);
|
|
4835
4971
|
return tail.map((e) => `${e.timestamp} ${e.message}`).join("\n");
|
|
@@ -4849,20 +4985,6 @@ function formatEnhancedProgressBar(progress, width = 30) {
|
|
|
4849
4985
|
label: `${clamped}%`
|
|
4850
4986
|
};
|
|
4851
4987
|
}
|
|
4852
|
-
var SPARK_CHARS = "\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
|
|
4853
|
-
function formatActivitySparkline(toolCalls, bucketCount = 20, windowMs = 6e4, now) {
|
|
4854
|
-
const currentTime = now ?? Date.now();
|
|
4855
|
-
const bucketSize = windowMs / bucketCount;
|
|
4856
|
-
const buckets = new Array(bucketCount).fill(0);
|
|
4857
|
-
for (const call of toolCalls) {
|
|
4858
|
-
const age = currentTime - call.timestamp;
|
|
4859
|
-
if (age < 0 || age >= windowMs) continue;
|
|
4860
|
-
const idx = Math.min(bucketCount - 1, Math.floor(age / bucketSize));
|
|
4861
|
-
buckets[bucketCount - 1 - idx]++;
|
|
4862
|
-
}
|
|
4863
|
-
const max = Math.max(1, ...buckets);
|
|
4864
|
-
return buckets.map((b) => SPARK_CHARS[Math.round(b / max * (SPARK_CHARS.length - 1))]).join("");
|
|
4865
|
-
}
|
|
4866
4988
|
function formatEnhancedChecklist(tasks, maxItems = 6) {
|
|
4867
4989
|
const visible = tasks.slice(0, maxItems);
|
|
4868
4990
|
const lines = visible.map((t) => t.completed ? ` \u2714 ${t.subject}` : ` \u25FB ${t.subject}`);
|
|
@@ -4931,12 +5053,7 @@ function FocusedAgentPanel({
|
|
|
4931
5053
|
agent,
|
|
4932
5054
|
objectives,
|
|
4933
5055
|
activeSkills,
|
|
4934
|
-
tasks,
|
|
4935
|
-
tools,
|
|
4936
|
-
inputs,
|
|
4937
|
-
outputs,
|
|
4938
5056
|
eventLog,
|
|
4939
|
-
toolCalls,
|
|
4940
5057
|
contextDecisions = [],
|
|
4941
5058
|
contextNotes = [],
|
|
4942
5059
|
width,
|
|
@@ -4961,11 +5078,7 @@ function FocusedAgentPanel({
|
|
|
4961
5078
|
const statusLabel = agent.status.toUpperCase();
|
|
4962
5079
|
const progressBar = formatEnhancedProgressBar(agent.progress);
|
|
4963
5080
|
const objective = formatObjective(objectives);
|
|
4964
|
-
const checklist = formatEnhancedChecklist(tasks);
|
|
4965
|
-
const toolIO = formatToolIO(tools, inputs, outputs);
|
|
4966
5081
|
const logs = formatLogTail(eventLog);
|
|
4967
|
-
const agentToolCalls = toolCalls.filter((tc) => tc.agentId === agent.id);
|
|
4968
|
-
const sparkline = formatActivitySparkline(agentToolCalls);
|
|
4969
5082
|
return /* @__PURE__ */ React4.createElement(
|
|
4970
5083
|
Box4,
|
|
4971
5084
|
{
|
|
@@ -4981,15 +5094,6 @@ function FocusedAgentPanel({
|
|
|
4981
5094
|
objective ? /* @__PURE__ */ React4.createElement(Text4, null, objective) : /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, "No objectives"),
|
|
4982
5095
|
/* @__PURE__ */ React4.createElement(SectionDivider, { title: "Skills" }),
|
|
4983
5096
|
activeSkills.length > 0 ? activeSkills.map((s, i) => /* @__PURE__ */ React4.createElement(Text4, { key: i }, " ", s)) : /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, "No skills"),
|
|
4984
|
-
/* @__PURE__ */ React4.createElement(SectionDivider, { title: "Checklist" }),
|
|
4985
|
-
checklist ? checklist.split("\n").map((line, i) => {
|
|
4986
|
-
const isCompleted = line.includes("\u2714");
|
|
4987
|
-
return /* @__PURE__ */ React4.createElement(Text4, { key: i, color: isCompleted ? "green" : void 0 }, line);
|
|
4988
|
-
}) : /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, "No tasks"),
|
|
4989
|
-
/* @__PURE__ */ React4.createElement(SectionDivider, { title: "Activity" }),
|
|
4990
|
-
/* @__PURE__ */ React4.createElement(Text4, null, sparkline),
|
|
4991
|
-
/* @__PURE__ */ React4.createElement(SectionDivider, { title: "Tools / IO" }),
|
|
4992
|
-
/* @__PURE__ */ React4.createElement(Text4, null, toolIO),
|
|
4993
5097
|
/* @__PURE__ */ React4.createElement(SectionDivider, { title: "Context" }),
|
|
4994
5098
|
contextDecisions.length > 0 || contextNotes.length > 0 ? /* @__PURE__ */ React4.createElement(ContextSection, { decisions: contextDecisions, notes: contextNotes, width }) : /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, "No context"),
|
|
4995
5099
|
/* @__PURE__ */ React4.createElement(SectionDivider, { title: "Event Log" }),
|
|
@@ -4997,9 +5101,115 @@ function FocusedAgentPanel({
|
|
|
4997
5101
|
);
|
|
4998
5102
|
}
|
|
4999
5103
|
|
|
5000
|
-
// src/tui/components/
|
|
5104
|
+
// src/tui/components/ChecklistPanel.tsx
|
|
5001
5105
|
import React5 from "react";
|
|
5002
5106
|
import { Box as Box5, Text as Text5 } from "ink";
|
|
5107
|
+
|
|
5108
|
+
// src/tui/components/checklist-panel.pure.ts
|
|
5109
|
+
function resolveChecklistTasks(tasks, contextDecisions, contextNotes) {
|
|
5110
|
+
if (tasks.length > 0) {
|
|
5111
|
+
return tasks;
|
|
5112
|
+
}
|
|
5113
|
+
if (contextDecisions.length > 0) {
|
|
5114
|
+
return [
|
|
5115
|
+
{ id: "fallback-decision", subject: `Review: ${contextDecisions[0]}`, completed: false }
|
|
5116
|
+
];
|
|
5117
|
+
}
|
|
5118
|
+
if (contextNotes.length > 0) {
|
|
5119
|
+
return [{ id: "fallback-note", subject: `Check: ${contextNotes[0]}`, completed: false }];
|
|
5120
|
+
}
|
|
5121
|
+
return [{ id: "fallback-default", subject: "Review current task objectives", completed: false }];
|
|
5122
|
+
}
|
|
5123
|
+
|
|
5124
|
+
// src/tui/components/ChecklistPanel.tsx
|
|
5125
|
+
function ChecklistPanel({
|
|
5126
|
+
tasks,
|
|
5127
|
+
contextDecisions = [],
|
|
5128
|
+
contextNotes = [],
|
|
5129
|
+
width,
|
|
5130
|
+
height
|
|
5131
|
+
}) {
|
|
5132
|
+
const resolvedTasks = resolveChecklistTasks(tasks, contextDecisions, contextNotes);
|
|
5133
|
+
const checklist = formatEnhancedChecklist(resolvedTasks);
|
|
5134
|
+
return /* @__PURE__ */ React5.createElement(
|
|
5135
|
+
Box5,
|
|
5136
|
+
{
|
|
5137
|
+
borderStyle: "single",
|
|
5138
|
+
borderColor: BORDER_COLORS.panel,
|
|
5139
|
+
flexDirection: "column",
|
|
5140
|
+
width,
|
|
5141
|
+
height
|
|
5142
|
+
},
|
|
5143
|
+
/* @__PURE__ */ React5.createElement(Text5, { bold: true, dimColor: true }, "\u2500\u2500\u2500 Checklist"),
|
|
5144
|
+
checklist.split("\n").map((line, i) => {
|
|
5145
|
+
const isCompleted = line.includes("\u2714");
|
|
5146
|
+
return /* @__PURE__ */ React5.createElement(Text5, { key: i, color: isCompleted ? "green" : void 0 }, line);
|
|
5147
|
+
})
|
|
5148
|
+
);
|
|
5149
|
+
}
|
|
5150
|
+
|
|
5151
|
+
// src/tui/components/StageHealthBar.tsx
|
|
5152
|
+
import React6 from "react";
|
|
5153
|
+
import { Box as Box6, Text as Text6 } from "ink";
|
|
5154
|
+
|
|
5155
|
+
// src/tui/components/stage-health.pure.ts
|
|
5156
|
+
function formatCount(n) {
|
|
5157
|
+
return n >= 1e3 ? `${Math.round(n / 1e3)}k` : String(n);
|
|
5158
|
+
}
|
|
5159
|
+
function computeStageHealth(agents) {
|
|
5160
|
+
const health = {
|
|
5161
|
+
PLAN: createEmptyStageStats(),
|
|
5162
|
+
ACT: createEmptyStageStats(),
|
|
5163
|
+
EVAL: createEmptyStageStats(),
|
|
5164
|
+
AUTO: createEmptyStageStats()
|
|
5165
|
+
};
|
|
5166
|
+
for (const agent of agents.values()) {
|
|
5167
|
+
const stage = health[agent.stage];
|
|
5168
|
+
if (!stage) continue;
|
|
5169
|
+
switch (agent.status) {
|
|
5170
|
+
case "running":
|
|
5171
|
+
stage.running++;
|
|
5172
|
+
break;
|
|
5173
|
+
case "blocked":
|
|
5174
|
+
stage.blocked++;
|
|
5175
|
+
break;
|
|
5176
|
+
case "idle":
|
|
5177
|
+
stage.waiting++;
|
|
5178
|
+
break;
|
|
5179
|
+
case "done":
|
|
5180
|
+
stage.done++;
|
|
5181
|
+
break;
|
|
5182
|
+
case "error":
|
|
5183
|
+
stage.error++;
|
|
5184
|
+
break;
|
|
5185
|
+
}
|
|
5186
|
+
}
|
|
5187
|
+
return health;
|
|
5188
|
+
}
|
|
5189
|
+
function detectBottlenecks(eventLog) {
|
|
5190
|
+
const bottlenecks = /* @__PURE__ */ new Set();
|
|
5191
|
+
for (const entry of eventLog) {
|
|
5192
|
+
if (entry.level === "error") {
|
|
5193
|
+
const testMatch = entry.message.match(/(?:test_run|tests?):\s*FAIL\s*\((\d+)\)/i);
|
|
5194
|
+
if (testMatch) {
|
|
5195
|
+
bottlenecks.add(`tests failing(${testMatch[1]})`);
|
|
5196
|
+
continue;
|
|
5197
|
+
}
|
|
5198
|
+
const lintMatch = entry.message.match(/lint\(([^)]+)\)/i);
|
|
5199
|
+
if (lintMatch) {
|
|
5200
|
+
bottlenecks.add(`lint(${lintMatch[1]})`);
|
|
5201
|
+
continue;
|
|
5202
|
+
}
|
|
5203
|
+
const envMatch = entry.message.match(/missing\s+env\(([^)]+)\)/i);
|
|
5204
|
+
if (envMatch) {
|
|
5205
|
+
bottlenecks.add(`missing env(${envMatch[1]})`);
|
|
5206
|
+
}
|
|
5207
|
+
}
|
|
5208
|
+
}
|
|
5209
|
+
return [...bottlenecks];
|
|
5210
|
+
}
|
|
5211
|
+
|
|
5212
|
+
// src/tui/components/StageHealthBar.tsx
|
|
5003
5213
|
function StageStatDisplay({
|
|
5004
5214
|
mode,
|
|
5005
5215
|
stats
|
|
@@ -5008,52 +5218,53 @@ function StageStatDisplay({
|
|
|
5008
5218
|
const parts = [];
|
|
5009
5219
|
if (stats.running > 0)
|
|
5010
5220
|
parts.push(
|
|
5011
|
-
/* @__PURE__ */
|
|
5221
|
+
/* @__PURE__ */ React6.createElement(Text6, { key: "r", color: "green" }, " ", "\u25CF ", stats.running, " running")
|
|
5012
5222
|
);
|
|
5013
5223
|
if (stats.blocked > 0)
|
|
5014
5224
|
parts.push(
|
|
5015
|
-
/* @__PURE__ */
|
|
5225
|
+
/* @__PURE__ */ React6.createElement(Text6, { key: "b", color: "yellow" }, " ", "\u23F8 ", stats.blocked, " blocked")
|
|
5016
5226
|
);
|
|
5017
5227
|
if (stats.waiting > 0)
|
|
5018
5228
|
parts.push(
|
|
5019
|
-
/* @__PURE__ */
|
|
5229
|
+
/* @__PURE__ */ React6.createElement(Text6, { key: "w", dimColor: true }, " ", "\u25CB ", stats.waiting, " waiting")
|
|
5020
5230
|
);
|
|
5021
5231
|
if (stats.done > 0)
|
|
5022
5232
|
parts.push(
|
|
5023
|
-
/* @__PURE__ */
|
|
5233
|
+
/* @__PURE__ */ React6.createElement(Text6, { key: "d", color: "green" }, " ", "\u2713 ", stats.done)
|
|
5024
5234
|
);
|
|
5025
5235
|
if (stats.error > 0)
|
|
5026
5236
|
parts.push(
|
|
5027
|
-
/* @__PURE__ */
|
|
5237
|
+
/* @__PURE__ */ React6.createElement(Text6, { key: "e", color: "red", bold: true }, " ", "! ", stats.error, " err")
|
|
5028
5238
|
);
|
|
5029
5239
|
if (parts.length === 0)
|
|
5030
5240
|
parts.push(
|
|
5031
|
-
/* @__PURE__ */
|
|
5241
|
+
/* @__PURE__ */ React6.createElement(Text6, { key: "idle", dimColor: true }, " ", "idle")
|
|
5032
5242
|
);
|
|
5033
|
-
return /* @__PURE__ */
|
|
5243
|
+
return /* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Text6, { color, bold: true }, mode, ":"), parts);
|
|
5034
5244
|
}
|
|
5035
5245
|
function StageHealthBar({
|
|
5036
5246
|
stageHealth,
|
|
5037
5247
|
bottlenecks,
|
|
5038
5248
|
toolCount,
|
|
5249
|
+
agentCount,
|
|
5250
|
+
skillCount,
|
|
5039
5251
|
width
|
|
5040
5252
|
}) {
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
Box5,
|
|
5253
|
+
return /* @__PURE__ */ React6.createElement(
|
|
5254
|
+
Box6,
|
|
5044
5255
|
{
|
|
5045
5256
|
borderStyle: "double",
|
|
5046
5257
|
borderColor: BORDER_COLORS.panel,
|
|
5047
5258
|
width,
|
|
5048
5259
|
flexDirection: "column"
|
|
5049
5260
|
},
|
|
5050
|
-
/* @__PURE__ */
|
|
5261
|
+
/* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Box6, { gap: 2 }, ["PLAN", "ACT", "EVAL"].map((mode) => /* @__PURE__ */ React6.createElement(StageStatDisplay, { key: mode, mode, stats: stageHealth[mode] }))), /* @__PURE__ */ React6.createElement(Box6, { flexGrow: 1 }), /* @__PURE__ */ React6.createElement(Box6, { gap: 2 }, bottlenecks.length > 0 && /* @__PURE__ */ React6.createElement(Text6, { color: "red", bold: true }, "\u26A1 Bottlenecks: ", bottlenecks.join(" / ")), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "\u{1F916} ", formatCount(agentCount)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "\u2699 ", formatCount(skillCount)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "\u{1F527} ", formatCount(toolCount))))
|
|
5051
5262
|
);
|
|
5052
5263
|
}
|
|
5053
5264
|
|
|
5054
5265
|
// src/tui/components/ActivityVisualizer.tsx
|
|
5055
|
-
import
|
|
5056
|
-
import { Box as
|
|
5266
|
+
import React7, { useMemo as useMemo2 } from "react";
|
|
5267
|
+
import { Box as Box7, Text as Text7 } from "ink";
|
|
5057
5268
|
|
|
5058
5269
|
// src/tui/utils/display-width.ts
|
|
5059
5270
|
function isWide(code) {
|
|
@@ -5087,180 +5298,202 @@ function truncateToDisplayWidth(str, maxWidth) {
|
|
|
5087
5298
|
}
|
|
5088
5299
|
return str.slice(0, codeUnitIndex);
|
|
5089
5300
|
}
|
|
5090
|
-
function padEndDisplayWidth(str, targetWidth) {
|
|
5091
|
-
const currentWidth = estimateDisplayWidth(str);
|
|
5092
|
-
if (currentWidth >= targetWidth) return str;
|
|
5093
|
-
return str + " ".repeat(targetWidth - currentWidth);
|
|
5094
|
-
}
|
|
5095
5301
|
|
|
5096
5302
|
// src/tui/components/activity-visualizer.pure.ts
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
const
|
|
5111
|
-
const
|
|
5112
|
-
|
|
5303
|
+
var ACTIVITY_STATUS_ICONS = Object.freeze({
|
|
5304
|
+
running: "\u25CF",
|
|
5305
|
+
idle: "\u25CB",
|
|
5306
|
+
blocked: "\u23F8",
|
|
5307
|
+
error: "!",
|
|
5308
|
+
done: "\u25CB"
|
|
5309
|
+
});
|
|
5310
|
+
function renderSubtree(nodeId, agents, childrenOf, visited, prefix, isLast, lines, height, width) {
|
|
5311
|
+
if (lines.length >= height) return;
|
|
5312
|
+
if (visited.has(nodeId)) return;
|
|
5313
|
+
visited.add(nodeId);
|
|
5314
|
+
const node = agents.get(nodeId);
|
|
5315
|
+
if (!node) return;
|
|
5316
|
+
const connector = isLast ? "\u2514" : "\u251C";
|
|
5317
|
+
const icon = ACTIVITY_STATUS_ICONS[node.status] ?? "?";
|
|
5318
|
+
lines.push(truncateToDisplayWidth(`${prefix}${connector} ${icon} ${node.name}`, width));
|
|
5319
|
+
const childIds = (childrenOf.get(nodeId) ?? []).filter((id) => agents.has(id));
|
|
5320
|
+
const nextPrefix = prefix + (isLast ? " " : "\u2502 ");
|
|
5321
|
+
for (let i = 0; i < childIds.length; i++) {
|
|
5113
5322
|
if (lines.length >= height) break;
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5323
|
+
renderSubtree(
|
|
5324
|
+
childIds[i],
|
|
5325
|
+
agents,
|
|
5326
|
+
childrenOf,
|
|
5327
|
+
visited,
|
|
5328
|
+
nextPrefix,
|
|
5329
|
+
i === childIds.length - 1,
|
|
5330
|
+
lines,
|
|
5331
|
+
height,
|
|
5332
|
+
width
|
|
5117
5333
|
);
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5334
|
+
}
|
|
5335
|
+
}
|
|
5336
|
+
function renderAgentTree(agents, edges, activeSkills, width, height) {
|
|
5337
|
+
if (height <= 0 || width <= 0) return [];
|
|
5338
|
+
const lines = [truncateToDisplayWidth("\u{1F4CA} Activity", width)];
|
|
5339
|
+
if (height <= 1) return lines;
|
|
5340
|
+
if (agents.size === 0) {
|
|
5341
|
+
lines.push(truncateToDisplayWidth(" No agents", width));
|
|
5342
|
+
return lines.slice(0, height);
|
|
5343
|
+
}
|
|
5344
|
+
const childrenOf = /* @__PURE__ */ new Map();
|
|
5345
|
+
for (const edge of edges) {
|
|
5346
|
+
if (!childrenOf.has(edge.from)) childrenOf.set(edge.from, []);
|
|
5347
|
+
childrenOf.get(edge.from).push(edge.to);
|
|
5348
|
+
}
|
|
5349
|
+
const root = [...agents.values()].find((a) => a.isPrimary) ?? [...agents.values()][0];
|
|
5350
|
+
const rootIcon = ACTIVITY_STATUS_ICONS[root.status] ?? "?";
|
|
5351
|
+
lines.push(truncateToDisplayWidth(`${rootIcon} ${root.name}`, width));
|
|
5352
|
+
const visited = /* @__PURE__ */ new Set([root.id]);
|
|
5353
|
+
const rootChildIds = (childrenOf.get(root.id) ?? []).filter((id) => agents.has(id));
|
|
5354
|
+
const totalChildren = rootChildIds.length + activeSkills.length;
|
|
5355
|
+
for (let i = 0; i < rootChildIds.length; i++) {
|
|
5356
|
+
if (lines.length >= height) break;
|
|
5357
|
+
const isLast = i === totalChildren - 1;
|
|
5358
|
+
renderSubtree(rootChildIds[i], agents, childrenOf, visited, " ", isLast, lines, height, width);
|
|
5359
|
+
}
|
|
5360
|
+
for (let i = 0; i < activeSkills.length; i++) {
|
|
5361
|
+
if (lines.length >= height) break;
|
|
5362
|
+
const isLast = rootChildIds.length + i === totalChildren - 1;
|
|
5363
|
+
const connector = isLast ? "\u2514" : "\u251C";
|
|
5364
|
+
lines.push(truncateToDisplayWidth(` ${connector} \u25C9 ${activeSkills[i]} (skill)`, width));
|
|
5123
5365
|
}
|
|
5124
5366
|
return lines.slice(0, height);
|
|
5125
5367
|
}
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
const
|
|
5368
|
+
function wordWrap(text, width) {
|
|
5369
|
+
if (width <= 0) return [];
|
|
5370
|
+
const words = text.split(" ");
|
|
5371
|
+
const result = [];
|
|
5372
|
+
let current = "";
|
|
5373
|
+
let currentWidth = 0;
|
|
5374
|
+
for (const word of words) {
|
|
5375
|
+
const wordWidth = estimateDisplayWidth(word);
|
|
5376
|
+
if (current.length === 0) {
|
|
5377
|
+
current = wordWidth <= width ? word : truncateToDisplayWidth(word, width);
|
|
5378
|
+
currentWidth = estimateDisplayWidth(current);
|
|
5379
|
+
} else if (currentWidth + 1 + wordWidth <= width) {
|
|
5380
|
+
current += " " + word;
|
|
5381
|
+
currentWidth += 1 + wordWidth;
|
|
5382
|
+
} else {
|
|
5383
|
+
result.push(current);
|
|
5384
|
+
current = wordWidth <= width ? word : truncateToDisplayWidth(word, width);
|
|
5385
|
+
currentWidth = estimateDisplayWidth(current);
|
|
5386
|
+
}
|
|
5387
|
+
}
|
|
5388
|
+
if (current.length > 0) result.push(current);
|
|
5389
|
+
return result;
|
|
5390
|
+
}
|
|
5391
|
+
function renderAgentStatusCard(focusedAgent, currentMode, objectives, activeSkills, width, height) {
|
|
5133
5392
|
if (height <= 0 || width <= 0) return [];
|
|
5134
5393
|
const lines = [truncateToDisplayWidth("\u{1F4AC} Live", width)];
|
|
5135
|
-
if (
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5394
|
+
if (height <= 1) return lines;
|
|
5395
|
+
lines.push(truncateToDisplayWidth(`\u27EB Mode: ${currentMode ?? "\u2014"}`, width));
|
|
5396
|
+
if (!focusedAgent) {
|
|
5397
|
+
lines.push(truncateToDisplayWidth(" No agent", width));
|
|
5398
|
+
return lines.slice(0, height);
|
|
5399
|
+
}
|
|
5400
|
+
lines.push(truncateToDisplayWidth(`\u{1F916} ${focusedAgent.name}`, width));
|
|
5401
|
+
const statusIcon = ACTIVITY_STATUS_ICONS[focusedAgent.status] ?? "?";
|
|
5402
|
+
lines.push(truncateToDisplayWidth(` ${statusIcon} ${focusedAgent.status}`, width));
|
|
5403
|
+
const separator = truncateToDisplayWidth("\u2500".repeat(width), width);
|
|
5404
|
+
if (lines.length < height) lines.push(separator);
|
|
5405
|
+
let objectivesAdded = false;
|
|
5406
|
+
if (objectives.length > 0 && lines.length < height) {
|
|
5407
|
+
const wrapped = wordWrap(objectives[0], width);
|
|
5408
|
+
for (const wline of wrapped) {
|
|
5409
|
+
if (lines.length >= height) break;
|
|
5410
|
+
lines.push(wline);
|
|
5411
|
+
objectivesAdded = true;
|
|
5412
|
+
}
|
|
5413
|
+
}
|
|
5414
|
+
if (objectivesAdded && lines.length < height) lines.push(separator);
|
|
5415
|
+
for (const skill of activeSkills) {
|
|
5416
|
+
if (lines.length >= height) break;
|
|
5417
|
+
lines.push(truncateToDisplayWidth(`\u2699 ${skill}`, width));
|
|
5149
5418
|
}
|
|
5150
5419
|
return lines.slice(0, height);
|
|
5151
5420
|
}
|
|
5152
5421
|
|
|
5153
5422
|
// src/tui/components/ActivityVisualizer.tsx
|
|
5154
5423
|
function ActivityVisualizer({
|
|
5155
|
-
toolCalls,
|
|
5156
5424
|
currentMode,
|
|
5425
|
+
focusedAgent,
|
|
5426
|
+
agents,
|
|
5427
|
+
edges,
|
|
5428
|
+
activeSkills,
|
|
5429
|
+
objectives,
|
|
5157
5430
|
width,
|
|
5158
5431
|
height
|
|
5159
5432
|
}) {
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
}
|
|
5163
|
-
const barChartWidth = Math.floor(width * 0.6);
|
|
5164
|
-
const livePanelWidth = width - barChartWidth;
|
|
5433
|
+
const treeWidth = Math.floor(width * 0.6);
|
|
5434
|
+
const cardWidth = width - treeWidth;
|
|
5165
5435
|
const contentHeight = Math.max(1, height - 2);
|
|
5166
|
-
const
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
[barChartData, barChartWidth, contentHeight]
|
|
5436
|
+
const treeLines = useMemo2(
|
|
5437
|
+
() => renderAgentTree(agents, edges, activeSkills, Math.max(1, treeWidth - 2), contentHeight),
|
|
5438
|
+
[agents, edges, activeSkills, treeWidth, contentHeight]
|
|
5170
5439
|
);
|
|
5171
|
-
const
|
|
5172
|
-
() =>
|
|
5173
|
-
|
|
5440
|
+
const cardLines = useMemo2(
|
|
5441
|
+
() => renderAgentStatusCard(
|
|
5442
|
+
focusedAgent,
|
|
5443
|
+
currentMode,
|
|
5444
|
+
objectives,
|
|
5445
|
+
activeSkills,
|
|
5446
|
+
Math.max(1, cardWidth - 2),
|
|
5447
|
+
contentHeight
|
|
5448
|
+
),
|
|
5449
|
+
[focusedAgent, currentMode, objectives, activeSkills, cardWidth, contentHeight]
|
|
5174
5450
|
);
|
|
5175
|
-
|
|
5176
|
-
|
|
5451
|
+
if (width <= 0 || height <= 0) {
|
|
5452
|
+
return /* @__PURE__ */ React7.createElement(Box7, null);
|
|
5453
|
+
}
|
|
5454
|
+
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "row", width, height }, /* @__PURE__ */ React7.createElement(
|
|
5455
|
+
Box7,
|
|
5177
5456
|
{
|
|
5178
5457
|
borderStyle: "single",
|
|
5179
5458
|
borderColor: BORDER_COLORS.panel,
|
|
5180
5459
|
flexDirection: "column",
|
|
5181
|
-
width:
|
|
5460
|
+
width: treeWidth,
|
|
5182
5461
|
height
|
|
5183
5462
|
},
|
|
5184
|
-
|
|
5185
|
-
), /* @__PURE__ */
|
|
5186
|
-
|
|
5463
|
+
treeLines.map((line, i) => /* @__PURE__ */ React7.createElement(Text7, { key: i }, line))
|
|
5464
|
+
), /* @__PURE__ */ React7.createElement(
|
|
5465
|
+
Box7,
|
|
5187
5466
|
{
|
|
5188
5467
|
borderStyle: "single",
|
|
5189
5468
|
borderColor: BORDER_COLORS.panel,
|
|
5190
5469
|
flexDirection: "column",
|
|
5191
|
-
width:
|
|
5470
|
+
width: cardWidth,
|
|
5192
5471
|
height
|
|
5193
5472
|
},
|
|
5194
|
-
|
|
5473
|
+
cardLines.map((line, i) => /* @__PURE__ */ React7.createElement(Text7, { key: i }, line))
|
|
5195
5474
|
));
|
|
5196
5475
|
}
|
|
5197
5476
|
|
|
5198
|
-
// src/tui/components/stage-health.pure.ts
|
|
5199
|
-
function computeStageHealth(agents) {
|
|
5200
|
-
const health = {
|
|
5201
|
-
PLAN: createEmptyStageStats(),
|
|
5202
|
-
ACT: createEmptyStageStats(),
|
|
5203
|
-
EVAL: createEmptyStageStats(),
|
|
5204
|
-
AUTO: createEmptyStageStats()
|
|
5205
|
-
};
|
|
5206
|
-
for (const agent of agents.values()) {
|
|
5207
|
-
const stage = health[agent.stage];
|
|
5208
|
-
if (!stage) continue;
|
|
5209
|
-
switch (agent.status) {
|
|
5210
|
-
case "running":
|
|
5211
|
-
stage.running++;
|
|
5212
|
-
break;
|
|
5213
|
-
case "blocked":
|
|
5214
|
-
stage.blocked++;
|
|
5215
|
-
break;
|
|
5216
|
-
case "idle":
|
|
5217
|
-
stage.waiting++;
|
|
5218
|
-
break;
|
|
5219
|
-
case "done":
|
|
5220
|
-
stage.done++;
|
|
5221
|
-
break;
|
|
5222
|
-
case "error":
|
|
5223
|
-
stage.error++;
|
|
5224
|
-
break;
|
|
5225
|
-
}
|
|
5226
|
-
}
|
|
5227
|
-
return health;
|
|
5228
|
-
}
|
|
5229
|
-
function detectBottlenecks(eventLog) {
|
|
5230
|
-
const bottlenecks = /* @__PURE__ */ new Set();
|
|
5231
|
-
for (const entry of eventLog) {
|
|
5232
|
-
if (entry.level === "error") {
|
|
5233
|
-
const testMatch = entry.message.match(/(?:test_run|tests?):\s*FAIL\s*\((\d+)\)/i);
|
|
5234
|
-
if (testMatch) {
|
|
5235
|
-
bottlenecks.add(`tests failing(${testMatch[1]})`);
|
|
5236
|
-
continue;
|
|
5237
|
-
}
|
|
5238
|
-
const lintMatch = entry.message.match(/lint\(([^)]+)\)/i);
|
|
5239
|
-
if (lintMatch) {
|
|
5240
|
-
bottlenecks.add(`lint(${lintMatch[1]})`);
|
|
5241
|
-
continue;
|
|
5242
|
-
}
|
|
5243
|
-
const envMatch = entry.message.match(/missing\s+env\(([^)]+)\)/i);
|
|
5244
|
-
if (envMatch) {
|
|
5245
|
-
bottlenecks.add(`missing env(${envMatch[1]})`);
|
|
5246
|
-
}
|
|
5247
|
-
}
|
|
5248
|
-
}
|
|
5249
|
-
return [...bottlenecks];
|
|
5250
|
-
}
|
|
5251
|
-
|
|
5252
5477
|
// src/tui/components/grid-layout.pure.ts
|
|
5253
5478
|
var HEADER_HEIGHT = 3;
|
|
5254
5479
|
var STAGE_HEALTH_HEIGHT = 3;
|
|
5255
5480
|
var NARROW_FLOW_MAP_HEIGHT = 5;
|
|
5256
5481
|
var MIN_ROWS = HEADER_HEIGHT + STAGE_HEALTH_HEIGHT + 2;
|
|
5257
5482
|
var MIN_COLUMNS = 20;
|
|
5483
|
+
var CHECKLIST_HEIGHT_MIN = 6;
|
|
5484
|
+
var CHECKLIST_HEIGHT_MAX = 10;
|
|
5258
5485
|
var FOCUSED_AGENT_WIDTH = {
|
|
5259
5486
|
wide: 63,
|
|
5260
5487
|
// was 70 → -10% (FlowMap/Activity gains +7 cols)
|
|
5261
5488
|
medium: 58
|
|
5262
5489
|
// was 64 → -9.4% (FlowMap/Activity gains +6 cols)
|
|
5263
5490
|
};
|
|
5491
|
+
function computeChecklistHeight(mainHeight) {
|
|
5492
|
+
return Math.max(
|
|
5493
|
+
CHECKLIST_HEIGHT_MIN,
|
|
5494
|
+
Math.min(CHECKLIST_HEIGHT_MAX, Math.ceil(mainHeight * 0.3))
|
|
5495
|
+
);
|
|
5496
|
+
}
|
|
5264
5497
|
function computeGridLayout(columns, rows, layoutMode) {
|
|
5265
5498
|
const cols = Math.max(MIN_COLUMNS, columns);
|
|
5266
5499
|
const r = Math.max(MIN_ROWS, rows);
|
|
@@ -5275,11 +5508,20 @@ function computeGridLayout(columns, rows, layoutMode) {
|
|
|
5275
5508
|
const mainHeight = r - HEADER_HEIGHT - STAGE_HEALTH_HEIGHT;
|
|
5276
5509
|
if (layoutMode === "narrow") {
|
|
5277
5510
|
const flowMapHeight2 = Math.min(NARROW_FLOW_MAP_HEIGHT, mainHeight - 1);
|
|
5278
|
-
const
|
|
5511
|
+
const availableForChecklist = mainHeight - flowMapHeight2;
|
|
5512
|
+
const rawChecklistHeight = computeChecklistHeight(mainHeight);
|
|
5513
|
+
const checklistHeight2 = Math.min(rawChecklistHeight, Math.max(0, availableForChecklist - 1));
|
|
5514
|
+
const focusedHeight = availableForChecklist - checklistHeight2;
|
|
5279
5515
|
return {
|
|
5280
5516
|
header,
|
|
5281
|
-
|
|
5282
|
-
|
|
5517
|
+
checklistPanel: { x: 0, y: mainY, width: cols, height: checklistHeight2 },
|
|
5518
|
+
focusedAgent: { x: 0, y: mainY + checklistHeight2, width: cols, height: focusedHeight },
|
|
5519
|
+
flowMap: {
|
|
5520
|
+
x: 0,
|
|
5521
|
+
y: mainY + checklistHeight2 + focusedHeight,
|
|
5522
|
+
width: cols,
|
|
5523
|
+
height: flowMapHeight2
|
|
5524
|
+
},
|
|
5283
5525
|
monitorPanel: { x: 0, y: 0, width: 0, height: 0 },
|
|
5284
5526
|
stageHealth,
|
|
5285
5527
|
total: { width: cols, height: r }
|
|
@@ -5289,119 +5531,148 @@ function computeGridLayout(columns, rows, layoutMode) {
|
|
|
5289
5531
|
const flowMapWidth = cols - focusedWidth;
|
|
5290
5532
|
const flowMapHeight = Math.ceil(mainHeight / 2);
|
|
5291
5533
|
const monitorHeight = mainHeight - flowMapHeight;
|
|
5534
|
+
const checklistHeight = computeChecklistHeight(mainHeight);
|
|
5535
|
+
const focusedAgentHeight = mainHeight - checklistHeight;
|
|
5292
5536
|
return {
|
|
5293
5537
|
header,
|
|
5538
|
+
checklistPanel: { x: flowMapWidth, y: mainY, width: focusedWidth, height: checklistHeight },
|
|
5294
5539
|
flowMap: { x: 0, y: mainY, width: flowMapWidth, height: flowMapHeight },
|
|
5295
5540
|
monitorPanel: { x: 0, y: mainY + flowMapHeight, width: flowMapWidth, height: monitorHeight },
|
|
5296
|
-
focusedAgent: {
|
|
5541
|
+
focusedAgent: {
|
|
5542
|
+
x: flowMapWidth,
|
|
5543
|
+
y: mainY + checklistHeight,
|
|
5544
|
+
width: focusedWidth,
|
|
5545
|
+
height: focusedAgentHeight
|
|
5546
|
+
},
|
|
5297
5547
|
stageHealth,
|
|
5298
5548
|
total: { width: cols, height: r }
|
|
5299
5549
|
};
|
|
5300
5550
|
}
|
|
5301
5551
|
|
|
5302
5552
|
// src/tui/dashboard-app.tsx
|
|
5303
|
-
function DashboardApp({
|
|
5553
|
+
function DashboardApp({
|
|
5554
|
+
eventBus,
|
|
5555
|
+
externalState,
|
|
5556
|
+
workspace: workspaceProp
|
|
5557
|
+
}) {
|
|
5304
5558
|
const { columns, rows, layoutMode } = useTerminalSize();
|
|
5305
5559
|
const internalState = useDashboardState(externalState ? void 0 : eventBus);
|
|
5306
5560
|
const state = externalState ?? internalState;
|
|
5307
5561
|
const focusedAgent = state.focusedAgentId ? state.agents.get(state.focusedAgentId) ?? null : null;
|
|
5308
5562
|
const stageHealth = useMemo3(() => computeStageHealth(state.agents), [state.agents]);
|
|
5309
|
-
const tools = useMemo3(() => {
|
|
5310
|
-
const seen = /* @__PURE__ */ new Set();
|
|
5311
|
-
for (const e of state.eventLog) {
|
|
5312
|
-
seen.add(e.message.split(" [")[0]);
|
|
5313
|
-
}
|
|
5314
|
-
return [...seen];
|
|
5315
|
-
}, [state.eventLog]);
|
|
5316
5563
|
const bottlenecks = useMemo3(() => detectBottlenecks(state.eventLog), [state.eventLog]);
|
|
5317
5564
|
const grid = useMemo3(
|
|
5318
5565
|
() => computeGridLayout(columns, rows, layoutMode),
|
|
5319
5566
|
[columns, rows, layoutMode]
|
|
5320
5567
|
);
|
|
5321
|
-
return /* @__PURE__ */
|
|
5568
|
+
return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", width: grid.total.width, height: grid.total.height }, /* @__PURE__ */ React8.createElement(
|
|
5322
5569
|
HeaderBar,
|
|
5323
5570
|
{
|
|
5324
|
-
workspace: state.workspace,
|
|
5325
|
-
sessionId: state.sessionId,
|
|
5571
|
+
workspace: workspaceProp ?? state.workspace,
|
|
5326
5572
|
currentMode: state.currentMode,
|
|
5327
5573
|
globalState: state.globalState,
|
|
5328
5574
|
layoutMode,
|
|
5329
5575
|
width: grid.header.width
|
|
5330
5576
|
}
|
|
5331
|
-
), layoutMode === "narrow" ? /* @__PURE__ */
|
|
5577
|
+
), layoutMode === "narrow" ? /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column" }, grid.checklistPanel.height > 0 && /* @__PURE__ */ React8.createElement(
|
|
5578
|
+
ChecklistPanel,
|
|
5579
|
+
{
|
|
5580
|
+
tasks: state.tasks,
|
|
5581
|
+
contextDecisions: state.contextDecisions,
|
|
5582
|
+
contextNotes: state.contextNotes,
|
|
5583
|
+
width: grid.checklistPanel.width,
|
|
5584
|
+
height: grid.checklistPanel.height
|
|
5585
|
+
}
|
|
5586
|
+
), /* @__PURE__ */ React8.createElement(
|
|
5332
5587
|
FocusedAgentPanel,
|
|
5333
5588
|
{
|
|
5334
5589
|
agent: focusedAgent,
|
|
5335
5590
|
objectives: state.objectives,
|
|
5336
5591
|
activeSkills: state.activeSkills,
|
|
5337
|
-
tasks: state.tasks,
|
|
5338
|
-
tools,
|
|
5339
|
-
inputs: tools,
|
|
5340
|
-
outputs: state.outputStats,
|
|
5341
5592
|
eventLog: state.eventLog,
|
|
5342
|
-
toolCalls: state.toolCalls,
|
|
5343
5593
|
contextDecisions: state.contextDecisions,
|
|
5344
5594
|
contextNotes: state.contextNotes,
|
|
5345
5595
|
width: grid.focusedAgent.width,
|
|
5346
5596
|
height: grid.focusedAgent.height
|
|
5347
5597
|
}
|
|
5348
|
-
), /* @__PURE__ */
|
|
5349
|
-
FlowMap,
|
|
5350
|
-
{
|
|
5351
|
-
agents: state.agents,
|
|
5352
|
-
edges: state.edges,
|
|
5353
|
-
layoutMode,
|
|
5354
|
-
width: grid.flowMap.width,
|
|
5355
|
-
height: grid.flowMap.height
|
|
5356
|
-
}
|
|
5357
|
-
)) : /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "row", width: grid.total.width, height: grid.focusedAgent.height }, /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", width: grid.flowMap.width }, /* @__PURE__ */ React7.createElement(
|
|
5598
|
+
), /* @__PURE__ */ React8.createElement(
|
|
5358
5599
|
FlowMap,
|
|
5359
5600
|
{
|
|
5360
5601
|
agents: state.agents,
|
|
5361
5602
|
edges: state.edges,
|
|
5362
5603
|
layoutMode,
|
|
5363
5604
|
width: grid.flowMap.width,
|
|
5364
|
-
height: grid.flowMap.height
|
|
5605
|
+
height: grid.flowMap.height,
|
|
5606
|
+
activeStage: state.currentMode
|
|
5365
5607
|
}
|
|
5366
|
-
)
|
|
5367
|
-
|
|
5608
|
+
)) : /* @__PURE__ */ React8.createElement(
|
|
5609
|
+
Box8,
|
|
5368
5610
|
{
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
}
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5611
|
+
flexDirection: "row",
|
|
5612
|
+
width: grid.total.width,
|
|
5613
|
+
height: grid.checklistPanel.height + grid.focusedAgent.height
|
|
5614
|
+
},
|
|
5615
|
+
/* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", width: grid.flowMap.width }, /* @__PURE__ */ React8.createElement(
|
|
5616
|
+
FlowMap,
|
|
5617
|
+
{
|
|
5618
|
+
agents: state.agents,
|
|
5619
|
+
edges: state.edges,
|
|
5620
|
+
layoutMode,
|
|
5621
|
+
width: grid.flowMap.width,
|
|
5622
|
+
height: grid.flowMap.height,
|
|
5623
|
+
activeStage: state.currentMode
|
|
5624
|
+
}
|
|
5625
|
+
), /* @__PURE__ */ React8.createElement(
|
|
5626
|
+
ActivityVisualizer,
|
|
5627
|
+
{
|
|
5628
|
+
currentMode: state.currentMode,
|
|
5629
|
+
focusedAgent,
|
|
5630
|
+
agents: state.agents,
|
|
5631
|
+
edges: state.edges,
|
|
5632
|
+
activeSkills: state.activeSkills,
|
|
5633
|
+
objectives: state.objectives,
|
|
5634
|
+
width: grid.monitorPanel.width,
|
|
5635
|
+
height: grid.monitorPanel.height
|
|
5636
|
+
}
|
|
5637
|
+
)),
|
|
5638
|
+
/* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", width: grid.checklistPanel.width }, /* @__PURE__ */ React8.createElement(
|
|
5639
|
+
ChecklistPanel,
|
|
5640
|
+
{
|
|
5641
|
+
tasks: state.tasks,
|
|
5642
|
+
contextDecisions: state.contextDecisions,
|
|
5643
|
+
contextNotes: state.contextNotes,
|
|
5644
|
+
width: grid.checklistPanel.width,
|
|
5645
|
+
height: grid.checklistPanel.height
|
|
5646
|
+
}
|
|
5647
|
+
), /* @__PURE__ */ React8.createElement(
|
|
5648
|
+
FocusedAgentPanel,
|
|
5649
|
+
{
|
|
5650
|
+
agent: focusedAgent,
|
|
5651
|
+
objectives: state.objectives,
|
|
5652
|
+
activeSkills: state.activeSkills,
|
|
5653
|
+
eventLog: state.eventLog,
|
|
5654
|
+
contextDecisions: state.contextDecisions,
|
|
5655
|
+
contextNotes: state.contextNotes,
|
|
5656
|
+
width: grid.focusedAgent.width,
|
|
5657
|
+
height: grid.focusedAgent.height
|
|
5658
|
+
}
|
|
5659
|
+
))
|
|
5660
|
+
), /* @__PURE__ */ React8.createElement(
|
|
5392
5661
|
StageHealthBar,
|
|
5393
5662
|
{
|
|
5394
5663
|
stageHealth,
|
|
5395
5664
|
bottlenecks,
|
|
5396
5665
|
toolCount: state.toolInvokeCount,
|
|
5666
|
+
agentCount: state.agentActivateCount,
|
|
5667
|
+
skillCount: state.skillInvokeCount,
|
|
5397
5668
|
width: grid.stageHealth.width
|
|
5398
5669
|
}
|
|
5399
5670
|
));
|
|
5400
5671
|
}
|
|
5401
5672
|
|
|
5402
5673
|
// src/tui/multi-session-app.tsx
|
|
5403
|
-
import
|
|
5404
|
-
import { Box as
|
|
5674
|
+
import React10, { useMemo as useMemo4, useCallback as useCallback2 } from "react";
|
|
5675
|
+
import { Box as Box10, useInput } from "ink";
|
|
5405
5676
|
import * as path8 from "path";
|
|
5406
5677
|
|
|
5407
5678
|
// src/tui/hooks/use-multi-session-state.ts
|
|
@@ -5557,8 +5828,8 @@ function useMultiSessionState(manager) {
|
|
|
5557
5828
|
}
|
|
5558
5829
|
|
|
5559
5830
|
// src/tui/components/SessionTabBar.tsx
|
|
5560
|
-
import
|
|
5561
|
-
import { Box as
|
|
5831
|
+
import React9 from "react";
|
|
5832
|
+
import { Box as Box9, Text as Text8 } from "ink";
|
|
5562
5833
|
|
|
5563
5834
|
// src/tui/components/session-tab-bar.pure.ts
|
|
5564
5835
|
var STATUS_ICONS2 = {
|
|
@@ -5612,7 +5883,7 @@ function SessionTabBar({
|
|
|
5612
5883
|
if (formatted === "") {
|
|
5613
5884
|
return null;
|
|
5614
5885
|
}
|
|
5615
|
-
return /* @__PURE__ */
|
|
5886
|
+
return /* @__PURE__ */ React9.createElement(Box9, { width, height: 1 }, /* @__PURE__ */ React9.createElement(Text8, null, formatted));
|
|
5616
5887
|
}
|
|
5617
5888
|
|
|
5618
5889
|
// src/tui/multi-session-app.tsx
|
|
@@ -5640,6 +5911,10 @@ function MultiSessionApp({ manager }) {
|
|
|
5640
5911
|
const found = managedSessions.find((s) => s.instance.pid === activeSessionPid);
|
|
5641
5912
|
return found?.eventBus;
|
|
5642
5913
|
}, [manager, activeSessionPid]);
|
|
5914
|
+
const activeProjectRoot = useMemo4(() => {
|
|
5915
|
+
if (activeSessionPid === null) return void 0;
|
|
5916
|
+
return sessions.get(activeSessionPid)?.projectRoot;
|
|
5917
|
+
}, [sessions, activeSessionPid]);
|
|
5643
5918
|
const handleInput = useCallback2(
|
|
5644
5919
|
(input, key) => {
|
|
5645
5920
|
if (key.rightArrow) {
|
|
@@ -5658,7 +5933,14 @@ function MultiSessionApp({ manager }) {
|
|
|
5658
5933
|
[switchNext, switchPrev, switchByIndex]
|
|
5659
5934
|
);
|
|
5660
5935
|
useInput(handleInput);
|
|
5661
|
-
return /* @__PURE__ */
|
|
5936
|
+
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(SessionTabBar, { sessions: tabs, width: columns, layoutMode }), /* @__PURE__ */ React10.createElement(
|
|
5937
|
+
DashboardApp,
|
|
5938
|
+
{
|
|
5939
|
+
key: activeSessionPid ?? "none",
|
|
5940
|
+
eventBus: activeEventBus,
|
|
5941
|
+
workspace: activeProjectRoot
|
|
5942
|
+
}
|
|
5943
|
+
));
|
|
5662
5944
|
}
|
|
5663
5945
|
|
|
5664
5946
|
// src/tui/types.ts
|
|
@@ -5721,10 +6003,10 @@ function useClock() {
|
|
|
5721
6003
|
// src/tui/index.tsx
|
|
5722
6004
|
function startTui(options) {
|
|
5723
6005
|
const renderOptions = options.stdout ? { stdout: options.stdout } : {};
|
|
5724
|
-
return render(/* @__PURE__ */
|
|
6006
|
+
return render(/* @__PURE__ */ React11.createElement(DashboardApp, { eventBus: options.eventBus }), renderOptions);
|
|
5725
6007
|
}
|
|
5726
6008
|
function renderMultiSession(options) {
|
|
5727
|
-
return render(/* @__PURE__ */
|
|
6009
|
+
return render(/* @__PURE__ */ React11.createElement(MultiSessionApp, { manager: options.manager }));
|
|
5728
6010
|
}
|
|
5729
6011
|
export {
|
|
5730
6012
|
AGENT_STATUSES,
|