codingbuddy 4.2.0 → 4.4.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/init/prompts/model-prompt.js +48 -6
- package/dist/src/cli/init/prompts/model-prompt.js.map +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/config/config.service.d.ts +7 -1
- package/dist/src/config/config.service.js +13 -1
- package/dist/src/config/config.service.js.map +1 -1
- package/dist/src/keyword/keyword.module.js +2 -0
- package/dist/src/keyword/keyword.module.js.map +1 -1
- package/dist/src/keyword/keyword.service.d.ts +3 -0
- package/dist/src/keyword/keyword.service.js +13 -1
- package/dist/src/keyword/keyword.service.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 +26 -1
- package/dist/src/mcp/handlers/mode.handler.js.map +1 -1
- package/dist/src/mcp/handlers/skill.handler.js +9 -2
- package/dist/src/mcp/handlers/skill.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/mcp/mcp.service.d.ts +1 -0
- package/dist/src/mcp/mcp.service.js +17 -0
- package/dist/src/mcp/mcp.service.js.map +1 -1
- package/dist/src/model/model.constants.d.ts +11 -0
- package/dist/src/model/model.constants.js +12 -1
- package/dist/src/model/model.constants.js.map +1 -1
- package/dist/src/model/model.resolver.d.ts +1 -1
- package/dist/src/model/model.resolver.js +15 -4
- package/dist/src/model/model.resolver.js.map +1 -1
- package/dist/src/shared/client-type.d.ts +6 -0
- package/dist/src/shared/client-type.js +21 -0
- package/dist/src/shared/client-type.js.map +1 -0
- 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/skill/i18n/keywords.js +1466 -15
- package/dist/src/skill/i18n/keywords.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 +631 -334
- 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 = [
|
|
@@ -3476,6 +3489,7 @@ ${file.content}
|
|
|
3476
3489
|
var ConfigService = class {
|
|
3477
3490
|
constructor() {
|
|
3478
3491
|
this.logger = new Logger6(ConfigService.name);
|
|
3492
|
+
this.projectRootSource = "auto_detect";
|
|
3479
3493
|
this.projectConfig = null;
|
|
3480
3494
|
this.isLoaded = false;
|
|
3481
3495
|
this.projectRoot = this.resolveProjectRoot();
|
|
@@ -3493,6 +3507,7 @@ var ConfigService = class {
|
|
|
3493
3507
|
const stat2 = statSync(normalizedPath);
|
|
3494
3508
|
if (stat2.isDirectory()) {
|
|
3495
3509
|
this.logger.log(`Using project root from CODINGBUDDY_PROJECT_ROOT: ${normalizedPath}`);
|
|
3510
|
+
this.projectRootSource = "env";
|
|
3496
3511
|
return normalizedPath;
|
|
3497
3512
|
}
|
|
3498
3513
|
this.logger.warn(
|
|
@@ -3530,7 +3545,7 @@ var ConfigService = class {
|
|
|
3530
3545
|
* @param root - Path to the project root directory
|
|
3531
3546
|
* @throws Error if path does not exist, is not a directory, or contains invalid characters
|
|
3532
3547
|
*/
|
|
3533
|
-
async setProjectRootAndReload(root) {
|
|
3548
|
+
async setProjectRootAndReload(root, source = "roots_list") {
|
|
3534
3549
|
if (root.includes("\0")) {
|
|
3535
3550
|
throw new Error("Path contains null bytes (possible null byte injection)");
|
|
3536
3551
|
}
|
|
@@ -3556,6 +3571,7 @@ var ConfigService = class {
|
|
|
3556
3571
|
}
|
|
3557
3572
|
clearProjectRootCache();
|
|
3558
3573
|
this.projectRoot = resolvedPath;
|
|
3574
|
+
this.projectRootSource = source;
|
|
3559
3575
|
this.isLoaded = false;
|
|
3560
3576
|
this.projectConfig = null;
|
|
3561
3577
|
await this.loadProjectConfig();
|
|
@@ -3567,6 +3583,18 @@ var ConfigService = class {
|
|
|
3567
3583
|
getProjectRoot() {
|
|
3568
3584
|
return this.projectRoot;
|
|
3569
3585
|
}
|
|
3586
|
+
/**
|
|
3587
|
+
* Get how the project root was resolved
|
|
3588
|
+
*/
|
|
3589
|
+
getProjectRootSource() {
|
|
3590
|
+
return this.projectRootSource;
|
|
3591
|
+
}
|
|
3592
|
+
getClientName() {
|
|
3593
|
+
return this.clientName;
|
|
3594
|
+
}
|
|
3595
|
+
setClientName(name) {
|
|
3596
|
+
this.clientName = name;
|
|
3597
|
+
}
|
|
3570
3598
|
/**
|
|
3571
3599
|
* Load all project configuration
|
|
3572
3600
|
*/
|
|
@@ -3933,6 +3961,7 @@ function selectFocusedAgent(agents, currentFocusId) {
|
|
|
3933
3961
|
var EVENT_LOG_MAX = 100;
|
|
3934
3962
|
var EDGE_MAX = 200;
|
|
3935
3963
|
var TOOL_CALLS_MAX = 200;
|
|
3964
|
+
var EXPECTED_AGENT_DURATION_MS = 12e4;
|
|
3936
3965
|
function createInitialDashboardState() {
|
|
3937
3966
|
return {
|
|
3938
3967
|
workspace: process.cwd(),
|
|
@@ -3948,6 +3977,8 @@ function createInitialDashboardState() {
|
|
|
3948
3977
|
objectives: [],
|
|
3949
3978
|
activeSkills: [],
|
|
3950
3979
|
toolInvokeCount: 0,
|
|
3980
|
+
agentActivateCount: 0,
|
|
3981
|
+
skillInvokeCount: 0,
|
|
3951
3982
|
outputStats: { files: 0, commits: 0 },
|
|
3952
3983
|
contextDecisions: [],
|
|
3953
3984
|
contextNotes: [],
|
|
@@ -3969,11 +4000,20 @@ function dashboardReducer(state, action) {
|
|
|
3969
4000
|
stage: state.currentMode ?? "PLAN",
|
|
3970
4001
|
status: "running",
|
|
3971
4002
|
isPrimary,
|
|
3972
|
-
progress: 0
|
|
4003
|
+
progress: 0,
|
|
4004
|
+
isParallel: false,
|
|
4005
|
+
// AGENT_ACTIVATED는 항상 단일 에이전트
|
|
4006
|
+
startedAt: Date.now()
|
|
3973
4007
|
});
|
|
3974
4008
|
const globalState = "RUNNING";
|
|
3975
4009
|
const focusedAgentId = selectFocusedAgent(agents, state.focusedAgentId);
|
|
3976
|
-
return {
|
|
4010
|
+
return {
|
|
4011
|
+
...state,
|
|
4012
|
+
agents,
|
|
4013
|
+
globalState,
|
|
4014
|
+
focusedAgentId,
|
|
4015
|
+
agentActivateCount: state.agentActivateCount + 1
|
|
4016
|
+
};
|
|
3977
4017
|
}
|
|
3978
4018
|
case "AGENT_DEACTIVATED": {
|
|
3979
4019
|
const { agentId, reason } = action.payload;
|
|
@@ -3983,7 +4023,8 @@ function dashboardReducer(state, action) {
|
|
|
3983
4023
|
agents.set(agentId, {
|
|
3984
4024
|
...existing,
|
|
3985
4025
|
status: reason === "error" ? "error" : "done",
|
|
3986
|
-
progress: reason === "error" ? existing.progress : 100
|
|
4026
|
+
progress: reason === "error" ? existing.progress : 100,
|
|
4027
|
+
completedAt: Date.now()
|
|
3987
4028
|
});
|
|
3988
4029
|
}
|
|
3989
4030
|
let anyRunning = false;
|
|
@@ -3998,24 +4039,19 @@ function dashboardReducer(state, action) {
|
|
|
3998
4039
|
return { ...state, agents, globalState, focusedAgentId };
|
|
3999
4040
|
}
|
|
4000
4041
|
case "MODE_CHANGED": {
|
|
4001
|
-
const newMode = action.payload
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
break;
|
|
4042
|
+
const { from, to: newMode } = action.payload;
|
|
4043
|
+
const agents = cloneAgents(state.agents);
|
|
4044
|
+
for (const [id, a] of agents) {
|
|
4045
|
+
if (from !== null && a.stage === from && (a.status === "done" || a.status === "idle" && a.isParallel)) {
|
|
4046
|
+
agents.delete(id);
|
|
4047
|
+
continue;
|
|
4008
4048
|
}
|
|
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
|
-
}
|
|
4049
|
+
if (a.status === "running") {
|
|
4050
|
+
agents.set(id, { ...a, stage: newMode });
|
|
4016
4051
|
}
|
|
4017
4052
|
}
|
|
4018
|
-
|
|
4053
|
+
const focusedAgentId = selectFocusedAgent(agents, state.focusedAgentId);
|
|
4054
|
+
return { ...state, currentMode: newMode, agents, activeSkills: [], focusedAgentId };
|
|
4019
4055
|
}
|
|
4020
4056
|
case "AGENT_RELATIONSHIP": {
|
|
4021
4057
|
const edge = {
|
|
@@ -4049,10 +4085,15 @@ function dashboardReducer(state, action) {
|
|
|
4049
4085
|
targetAgent = state.agents.get(state.focusedAgentId) ?? null;
|
|
4050
4086
|
}
|
|
4051
4087
|
if (targetAgent && targetAgent.status === "running") {
|
|
4088
|
+
const now = Date.now();
|
|
4089
|
+
const elapsed = targetAgent.startedAt !== void 0 ? now - targetAgent.startedAt : 0;
|
|
4090
|
+
const timeBased = Math.min(90, elapsed / EXPECTED_AGENT_DURATION_MS * 100);
|
|
4091
|
+
const toolBased = Math.min(95, targetAgent.progress + 3);
|
|
4092
|
+
const newProgress = Math.round(Math.max(timeBased, toolBased));
|
|
4052
4093
|
agents = cloneAgents(state.agents);
|
|
4053
4094
|
agents.set(targetAgent.id, {
|
|
4054
4095
|
...targetAgent,
|
|
4055
|
-
progress:
|
|
4096
|
+
progress: newProgress
|
|
4056
4097
|
});
|
|
4057
4098
|
}
|
|
4058
4099
|
const toolCall = {
|
|
@@ -4075,7 +4116,11 @@ function dashboardReducer(state, action) {
|
|
|
4075
4116
|
case "SKILL_RECOMMENDED": {
|
|
4076
4117
|
const { skillName } = action.payload;
|
|
4077
4118
|
if (state.activeSkills.includes(skillName)) return state;
|
|
4078
|
-
return {
|
|
4119
|
+
return {
|
|
4120
|
+
...state,
|
|
4121
|
+
activeSkills: [...state.activeSkills, skillName],
|
|
4122
|
+
skillInvokeCount: state.skillInvokeCount + 1
|
|
4123
|
+
};
|
|
4079
4124
|
}
|
|
4080
4125
|
case "PARALLEL_STARTED": {
|
|
4081
4126
|
const { specialists, mode } = action.payload;
|
|
@@ -4089,7 +4134,10 @@ function dashboardReducer(state, action) {
|
|
|
4089
4134
|
stage: mode,
|
|
4090
4135
|
status: "idle",
|
|
4091
4136
|
isPrimary: false,
|
|
4092
|
-
progress: 0
|
|
4137
|
+
progress: 0,
|
|
4138
|
+
isParallel: true,
|
|
4139
|
+
// parallel dispatch로 등록된 에이전트
|
|
4140
|
+
startedAt: Date.now()
|
|
4093
4141
|
});
|
|
4094
4142
|
}
|
|
4095
4143
|
return { ...state, agents };
|
|
@@ -4106,6 +4154,21 @@ function dashboardReducer(state, action) {
|
|
|
4106
4154
|
}
|
|
4107
4155
|
case "SESSION_RESET":
|
|
4108
4156
|
return createInitialDashboardState();
|
|
4157
|
+
case "CLEANUP_STALE_AGENTS": {
|
|
4158
|
+
const { now, ttlMs } = action.payload;
|
|
4159
|
+
let changed = false;
|
|
4160
|
+
const agents = cloneAgents(state.agents);
|
|
4161
|
+
for (const [id, a] of agents) {
|
|
4162
|
+
if (a.status === "running") continue;
|
|
4163
|
+
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) {
|
|
4164
|
+
agents.delete(id);
|
|
4165
|
+
changed = true;
|
|
4166
|
+
}
|
|
4167
|
+
}
|
|
4168
|
+
if (!changed) return state;
|
|
4169
|
+
const focusedAgentId = selectFocusedAgent(agents, state.focusedAgentId);
|
|
4170
|
+
return { ...state, agents, focusedAgentId };
|
|
4171
|
+
}
|
|
4109
4172
|
// Reserved: no emitter currently produces PARALLEL_COMPLETED. Subscription kept for forward compatibility.
|
|
4110
4173
|
case "PARALLEL_COMPLETED":
|
|
4111
4174
|
case "AGENTS_LOADED":
|
|
@@ -4162,6 +4225,12 @@ function useDashboardState(eventBus) {
|
|
|
4162
4225
|
eventBus.off(TUI_EVENTS.CONTEXT_UPDATED, onContextUpdated);
|
|
4163
4226
|
};
|
|
4164
4227
|
}, [eventBus]);
|
|
4228
|
+
useEffect2(() => {
|
|
4229
|
+
const cleanupInterval = setInterval(() => {
|
|
4230
|
+
dispatch({ type: "CLEANUP_STALE_AGENTS", payload: { now: Date.now(), ttlMs: 3e4 } });
|
|
4231
|
+
}, 1e4);
|
|
4232
|
+
return () => clearInterval(cleanupInterval);
|
|
4233
|
+
}, []);
|
|
4165
4234
|
return state;
|
|
4166
4235
|
}
|
|
4167
4236
|
|
|
@@ -4296,7 +4365,6 @@ function StateIndicator({ globalState }) {
|
|
|
4296
4365
|
}
|
|
4297
4366
|
function HeaderBar({
|
|
4298
4367
|
workspace,
|
|
4299
|
-
sessionId,
|
|
4300
4368
|
currentMode,
|
|
4301
4369
|
globalState,
|
|
4302
4370
|
layoutMode,
|
|
@@ -4319,7 +4387,6 @@ function HeaderBar({
|
|
|
4319
4387
|
/* @__PURE__ */ React.createElement(StateIndicator, { globalState })
|
|
4320
4388
|
);
|
|
4321
4389
|
}
|
|
4322
|
-
const sessDisplay = sessionId.length > 8 ? sessionId.slice(0, 8) : sessionId;
|
|
4323
4390
|
return /* @__PURE__ */ React.createElement(
|
|
4324
4391
|
Box,
|
|
4325
4392
|
{
|
|
@@ -4329,9 +4396,9 @@ function HeaderBar({
|
|
|
4329
4396
|
overflowX: "hidden",
|
|
4330
4397
|
flexDirection: "row"
|
|
4331
4398
|
},
|
|
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 })),
|
|
4399
|
+
/* @__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
4400
|
/* @__PURE__ */ React.createElement(Box, { flexGrow: 1 }),
|
|
4334
|
-
/* @__PURE__ */ React.createElement(Box, { flexShrink: 1, overflowX: "hidden" }, /* @__PURE__ */ React.createElement(Text, { dimColor: true, wrap: "truncate" }, workspace
|
|
4401
|
+
/* @__PURE__ */ React.createElement(Box, { flexShrink: 1, overflowX: "hidden" }, /* @__PURE__ */ React.createElement(Text, { dimColor: true, wrap: "truncate" }, workspace))
|
|
4335
4402
|
);
|
|
4336
4403
|
}
|
|
4337
4404
|
|
|
@@ -4491,9 +4558,16 @@ function computeLabelPosition(path9, label) {
|
|
|
4491
4558
|
// src/tui/components/flow-map.pure.ts
|
|
4492
4559
|
var NODE_WIDTH = 17;
|
|
4493
4560
|
var NODE_HEIGHT = 4;
|
|
4561
|
+
var PARALLEL_STYLES = {
|
|
4562
|
+
parallel: { fg: "cyan" }
|
|
4563
|
+
// 파랑 — 병렬 실행
|
|
4564
|
+
};
|
|
4565
|
+
var TREE_CONNECTOR_STYLE = { fg: "cyan", dim: true };
|
|
4494
4566
|
var STAGE_ORDER = ["PLAN", "ACT", "EVAL", "AUTO"];
|
|
4495
|
-
var STAGE_SLOT_WIDTH =
|
|
4567
|
+
var STAGE_SLOT_WIDTH = 18;
|
|
4496
4568
|
var PIPELINE_RIGHT_MARGIN = 10;
|
|
4569
|
+
var DIMMED_STYLE = { dim: true };
|
|
4570
|
+
var WAITING_STYLE = { fg: "gray", dim: true };
|
|
4497
4571
|
function groupByStage(agents) {
|
|
4498
4572
|
const byStage = /* @__PURE__ */ new Map();
|
|
4499
4573
|
for (const agent of agents.values()) {
|
|
@@ -4503,9 +4577,15 @@ function groupByStage(agents) {
|
|
|
4503
4577
|
}
|
|
4504
4578
|
return byStage;
|
|
4505
4579
|
}
|
|
4580
|
+
function isBoxAgent(agent) {
|
|
4581
|
+
return agent.isPrimary || agent.isParallel;
|
|
4582
|
+
}
|
|
4506
4583
|
function sortAgents(agents) {
|
|
4507
4584
|
return [...agents].sort((a, b) => {
|
|
4508
4585
|
if (a.isPrimary !== b.isPrimary) return a.isPrimary ? -1 : 1;
|
|
4586
|
+
if (!a.isPrimary && !b.isPrimary) {
|
|
4587
|
+
if (a.isParallel !== b.isParallel) return a.isParallel ? -1 : 1;
|
|
4588
|
+
}
|
|
4509
4589
|
return a.name.localeCompare(b.name);
|
|
4510
4590
|
});
|
|
4511
4591
|
}
|
|
@@ -4539,14 +4619,18 @@ function layoutAgentNodes(agents, columns) {
|
|
|
4539
4619
|
if (!col) continue;
|
|
4540
4620
|
const sorted = sortAgents(stageAgents);
|
|
4541
4621
|
const startY = 3;
|
|
4542
|
-
|
|
4622
|
+
let currentY = startY;
|
|
4623
|
+
for (const agent of sorted) {
|
|
4624
|
+
const boxAgent = isBoxAgent(agent);
|
|
4625
|
+
const height = boxAgent ? NODE_HEIGHT : 1;
|
|
4543
4626
|
positions.set(agent.id, {
|
|
4544
4627
|
x: col.startX + Math.floor((col.width - NODE_WIDTH) / 2),
|
|
4545
|
-
y:
|
|
4628
|
+
y: currentY,
|
|
4546
4629
|
width: NODE_WIDTH,
|
|
4547
|
-
height
|
|
4630
|
+
height
|
|
4548
4631
|
});
|
|
4549
|
-
|
|
4632
|
+
currentY += boxAgent ? height + 1 : height;
|
|
4633
|
+
}
|
|
4550
4634
|
}
|
|
4551
4635
|
return positions;
|
|
4552
4636
|
}
|
|
@@ -4554,8 +4638,27 @@ function getNodeTextStyle(status) {
|
|
|
4554
4638
|
if (status === "running") return { fg: "white", bold: true };
|
|
4555
4639
|
return { dim: true };
|
|
4556
4640
|
}
|
|
4557
|
-
function
|
|
4558
|
-
const
|
|
4641
|
+
function drawTreeConnector(buf, x, y, agent, isLast, dimmed = false) {
|
|
4642
|
+
const connector = isLast ? "\u2514\u2500" : "\u251C\u2500";
|
|
4643
|
+
const icon = STATUS_ICONS[agent.status];
|
|
4644
|
+
const maxNameLen = Math.max(1, NODE_WIDTH - connector.length - icon.length - 3);
|
|
4645
|
+
const nameStr = agent.name.length > maxNameLen ? agent.name.slice(0, maxNameLen - 3) + "..." : agent.name;
|
|
4646
|
+
buf.writeText(x, y, connector, dimmed ? DIMMED_STYLE : TREE_CONNECTOR_STYLE);
|
|
4647
|
+
buf.writeText(
|
|
4648
|
+
x + connector.length + 1,
|
|
4649
|
+
y,
|
|
4650
|
+
icon,
|
|
4651
|
+
dimmed ? DIMMED_STYLE : STATUS_STYLES[agent.status]
|
|
4652
|
+
);
|
|
4653
|
+
buf.writeText(
|
|
4654
|
+
x + connector.length + 1 + icon.length + 1,
|
|
4655
|
+
y,
|
|
4656
|
+
nameStr,
|
|
4657
|
+
dimmed ? DIMMED_STYLE : getNodeTextStyle(agent.status)
|
|
4658
|
+
);
|
|
4659
|
+
}
|
|
4660
|
+
function drawAgentNode(buf, x, y, boxW, agent, dimmed = false) {
|
|
4661
|
+
const borderStyle = dimmed ? DIMMED_STYLE : getStatusStyle(agent.status);
|
|
4559
4662
|
if (agent.isPrimary) {
|
|
4560
4663
|
buf.drawDoubleBox(x, y, boxW, NODE_HEIGHT, borderStyle);
|
|
4561
4664
|
} else {
|
|
@@ -4564,15 +4667,26 @@ function drawAgentNode(buf, x, y, boxW, agent) {
|
|
|
4564
4667
|
const icon = STATUS_ICONS[agent.status];
|
|
4565
4668
|
const maxNameLen = Math.max(1, boxW - 5);
|
|
4566
4669
|
const nameStr = agent.name.length > maxNameLen ? agent.name.slice(0, maxNameLen - 3) + "..." : agent.name;
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4670
|
+
const textStyle = dimmed ? DIMMED_STYLE : getNodeTextStyle(agent.status);
|
|
4671
|
+
const iconStyle = dimmed ? DIMMED_STYLE : STATUS_STYLES[agent.status];
|
|
4672
|
+
buf.writeText(x + 2, y + 1, nameStr, textStyle);
|
|
4673
|
+
buf.writeText(x + 2 + nameStr.length + 1, y + 1, icon, iconStyle);
|
|
4674
|
+
if (agent.isPrimary) {
|
|
4675
|
+
const barWidth = Math.max(1, boxW - 8);
|
|
4676
|
+
const bar = buildProgressBar(agent.progress, barWidth);
|
|
4677
|
+
const filledStr = PROGRESS_BAR_CHARS.filled.repeat(bar.filled);
|
|
4678
|
+
const emptyStr = PROGRESS_BAR_CHARS.empty.repeat(bar.empty);
|
|
4679
|
+
const filledStyle = dimmed ? DIMMED_STYLE : PROGRESS_BAR_STYLES.filled;
|
|
4680
|
+
const emptyStyle = dimmed ? DIMMED_STYLE : PROGRESS_BAR_STYLES.empty;
|
|
4681
|
+
buf.writeText(x + 2, y + 2, filledStr, filledStyle);
|
|
4682
|
+
if (bar.empty > 0) {
|
|
4683
|
+
buf.writeText(x + 2 + bar.filled, y + 2, emptyStr, emptyStyle);
|
|
4684
|
+
}
|
|
4685
|
+
buf.writeText(x + 2 + barWidth + 1, y + 2, bar.label, dimmed ? DIMMED_STYLE : WAITING_STYLE);
|
|
4686
|
+
} else if (agent.status === "idle") {
|
|
4687
|
+
buf.writeText(x + 2, y + 2, "\u231B waiting...", dimmed ? DIMMED_STYLE : WAITING_STYLE);
|
|
4688
|
+
} else if (agent.isParallel) {
|
|
4689
|
+
buf.writeText(x + 2, y + 2, "\u2AF8 parallel", dimmed ? DIMMED_STYLE : PARALLEL_STYLES.parallel);
|
|
4576
4690
|
}
|
|
4577
4691
|
}
|
|
4578
4692
|
function buildProgressBar(value, barWidth) {
|
|
@@ -4607,7 +4721,17 @@ function countByStatus(agents) {
|
|
|
4607
4721
|
}
|
|
4608
4722
|
return counts;
|
|
4609
4723
|
}
|
|
4610
|
-
function
|
|
4724
|
+
function countStageRunningDone(agents, stage) {
|
|
4725
|
+
let running = 0;
|
|
4726
|
+
let done = 0;
|
|
4727
|
+
for (const agent of agents.values()) {
|
|
4728
|
+
if (agent.stage !== stage) continue;
|
|
4729
|
+
if (agent.status === "running") running++;
|
|
4730
|
+
else if (agent.status === "done") done++;
|
|
4731
|
+
}
|
|
4732
|
+
return { running, done };
|
|
4733
|
+
}
|
|
4734
|
+
function renderPipelineHeader(buf, width, activeStage, hasAutoAgents = false, agents) {
|
|
4611
4735
|
const stages = hasAutoAgents ? STAGE_ORDER : STAGE_ORDER.filter((s) => s !== "AUTO");
|
|
4612
4736
|
let x = 1;
|
|
4613
4737
|
for (let i = 0; i < stages.length; i++) {
|
|
@@ -4618,6 +4742,17 @@ function renderPipelineHeader(buf, width, activeStage, hasAutoAgents = false) {
|
|
|
4618
4742
|
x += 2;
|
|
4619
4743
|
buf.writeText(x, 0, stage, stageStyle);
|
|
4620
4744
|
x += stage.length;
|
|
4745
|
+
if (agents && agents.size > 0) {
|
|
4746
|
+
const { running, done } = countStageRunningDone(agents, stage);
|
|
4747
|
+
if (running > 0 || done > 0) {
|
|
4748
|
+
const parts = [];
|
|
4749
|
+
if (running > 0) parts.push(`${running}\u2191`);
|
|
4750
|
+
if (done > 0) parts.push(`${done}\u2713`);
|
|
4751
|
+
const statsStr = ` (${parts.join(" ")})`;
|
|
4752
|
+
buf.writeText(x, 0, statsStr, { fg: "gray", dim: !isActive });
|
|
4753
|
+
x += statsStr.length;
|
|
4754
|
+
}
|
|
4755
|
+
}
|
|
4621
4756
|
if (i < stages.length - 1) {
|
|
4622
4757
|
x += 1;
|
|
4623
4758
|
const connLen = Math.max(
|
|
@@ -4644,20 +4779,36 @@ function renderFlowMap(agents, edges, width, height, activeStage = null) {
|
|
|
4644
4779
|
const buf = new ColorBuffer(width, height);
|
|
4645
4780
|
const columns = layoutStageColumns(width, hasAutoAgents);
|
|
4646
4781
|
const positions = layoutAgentNodes(agents, columns);
|
|
4647
|
-
renderPipelineHeader(buf, width, activeStage, hasAutoAgents);
|
|
4782
|
+
renderPipelineHeader(buf, width, activeStage, hasAutoAgents, agents);
|
|
4783
|
+
const inactiveIds = activeStage !== null ? new Set([...agents.values()].filter((a) => a.stage !== activeStage).map((a) => a.id)) : /* @__PURE__ */ new Set();
|
|
4648
4784
|
for (const [id, pos] of positions) {
|
|
4649
4785
|
const agent = agents.get(id);
|
|
4650
4786
|
if (!agent) continue;
|
|
4651
|
-
if (agent.status === "running" && agent.isPrimary) {
|
|
4787
|
+
if (agent.status === "running" && agent.isPrimary && !inactiveIds.has(id)) {
|
|
4652
4788
|
drawGlow(buf, pos.x, pos.y, pos.width, pos.height, GLOW_STYLE);
|
|
4653
4789
|
}
|
|
4654
4790
|
}
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4791
|
+
const byStage = groupByStage(agents);
|
|
4792
|
+
for (const [, stageAgents] of byStage) {
|
|
4793
|
+
const sorted = sortAgents(stageAgents);
|
|
4794
|
+
const connectorAgents = sorted.filter((a) => !isBoxAgent(a));
|
|
4795
|
+
const connectorLastIdx = connectorAgents.length - 1;
|
|
4796
|
+
const connectorIndexMap = new Map(connectorAgents.map((a, i) => [a.id, i]));
|
|
4797
|
+
for (const agent of sorted) {
|
|
4798
|
+
const pos = positions.get(agent.id);
|
|
4799
|
+
if (!pos) continue;
|
|
4800
|
+
if (isBoxAgent(agent)) {
|
|
4801
|
+
drawAgentNode(buf, pos.x, pos.y, pos.width, agent, inactiveIds.has(agent.id));
|
|
4802
|
+
} else {
|
|
4803
|
+
const isLast = connectorIndexMap.get(agent.id) === connectorLastIdx;
|
|
4804
|
+
drawTreeConnector(buf, pos.x, pos.y, agent, isLast, inactiveIds.has(agent.id));
|
|
4805
|
+
}
|
|
4806
|
+
}
|
|
4659
4807
|
}
|
|
4660
4808
|
for (const edge of edges) {
|
|
4809
|
+
const fromAgent = agents.get(edge.from);
|
|
4810
|
+
const toAgent = agents.get(edge.to);
|
|
4811
|
+
if (fromAgent && toAgent && fromAgent.stage === toAgent.stage) continue;
|
|
4661
4812
|
const fromPos = positions.get(edge.from);
|
|
4662
4813
|
const toPos = positions.get(edge.to);
|
|
4663
4814
|
if (!fromPos || !toPos) continue;
|
|
@@ -4670,13 +4821,20 @@ function renderFlowMap(agents, edges, width, height, activeStage = null) {
|
|
|
4670
4821
|
y: toPos.y + Math.floor(toPos.height / 2)
|
|
4671
4822
|
};
|
|
4672
4823
|
const path9 = computeEdgePath(fromPoint, toPoint);
|
|
4824
|
+
const edgeDimmed = inactiveIds.has(edge.from) && inactiveIds.has(edge.to);
|
|
4673
4825
|
for (const seg of path9) {
|
|
4674
4826
|
const isArrow = seg.char === "\u25B8" || seg.char === "\u25C2" || seg.char === "\u25BE" || seg.char === "\u25B4";
|
|
4675
|
-
|
|
4827
|
+
const segStyle = edgeDimmed ? DIMMED_STYLE : isArrow ? EDGE_STYLES.arrow : EDGE_STYLES.path;
|
|
4828
|
+
buf.setChar(seg.x, seg.y, seg.char, segStyle);
|
|
4676
4829
|
}
|
|
4677
4830
|
const labelPos = computeLabelPosition(path9, edge.label);
|
|
4678
4831
|
if (labelPos) {
|
|
4679
|
-
buf.writeText(
|
|
4832
|
+
buf.writeText(
|
|
4833
|
+
labelPos.x,
|
|
4834
|
+
labelPos.y - 1,
|
|
4835
|
+
edge.label,
|
|
4836
|
+
edgeDimmed ? DIMMED_STYLE : EDGE_STYLES.label
|
|
4837
|
+
);
|
|
4680
4838
|
}
|
|
4681
4839
|
}
|
|
4682
4840
|
const counts = countByStatus(agents);
|
|
@@ -4695,20 +4853,22 @@ function renderFlowMap(agents, edges, width, height, activeStage = null) {
|
|
|
4695
4853
|
}
|
|
4696
4854
|
return buf;
|
|
4697
4855
|
}
|
|
4698
|
-
function renderFlowMapSimplified(agents, width, height) {
|
|
4856
|
+
function renderFlowMapSimplified(agents, width, height, activeStage = null) {
|
|
4699
4857
|
const buf = new ColorBuffer(width, height);
|
|
4700
4858
|
const byStage = groupByStage(agents);
|
|
4701
4859
|
let y = 0;
|
|
4702
4860
|
for (const stage of STAGE_ORDER) {
|
|
4703
4861
|
const stageAgents = byStage.get(stage);
|
|
4704
4862
|
if (!stageAgents || stageAgents.length === 0) continue;
|
|
4705
|
-
|
|
4863
|
+
const isInactiveStage = activeStage !== null && stage !== activeStage;
|
|
4864
|
+
const stageLabelStyle = isInactiveStage ? { fg: STAGE_LABEL_STYLES[stage].fg, dim: true } : STAGE_LABEL_STYLES[stage];
|
|
4865
|
+
buf.writeText(1, y, stage, stageLabelStyle);
|
|
4706
4866
|
y++;
|
|
4707
4867
|
const sorted = sortAgents(stageAgents);
|
|
4708
4868
|
for (const agent of sorted) {
|
|
4709
4869
|
if (y >= height - 1) break;
|
|
4710
4870
|
const boxW = Math.min(width - 2, NODE_WIDTH);
|
|
4711
|
-
drawAgentNode(buf, 1, y, boxW, agent);
|
|
4871
|
+
drawAgentNode(buf, 1, y, boxW, agent, isInactiveStage);
|
|
4712
4872
|
y += NODE_HEIGHT + 1;
|
|
4713
4873
|
}
|
|
4714
4874
|
}
|
|
@@ -4821,15 +4981,6 @@ function formatObjective(objectives, maxLines = 3) {
|
|
|
4821
4981
|
}
|
|
4822
4982
|
return lines.join("\n");
|
|
4823
4983
|
}
|
|
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
4984
|
function formatLogTail(events, maxLines = 10) {
|
|
4834
4985
|
const tail = events.slice(-maxLines);
|
|
4835
4986
|
return tail.map((e) => `${e.timestamp} ${e.message}`).join("\n");
|
|
@@ -4849,20 +5000,6 @@ function formatEnhancedProgressBar(progress, width = 30) {
|
|
|
4849
5000
|
label: `${clamped}%`
|
|
4850
5001
|
};
|
|
4851
5002
|
}
|
|
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
5003
|
function formatEnhancedChecklist(tasks, maxItems = 6) {
|
|
4867
5004
|
const visible = tasks.slice(0, maxItems);
|
|
4868
5005
|
const lines = visible.map((t) => t.completed ? ` \u2714 ${t.subject}` : ` \u25FB ${t.subject}`);
|
|
@@ -4931,12 +5068,7 @@ function FocusedAgentPanel({
|
|
|
4931
5068
|
agent,
|
|
4932
5069
|
objectives,
|
|
4933
5070
|
activeSkills,
|
|
4934
|
-
tasks,
|
|
4935
|
-
tools,
|
|
4936
|
-
inputs,
|
|
4937
|
-
outputs,
|
|
4938
5071
|
eventLog,
|
|
4939
|
-
toolCalls,
|
|
4940
5072
|
contextDecisions = [],
|
|
4941
5073
|
contextNotes = [],
|
|
4942
5074
|
width,
|
|
@@ -4961,11 +5093,7 @@ function FocusedAgentPanel({
|
|
|
4961
5093
|
const statusLabel = agent.status.toUpperCase();
|
|
4962
5094
|
const progressBar = formatEnhancedProgressBar(agent.progress);
|
|
4963
5095
|
const objective = formatObjective(objectives);
|
|
4964
|
-
const checklist = formatEnhancedChecklist(tasks);
|
|
4965
|
-
const toolIO = formatToolIO(tools, inputs, outputs);
|
|
4966
5096
|
const logs = formatLogTail(eventLog);
|
|
4967
|
-
const agentToolCalls = toolCalls.filter((tc) => tc.agentId === agent.id);
|
|
4968
|
-
const sparkline = formatActivitySparkline(agentToolCalls);
|
|
4969
5097
|
return /* @__PURE__ */ React4.createElement(
|
|
4970
5098
|
Box4,
|
|
4971
5099
|
{
|
|
@@ -4981,15 +5109,6 @@ function FocusedAgentPanel({
|
|
|
4981
5109
|
objective ? /* @__PURE__ */ React4.createElement(Text4, null, objective) : /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, "No objectives"),
|
|
4982
5110
|
/* @__PURE__ */ React4.createElement(SectionDivider, { title: "Skills" }),
|
|
4983
5111
|
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
5112
|
/* @__PURE__ */ React4.createElement(SectionDivider, { title: "Context" }),
|
|
4994
5113
|
contextDecisions.length > 0 || contextNotes.length > 0 ? /* @__PURE__ */ React4.createElement(ContextSection, { decisions: contextDecisions, notes: contextNotes, width }) : /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, "No context"),
|
|
4995
5114
|
/* @__PURE__ */ React4.createElement(SectionDivider, { title: "Event Log" }),
|
|
@@ -4997,9 +5116,115 @@ function FocusedAgentPanel({
|
|
|
4997
5116
|
);
|
|
4998
5117
|
}
|
|
4999
5118
|
|
|
5000
|
-
// src/tui/components/
|
|
5119
|
+
// src/tui/components/ChecklistPanel.tsx
|
|
5001
5120
|
import React5 from "react";
|
|
5002
5121
|
import { Box as Box5, Text as Text5 } from "ink";
|
|
5122
|
+
|
|
5123
|
+
// src/tui/components/checklist-panel.pure.ts
|
|
5124
|
+
function resolveChecklistTasks(tasks, contextDecisions, contextNotes) {
|
|
5125
|
+
if (tasks.length > 0) {
|
|
5126
|
+
return tasks;
|
|
5127
|
+
}
|
|
5128
|
+
if (contextDecisions.length > 0) {
|
|
5129
|
+
return [
|
|
5130
|
+
{ id: "fallback-decision", subject: `Review: ${contextDecisions[0]}`, completed: false }
|
|
5131
|
+
];
|
|
5132
|
+
}
|
|
5133
|
+
if (contextNotes.length > 0) {
|
|
5134
|
+
return [{ id: "fallback-note", subject: `Check: ${contextNotes[0]}`, completed: false }];
|
|
5135
|
+
}
|
|
5136
|
+
return [{ id: "fallback-default", subject: "Review current task objectives", completed: false }];
|
|
5137
|
+
}
|
|
5138
|
+
|
|
5139
|
+
// src/tui/components/ChecklistPanel.tsx
|
|
5140
|
+
function ChecklistPanel({
|
|
5141
|
+
tasks,
|
|
5142
|
+
contextDecisions = [],
|
|
5143
|
+
contextNotes = [],
|
|
5144
|
+
width,
|
|
5145
|
+
height
|
|
5146
|
+
}) {
|
|
5147
|
+
const resolvedTasks = resolveChecklistTasks(tasks, contextDecisions, contextNotes);
|
|
5148
|
+
const checklist = formatEnhancedChecklist(resolvedTasks);
|
|
5149
|
+
return /* @__PURE__ */ React5.createElement(
|
|
5150
|
+
Box5,
|
|
5151
|
+
{
|
|
5152
|
+
borderStyle: "single",
|
|
5153
|
+
borderColor: BORDER_COLORS.panel,
|
|
5154
|
+
flexDirection: "column",
|
|
5155
|
+
width,
|
|
5156
|
+
height
|
|
5157
|
+
},
|
|
5158
|
+
/* @__PURE__ */ React5.createElement(Text5, { bold: true, dimColor: true }, "\u2500\u2500\u2500 Checklist"),
|
|
5159
|
+
checklist.split("\n").map((line, i) => {
|
|
5160
|
+
const isCompleted = line.includes("\u2714");
|
|
5161
|
+
return /* @__PURE__ */ React5.createElement(Text5, { key: i, color: isCompleted ? "green" : void 0 }, line);
|
|
5162
|
+
})
|
|
5163
|
+
);
|
|
5164
|
+
}
|
|
5165
|
+
|
|
5166
|
+
// src/tui/components/StageHealthBar.tsx
|
|
5167
|
+
import React6 from "react";
|
|
5168
|
+
import { Box as Box6, Text as Text6 } from "ink";
|
|
5169
|
+
|
|
5170
|
+
// src/tui/components/stage-health.pure.ts
|
|
5171
|
+
function formatCount(n) {
|
|
5172
|
+
return n >= 1e3 ? `${Math.round(n / 1e3)}k` : String(n);
|
|
5173
|
+
}
|
|
5174
|
+
function computeStageHealth(agents) {
|
|
5175
|
+
const health = {
|
|
5176
|
+
PLAN: createEmptyStageStats(),
|
|
5177
|
+
ACT: createEmptyStageStats(),
|
|
5178
|
+
EVAL: createEmptyStageStats(),
|
|
5179
|
+
AUTO: createEmptyStageStats()
|
|
5180
|
+
};
|
|
5181
|
+
for (const agent of agents.values()) {
|
|
5182
|
+
const stage = health[agent.stage];
|
|
5183
|
+
if (!stage) continue;
|
|
5184
|
+
switch (agent.status) {
|
|
5185
|
+
case "running":
|
|
5186
|
+
stage.running++;
|
|
5187
|
+
break;
|
|
5188
|
+
case "blocked":
|
|
5189
|
+
stage.blocked++;
|
|
5190
|
+
break;
|
|
5191
|
+
case "idle":
|
|
5192
|
+
stage.waiting++;
|
|
5193
|
+
break;
|
|
5194
|
+
case "done":
|
|
5195
|
+
stage.done++;
|
|
5196
|
+
break;
|
|
5197
|
+
case "error":
|
|
5198
|
+
stage.error++;
|
|
5199
|
+
break;
|
|
5200
|
+
}
|
|
5201
|
+
}
|
|
5202
|
+
return health;
|
|
5203
|
+
}
|
|
5204
|
+
function detectBottlenecks(eventLog) {
|
|
5205
|
+
const bottlenecks = /* @__PURE__ */ new Set();
|
|
5206
|
+
for (const entry of eventLog) {
|
|
5207
|
+
if (entry.level === "error") {
|
|
5208
|
+
const testMatch = entry.message.match(/(?:test_run|tests?):\s*FAIL\s*\((\d+)\)/i);
|
|
5209
|
+
if (testMatch) {
|
|
5210
|
+
bottlenecks.add(`tests failing(${testMatch[1]})`);
|
|
5211
|
+
continue;
|
|
5212
|
+
}
|
|
5213
|
+
const lintMatch = entry.message.match(/lint\(([^)]+)\)/i);
|
|
5214
|
+
if (lintMatch) {
|
|
5215
|
+
bottlenecks.add(`lint(${lintMatch[1]})`);
|
|
5216
|
+
continue;
|
|
5217
|
+
}
|
|
5218
|
+
const envMatch = entry.message.match(/missing\s+env\(([^)]+)\)/i);
|
|
5219
|
+
if (envMatch) {
|
|
5220
|
+
bottlenecks.add(`missing env(${envMatch[1]})`);
|
|
5221
|
+
}
|
|
5222
|
+
}
|
|
5223
|
+
}
|
|
5224
|
+
return [...bottlenecks];
|
|
5225
|
+
}
|
|
5226
|
+
|
|
5227
|
+
// src/tui/components/StageHealthBar.tsx
|
|
5003
5228
|
function StageStatDisplay({
|
|
5004
5229
|
mode,
|
|
5005
5230
|
stats
|
|
@@ -5008,52 +5233,53 @@ function StageStatDisplay({
|
|
|
5008
5233
|
const parts = [];
|
|
5009
5234
|
if (stats.running > 0)
|
|
5010
5235
|
parts.push(
|
|
5011
|
-
/* @__PURE__ */
|
|
5236
|
+
/* @__PURE__ */ React6.createElement(Text6, { key: "r", color: "green" }, " ", "\u25CF ", stats.running, " running")
|
|
5012
5237
|
);
|
|
5013
5238
|
if (stats.blocked > 0)
|
|
5014
5239
|
parts.push(
|
|
5015
|
-
/* @__PURE__ */
|
|
5240
|
+
/* @__PURE__ */ React6.createElement(Text6, { key: "b", color: "yellow" }, " ", "\u23F8 ", stats.blocked, " blocked")
|
|
5016
5241
|
);
|
|
5017
5242
|
if (stats.waiting > 0)
|
|
5018
5243
|
parts.push(
|
|
5019
|
-
/* @__PURE__ */
|
|
5244
|
+
/* @__PURE__ */ React6.createElement(Text6, { key: "w", dimColor: true }, " ", "\u25CB ", stats.waiting, " waiting")
|
|
5020
5245
|
);
|
|
5021
5246
|
if (stats.done > 0)
|
|
5022
5247
|
parts.push(
|
|
5023
|
-
/* @__PURE__ */
|
|
5248
|
+
/* @__PURE__ */ React6.createElement(Text6, { key: "d", color: "green" }, " ", "\u2713 ", stats.done)
|
|
5024
5249
|
);
|
|
5025
5250
|
if (stats.error > 0)
|
|
5026
5251
|
parts.push(
|
|
5027
|
-
/* @__PURE__ */
|
|
5252
|
+
/* @__PURE__ */ React6.createElement(Text6, { key: "e", color: "red", bold: true }, " ", "! ", stats.error, " err")
|
|
5028
5253
|
);
|
|
5029
5254
|
if (parts.length === 0)
|
|
5030
5255
|
parts.push(
|
|
5031
|
-
/* @__PURE__ */
|
|
5256
|
+
/* @__PURE__ */ React6.createElement(Text6, { key: "idle", dimColor: true }, " ", "idle")
|
|
5032
5257
|
);
|
|
5033
|
-
return /* @__PURE__ */
|
|
5258
|
+
return /* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Text6, { color, bold: true }, mode, ":"), parts);
|
|
5034
5259
|
}
|
|
5035
5260
|
function StageHealthBar({
|
|
5036
5261
|
stageHealth,
|
|
5037
5262
|
bottlenecks,
|
|
5038
5263
|
toolCount,
|
|
5264
|
+
agentCount,
|
|
5265
|
+
skillCount,
|
|
5039
5266
|
width
|
|
5040
5267
|
}) {
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
Box5,
|
|
5268
|
+
return /* @__PURE__ */ React6.createElement(
|
|
5269
|
+
Box6,
|
|
5044
5270
|
{
|
|
5045
5271
|
borderStyle: "double",
|
|
5046
5272
|
borderColor: BORDER_COLORS.panel,
|
|
5047
5273
|
width,
|
|
5048
5274
|
flexDirection: "column"
|
|
5049
5275
|
},
|
|
5050
|
-
/* @__PURE__ */
|
|
5276
|
+
/* @__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
5277
|
);
|
|
5052
5278
|
}
|
|
5053
5279
|
|
|
5054
5280
|
// src/tui/components/ActivityVisualizer.tsx
|
|
5055
|
-
import
|
|
5056
|
-
import { Box as
|
|
5281
|
+
import React7, { useMemo as useMemo2 } from "react";
|
|
5282
|
+
import { Box as Box7, Text as Text7 } from "ink";
|
|
5057
5283
|
|
|
5058
5284
|
// src/tui/utils/display-width.ts
|
|
5059
5285
|
function isWide(code) {
|
|
@@ -5087,180 +5313,202 @@ function truncateToDisplayWidth(str, maxWidth) {
|
|
|
5087
5313
|
}
|
|
5088
5314
|
return str.slice(0, codeUnitIndex);
|
|
5089
5315
|
}
|
|
5090
|
-
function padEndDisplayWidth(str, targetWidth) {
|
|
5091
|
-
const currentWidth = estimateDisplayWidth(str);
|
|
5092
|
-
if (currentWidth >= targetWidth) return str;
|
|
5093
|
-
return str + " ".repeat(targetWidth - currentWidth);
|
|
5094
|
-
}
|
|
5095
5316
|
|
|
5096
5317
|
// 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
|
-
|
|
5318
|
+
var ACTIVITY_STATUS_ICONS = Object.freeze({
|
|
5319
|
+
running: "\u25CF",
|
|
5320
|
+
idle: "\u25CB",
|
|
5321
|
+
blocked: "\u23F8",
|
|
5322
|
+
error: "!",
|
|
5323
|
+
done: "\u25CB"
|
|
5324
|
+
});
|
|
5325
|
+
function renderSubtree(nodeId, agents, childrenOf, visited, prefix, isLast, lines, height, width) {
|
|
5326
|
+
if (lines.length >= height) return;
|
|
5327
|
+
if (visited.has(nodeId)) return;
|
|
5328
|
+
visited.add(nodeId);
|
|
5329
|
+
const node = agents.get(nodeId);
|
|
5330
|
+
if (!node) return;
|
|
5331
|
+
const connector = isLast ? "\u2514" : "\u251C";
|
|
5332
|
+
const icon = ACTIVITY_STATUS_ICONS[node.status] ?? "?";
|
|
5333
|
+
lines.push(truncateToDisplayWidth(`${prefix}${connector} ${icon} ${node.name}`, width));
|
|
5334
|
+
const childIds = (childrenOf.get(nodeId) ?? []).filter((id) => agents.has(id));
|
|
5335
|
+
const nextPrefix = prefix + (isLast ? " " : "\u2502 ");
|
|
5336
|
+
for (let i = 0; i < childIds.length; i++) {
|
|
5113
5337
|
if (lines.length >= height) break;
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5338
|
+
renderSubtree(
|
|
5339
|
+
childIds[i],
|
|
5340
|
+
agents,
|
|
5341
|
+
childrenOf,
|
|
5342
|
+
visited,
|
|
5343
|
+
nextPrefix,
|
|
5344
|
+
i === childIds.length - 1,
|
|
5345
|
+
lines,
|
|
5346
|
+
height,
|
|
5347
|
+
width
|
|
5117
5348
|
);
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5349
|
+
}
|
|
5350
|
+
}
|
|
5351
|
+
function renderAgentTree(agents, edges, activeSkills, width, height) {
|
|
5352
|
+
if (height <= 0 || width <= 0) return [];
|
|
5353
|
+
const lines = [truncateToDisplayWidth("\u{1F4CA} Activity", width)];
|
|
5354
|
+
if (height <= 1) return lines;
|
|
5355
|
+
if (agents.size === 0) {
|
|
5356
|
+
lines.push(truncateToDisplayWidth(" No agents", width));
|
|
5357
|
+
return lines.slice(0, height);
|
|
5358
|
+
}
|
|
5359
|
+
const childrenOf = /* @__PURE__ */ new Map();
|
|
5360
|
+
for (const edge of edges) {
|
|
5361
|
+
if (!childrenOf.has(edge.from)) childrenOf.set(edge.from, []);
|
|
5362
|
+
childrenOf.get(edge.from).push(edge.to);
|
|
5363
|
+
}
|
|
5364
|
+
const root = [...agents.values()].find((a) => a.isPrimary) ?? [...agents.values()][0];
|
|
5365
|
+
const rootIcon = ACTIVITY_STATUS_ICONS[root.status] ?? "?";
|
|
5366
|
+
lines.push(truncateToDisplayWidth(`${rootIcon} ${root.name}`, width));
|
|
5367
|
+
const visited = /* @__PURE__ */ new Set([root.id]);
|
|
5368
|
+
const rootChildIds = (childrenOf.get(root.id) ?? []).filter((id) => agents.has(id));
|
|
5369
|
+
const totalChildren = rootChildIds.length + activeSkills.length;
|
|
5370
|
+
for (let i = 0; i < rootChildIds.length; i++) {
|
|
5371
|
+
if (lines.length >= height) break;
|
|
5372
|
+
const isLast = i === totalChildren - 1;
|
|
5373
|
+
renderSubtree(rootChildIds[i], agents, childrenOf, visited, " ", isLast, lines, height, width);
|
|
5374
|
+
}
|
|
5375
|
+
for (let i = 0; i < activeSkills.length; i++) {
|
|
5376
|
+
if (lines.length >= height) break;
|
|
5377
|
+
const isLast = rootChildIds.length + i === totalChildren - 1;
|
|
5378
|
+
const connector = isLast ? "\u2514" : "\u251C";
|
|
5379
|
+
lines.push(truncateToDisplayWidth(` ${connector} \u25C9 ${activeSkills[i]} (skill)`, width));
|
|
5123
5380
|
}
|
|
5124
5381
|
return lines.slice(0, height);
|
|
5125
5382
|
}
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
const
|
|
5383
|
+
function wordWrap(text, width) {
|
|
5384
|
+
if (width <= 0) return [];
|
|
5385
|
+
const words = text.split(" ");
|
|
5386
|
+
const result = [];
|
|
5387
|
+
let current = "";
|
|
5388
|
+
let currentWidth = 0;
|
|
5389
|
+
for (const word of words) {
|
|
5390
|
+
const wordWidth = estimateDisplayWidth(word);
|
|
5391
|
+
if (current.length === 0) {
|
|
5392
|
+
current = wordWidth <= width ? word : truncateToDisplayWidth(word, width);
|
|
5393
|
+
currentWidth = estimateDisplayWidth(current);
|
|
5394
|
+
} else if (currentWidth + 1 + wordWidth <= width) {
|
|
5395
|
+
current += " " + word;
|
|
5396
|
+
currentWidth += 1 + wordWidth;
|
|
5397
|
+
} else {
|
|
5398
|
+
result.push(current);
|
|
5399
|
+
current = wordWidth <= width ? word : truncateToDisplayWidth(word, width);
|
|
5400
|
+
currentWidth = estimateDisplayWidth(current);
|
|
5401
|
+
}
|
|
5402
|
+
}
|
|
5403
|
+
if (current.length > 0) result.push(current);
|
|
5404
|
+
return result;
|
|
5405
|
+
}
|
|
5406
|
+
function renderAgentStatusCard(focusedAgent, currentMode, objectives, activeSkills, width, height) {
|
|
5133
5407
|
if (height <= 0 || width <= 0) return [];
|
|
5134
5408
|
const lines = [truncateToDisplayWidth("\u{1F4AC} Live", width)];
|
|
5135
|
-
if (
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5409
|
+
if (height <= 1) return lines;
|
|
5410
|
+
lines.push(truncateToDisplayWidth(`\u27EB Mode: ${currentMode ?? "\u2014"}`, width));
|
|
5411
|
+
if (!focusedAgent) {
|
|
5412
|
+
lines.push(truncateToDisplayWidth(" No agent", width));
|
|
5413
|
+
return lines.slice(0, height);
|
|
5414
|
+
}
|
|
5415
|
+
lines.push(truncateToDisplayWidth(`\u{1F916} ${focusedAgent.name}`, width));
|
|
5416
|
+
const statusIcon = ACTIVITY_STATUS_ICONS[focusedAgent.status] ?? "?";
|
|
5417
|
+
lines.push(truncateToDisplayWidth(` ${statusIcon} ${focusedAgent.status}`, width));
|
|
5418
|
+
const separator = truncateToDisplayWidth("\u2500".repeat(width), width);
|
|
5419
|
+
if (lines.length < height) lines.push(separator);
|
|
5420
|
+
let objectivesAdded = false;
|
|
5421
|
+
if (objectives.length > 0 && lines.length < height) {
|
|
5422
|
+
const wrapped = wordWrap(objectives[0], width);
|
|
5423
|
+
for (const wline of wrapped) {
|
|
5424
|
+
if (lines.length >= height) break;
|
|
5425
|
+
lines.push(wline);
|
|
5426
|
+
objectivesAdded = true;
|
|
5427
|
+
}
|
|
5428
|
+
}
|
|
5429
|
+
if (objectivesAdded && lines.length < height) lines.push(separator);
|
|
5430
|
+
for (const skill of activeSkills) {
|
|
5431
|
+
if (lines.length >= height) break;
|
|
5432
|
+
lines.push(truncateToDisplayWidth(`\u2699 ${skill}`, width));
|
|
5149
5433
|
}
|
|
5150
5434
|
return lines.slice(0, height);
|
|
5151
5435
|
}
|
|
5152
5436
|
|
|
5153
5437
|
// src/tui/components/ActivityVisualizer.tsx
|
|
5154
5438
|
function ActivityVisualizer({
|
|
5155
|
-
toolCalls,
|
|
5156
5439
|
currentMode,
|
|
5440
|
+
focusedAgent,
|
|
5441
|
+
agents,
|
|
5442
|
+
edges,
|
|
5443
|
+
activeSkills,
|
|
5444
|
+
objectives,
|
|
5157
5445
|
width,
|
|
5158
5446
|
height
|
|
5159
5447
|
}) {
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
}
|
|
5163
|
-
const barChartWidth = Math.floor(width * 0.6);
|
|
5164
|
-
const livePanelWidth = width - barChartWidth;
|
|
5448
|
+
const treeWidth = Math.floor(width * 0.6);
|
|
5449
|
+
const cardWidth = width - treeWidth;
|
|
5165
5450
|
const contentHeight = Math.max(1, height - 2);
|
|
5166
|
-
const
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
[barChartData, barChartWidth, contentHeight]
|
|
5451
|
+
const treeLines = useMemo2(
|
|
5452
|
+
() => renderAgentTree(agents, edges, activeSkills, Math.max(1, treeWidth - 2), contentHeight),
|
|
5453
|
+
[agents, edges, activeSkills, treeWidth, contentHeight]
|
|
5170
5454
|
);
|
|
5171
|
-
const
|
|
5172
|
-
() =>
|
|
5173
|
-
|
|
5455
|
+
const cardLines = useMemo2(
|
|
5456
|
+
() => renderAgentStatusCard(
|
|
5457
|
+
focusedAgent,
|
|
5458
|
+
currentMode,
|
|
5459
|
+
objectives,
|
|
5460
|
+
activeSkills,
|
|
5461
|
+
Math.max(1, cardWidth - 2),
|
|
5462
|
+
contentHeight
|
|
5463
|
+
),
|
|
5464
|
+
[focusedAgent, currentMode, objectives, activeSkills, cardWidth, contentHeight]
|
|
5174
5465
|
);
|
|
5175
|
-
|
|
5176
|
-
|
|
5466
|
+
if (width <= 0 || height <= 0) {
|
|
5467
|
+
return /* @__PURE__ */ React7.createElement(Box7, null);
|
|
5468
|
+
}
|
|
5469
|
+
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "row", width, height }, /* @__PURE__ */ React7.createElement(
|
|
5470
|
+
Box7,
|
|
5177
5471
|
{
|
|
5178
5472
|
borderStyle: "single",
|
|
5179
5473
|
borderColor: BORDER_COLORS.panel,
|
|
5180
5474
|
flexDirection: "column",
|
|
5181
|
-
width:
|
|
5475
|
+
width: treeWidth,
|
|
5182
5476
|
height
|
|
5183
5477
|
},
|
|
5184
|
-
|
|
5185
|
-
), /* @__PURE__ */
|
|
5186
|
-
|
|
5478
|
+
treeLines.map((line, i) => /* @__PURE__ */ React7.createElement(Text7, { key: i }, line))
|
|
5479
|
+
), /* @__PURE__ */ React7.createElement(
|
|
5480
|
+
Box7,
|
|
5187
5481
|
{
|
|
5188
5482
|
borderStyle: "single",
|
|
5189
5483
|
borderColor: BORDER_COLORS.panel,
|
|
5190
5484
|
flexDirection: "column",
|
|
5191
|
-
width:
|
|
5485
|
+
width: cardWidth,
|
|
5192
5486
|
height
|
|
5193
5487
|
},
|
|
5194
|
-
|
|
5488
|
+
cardLines.map((line, i) => /* @__PURE__ */ React7.createElement(Text7, { key: i }, line))
|
|
5195
5489
|
));
|
|
5196
5490
|
}
|
|
5197
5491
|
|
|
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
5492
|
// src/tui/components/grid-layout.pure.ts
|
|
5253
5493
|
var HEADER_HEIGHT = 3;
|
|
5254
5494
|
var STAGE_HEALTH_HEIGHT = 3;
|
|
5255
5495
|
var NARROW_FLOW_MAP_HEIGHT = 5;
|
|
5256
5496
|
var MIN_ROWS = HEADER_HEIGHT + STAGE_HEALTH_HEIGHT + 2;
|
|
5257
5497
|
var MIN_COLUMNS = 20;
|
|
5498
|
+
var CHECKLIST_HEIGHT_MIN = 6;
|
|
5499
|
+
var CHECKLIST_HEIGHT_MAX = 10;
|
|
5258
5500
|
var FOCUSED_AGENT_WIDTH = {
|
|
5259
5501
|
wide: 63,
|
|
5260
5502
|
// was 70 → -10% (FlowMap/Activity gains +7 cols)
|
|
5261
5503
|
medium: 58
|
|
5262
5504
|
// was 64 → -9.4% (FlowMap/Activity gains +6 cols)
|
|
5263
5505
|
};
|
|
5506
|
+
function computeChecklistHeight(mainHeight) {
|
|
5507
|
+
return Math.max(
|
|
5508
|
+
CHECKLIST_HEIGHT_MIN,
|
|
5509
|
+
Math.min(CHECKLIST_HEIGHT_MAX, Math.ceil(mainHeight * 0.3))
|
|
5510
|
+
);
|
|
5511
|
+
}
|
|
5264
5512
|
function computeGridLayout(columns, rows, layoutMode) {
|
|
5265
5513
|
const cols = Math.max(MIN_COLUMNS, columns);
|
|
5266
5514
|
const r = Math.max(MIN_ROWS, rows);
|
|
@@ -5275,11 +5523,20 @@ function computeGridLayout(columns, rows, layoutMode) {
|
|
|
5275
5523
|
const mainHeight = r - HEADER_HEIGHT - STAGE_HEALTH_HEIGHT;
|
|
5276
5524
|
if (layoutMode === "narrow") {
|
|
5277
5525
|
const flowMapHeight2 = Math.min(NARROW_FLOW_MAP_HEIGHT, mainHeight - 1);
|
|
5278
|
-
const
|
|
5526
|
+
const availableForChecklist = mainHeight - flowMapHeight2;
|
|
5527
|
+
const rawChecklistHeight = computeChecklistHeight(mainHeight);
|
|
5528
|
+
const checklistHeight2 = Math.min(rawChecklistHeight, Math.max(0, availableForChecklist - 1));
|
|
5529
|
+
const focusedHeight = availableForChecklist - checklistHeight2;
|
|
5279
5530
|
return {
|
|
5280
5531
|
header,
|
|
5281
|
-
|
|
5282
|
-
|
|
5532
|
+
checklistPanel: { x: 0, y: mainY, width: cols, height: checklistHeight2 },
|
|
5533
|
+
focusedAgent: { x: 0, y: mainY + checklistHeight2, width: cols, height: focusedHeight },
|
|
5534
|
+
flowMap: {
|
|
5535
|
+
x: 0,
|
|
5536
|
+
y: mainY + checklistHeight2 + focusedHeight,
|
|
5537
|
+
width: cols,
|
|
5538
|
+
height: flowMapHeight2
|
|
5539
|
+
},
|
|
5283
5540
|
monitorPanel: { x: 0, y: 0, width: 0, height: 0 },
|
|
5284
5541
|
stageHealth,
|
|
5285
5542
|
total: { width: cols, height: r }
|
|
@@ -5289,119 +5546,148 @@ function computeGridLayout(columns, rows, layoutMode) {
|
|
|
5289
5546
|
const flowMapWidth = cols - focusedWidth;
|
|
5290
5547
|
const flowMapHeight = Math.ceil(mainHeight / 2);
|
|
5291
5548
|
const monitorHeight = mainHeight - flowMapHeight;
|
|
5549
|
+
const checklistHeight = computeChecklistHeight(mainHeight);
|
|
5550
|
+
const focusedAgentHeight = mainHeight - checklistHeight;
|
|
5292
5551
|
return {
|
|
5293
5552
|
header,
|
|
5553
|
+
checklistPanel: { x: flowMapWidth, y: mainY, width: focusedWidth, height: checklistHeight },
|
|
5294
5554
|
flowMap: { x: 0, y: mainY, width: flowMapWidth, height: flowMapHeight },
|
|
5295
5555
|
monitorPanel: { x: 0, y: mainY + flowMapHeight, width: flowMapWidth, height: monitorHeight },
|
|
5296
|
-
focusedAgent: {
|
|
5556
|
+
focusedAgent: {
|
|
5557
|
+
x: flowMapWidth,
|
|
5558
|
+
y: mainY + checklistHeight,
|
|
5559
|
+
width: focusedWidth,
|
|
5560
|
+
height: focusedAgentHeight
|
|
5561
|
+
},
|
|
5297
5562
|
stageHealth,
|
|
5298
5563
|
total: { width: cols, height: r }
|
|
5299
5564
|
};
|
|
5300
5565
|
}
|
|
5301
5566
|
|
|
5302
5567
|
// src/tui/dashboard-app.tsx
|
|
5303
|
-
function DashboardApp({
|
|
5568
|
+
function DashboardApp({
|
|
5569
|
+
eventBus,
|
|
5570
|
+
externalState,
|
|
5571
|
+
workspace: workspaceProp
|
|
5572
|
+
}) {
|
|
5304
5573
|
const { columns, rows, layoutMode } = useTerminalSize();
|
|
5305
5574
|
const internalState = useDashboardState(externalState ? void 0 : eventBus);
|
|
5306
5575
|
const state = externalState ?? internalState;
|
|
5307
5576
|
const focusedAgent = state.focusedAgentId ? state.agents.get(state.focusedAgentId) ?? null : null;
|
|
5308
5577
|
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
5578
|
const bottlenecks = useMemo3(() => detectBottlenecks(state.eventLog), [state.eventLog]);
|
|
5317
5579
|
const grid = useMemo3(
|
|
5318
5580
|
() => computeGridLayout(columns, rows, layoutMode),
|
|
5319
5581
|
[columns, rows, layoutMode]
|
|
5320
5582
|
);
|
|
5321
|
-
return /* @__PURE__ */
|
|
5583
|
+
return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", width: grid.total.width, height: grid.total.height }, /* @__PURE__ */ React8.createElement(
|
|
5322
5584
|
HeaderBar,
|
|
5323
5585
|
{
|
|
5324
|
-
workspace: state.workspace,
|
|
5325
|
-
sessionId: state.sessionId,
|
|
5586
|
+
workspace: workspaceProp ?? state.workspace,
|
|
5326
5587
|
currentMode: state.currentMode,
|
|
5327
5588
|
globalState: state.globalState,
|
|
5328
5589
|
layoutMode,
|
|
5329
5590
|
width: grid.header.width
|
|
5330
5591
|
}
|
|
5331
|
-
), layoutMode === "narrow" ? /* @__PURE__ */
|
|
5592
|
+
), layoutMode === "narrow" ? /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column" }, grid.checklistPanel.height > 0 && /* @__PURE__ */ React8.createElement(
|
|
5593
|
+
ChecklistPanel,
|
|
5594
|
+
{
|
|
5595
|
+
tasks: state.tasks,
|
|
5596
|
+
contextDecisions: state.contextDecisions,
|
|
5597
|
+
contextNotes: state.contextNotes,
|
|
5598
|
+
width: grid.checklistPanel.width,
|
|
5599
|
+
height: grid.checklistPanel.height
|
|
5600
|
+
}
|
|
5601
|
+
), /* @__PURE__ */ React8.createElement(
|
|
5332
5602
|
FocusedAgentPanel,
|
|
5333
5603
|
{
|
|
5334
5604
|
agent: focusedAgent,
|
|
5335
5605
|
objectives: state.objectives,
|
|
5336
5606
|
activeSkills: state.activeSkills,
|
|
5337
|
-
tasks: state.tasks,
|
|
5338
|
-
tools,
|
|
5339
|
-
inputs: tools,
|
|
5340
|
-
outputs: state.outputStats,
|
|
5341
5607
|
eventLog: state.eventLog,
|
|
5342
|
-
toolCalls: state.toolCalls,
|
|
5343
5608
|
contextDecisions: state.contextDecisions,
|
|
5344
5609
|
contextNotes: state.contextNotes,
|
|
5345
5610
|
width: grid.focusedAgent.width,
|
|
5346
5611
|
height: grid.focusedAgent.height
|
|
5347
5612
|
}
|
|
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(
|
|
5613
|
+
), /* @__PURE__ */ React8.createElement(
|
|
5358
5614
|
FlowMap,
|
|
5359
5615
|
{
|
|
5360
5616
|
agents: state.agents,
|
|
5361
5617
|
edges: state.edges,
|
|
5362
5618
|
layoutMode,
|
|
5363
5619
|
width: grid.flowMap.width,
|
|
5364
|
-
height: grid.flowMap.height
|
|
5620
|
+
height: grid.flowMap.height,
|
|
5621
|
+
activeStage: state.currentMode
|
|
5365
5622
|
}
|
|
5366
|
-
)
|
|
5367
|
-
|
|
5623
|
+
)) : /* @__PURE__ */ React8.createElement(
|
|
5624
|
+
Box8,
|
|
5368
5625
|
{
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
}
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5626
|
+
flexDirection: "row",
|
|
5627
|
+
width: grid.total.width,
|
|
5628
|
+
height: grid.checklistPanel.height + grid.focusedAgent.height
|
|
5629
|
+
},
|
|
5630
|
+
/* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", width: grid.flowMap.width }, /* @__PURE__ */ React8.createElement(
|
|
5631
|
+
FlowMap,
|
|
5632
|
+
{
|
|
5633
|
+
agents: state.agents,
|
|
5634
|
+
edges: state.edges,
|
|
5635
|
+
layoutMode,
|
|
5636
|
+
width: grid.flowMap.width,
|
|
5637
|
+
height: grid.flowMap.height,
|
|
5638
|
+
activeStage: state.currentMode
|
|
5639
|
+
}
|
|
5640
|
+
), /* @__PURE__ */ React8.createElement(
|
|
5641
|
+
ActivityVisualizer,
|
|
5642
|
+
{
|
|
5643
|
+
currentMode: state.currentMode,
|
|
5644
|
+
focusedAgent,
|
|
5645
|
+
agents: state.agents,
|
|
5646
|
+
edges: state.edges,
|
|
5647
|
+
activeSkills: state.activeSkills,
|
|
5648
|
+
objectives: state.objectives,
|
|
5649
|
+
width: grid.monitorPanel.width,
|
|
5650
|
+
height: grid.monitorPanel.height
|
|
5651
|
+
}
|
|
5652
|
+
)),
|
|
5653
|
+
/* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", width: grid.checklistPanel.width }, /* @__PURE__ */ React8.createElement(
|
|
5654
|
+
ChecklistPanel,
|
|
5655
|
+
{
|
|
5656
|
+
tasks: state.tasks,
|
|
5657
|
+
contextDecisions: state.contextDecisions,
|
|
5658
|
+
contextNotes: state.contextNotes,
|
|
5659
|
+
width: grid.checklistPanel.width,
|
|
5660
|
+
height: grid.checklistPanel.height
|
|
5661
|
+
}
|
|
5662
|
+
), /* @__PURE__ */ React8.createElement(
|
|
5663
|
+
FocusedAgentPanel,
|
|
5664
|
+
{
|
|
5665
|
+
agent: focusedAgent,
|
|
5666
|
+
objectives: state.objectives,
|
|
5667
|
+
activeSkills: state.activeSkills,
|
|
5668
|
+
eventLog: state.eventLog,
|
|
5669
|
+
contextDecisions: state.contextDecisions,
|
|
5670
|
+
contextNotes: state.contextNotes,
|
|
5671
|
+
width: grid.focusedAgent.width,
|
|
5672
|
+
height: grid.focusedAgent.height
|
|
5673
|
+
}
|
|
5674
|
+
))
|
|
5675
|
+
), /* @__PURE__ */ React8.createElement(
|
|
5392
5676
|
StageHealthBar,
|
|
5393
5677
|
{
|
|
5394
5678
|
stageHealth,
|
|
5395
5679
|
bottlenecks,
|
|
5396
5680
|
toolCount: state.toolInvokeCount,
|
|
5681
|
+
agentCount: state.agentActivateCount,
|
|
5682
|
+
skillCount: state.skillInvokeCount,
|
|
5397
5683
|
width: grid.stageHealth.width
|
|
5398
5684
|
}
|
|
5399
5685
|
));
|
|
5400
5686
|
}
|
|
5401
5687
|
|
|
5402
5688
|
// src/tui/multi-session-app.tsx
|
|
5403
|
-
import
|
|
5404
|
-
import { Box as
|
|
5689
|
+
import React10, { useMemo as useMemo4, useCallback as useCallback2 } from "react";
|
|
5690
|
+
import { Box as Box10, useInput } from "ink";
|
|
5405
5691
|
import * as path8 from "path";
|
|
5406
5692
|
|
|
5407
5693
|
// src/tui/hooks/use-multi-session-state.ts
|
|
@@ -5557,8 +5843,8 @@ function useMultiSessionState(manager) {
|
|
|
5557
5843
|
}
|
|
5558
5844
|
|
|
5559
5845
|
// src/tui/components/SessionTabBar.tsx
|
|
5560
|
-
import
|
|
5561
|
-
import { Box as
|
|
5846
|
+
import React9 from "react";
|
|
5847
|
+
import { Box as Box9, Text as Text8 } from "ink";
|
|
5562
5848
|
|
|
5563
5849
|
// src/tui/components/session-tab-bar.pure.ts
|
|
5564
5850
|
var STATUS_ICONS2 = {
|
|
@@ -5612,7 +5898,7 @@ function SessionTabBar({
|
|
|
5612
5898
|
if (formatted === "") {
|
|
5613
5899
|
return null;
|
|
5614
5900
|
}
|
|
5615
|
-
return /* @__PURE__ */
|
|
5901
|
+
return /* @__PURE__ */ React9.createElement(Box9, { width, height: 1 }, /* @__PURE__ */ React9.createElement(Text8, null, formatted));
|
|
5616
5902
|
}
|
|
5617
5903
|
|
|
5618
5904
|
// src/tui/multi-session-app.tsx
|
|
@@ -5640,6 +5926,10 @@ function MultiSessionApp({ manager }) {
|
|
|
5640
5926
|
const found = managedSessions.find((s) => s.instance.pid === activeSessionPid);
|
|
5641
5927
|
return found?.eventBus;
|
|
5642
5928
|
}, [manager, activeSessionPid]);
|
|
5929
|
+
const activeProjectRoot = useMemo4(() => {
|
|
5930
|
+
if (activeSessionPid === null) return void 0;
|
|
5931
|
+
return sessions.get(activeSessionPid)?.projectRoot;
|
|
5932
|
+
}, [sessions, activeSessionPid]);
|
|
5643
5933
|
const handleInput = useCallback2(
|
|
5644
5934
|
(input, key) => {
|
|
5645
5935
|
if (key.rightArrow) {
|
|
@@ -5658,7 +5948,14 @@ function MultiSessionApp({ manager }) {
|
|
|
5658
5948
|
[switchNext, switchPrev, switchByIndex]
|
|
5659
5949
|
);
|
|
5660
5950
|
useInput(handleInput);
|
|
5661
|
-
return /* @__PURE__ */
|
|
5951
|
+
return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(SessionTabBar, { sessions: tabs, width: columns, layoutMode }), /* @__PURE__ */ React10.createElement(
|
|
5952
|
+
DashboardApp,
|
|
5953
|
+
{
|
|
5954
|
+
key: activeSessionPid ?? "none",
|
|
5955
|
+
eventBus: activeEventBus,
|
|
5956
|
+
workspace: activeProjectRoot
|
|
5957
|
+
}
|
|
5958
|
+
));
|
|
5662
5959
|
}
|
|
5663
5960
|
|
|
5664
5961
|
// src/tui/types.ts
|
|
@@ -5721,10 +6018,10 @@ function useClock() {
|
|
|
5721
6018
|
// src/tui/index.tsx
|
|
5722
6019
|
function startTui(options) {
|
|
5723
6020
|
const renderOptions = options.stdout ? { stdout: options.stdout } : {};
|
|
5724
|
-
return render(/* @__PURE__ */
|
|
6021
|
+
return render(/* @__PURE__ */ React11.createElement(DashboardApp, { eventBus: options.eventBus }), renderOptions);
|
|
5725
6022
|
}
|
|
5726
6023
|
function renderMultiSession(options) {
|
|
5727
|
-
return render(/* @__PURE__ */
|
|
6024
|
+
return render(/* @__PURE__ */ React11.createElement(MultiSessionApp, { manager: options.manager }));
|
|
5728
6025
|
}
|
|
5729
6026
|
export {
|
|
5730
6027
|
AGENT_STATUSES,
|