codingbuddy 5.0.0 → 5.1.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/config/config.schema.d.ts +6 -0
- package/dist/src/config/config.schema.js +3 -0
- package/dist/src/config/config.schema.js.map +1 -1
- package/dist/src/context/context-archive.service.d.ts +14 -0
- package/dist/src/context/context-archive.service.js +257 -0
- package/dist/src/context/context-archive.service.js.map +1 -0
- package/dist/src/context/context-archive.types.d.ts +37 -0
- package/dist/src/context/context-archive.types.js +47 -0
- package/dist/src/context/context-archive.types.js.map +1 -0
- package/dist/src/context/context-document.service.d.ts +3 -1
- package/dist/src/context/context-document.service.js +18 -2
- package/dist/src/context/context-document.service.js.map +1 -1
- package/dist/src/context/context.module.js +3 -2
- package/dist/src/context/context.module.js.map +1 -1
- package/dist/src/context/index.d.ts +1 -0
- package/dist/src/context/index.js +1 -0
- package/dist/src/context/index.js.map +1 -1
- package/dist/src/impact/impact-event.service.d.ts +8 -0
- package/dist/src/impact/impact-event.service.js +53 -0
- package/dist/src/impact/impact-event.service.js.map +1 -0
- package/dist/src/impact/impact-report.service.d.ts +7 -0
- package/dist/src/impact/impact-report.service.js +92 -0
- package/dist/src/impact/impact-report.service.js.map +1 -0
- package/dist/src/impact/impact.module.d.ts +2 -0
- package/dist/src/impact/impact.module.js +22 -0
- package/dist/src/impact/impact.module.js.map +1 -0
- package/dist/src/impact/impact.types.d.ts +32 -0
- package/dist/src/impact/impact.types.js +5 -0
- package/dist/src/impact/impact.types.js.map +1 -0
- package/dist/src/impact/index.d.ts +4 -0
- package/dist/src/impact/index.js +25 -0
- package/dist/src/impact/index.js.map +1 -0
- package/dist/src/keyword/diff-analyzer.d.ts +19 -0
- package/dist/src/keyword/diff-analyzer.js +127 -0
- package/dist/src/keyword/diff-analyzer.js.map +1 -0
- package/dist/src/keyword/keyword.service.d.ts +1 -0
- package/dist/src/keyword/keyword.service.js +25 -3
- package/dist/src/keyword/keyword.service.js.map +1 -1
- package/dist/src/keyword/keyword.types.d.ts +25 -0
- package/dist/src/keyword/keyword.types.js +27 -0
- package/dist/src/keyword/keyword.types.js.map +1 -1
- package/dist/src/keyword/primary-agent-resolver.d.ts +2 -1
- package/dist/src/keyword/primary-agent-resolver.js +2 -1
- package/dist/src/keyword/primary-agent-resolver.js.map +1 -1
- package/dist/src/keyword/strategies/act-agent.strategy.js +8 -0
- package/dist/src/keyword/strategies/act-agent.strategy.js.map +1 -1
- package/dist/src/keyword/strategies/resolution-strategy.interface.d.ts +2 -0
- package/dist/src/keyword/visual-data.builder.d.ts +10 -0
- package/dist/src/keyword/visual-data.builder.js +62 -0
- package/dist/src/keyword/visual-data.builder.js.map +1 -0
- package/dist/src/mcp/handlers/agent.handler.d.ts +3 -1
- package/dist/src/mcp/handlers/agent.handler.js +13 -2
- package/dist/src/mcp/handlers/agent.handler.js.map +1 -1
- package/dist/src/mcp/handlers/checklist-context.handler.d.ts +3 -1
- package/dist/src/mcp/handlers/checklist-context.handler.js +13 -2
- package/dist/src/mcp/handlers/checklist-context.handler.js.map +1 -1
- package/dist/src/mcp/handlers/context-archive.handler.d.ts +14 -0
- package/dist/src/mcp/handlers/context-archive.handler.js +136 -0
- package/dist/src/mcp/handlers/context-archive.handler.js.map +1 -0
- package/dist/src/mcp/handlers/context-document.handler.d.ts +3 -1
- package/dist/src/mcp/handlers/context-document.handler.js +22 -2
- package/dist/src/mcp/handlers/context-document.handler.js.map +1 -1
- package/dist/src/mcp/handlers/impact.handler.d.ts +11 -0
- package/dist/src/mcp/handlers/impact.handler.js +53 -0
- package/dist/src/mcp/handlers/impact.handler.js.map +1 -0
- package/dist/src/mcp/handlers/index.d.ts +3 -0
- package/dist/src/mcp/handlers/index.js +7 -1
- package/dist/src/mcp/handlers/index.js.map +1 -1
- package/dist/src/mcp/handlers/mode.handler.d.ts +4 -1
- package/dist/src/mcp/handlers/mode.handler.js +51 -3
- package/dist/src/mcp/handlers/mode.handler.js.map +1 -1
- package/dist/src/mcp/handlers/rule-insights.handler.d.ts +14 -0
- package/dist/src/mcp/handlers/rule-insights.handler.js +78 -0
- package/dist/src/mcp/handlers/rule-insights.handler.js.map +1 -0
- package/dist/src/mcp/handlers/rules.handler.d.ts +3 -1
- package/dist/src/mcp/handlers/rules.handler.js +14 -2
- package/dist/src/mcp/handlers/rules.handler.js.map +1 -1
- package/dist/src/mcp/mcp.module.js +5 -0
- package/dist/src/mcp/mcp.module.js.map +1 -1
- package/dist/src/rules/rule-insights.service.d.ts +31 -0
- package/dist/src/rules/rule-insights.service.js +102 -0
- package/dist/src/rules/rule-insights.service.js.map +1 -0
- package/dist/src/rules/rules.module.js +3 -2
- package/dist/src/rules/rules.module.js.map +1 -1
- package/dist/src/shared/version.d.ts +1 -1
- package/dist/src/shared/version.js +1 -1
- package/dist/src/skill/i18n/keywords.types.d.ts +4 -2
- package/dist/src/skill/i18n/keywords.types.js +3 -0
- package/dist/src/skill/i18n/keywords.types.js.map +1 -1
- package/dist/src/tui/components/ActModeScreen.d.ts +10 -0
- package/dist/src/tui/components/ActModeScreen.js +25 -0
- package/dist/src/tui/components/ActModeScreen.js.map +1 -0
- package/dist/src/tui/components/AgentDiscussionPanel.js +105 -11
- package/dist/src/tui/components/AgentDiscussionPanel.js.map +1 -1
- package/dist/src/tui/components/AgentDiscussionPanel.spec.js +154 -10
- package/dist/src/tui/components/AgentDiscussionPanel.spec.js.map +1 -1
- package/dist/src/tui/components/EvalModeScreen.d.ts +8 -0
- package/dist/src/tui/components/EvalModeScreen.js +21 -0
- package/dist/src/tui/components/EvalModeScreen.js.map +1 -0
- package/dist/src/tui/components/FlowMap.spec.js.map +1 -1
- package/dist/src/tui/components/FocusedAgentPanel.js +1 -1
- package/dist/src/tui/components/FocusedAgentPanel.js.map +1 -1
- package/dist/src/tui/components/FocusedAgentPanel.spec.js +1 -3
- package/dist/src/tui/components/FocusedAgentPanel.spec.js.map +1 -1
- package/dist/src/tui/components/HeaderBar.js +3 -3
- package/dist/src/tui/components/HeaderBar.js.map +1 -1
- package/dist/src/tui/components/ModeScreenRouter.d.ts +13 -0
- package/dist/src/tui/components/ModeScreenRouter.js +51 -0
- package/dist/src/tui/components/ModeScreenRouter.js.map +1 -0
- package/dist/src/tui/components/PlanModeScreen.d.ts +10 -0
- package/dist/src/tui/components/PlanModeScreen.js +24 -0
- package/dist/src/tui/components/PlanModeScreen.js.map +1 -0
- package/dist/src/tui/components/SessionDashboard.d.ts +17 -0
- package/dist/src/tui/components/SessionDashboard.js +58 -0
- package/dist/src/tui/components/SessionDashboard.js.map +1 -0
- package/dist/src/tui/components/act-screen.pure.d.ts +12 -0
- package/dist/src/tui/components/act-screen.pure.js +93 -0
- package/dist/src/tui/components/act-screen.pure.js.map +1 -0
- package/dist/src/tui/components/agent-discussion-panel.pure.d.ts +45 -0
- package/dist/src/tui/components/agent-discussion-panel.pure.js +130 -23
- package/dist/src/tui/components/agent-discussion-panel.pure.js.map +1 -1
- package/dist/src/tui/components/eval-screen.pure.d.ts +13 -0
- package/dist/src/tui/components/eval-screen.pure.js +76 -0
- package/dist/src/tui/components/eval-screen.pure.js.map +1 -0
- package/dist/src/tui/components/index.d.ts +14 -0
- package/dist/src/tui/components/index.js +40 -1
- package/dist/src/tui/components/index.js.map +1 -1
- package/dist/src/tui/components/plan-screen.pure.d.ts +9 -0
- package/dist/src/tui/components/plan-screen.pure.js +61 -0
- package/dist/src/tui/components/plan-screen.pure.js.map +1 -0
- package/dist/src/tui/components/session-dashboard.pure.d.ts +43 -0
- package/dist/src/tui/components/session-dashboard.pure.js +182 -0
- package/dist/src/tui/components/session-dashboard.pure.js.map +1 -0
- package/dist/src/tui/dashboard-app.js +3 -4
- package/dist/src/tui/dashboard-app.js.map +1 -1
- package/dist/src/tui/dashboard-types.d.ts +47 -0
- package/dist/src/tui/dashboard-types.js +20 -1
- package/dist/src/tui/dashboard-types.js.map +1 -1
- package/dist/src/tui/events/index.d.ts +1 -1
- package/dist/src/tui/events/index.js.map +1 -1
- package/dist/src/tui/events/types.d.ts +23 -1
- package/dist/src/tui/events/types.js +4 -0
- package/dist/src/tui/events/types.js.map +1 -1
- package/dist/src/tui/hooks/use-dashboard-state.d.ts +13 -1
- package/dist/src/tui/hooks/use-dashboard-state.js +60 -1
- package/dist/src/tui/hooks/use-dashboard-state.js.map +1 -1
- package/dist/src/tui-bundle.mjs +965 -278
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
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 React16 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 React13, { useMemo as useMemo7 } from "react";
|
|
1379
|
+
import { Box as Box13 } from "ink";
|
|
1380
1380
|
|
|
1381
1381
|
// src/tui/hooks/use-terminal-size.ts
|
|
1382
1382
|
import { useState, useEffect } from "react";
|
|
@@ -1407,6 +1407,23 @@ function createDefaultDashboardNode(params) {
|
|
|
1407
1407
|
function createEmptyStageStats() {
|
|
1408
1408
|
return { running: 0, blocked: 0, waiting: 0, done: 0, error: 0 };
|
|
1409
1409
|
}
|
|
1410
|
+
var TDD_PHASES = Object.freeze(["RED", "GREEN", "REFACTOR"]);
|
|
1411
|
+
function createDefaultTddStep(params) {
|
|
1412
|
+
return {
|
|
1413
|
+
agentId: null,
|
|
1414
|
+
status: "pending",
|
|
1415
|
+
...params
|
|
1416
|
+
};
|
|
1417
|
+
}
|
|
1418
|
+
function createDefaultReviewResult(params) {
|
|
1419
|
+
return {
|
|
1420
|
+
categories: [],
|
|
1421
|
+
totalScore: 0,
|
|
1422
|
+
maxTotalScore: 100,
|
|
1423
|
+
status: "pending",
|
|
1424
|
+
...params
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1410
1427
|
|
|
1411
1428
|
// src/tui/hooks/use-terminal-size.ts
|
|
1412
1429
|
var DEFAULT_SIZE = { columns: 120, rows: 40 };
|
|
@@ -1497,7 +1514,11 @@ var TUI_EVENTS = Object.freeze({
|
|
|
1497
1514
|
OBJECTIVE_SET: "objective:set",
|
|
1498
1515
|
SESSION_RESET: "session:reset",
|
|
1499
1516
|
CONTEXT_UPDATED: "context:updated",
|
|
1500
|
-
DISCUSSION_ROUND_ADDED: "discussion:round-added"
|
|
1517
|
+
DISCUSSION_ROUND_ADDED: "discussion:round-added",
|
|
1518
|
+
TDD_PHASE_CHANGED: "tdd:phase-changed",
|
|
1519
|
+
TDD_STEP_UPDATED: "tdd:step-updated",
|
|
1520
|
+
REVIEW_RESULT_ADDED: "review:result-added",
|
|
1521
|
+
CONNECTION_STATUS_CHANGED: "connection:status-changed"
|
|
1501
1522
|
});
|
|
1502
1523
|
|
|
1503
1524
|
// src/tui/events/parse-agent.ts
|
|
@@ -2151,6 +2172,21 @@ var SUPPORTED_LANGUAGES = {
|
|
|
2151
2172
|
name: "Spanish",
|
|
2152
2173
|
nativeName: "Espa\xF1ol",
|
|
2153
2174
|
description: "AI responses will be in Spanish"
|
|
2175
|
+
},
|
|
2176
|
+
pt: {
|
|
2177
|
+
name: "Portuguese",
|
|
2178
|
+
nativeName: "Portugu\xEAs",
|
|
2179
|
+
description: "AI responses will be in Portuguese"
|
|
2180
|
+
},
|
|
2181
|
+
de: {
|
|
2182
|
+
name: "German",
|
|
2183
|
+
nativeName: "Deutsch",
|
|
2184
|
+
description: "AI responses will be in German"
|
|
2185
|
+
},
|
|
2186
|
+
fr: {
|
|
2187
|
+
name: "French",
|
|
2188
|
+
nativeName: "Fran\xE7ais",
|
|
2189
|
+
description: "AI responses will be in French"
|
|
2154
2190
|
}
|
|
2155
2191
|
};
|
|
2156
2192
|
var SUPPORTED_LANGUAGE_CODES = Object.keys(
|
|
@@ -2630,11 +2666,106 @@ RulesService = __decorateClass([
|
|
|
2630
2666
|
Injectable4()
|
|
2631
2667
|
], RulesService);
|
|
2632
2668
|
|
|
2669
|
+
// src/rules/rule-insights.service.ts
|
|
2670
|
+
import { Injectable as Injectable5 } from "@nestjs/common";
|
|
2671
|
+
var WEEK_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
2672
|
+
var MONTH_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
2673
|
+
var TOP_RULES_LIMIT = 10;
|
|
2674
|
+
var EMERGING_THRESHOLD = 3;
|
|
2675
|
+
var SUGGESTION_UNUSED_PREVIEW = 5;
|
|
2676
|
+
var RuleInsightsService = class {
|
|
2677
|
+
generateInsights(stats, allRuleNames, now = Date.now()) {
|
|
2678
|
+
const entries = Object.entries(stats);
|
|
2679
|
+
const totalUsageCount = entries.reduce((sum, [, s]) => sum + s.count, 0);
|
|
2680
|
+
const avgCount = entries.length > 0 ? totalUsageCount / entries.length : 0;
|
|
2681
|
+
const topRules = this.buildTopRules(entries, avgCount);
|
|
2682
|
+
const unusedRules = this.findUnusedRules(stats, allRuleNames, now);
|
|
2683
|
+
const activeRules = entries.filter(([, s]) => now - s.lastUsed <= WEEK_MS).length;
|
|
2684
|
+
const staleRules = entries.filter(([, s]) => now - s.lastUsed > MONTH_MS).length;
|
|
2685
|
+
const trends = this.analyzeTrends(entries, avgCount, now);
|
|
2686
|
+
const suggestions = this.generateSuggestions(
|
|
2687
|
+
topRules,
|
|
2688
|
+
unusedRules,
|
|
2689
|
+
trends.declining,
|
|
2690
|
+
entries.length
|
|
2691
|
+
);
|
|
2692
|
+
return {
|
|
2693
|
+
generatedAt: now,
|
|
2694
|
+
summary: {
|
|
2695
|
+
totalRulesTracked: entries.length,
|
|
2696
|
+
totalUsageCount,
|
|
2697
|
+
activeRules,
|
|
2698
|
+
staleRules
|
|
2699
|
+
},
|
|
2700
|
+
topRules: topRules.slice(0, TOP_RULES_LIMIT),
|
|
2701
|
+
unusedRules,
|
|
2702
|
+
trends,
|
|
2703
|
+
suggestions
|
|
2704
|
+
};
|
|
2705
|
+
}
|
|
2706
|
+
buildTopRules(entries, avgCount) {
|
|
2707
|
+
return entries.map(([name, s]) => ({
|
|
2708
|
+
name,
|
|
2709
|
+
count: s.count,
|
|
2710
|
+
lastUsed: s.lastUsed,
|
|
2711
|
+
classification: this.classifyFrequency(s.count, avgCount)
|
|
2712
|
+
})).sort((a, b) => b.count - a.count);
|
|
2713
|
+
}
|
|
2714
|
+
classifyFrequency(count, avgCount) {
|
|
2715
|
+
if (avgCount === 0) return "low";
|
|
2716
|
+
if (count > avgCount * 2) return "high";
|
|
2717
|
+
if (count > avgCount) return "medium";
|
|
2718
|
+
return "low";
|
|
2719
|
+
}
|
|
2720
|
+
findUnusedRules(stats, allRuleNames, now) {
|
|
2721
|
+
return allRuleNames.filter((name) => {
|
|
2722
|
+
const s = stats[name];
|
|
2723
|
+
return !s || now - s.lastUsed > MONTH_MS;
|
|
2724
|
+
});
|
|
2725
|
+
}
|
|
2726
|
+
analyzeTrends(entries, avgCount, now) {
|
|
2727
|
+
const recentlyActive = entries.filter(([, s]) => now - s.lastUsed <= WEEK_MS).map(([name]) => name);
|
|
2728
|
+
const declining = entries.filter(([, s]) => now - s.lastUsed > MONTH_MS && s.count > avgCount).map(([name]) => name);
|
|
2729
|
+
const emerging = entries.filter(([, s]) => now - s.lastUsed <= WEEK_MS && s.count <= EMERGING_THRESHOLD).map(([name]) => name);
|
|
2730
|
+
return { recentlyActive, declining, emerging };
|
|
2731
|
+
}
|
|
2732
|
+
generateSuggestions(topRules, unusedRules, declining, totalTracked) {
|
|
2733
|
+
const suggestions = [];
|
|
2734
|
+
if (totalTracked === 0) {
|
|
2735
|
+
suggestions.push(
|
|
2736
|
+
"No tracking data available yet \u2014 use parse_mode to start collecting rule usage data"
|
|
2737
|
+
);
|
|
2738
|
+
return suggestions;
|
|
2739
|
+
}
|
|
2740
|
+
const highFreq = topRules.filter((r) => r.classification === "high");
|
|
2741
|
+
if (highFreq.length > 0) {
|
|
2742
|
+
suggestions.push(
|
|
2743
|
+
`High-frequency rules [${highFreq.map((r) => r.name).join(", ")}] may need stricter enforcement or developer education`
|
|
2744
|
+
);
|
|
2745
|
+
}
|
|
2746
|
+
if (unusedRules.length > 0) {
|
|
2747
|
+
const preview = unusedRules.slice(0, SUGGESTION_UNUSED_PREVIEW).join(", ");
|
|
2748
|
+
suggestions.push(
|
|
2749
|
+
`${unusedRules.length} unused/stale rules detected \u2014 consider removing or updating: ${preview}`
|
|
2750
|
+
);
|
|
2751
|
+
}
|
|
2752
|
+
if (declining.length > 0) {
|
|
2753
|
+
suggestions.push(
|
|
2754
|
+
`Rules [${declining.join(", ")}] were once active but have declined \u2014 verify they are still relevant`
|
|
2755
|
+
);
|
|
2756
|
+
}
|
|
2757
|
+
return suggestions;
|
|
2758
|
+
}
|
|
2759
|
+
};
|
|
2760
|
+
RuleInsightsService = __decorateClass([
|
|
2761
|
+
Injectable5()
|
|
2762
|
+
], RuleInsightsService);
|
|
2763
|
+
|
|
2633
2764
|
// src/custom/custom.module.ts
|
|
2634
2765
|
import { Module } from "@nestjs/common";
|
|
2635
2766
|
|
|
2636
2767
|
// src/custom/custom.service.ts
|
|
2637
|
-
import { Injectable as
|
|
2768
|
+
import { Injectable as Injectable6, Logger as Logger5 } from "@nestjs/common";
|
|
2638
2769
|
import * as fs from "fs/promises";
|
|
2639
2770
|
import * as path3 from "path";
|
|
2640
2771
|
|
|
@@ -2754,7 +2885,7 @@ var CustomService = class {
|
|
|
2754
2885
|
}
|
|
2755
2886
|
};
|
|
2756
2887
|
CustomService = __decorateClass([
|
|
2757
|
-
|
|
2888
|
+
Injectable6()
|
|
2758
2889
|
], CustomService);
|
|
2759
2890
|
|
|
2760
2891
|
// src/custom/custom.module.ts
|
|
@@ -2771,7 +2902,7 @@ CustomModule = __decorateClass([
|
|
|
2771
2902
|
import { Module as Module2 } from "@nestjs/common";
|
|
2772
2903
|
|
|
2773
2904
|
// src/config/config.service.ts
|
|
2774
|
-
import { Injectable as
|
|
2905
|
+
import { Injectable as Injectable7, Logger as Logger6 } from "@nestjs/common";
|
|
2775
2906
|
import { existsSync as existsSync5, statSync } from "fs";
|
|
2776
2907
|
import { stat, realpath } from "fs/promises";
|
|
2777
2908
|
import * as path7 from "path";
|
|
@@ -2916,6 +3047,10 @@ var CodingBuddyConfigSchema = z3.object({
|
|
|
2916
3047
|
projectName: z3.string().optional(),
|
|
2917
3048
|
description: z3.string().optional(),
|
|
2918
3049
|
repository: z3.string().url().optional(),
|
|
3050
|
+
// Feature Flags
|
|
3051
|
+
eco: z3.boolean().default(true).optional(),
|
|
3052
|
+
tui: z3.boolean().default(true).optional(),
|
|
3053
|
+
tone: z3.enum(["casual", "formal"]).default("casual").optional(),
|
|
2919
3054
|
// Technical Configuration
|
|
2920
3055
|
techStack: TechStackConfigSchema.optional(),
|
|
2921
3056
|
architecture: ArchitectureConfigSchema.optional(),
|
|
@@ -3777,11 +3912,11 @@ var ConfigService = class {
|
|
|
3777
3912
|
}
|
|
3778
3913
|
};
|
|
3779
3914
|
ConfigService = __decorateClass([
|
|
3780
|
-
|
|
3915
|
+
Injectable7()
|
|
3781
3916
|
], ConfigService);
|
|
3782
3917
|
|
|
3783
3918
|
// src/config/config-diff.service.ts
|
|
3784
|
-
import { Injectable as
|
|
3919
|
+
import { Injectable as Injectable8 } from "@nestjs/common";
|
|
3785
3920
|
var ConfigDiffService = class {
|
|
3786
3921
|
/**
|
|
3787
3922
|
* Compare project analysis with current config
|
|
@@ -3953,7 +4088,7 @@ var ConfigDiffService = class {
|
|
|
3953
4088
|
}
|
|
3954
4089
|
};
|
|
3955
4090
|
ConfigDiffService = __decorateClass([
|
|
3956
|
-
|
|
4091
|
+
Injectable8()
|
|
3957
4092
|
], ConfigDiffService);
|
|
3958
4093
|
|
|
3959
4094
|
// src/config/config.module.ts
|
|
@@ -3972,8 +4107,8 @@ var RulesModule = class {
|
|
|
3972
4107
|
RulesModule = __decorateClass([
|
|
3973
4108
|
Module3({
|
|
3974
4109
|
imports: [CustomModule, CodingBuddyConfigModule],
|
|
3975
|
-
providers: [RulesService],
|
|
3976
|
-
exports: [RulesService]
|
|
4110
|
+
providers: [RulesService, RuleInsightsService],
|
|
4111
|
+
exports: [RulesService, RuleInsightsService]
|
|
3977
4112
|
})
|
|
3978
4113
|
], RulesModule);
|
|
3979
4114
|
|
|
@@ -4037,7 +4172,14 @@ function createInitialDashboardState() {
|
|
|
4037
4172
|
contextNotes: [],
|
|
4038
4173
|
contextMode: null,
|
|
4039
4174
|
contextStatus: null,
|
|
4040
|
-
discussionRounds: []
|
|
4175
|
+
discussionRounds: [],
|
|
4176
|
+
tddCurrentPhase: null,
|
|
4177
|
+
tddSteps: [],
|
|
4178
|
+
reviewResults: [],
|
|
4179
|
+
connectionStatus: "connected",
|
|
4180
|
+
sessionStartedAt: Date.now(),
|
|
4181
|
+
modeTransitions: [],
|
|
4182
|
+
fileChanges: { created: 0, modified: 0, deleted: 0 }
|
|
4041
4183
|
};
|
|
4042
4184
|
}
|
|
4043
4185
|
function cloneAgents(agents) {
|
|
@@ -4105,7 +4247,16 @@ function dashboardReducer(state, action) {
|
|
|
4105
4247
|
}
|
|
4106
4248
|
}
|
|
4107
4249
|
const focusedAgentId = selectFocusedAgent(agents, state.focusedAgentId);
|
|
4108
|
-
|
|
4250
|
+
const transition = { from, to: newMode, timestamp: Date.now() };
|
|
4251
|
+
const modeTransitions = [...state.modeTransitions, transition];
|
|
4252
|
+
return {
|
|
4253
|
+
...state,
|
|
4254
|
+
currentMode: newMode,
|
|
4255
|
+
agents,
|
|
4256
|
+
activeSkills: [],
|
|
4257
|
+
focusedAgentId,
|
|
4258
|
+
modeTransitions
|
|
4259
|
+
};
|
|
4109
4260
|
}
|
|
4110
4261
|
case "AGENT_RELATIONSHIP": {
|
|
4111
4262
|
const edge = {
|
|
@@ -4170,13 +4321,21 @@ function dashboardReducer(state, action) {
|
|
|
4170
4321
|
} else {
|
|
4171
4322
|
activityHistory = [...history.slice(-59), { timestamp: sec, toolCalls: 1 }];
|
|
4172
4323
|
}
|
|
4324
|
+
const toolLower = action.payload.toolName.toLowerCase();
|
|
4325
|
+
let fileChanges = state.fileChanges;
|
|
4326
|
+
if (toolLower === "write" || toolLower === "notebookedit") {
|
|
4327
|
+
fileChanges = { ...fileChanges, created: fileChanges.created + 1 };
|
|
4328
|
+
} else if (toolLower === "edit") {
|
|
4329
|
+
fileChanges = { ...fileChanges, modified: fileChanges.modified + 1 };
|
|
4330
|
+
}
|
|
4173
4331
|
return {
|
|
4174
4332
|
...state,
|
|
4175
4333
|
agents,
|
|
4176
4334
|
eventLog: [...base, entry],
|
|
4177
4335
|
toolCalls: [...toolCallsBase, toolCall],
|
|
4178
4336
|
activityHistory,
|
|
4179
|
-
toolInvokeCount: state.toolInvokeCount + 1
|
|
4337
|
+
toolInvokeCount: state.toolInvokeCount + 1,
|
|
4338
|
+
fileChanges
|
|
4180
4339
|
};
|
|
4181
4340
|
}
|
|
4182
4341
|
case "OBJECTIVE_SET":
|
|
@@ -4243,6 +4402,24 @@ function dashboardReducer(state, action) {
|
|
|
4243
4402
|
const focusedAgentId = selectFocusedAgent(agents, state.focusedAgentId);
|
|
4244
4403
|
return { ...state, agents, focusedAgentId };
|
|
4245
4404
|
}
|
|
4405
|
+
case "TDD_PHASE_CHANGED": {
|
|
4406
|
+
return { ...state, tddCurrentPhase: action.payload.phase };
|
|
4407
|
+
}
|
|
4408
|
+
case "TDD_STEP_UPDATED": {
|
|
4409
|
+
const { step } = action.payload;
|
|
4410
|
+
const existing = state.tddSteps.findIndex((s) => s.id === step.id);
|
|
4411
|
+
const tddSteps = existing >= 0 ? state.tddSteps.map((s, i) => i === existing ? step : s) : [...state.tddSteps, step];
|
|
4412
|
+
return { ...state, tddSteps };
|
|
4413
|
+
}
|
|
4414
|
+
case "REVIEW_RESULT_ADDED": {
|
|
4415
|
+
const { result } = action.payload;
|
|
4416
|
+
const idx = state.reviewResults.findIndex((r) => r.agentId === result.agentId);
|
|
4417
|
+
const reviewResults = idx >= 0 ? state.reviewResults.map((r, i) => i === idx ? result : r) : [...state.reviewResults, result];
|
|
4418
|
+
return { ...state, reviewResults };
|
|
4419
|
+
}
|
|
4420
|
+
case "CONNECTION_STATUS_CHANGED": {
|
|
4421
|
+
return { ...state, connectionStatus: action.payload.status };
|
|
4422
|
+
}
|
|
4246
4423
|
// Reserved: no emitter currently produces PARALLEL_COMPLETED. Subscription kept for forward compatibility.
|
|
4247
4424
|
case "PARALLEL_COMPLETED":
|
|
4248
4425
|
case "AGENTS_LOADED":
|
|
@@ -4271,6 +4448,10 @@ function useDashboardState(eventBus) {
|
|
|
4271
4448
|
const onSessionReset = (p) => dispatch({ type: "SESSION_RESET", payload: p });
|
|
4272
4449
|
const onContextUpdated = (p) => dispatch({ type: "CONTEXT_UPDATED", payload: p });
|
|
4273
4450
|
const onDiscussionRoundAdded = (p) => dispatch({ type: "ADD_DISCUSSION_ROUND", payload: p });
|
|
4451
|
+
const onTddPhaseChanged = (p) => dispatch({ type: "TDD_PHASE_CHANGED", payload: p });
|
|
4452
|
+
const onTddStepUpdated = (p) => dispatch({ type: "TDD_STEP_UPDATED", payload: p });
|
|
4453
|
+
const onReviewResultAdded = (p) => dispatch({ type: "REVIEW_RESULT_ADDED", payload: p });
|
|
4454
|
+
const onConnectionStatusChanged = (p) => dispatch({ type: "CONNECTION_STATUS_CHANGED", payload: p });
|
|
4274
4455
|
eventBus.on(TUI_EVENTS.AGENT_ACTIVATED, onActivated);
|
|
4275
4456
|
eventBus.on(TUI_EVENTS.AGENT_DEACTIVATED, onDeactivated);
|
|
4276
4457
|
eventBus.on(TUI_EVENTS.MODE_CHANGED, onModeChanged);
|
|
@@ -4285,6 +4466,10 @@ function useDashboardState(eventBus) {
|
|
|
4285
4466
|
eventBus.on(TUI_EVENTS.SESSION_RESET, onSessionReset);
|
|
4286
4467
|
eventBus.on(TUI_EVENTS.CONTEXT_UPDATED, onContextUpdated);
|
|
4287
4468
|
eventBus.on(TUI_EVENTS.DISCUSSION_ROUND_ADDED, onDiscussionRoundAdded);
|
|
4469
|
+
eventBus.on(TUI_EVENTS.TDD_PHASE_CHANGED, onTddPhaseChanged);
|
|
4470
|
+
eventBus.on(TUI_EVENTS.TDD_STEP_UPDATED, onTddStepUpdated);
|
|
4471
|
+
eventBus.on(TUI_EVENTS.REVIEW_RESULT_ADDED, onReviewResultAdded);
|
|
4472
|
+
eventBus.on(TUI_EVENTS.CONNECTION_STATUS_CHANGED, onConnectionStatusChanged);
|
|
4288
4473
|
return () => {
|
|
4289
4474
|
eventBus.off(TUI_EVENTS.AGENT_ACTIVATED, onActivated);
|
|
4290
4475
|
eventBus.off(TUI_EVENTS.AGENT_DEACTIVATED, onDeactivated);
|
|
@@ -4300,6 +4485,10 @@ function useDashboardState(eventBus) {
|
|
|
4300
4485
|
eventBus.off(TUI_EVENTS.SESSION_RESET, onSessionReset);
|
|
4301
4486
|
eventBus.off(TUI_EVENTS.CONTEXT_UPDATED, onContextUpdated);
|
|
4302
4487
|
eventBus.off(TUI_EVENTS.DISCUSSION_ROUND_ADDED, onDiscussionRoundAdded);
|
|
4488
|
+
eventBus.off(TUI_EVENTS.TDD_PHASE_CHANGED, onTddPhaseChanged);
|
|
4489
|
+
eventBus.off(TUI_EVENTS.TDD_STEP_UPDATED, onTddStepUpdated);
|
|
4490
|
+
eventBus.off(TUI_EVENTS.REVIEW_RESULT_ADDED, onReviewResultAdded);
|
|
4491
|
+
eventBus.off(TUI_EVENTS.CONNECTION_STATUS_CHANGED, onConnectionStatusChanged);
|
|
4303
4492
|
};
|
|
4304
4493
|
}, [eventBus]);
|
|
4305
4494
|
useEffect3(() => {
|
|
@@ -4539,10 +4728,596 @@ function HeaderBar({
|
|
|
4539
4728
|
);
|
|
4540
4729
|
}
|
|
4541
4730
|
|
|
4542
|
-
// src/tui/components/
|
|
4731
|
+
// src/tui/components/ModeScreenRouter.tsx
|
|
4732
|
+
import React7 from "react";
|
|
4733
|
+
import { Box as Box7, Text as Text7 } from "ink";
|
|
4734
|
+
|
|
4735
|
+
// src/tui/components/PlanModeScreen.tsx
|
|
4736
|
+
import React3, { useMemo as useMemo2 } from "react";
|
|
4737
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
4738
|
+
|
|
4739
|
+
// src/collaboration/types.ts
|
|
4740
|
+
var STANCES = Object.freeze(["approve", "concern", "reject"]);
|
|
4741
|
+
var STANCE_ICONS = Object.freeze({
|
|
4742
|
+
approve: "\u2705",
|
|
4743
|
+
concern: "\u26A0\uFE0F",
|
|
4744
|
+
reject: "\u274C"
|
|
4745
|
+
});
|
|
4746
|
+
function calculateConsensus(opinions) {
|
|
4747
|
+
const approveCount = opinions.filter((o) => o.stance === "approve").length;
|
|
4748
|
+
const concernCount = opinions.filter((o) => o.stance === "concern").length;
|
|
4749
|
+
const rejectCount = opinions.filter((o) => o.stance === "reject").length;
|
|
4750
|
+
return {
|
|
4751
|
+
totalAgents: opinions.length,
|
|
4752
|
+
approveCount,
|
|
4753
|
+
concernCount,
|
|
4754
|
+
rejectCount,
|
|
4755
|
+
reached: opinions.length > 0 && rejectCount === 0,
|
|
4756
|
+
criticalCount: rejectCount
|
|
4757
|
+
};
|
|
4758
|
+
}
|
|
4759
|
+
|
|
4760
|
+
// src/tui/components/plan-screen.pure.ts
|
|
4761
|
+
function renderAgentSummonList(agents, width) {
|
|
4762
|
+
const lines = [];
|
|
4763
|
+
lines.push({ type: "header", text: "\u{1F4CB} Summoned Agents" });
|
|
4764
|
+
if (agents.size === 0) {
|
|
4765
|
+
lines.push({ type: "empty", text: " (no agents summoned)" });
|
|
4766
|
+
return lines;
|
|
4767
|
+
}
|
|
4768
|
+
for (const agent of agents.values()) {
|
|
4769
|
+
const statusIcon = getAgentStatusIcon(agent.status);
|
|
4770
|
+
const primaryTag = agent.isPrimary ? " \u2605" : "";
|
|
4771
|
+
const text = ` ${statusIcon} ${agent.name}${primaryTag} [${agent.status}]`;
|
|
4772
|
+
lines.push({ type: "agent", text: text.slice(0, width) });
|
|
4773
|
+
}
|
|
4774
|
+
return lines;
|
|
4775
|
+
}
|
|
4776
|
+
function getAgentStatusIcon(status) {
|
|
4777
|
+
switch (status) {
|
|
4778
|
+
case "running":
|
|
4779
|
+
return "\u{1F504}";
|
|
4780
|
+
case "done":
|
|
4781
|
+
return "\u2705";
|
|
4782
|
+
case "error":
|
|
4783
|
+
return "\u274C";
|
|
4784
|
+
case "idle":
|
|
4785
|
+
return "\u23F3";
|
|
4786
|
+
case "blocked":
|
|
4787
|
+
return "\u{1F6AB}";
|
|
4788
|
+
}
|
|
4789
|
+
}
|
|
4790
|
+
function renderConsensusSummary(rounds) {
|
|
4791
|
+
if (rounds.length === 0) {
|
|
4792
|
+
return [{ type: "empty", text: " (no discussion yet)" }];
|
|
4793
|
+
}
|
|
4794
|
+
const lastRound = rounds[rounds.length - 1];
|
|
4795
|
+
const consensus = calculateConsensus(lastRound.opinions);
|
|
4796
|
+
const lines = [];
|
|
4797
|
+
lines.push({ type: "header", text: `\u{1F5F3}\uFE0F Consensus (Round ${lastRound.roundNumber})` });
|
|
4798
|
+
lines.push({
|
|
4799
|
+
type: "consensus",
|
|
4800
|
+
text: ` ${STANCE_ICONS.approve} ${consensus.approveCount} ${STANCE_ICONS.concern} ${consensus.concernCount} ${STANCE_ICONS.reject} ${consensus.rejectCount}`
|
|
4801
|
+
});
|
|
4802
|
+
lines.push({
|
|
4803
|
+
type: "consensus",
|
|
4804
|
+
text: consensus.reached ? " \u2705 Consensus reached" : " \u23F3 Consensus not reached"
|
|
4805
|
+
});
|
|
4806
|
+
return lines;
|
|
4807
|
+
}
|
|
4808
|
+
function renderPlanScreen(agents, rounds, width) {
|
|
4809
|
+
const lines = [];
|
|
4810
|
+
lines.push(...renderAgentSummonList(agents, width));
|
|
4811
|
+
lines.push({ type: "empty", text: "" });
|
|
4812
|
+
lines.push(...renderConsensusSummary(rounds));
|
|
4813
|
+
return lines;
|
|
4814
|
+
}
|
|
4815
|
+
|
|
4816
|
+
// src/tui/components/AgentDiscussionPanel.tsx
|
|
4543
4817
|
import React2, { useMemo } from "react";
|
|
4544
4818
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
4545
4819
|
|
|
4820
|
+
// src/tui/components/agent-discussion-panel.pure.ts
|
|
4821
|
+
var AGENT_PALETTE = [
|
|
4822
|
+
"cyan",
|
|
4823
|
+
"magenta",
|
|
4824
|
+
"yellow",
|
|
4825
|
+
"green",
|
|
4826
|
+
"blue",
|
|
4827
|
+
"red",
|
|
4828
|
+
"white"
|
|
4829
|
+
];
|
|
4830
|
+
var CROSS_REVIEW_VERBS = {
|
|
4831
|
+
approve: "agrees",
|
|
4832
|
+
concern: "notes",
|
|
4833
|
+
reject: "disagrees"
|
|
4834
|
+
};
|
|
4835
|
+
function renderStanceHistory(stances) {
|
|
4836
|
+
if (stances.length <= 1) return "";
|
|
4837
|
+
return stances.map((s) => STANCE_ICONS[s]).join(" \u2192 ");
|
|
4838
|
+
}
|
|
4839
|
+
function assignAgentColors(rounds) {
|
|
4840
|
+
const colors = {};
|
|
4841
|
+
let idx = 0;
|
|
4842
|
+
for (const round of rounds) {
|
|
4843
|
+
for (const opinion of round.opinions) {
|
|
4844
|
+
if (!colors[opinion.agentId]) {
|
|
4845
|
+
colors[opinion.agentId] = AGENT_PALETTE[idx % AGENT_PALETTE.length];
|
|
4846
|
+
idx++;
|
|
4847
|
+
}
|
|
4848
|
+
}
|
|
4849
|
+
}
|
|
4850
|
+
return colors;
|
|
4851
|
+
}
|
|
4852
|
+
function detectConflicts(opinions) {
|
|
4853
|
+
const hasApprove = opinions.some((o) => o.stance === "approve");
|
|
4854
|
+
const hasReject = opinions.some((o) => o.stance === "reject");
|
|
4855
|
+
if (!hasApprove || !hasReject) return /* @__PURE__ */ new Set();
|
|
4856
|
+
const conflicting = /* @__PURE__ */ new Set();
|
|
4857
|
+
for (const opinion of opinions) {
|
|
4858
|
+
if (opinion.stance === "reject") {
|
|
4859
|
+
conflicting.add(opinion.agentId);
|
|
4860
|
+
}
|
|
4861
|
+
}
|
|
4862
|
+
return conflicting;
|
|
4863
|
+
}
|
|
4864
|
+
function estimateBlockHeight(block) {
|
|
4865
|
+
switch (block.type) {
|
|
4866
|
+
case "agent-bubble":
|
|
4867
|
+
return 4;
|
|
4868
|
+
// label + border-top + content + border-bottom
|
|
4869
|
+
case "consensus-bar":
|
|
4870
|
+
return 2;
|
|
4871
|
+
default:
|
|
4872
|
+
return 1;
|
|
4873
|
+
}
|
|
4874
|
+
}
|
|
4875
|
+
function buildAgentNameMap(rounds) {
|
|
4876
|
+
const map = {};
|
|
4877
|
+
for (const round of rounds) {
|
|
4878
|
+
for (const opinion of round.opinions) {
|
|
4879
|
+
map[opinion.agentId] = opinion.agentName;
|
|
4880
|
+
}
|
|
4881
|
+
}
|
|
4882
|
+
return map;
|
|
4883
|
+
}
|
|
4884
|
+
function buildStanceHistories(rounds) {
|
|
4885
|
+
const histories = {};
|
|
4886
|
+
for (const round of rounds) {
|
|
4887
|
+
for (const opinion of round.opinions) {
|
|
4888
|
+
if (!histories[opinion.agentId]) {
|
|
4889
|
+
histories[opinion.agentId] = [];
|
|
4890
|
+
}
|
|
4891
|
+
histories[opinion.agentId].push(opinion.stance);
|
|
4892
|
+
}
|
|
4893
|
+
}
|
|
4894
|
+
return histories;
|
|
4895
|
+
}
|
|
4896
|
+
function renderCollaborationBlocks(rounds, _width) {
|
|
4897
|
+
if (rounds.length === 0) {
|
|
4898
|
+
return [{ type: "empty", text: "No agent discussion yet" }];
|
|
4899
|
+
}
|
|
4900
|
+
const blocks = [];
|
|
4901
|
+
const agentNames = buildAgentNameMap(rounds);
|
|
4902
|
+
const agentColors = assignAgentColors(rounds);
|
|
4903
|
+
const stanceHistories = buildStanceHistories(rounds);
|
|
4904
|
+
const latestRound = rounds[rounds.length - 1];
|
|
4905
|
+
const conflicts = detectConflicts(latestRound.opinions);
|
|
4906
|
+
blocks.push({
|
|
4907
|
+
type: "header",
|
|
4908
|
+
text: `\u2500\u2500 Agent Discussion (Round ${latestRound.roundNumber}) \u2500\u2500`
|
|
4909
|
+
});
|
|
4910
|
+
for (const opinion of latestRound.opinions) {
|
|
4911
|
+
const history = stanceHistories[opinion.agentId] ?? [];
|
|
4912
|
+
blocks.push({
|
|
4913
|
+
type: "agent-bubble",
|
|
4914
|
+
agentName: opinion.agentName,
|
|
4915
|
+
agentAvatar: getAgentAvatar(opinion.agentName),
|
|
4916
|
+
color: agentColors[opinion.agentId] ?? "white",
|
|
4917
|
+
stanceIcon: STANCE_ICONS[opinion.stance],
|
|
4918
|
+
reasoning: opinion.reasoning,
|
|
4919
|
+
isConflict: conflicts.has(opinion.agentId),
|
|
4920
|
+
stanceHistoryText: renderStanceHistory(history)
|
|
4921
|
+
});
|
|
4922
|
+
}
|
|
4923
|
+
for (const review of latestRound.crossReviews) {
|
|
4924
|
+
const fromName = agentNames[review.fromAgentId] ?? review.fromAgentId;
|
|
4925
|
+
const toName = agentNames[review.toAgentId] ?? review.toAgentId;
|
|
4926
|
+
blocks.push({
|
|
4927
|
+
type: "cross-review-block",
|
|
4928
|
+
fromName,
|
|
4929
|
+
fromAvatar: getAgentAvatar(fromName),
|
|
4930
|
+
fromColor: agentColors[review.fromAgentId] ?? "white",
|
|
4931
|
+
toName,
|
|
4932
|
+
toAvatar: getAgentAvatar(toName),
|
|
4933
|
+
toColor: agentColors[review.toAgentId] ?? "white",
|
|
4934
|
+
verb: CROSS_REVIEW_VERBS[review.stance],
|
|
4935
|
+
comment: review.comment
|
|
4936
|
+
});
|
|
4937
|
+
}
|
|
4938
|
+
const consensus = calculateConsensus(latestRound.opinions);
|
|
4939
|
+
const percentage = consensus.totalAgents > 0 ? Math.round(consensus.approveCount / consensus.totalAgents * 100) : 0;
|
|
4940
|
+
blocks.push({
|
|
4941
|
+
type: "consensus-bar",
|
|
4942
|
+
approveCount: consensus.approveCount,
|
|
4943
|
+
concernCount: consensus.concernCount,
|
|
4944
|
+
rejectCount: consensus.rejectCount,
|
|
4945
|
+
totalAgents: consensus.totalAgents,
|
|
4946
|
+
reached: consensus.reached,
|
|
4947
|
+
percentage
|
|
4948
|
+
});
|
|
4949
|
+
return blocks;
|
|
4950
|
+
}
|
|
4951
|
+
|
|
4952
|
+
// src/tui/components/AgentDiscussionPanel.tsx
|
|
4953
|
+
function SpeechBubble({
|
|
4954
|
+
block,
|
|
4955
|
+
maxWidth
|
|
4956
|
+
}) {
|
|
4957
|
+
const borderColor = block.isConflict ? "red" : block.color;
|
|
4958
|
+
const bubbleWidth = Math.min(maxWidth, 60);
|
|
4959
|
+
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React2.createElement(Box2, null, /* @__PURE__ */ React2.createElement(Text2, { color: block.color, bold: true }, block.agentAvatar, " ", block.agentName), block.isConflict && /* @__PURE__ */ React2.createElement(Text2, { color: "red", bold: true }, " ", "\u26A1"), block.stanceHistoryText !== "" && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " (", block.stanceHistoryText, ")")), /* @__PURE__ */ React2.createElement(
|
|
4960
|
+
Box2,
|
|
4961
|
+
{
|
|
4962
|
+
borderStyle: "round",
|
|
4963
|
+
borderColor,
|
|
4964
|
+
paddingLeft: 1,
|
|
4965
|
+
paddingRight: 1,
|
|
4966
|
+
width: bubbleWidth
|
|
4967
|
+
},
|
|
4968
|
+
/* @__PURE__ */ React2.createElement(Text2, { wrap: "truncate" }, block.stanceIcon, " ", block.reasoning)
|
|
4969
|
+
));
|
|
4970
|
+
}
|
|
4971
|
+
function ConsensusProgressBar({
|
|
4972
|
+
block,
|
|
4973
|
+
maxWidth
|
|
4974
|
+
}) {
|
|
4975
|
+
const barWidth = Math.min(20, Math.max(8, maxWidth - 30));
|
|
4976
|
+
const total = block.totalAgents || 1;
|
|
4977
|
+
const approveLen = Math.round(block.approveCount / total * barWidth);
|
|
4978
|
+
const concernLen = Math.round(block.concernCount / total * barWidth);
|
|
4979
|
+
const remaining = Math.max(0, barWidth - approveLen - concernLen);
|
|
4980
|
+
const filled = "\u2588";
|
|
4981
|
+
const empty = "\u2591";
|
|
4982
|
+
const statusIcon = block.reached ? "\u2705" : "\u23F3";
|
|
4983
|
+
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React2.createElement(Box2, null, /* @__PURE__ */ React2.createElement(Text2, { bold: true }, statusIcon, " Consensus "), /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, filled.repeat(approveLen)), /* @__PURE__ */ React2.createElement(Text2, { color: "yellow" }, filled.repeat(concernLen)), block.rejectCount > 0 ? /* @__PURE__ */ React2.createElement(Text2, { color: "red" }, filled.repeat(remaining)) : /* @__PURE__ */ React2.createElement(Text2, { color: "gray" }, empty.repeat(remaining)), /* @__PURE__ */ React2.createElement(Text2, { bold: true }, " ", block.percentage, "%")), /* @__PURE__ */ React2.createElement(Box2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2705", " ", block.approveCount), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, { color: "yellow" }, "\u26A0\uFE0F", " ", block.concernCount), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, { color: "red" }, "\u274C", " ", block.rejectCount)));
|
|
4984
|
+
}
|
|
4985
|
+
function CrossReviewItem({ block }) {
|
|
4986
|
+
return /* @__PURE__ */ React2.createElement(Box2, null, /* @__PURE__ */ React2.createElement(Text2, { color: block.fromColor }, block.fromAvatar, " ", block.fromName), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React2.createElement(Text2, { color: block.toColor }, block.toAvatar, " ", block.toName), /* @__PURE__ */ React2.createElement(Text2, null, " ", block.verb, ": "), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, '"', block.comment, '"'));
|
|
4987
|
+
}
|
|
4988
|
+
function AgentDiscussionPanel({
|
|
4989
|
+
rounds,
|
|
4990
|
+
width,
|
|
4991
|
+
height
|
|
4992
|
+
}) {
|
|
4993
|
+
const blocks = useMemo(() => renderCollaborationBlocks(rounds, width), [rounds, width]);
|
|
4994
|
+
const maxHeight = Math.max(0, height - 2);
|
|
4995
|
+
const visibleBlocks = [];
|
|
4996
|
+
let usedHeight = 0;
|
|
4997
|
+
for (const block of blocks) {
|
|
4998
|
+
const h = estimateBlockHeight(block);
|
|
4999
|
+
if (usedHeight + h > maxHeight) break;
|
|
5000
|
+
visibleBlocks.push(block);
|
|
5001
|
+
usedHeight += h;
|
|
5002
|
+
}
|
|
5003
|
+
const innerWidth = Math.max(10, width - 4);
|
|
5004
|
+
return /* @__PURE__ */ React2.createElement(
|
|
5005
|
+
Box2,
|
|
5006
|
+
{
|
|
5007
|
+
flexDirection: "column",
|
|
5008
|
+
width,
|
|
5009
|
+
height,
|
|
5010
|
+
borderStyle: "round",
|
|
5011
|
+
borderColor: BORDER_COLORS.panel
|
|
5012
|
+
},
|
|
5013
|
+
visibleBlocks.map((block, i) => {
|
|
5014
|
+
switch (block.type) {
|
|
5015
|
+
case "header":
|
|
5016
|
+
return /* @__PURE__ */ React2.createElement(Text2, { key: i, color: "magenta", bold: true }, block.text);
|
|
5017
|
+
case "agent-bubble":
|
|
5018
|
+
return /* @__PURE__ */ React2.createElement(SpeechBubble, { key: i, block, maxWidth: innerWidth });
|
|
5019
|
+
case "cross-review-block":
|
|
5020
|
+
return /* @__PURE__ */ React2.createElement(CrossReviewItem, { key: i, block });
|
|
5021
|
+
case "consensus-bar":
|
|
5022
|
+
return /* @__PURE__ */ React2.createElement(ConsensusProgressBar, { key: i, block, maxWidth: innerWidth });
|
|
5023
|
+
case "empty":
|
|
5024
|
+
return /* @__PURE__ */ React2.createElement(Text2, { key: i, color: "gray", dimColor: true }, block.text);
|
|
5025
|
+
}
|
|
5026
|
+
})
|
|
5027
|
+
);
|
|
5028
|
+
}
|
|
5029
|
+
|
|
5030
|
+
// src/tui/components/PlanModeScreen.tsx
|
|
5031
|
+
var LINE_COLORS = {
|
|
5032
|
+
header: "magenta",
|
|
5033
|
+
agent: "white",
|
|
5034
|
+
discussion: "cyan",
|
|
5035
|
+
consensus: "green",
|
|
5036
|
+
empty: "gray"
|
|
5037
|
+
};
|
|
5038
|
+
function PlanModeScreen({
|
|
5039
|
+
agents,
|
|
5040
|
+
rounds,
|
|
5041
|
+
width,
|
|
5042
|
+
height
|
|
5043
|
+
}) {
|
|
5044
|
+
const summaryLines = useMemo2(
|
|
5045
|
+
() => renderPlanScreen(agents, rounds, width - 2),
|
|
5046
|
+
[agents, rounds, width]
|
|
5047
|
+
);
|
|
5048
|
+
const summaryHeight = Math.max(5, Math.floor(height * 0.4));
|
|
5049
|
+
const discussionHeight = height - summaryHeight;
|
|
5050
|
+
return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", width, height }, /* @__PURE__ */ React3.createElement(
|
|
5051
|
+
Box3,
|
|
5052
|
+
{
|
|
5053
|
+
flexDirection: "column",
|
|
5054
|
+
width,
|
|
5055
|
+
height: summaryHeight,
|
|
5056
|
+
borderStyle: "round",
|
|
5057
|
+
borderColor: BORDER_COLORS.panel
|
|
5058
|
+
},
|
|
5059
|
+
summaryLines.slice(0, summaryHeight - 2).map((line, i) => /* @__PURE__ */ React3.createElement(
|
|
5060
|
+
Text3,
|
|
5061
|
+
{
|
|
5062
|
+
key: i,
|
|
5063
|
+
color: LINE_COLORS[line.type],
|
|
5064
|
+
bold: line.type === "header" || line.type === "consensus",
|
|
5065
|
+
dimColor: line.type === "empty",
|
|
5066
|
+
wrap: "truncate"
|
|
5067
|
+
},
|
|
5068
|
+
line.text
|
|
5069
|
+
))
|
|
5070
|
+
), rounds.length > 0 && discussionHeight > 3 && /* @__PURE__ */ React3.createElement(AgentDiscussionPanel, { rounds, width, height: discussionHeight }));
|
|
5071
|
+
}
|
|
5072
|
+
|
|
5073
|
+
// src/tui/components/ActModeScreen.tsx
|
|
5074
|
+
import React4, { useMemo as useMemo3 } from "react";
|
|
5075
|
+
import { Box as Box4, Text as Text4 } from "ink";
|
|
5076
|
+
|
|
5077
|
+
// src/tui/components/act-screen.pure.ts
|
|
5078
|
+
var PHASE_ICONS = {
|
|
5079
|
+
RED: "\u{1F534}",
|
|
5080
|
+
GREEN: "\u{1F7E2}",
|
|
5081
|
+
REFACTOR: "\u{1F527}"
|
|
5082
|
+
};
|
|
5083
|
+
var PHASE_COLORS = {
|
|
5084
|
+
RED: "red",
|
|
5085
|
+
GREEN: "green",
|
|
5086
|
+
REFACTOR: "yellow"
|
|
5087
|
+
};
|
|
5088
|
+
function renderTddPhaseBar(currentPhase, _width) {
|
|
5089
|
+
const lines = [];
|
|
5090
|
+
lines.push({ type: "header", text: "\u{1F9EA} TDD Cycle" });
|
|
5091
|
+
const phases = ["RED", "GREEN", "REFACTOR"];
|
|
5092
|
+
const parts = phases.map((phase) => {
|
|
5093
|
+
const icon = PHASE_ICONS[phase];
|
|
5094
|
+
const active = phase === currentPhase;
|
|
5095
|
+
const marker = active ? "\u25BA" : " ";
|
|
5096
|
+
return `${marker}${icon} ${phase}`;
|
|
5097
|
+
});
|
|
5098
|
+
lines.push({ type: "phase-bar", text: ` ${parts.join(" \u2192 ")}` });
|
|
5099
|
+
return lines;
|
|
5100
|
+
}
|
|
5101
|
+
function renderProgressBar(percent, barWidth) {
|
|
5102
|
+
const filled = Math.round(percent / 100 * barWidth);
|
|
5103
|
+
const empty = barWidth - filled;
|
|
5104
|
+
return `[${"\u2588".repeat(filled)}${"\u2591".repeat(empty)}] ${percent}%`;
|
|
5105
|
+
}
|
|
5106
|
+
function renderTddSteps(steps, width) {
|
|
5107
|
+
const lines = [];
|
|
5108
|
+
lines.push({ type: "header", text: "\u{1F4DD} Steps" });
|
|
5109
|
+
if (steps.length === 0) {
|
|
5110
|
+
lines.push({ type: "empty", text: " (no steps yet)" });
|
|
5111
|
+
return lines;
|
|
5112
|
+
}
|
|
5113
|
+
for (const step of steps) {
|
|
5114
|
+
const statusIcon = getStepStatusIcon(step.status);
|
|
5115
|
+
const phaseIcon = PHASE_ICONS[step.phase];
|
|
5116
|
+
const agent = step.agentId ? ` [${step.agentId}]` : "";
|
|
5117
|
+
const text = ` ${statusIcon} ${phaseIcon} ${step.label}${agent}`;
|
|
5118
|
+
lines.push({ type: "step", text: text.slice(0, width) });
|
|
5119
|
+
}
|
|
5120
|
+
return lines;
|
|
5121
|
+
}
|
|
5122
|
+
function getStepStatusIcon(status) {
|
|
5123
|
+
switch (status) {
|
|
5124
|
+
case "pending":
|
|
5125
|
+
return "\u25CB";
|
|
5126
|
+
case "active":
|
|
5127
|
+
return "\u25CF";
|
|
5128
|
+
case "done":
|
|
5129
|
+
return "\u2713";
|
|
5130
|
+
case "failed":
|
|
5131
|
+
return "\u2717";
|
|
5132
|
+
}
|
|
5133
|
+
}
|
|
5134
|
+
function renderOverallProgress(agents, steps, width) {
|
|
5135
|
+
const lines = [];
|
|
5136
|
+
const totalSteps = steps.length;
|
|
5137
|
+
const doneSteps = steps.filter((s) => s.status === "done").length;
|
|
5138
|
+
const stepPercent = totalSteps > 0 ? Math.round(doneSteps / totalSteps * 100) : 0;
|
|
5139
|
+
const agentArr = Array.from(agents.values()).filter((a) => a.status !== "idle" || a.isParallel);
|
|
5140
|
+
const agentPercent = agentArr.length > 0 ? Math.round(agentArr.reduce((sum, a) => sum + a.progress, 0) / agentArr.length) : 0;
|
|
5141
|
+
const overallPercent = totalSteps > 0 ? stepPercent : agentPercent;
|
|
5142
|
+
const barWidth = Math.max(10, Math.min(40, width - 20));
|
|
5143
|
+
lines.push({ type: "header", text: "\u{1F4CA} Overall Progress" });
|
|
5144
|
+
lines.push({ type: "progress", text: ` ${renderProgressBar(overallPercent, barWidth)}` });
|
|
5145
|
+
if (totalSteps > 0) {
|
|
5146
|
+
lines.push({ type: "progress", text: ` Steps: ${doneSteps}/${totalSteps}` });
|
|
5147
|
+
}
|
|
5148
|
+
return lines;
|
|
5149
|
+
}
|
|
5150
|
+
function renderActScreen(currentPhase, steps, agents, width) {
|
|
5151
|
+
const lines = [];
|
|
5152
|
+
lines.push(...renderTddPhaseBar(currentPhase, width));
|
|
5153
|
+
lines.push({ type: "empty", text: "" });
|
|
5154
|
+
lines.push(...renderTddSteps(steps, width));
|
|
5155
|
+
lines.push({ type: "empty", text: "" });
|
|
5156
|
+
lines.push(...renderOverallProgress(agents, steps, width));
|
|
5157
|
+
return lines;
|
|
5158
|
+
}
|
|
5159
|
+
|
|
5160
|
+
// src/tui/components/ActModeScreen.tsx
|
|
5161
|
+
function getLineColor(line, currentPhase) {
|
|
5162
|
+
if (line.type === "header") return "magenta";
|
|
5163
|
+
if (line.type === "phase-bar" && currentPhase) return PHASE_COLORS[currentPhase];
|
|
5164
|
+
if (line.type === "progress") return "cyan";
|
|
5165
|
+
if (line.type === "empty") return "gray";
|
|
5166
|
+
return "white";
|
|
5167
|
+
}
|
|
5168
|
+
function ActModeScreen({
|
|
5169
|
+
currentPhase,
|
|
5170
|
+
steps,
|
|
5171
|
+
agents,
|
|
5172
|
+
width,
|
|
5173
|
+
height
|
|
5174
|
+
}) {
|
|
5175
|
+
const lines = useMemo3(
|
|
5176
|
+
() => renderActScreen(currentPhase, steps, agents, width - 2),
|
|
5177
|
+
[currentPhase, steps, agents, width]
|
|
5178
|
+
);
|
|
5179
|
+
const maxLines = Math.max(0, height - 2);
|
|
5180
|
+
const visibleLines = lines.slice(0, maxLines);
|
|
5181
|
+
return /* @__PURE__ */ React4.createElement(
|
|
5182
|
+
Box4,
|
|
5183
|
+
{
|
|
5184
|
+
flexDirection: "column",
|
|
5185
|
+
width,
|
|
5186
|
+
height,
|
|
5187
|
+
borderStyle: "round",
|
|
5188
|
+
borderColor: BORDER_COLORS.panel
|
|
5189
|
+
},
|
|
5190
|
+
visibleLines.map((line, i) => /* @__PURE__ */ React4.createElement(
|
|
5191
|
+
Text4,
|
|
5192
|
+
{
|
|
5193
|
+
key: i,
|
|
5194
|
+
color: getLineColor(line, currentPhase),
|
|
5195
|
+
bold: line.type === "header" || line.type === "phase-bar",
|
|
5196
|
+
dimColor: line.type === "empty",
|
|
5197
|
+
wrap: "truncate"
|
|
5198
|
+
},
|
|
5199
|
+
line.text
|
|
5200
|
+
))
|
|
5201
|
+
);
|
|
5202
|
+
}
|
|
5203
|
+
|
|
5204
|
+
// src/tui/components/EvalModeScreen.tsx
|
|
5205
|
+
import React5, { useMemo as useMemo4 } from "react";
|
|
5206
|
+
import { Box as Box5, Text as Text5 } from "ink";
|
|
5207
|
+
|
|
5208
|
+
// src/tui/components/eval-screen.pure.ts
|
|
5209
|
+
function renderScoreBar(score, maxScore, barWidth) {
|
|
5210
|
+
const percent = maxScore > 0 ? Math.round(score / maxScore * 100) : 0;
|
|
5211
|
+
const filled = Math.round(percent / 100 * barWidth);
|
|
5212
|
+
const empty = barWidth - filled;
|
|
5213
|
+
return `[${"\u2588".repeat(filled)}${"\u2591".repeat(empty)}] ${score}/${maxScore}`;
|
|
5214
|
+
}
|
|
5215
|
+
function renderAgentResult(result, width) {
|
|
5216
|
+
const lines = [];
|
|
5217
|
+
const statusIcon = getResultStatusIcon(result.status);
|
|
5218
|
+
const barWidth = Math.max(8, Math.min(20, width - 30));
|
|
5219
|
+
lines.push({
|
|
5220
|
+
type: "agent-result",
|
|
5221
|
+
text: ` ${statusIcon} ${result.agentName}`
|
|
5222
|
+
});
|
|
5223
|
+
for (const cat of result.categories) {
|
|
5224
|
+
const bar = renderScoreBar(cat.score, cat.maxScore, barWidth);
|
|
5225
|
+
lines.push({
|
|
5226
|
+
type: "category",
|
|
5227
|
+
text: ` ${padRight(cat.name, 16)} ${bar}`
|
|
5228
|
+
});
|
|
5229
|
+
}
|
|
5230
|
+
const totalBar = renderScoreBar(result.totalScore, result.maxTotalScore, barWidth);
|
|
5231
|
+
lines.push({
|
|
5232
|
+
type: "total-score",
|
|
5233
|
+
text: ` ${"Total".padEnd(16)} ${totalBar}`
|
|
5234
|
+
});
|
|
5235
|
+
return lines;
|
|
5236
|
+
}
|
|
5237
|
+
function getResultStatusIcon(status) {
|
|
5238
|
+
switch (status) {
|
|
5239
|
+
case "pending":
|
|
5240
|
+
return "\u23F3";
|
|
5241
|
+
case "in-progress":
|
|
5242
|
+
return "\u{1F504}";
|
|
5243
|
+
case "done":
|
|
5244
|
+
return "\u2705";
|
|
5245
|
+
}
|
|
5246
|
+
}
|
|
5247
|
+
function padRight(str, len) {
|
|
5248
|
+
return str.length >= len ? str.slice(0, len) : str + " ".repeat(len - str.length);
|
|
5249
|
+
}
|
|
5250
|
+
function calculateAggregateScore(results) {
|
|
5251
|
+
if (results.length === 0) return { total: 0, max: 0, percent: 0 };
|
|
5252
|
+
const total = results.reduce((sum, r) => sum + r.totalScore, 0);
|
|
5253
|
+
const max = results.reduce((sum, r) => sum + r.maxTotalScore, 0);
|
|
5254
|
+
const percent = max > 0 ? Math.round(total / max * 100) : 0;
|
|
5255
|
+
return { total, max, percent };
|
|
5256
|
+
}
|
|
5257
|
+
function renderEvalScreen(results, width) {
|
|
5258
|
+
const lines = [];
|
|
5259
|
+
lines.push({ type: "header", text: "\u{1F4CA} Review Results" });
|
|
5260
|
+
if (results.length === 0) {
|
|
5261
|
+
lines.push({ type: "empty", text: " (no review results yet)" });
|
|
5262
|
+
return lines;
|
|
5263
|
+
}
|
|
5264
|
+
for (const result of results) {
|
|
5265
|
+
lines.push(...renderAgentResult(result, width));
|
|
5266
|
+
lines.push({ type: "empty", text: "" });
|
|
5267
|
+
}
|
|
5268
|
+
const agg = calculateAggregateScore(results);
|
|
5269
|
+
const barWidth = Math.max(8, Math.min(20, width - 30));
|
|
5270
|
+
lines.push({ type: "header", text: "\u{1F3C6} Aggregate Score" });
|
|
5271
|
+
lines.push({
|
|
5272
|
+
type: "total-score",
|
|
5273
|
+
text: ` ${renderScoreBar(agg.total, agg.max, barWidth)} (${agg.percent}%)`
|
|
5274
|
+
});
|
|
5275
|
+
return lines;
|
|
5276
|
+
}
|
|
5277
|
+
|
|
5278
|
+
// src/tui/components/EvalModeScreen.tsx
|
|
5279
|
+
var LINE_COLORS2 = {
|
|
5280
|
+
header: "magenta",
|
|
5281
|
+
"agent-result": "white",
|
|
5282
|
+
category: "cyan",
|
|
5283
|
+
"total-score": "green",
|
|
5284
|
+
empty: "gray"
|
|
5285
|
+
};
|
|
5286
|
+
function EvalModeScreen({
|
|
5287
|
+
results,
|
|
5288
|
+
width,
|
|
5289
|
+
height
|
|
5290
|
+
}) {
|
|
5291
|
+
const lines = useMemo4(() => renderEvalScreen(results, width - 2), [results, width]);
|
|
5292
|
+
const maxLines = Math.max(0, height - 2);
|
|
5293
|
+
const visibleLines = lines.slice(0, maxLines);
|
|
5294
|
+
return /* @__PURE__ */ React5.createElement(
|
|
5295
|
+
Box5,
|
|
5296
|
+
{
|
|
5297
|
+
flexDirection: "column",
|
|
5298
|
+
width,
|
|
5299
|
+
height,
|
|
5300
|
+
borderStyle: "round",
|
|
5301
|
+
borderColor: BORDER_COLORS.panel
|
|
5302
|
+
},
|
|
5303
|
+
visibleLines.map((line, i) => /* @__PURE__ */ React5.createElement(
|
|
5304
|
+
Text5,
|
|
5305
|
+
{
|
|
5306
|
+
key: i,
|
|
5307
|
+
color: LINE_COLORS2[line.type],
|
|
5308
|
+
bold: line.type === "header" || line.type === "total-score",
|
|
5309
|
+
dimColor: line.type === "empty",
|
|
5310
|
+
wrap: "truncate"
|
|
5311
|
+
},
|
|
5312
|
+
line.text
|
|
5313
|
+
))
|
|
5314
|
+
);
|
|
5315
|
+
}
|
|
5316
|
+
|
|
5317
|
+
// src/tui/components/FlowMap.tsx
|
|
5318
|
+
import React6, { useMemo as useMemo5 } from "react";
|
|
5319
|
+
import { Box as Box6, Text as Text6 } from "ink";
|
|
5320
|
+
|
|
4546
5321
|
// src/tui/utils/color-buffer.ts
|
|
4547
5322
|
var DEFAULT_CELL = Object.freeze({ char: " ", style: Object.freeze({}) });
|
|
4548
5323
|
function stylesEqual(a, b) {
|
|
@@ -5038,13 +5813,13 @@ function trimTrailingSpaces(cells) {
|
|
|
5038
5813
|
}
|
|
5039
5814
|
return end === cells.length ? cells : cells.slice(0, end);
|
|
5040
5815
|
}
|
|
5041
|
-
var ColorRow =
|
|
5816
|
+
var ColorRow = React6.memo(function ColorRow2({
|
|
5042
5817
|
cells
|
|
5043
5818
|
}) {
|
|
5044
5819
|
const trimmed = trimTrailingSpaces(cells);
|
|
5045
|
-
if (trimmed.length === 0) return /* @__PURE__ */
|
|
5820
|
+
if (trimmed.length === 0) return /* @__PURE__ */ React6.createElement(Box6, null);
|
|
5046
5821
|
const segments = groupByStyle(trimmed);
|
|
5047
|
-
return /* @__PURE__ */
|
|
5822
|
+
return /* @__PURE__ */ React6.createElement(Box6, null, segments.map((seg, i) => /* @__PURE__ */ React6.createElement(Text6, { key: i, color: seg.style.fg, bold: seg.style.bold, dimColor: seg.style.dim }, seg.text)));
|
|
5048
5823
|
});
|
|
5049
5824
|
function FlowMap({
|
|
5050
5825
|
agents,
|
|
@@ -5058,22 +5833,22 @@ function FlowMap({
|
|
|
5058
5833
|
}) {
|
|
5059
5834
|
const contentWidth = Math.max(1, width - 2);
|
|
5060
5835
|
const contentHeight = Math.max(1, height - 3);
|
|
5061
|
-
const hasRunningAgents =
|
|
5836
|
+
const hasRunningAgents = useMemo5(
|
|
5062
5837
|
() => [...agents.values()].some((a) => a.status === "running"),
|
|
5063
5838
|
[agents]
|
|
5064
5839
|
);
|
|
5065
5840
|
const liveTick = hasRunningAgents ? tick ?? 0 : 0;
|
|
5066
5841
|
const liveNow = hasRunningAgents ? now : void 0;
|
|
5067
|
-
const compactContent =
|
|
5842
|
+
const compactContent = useMemo5(() => {
|
|
5068
5843
|
if (layoutMode !== "narrow") return null;
|
|
5069
5844
|
return renderFlowMapCompact(agents);
|
|
5070
5845
|
}, [agents, layoutMode]);
|
|
5071
|
-
const lines =
|
|
5846
|
+
const lines = useMemo5(() => {
|
|
5072
5847
|
if (layoutMode === "narrow") return null;
|
|
5073
5848
|
const buf = layoutMode === "wide" ? renderFlowMap(agents, edges, contentWidth, contentHeight, activeStage) : renderFlowMapSimplified(agents, contentWidth, contentHeight);
|
|
5074
5849
|
return buf.toLinesDirect();
|
|
5075
5850
|
}, [agents, edges, contentWidth, contentHeight, layoutMode, activeStage]);
|
|
5076
|
-
const liveOverlays =
|
|
5851
|
+
const liveOverlays = useMemo5(() => {
|
|
5077
5852
|
if (liveNow === void 0) return null;
|
|
5078
5853
|
const overlays = [];
|
|
5079
5854
|
for (const [id, agent] of agents) {
|
|
@@ -5088,8 +5863,8 @@ function FlowMap({
|
|
|
5088
5863
|
return overlays.length > 0 ? overlays : null;
|
|
5089
5864
|
}, [agents, liveTick, liveNow]);
|
|
5090
5865
|
if (layoutMode === "narrow") {
|
|
5091
|
-
return /* @__PURE__ */
|
|
5092
|
-
|
|
5866
|
+
return /* @__PURE__ */ React6.createElement(
|
|
5867
|
+
Box6,
|
|
5093
5868
|
{
|
|
5094
5869
|
borderStyle: "single",
|
|
5095
5870
|
borderColor: BORDER_COLORS.panel,
|
|
@@ -5097,14 +5872,14 @@ function FlowMap({
|
|
|
5097
5872
|
width,
|
|
5098
5873
|
height
|
|
5099
5874
|
},
|
|
5100
|
-
/* @__PURE__ */
|
|
5101
|
-
/* @__PURE__ */
|
|
5102
|
-
liveOverlays?.map((o) => /* @__PURE__ */
|
|
5875
|
+
/* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "FLOW MAP"),
|
|
5876
|
+
/* @__PURE__ */ React6.createElement(Text6, null, compactContent),
|
|
5877
|
+
liveOverlays?.map((o) => /* @__PURE__ */ React6.createElement(Text6, { key: o.id, color: "yellow" }, o.icon, " ", o.elapsed))
|
|
5103
5878
|
);
|
|
5104
5879
|
}
|
|
5105
5880
|
if (!lines) {
|
|
5106
|
-
return /* @__PURE__ */
|
|
5107
|
-
|
|
5881
|
+
return /* @__PURE__ */ React6.createElement(
|
|
5882
|
+
Box6,
|
|
5108
5883
|
{
|
|
5109
5884
|
borderStyle: "single",
|
|
5110
5885
|
borderColor: BORDER_COLORS.panel,
|
|
@@ -5112,11 +5887,11 @@ function FlowMap({
|
|
|
5112
5887
|
width,
|
|
5113
5888
|
height
|
|
5114
5889
|
},
|
|
5115
|
-
/* @__PURE__ */
|
|
5890
|
+
/* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "FLOW MAP")
|
|
5116
5891
|
);
|
|
5117
5892
|
}
|
|
5118
|
-
return /* @__PURE__ */
|
|
5119
|
-
|
|
5893
|
+
return /* @__PURE__ */ React6.createElement(
|
|
5894
|
+
Box6,
|
|
5120
5895
|
{
|
|
5121
5896
|
borderStyle: "single",
|
|
5122
5897
|
borderColor: BORDER_COLORS.panel,
|
|
@@ -5124,163 +5899,90 @@ function FlowMap({
|
|
|
5124
5899
|
width,
|
|
5125
5900
|
height
|
|
5126
5901
|
},
|
|
5127
|
-
/* @__PURE__ */
|
|
5128
|
-
lines.map((row, y) => /* @__PURE__ */
|
|
5129
|
-
liveOverlays?.map((o) => /* @__PURE__ */
|
|
5902
|
+
/* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "FLOW MAP"),
|
|
5903
|
+
lines.map((row, y) => /* @__PURE__ */ React6.createElement(ColorRow, { key: y, cells: row })),
|
|
5904
|
+
liveOverlays?.map((o) => /* @__PURE__ */ React6.createElement(Text6, { key: o.id, color: "yellow" }, o.icon, " ", o.elapsed))
|
|
5130
5905
|
);
|
|
5131
5906
|
}
|
|
5132
5907
|
|
|
5133
|
-
// src/tui/components/
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
}
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
var CROSS_REVIEW_VERBS = {
|
|
5160
|
-
approve: "agrees",
|
|
5161
|
-
concern: "notes",
|
|
5162
|
-
reject: "disagrees"
|
|
5163
|
-
};
|
|
5164
|
-
function renderOpinionLine(opinion, stanceHistory) {
|
|
5165
|
-
const avatar = getAgentAvatar(opinion.agentName);
|
|
5166
|
-
const icon = STANCE_ICONS[opinion.stance];
|
|
5167
|
-
let suffix = "";
|
|
5168
|
-
if (stanceHistory && stanceHistory.length > 1) {
|
|
5169
|
-
const lastStance = stanceHistory[stanceHistory.length - 1];
|
|
5170
|
-
const prevStance = stanceHistory[stanceHistory.length - 2];
|
|
5171
|
-
if (lastStance !== prevStance) {
|
|
5172
|
-
suffix = ` (${prevStance === "reject" || prevStance === "concern" ? "revised" : "alt"})`;
|
|
5173
|
-
}
|
|
5174
|
-
}
|
|
5175
|
-
return {
|
|
5176
|
-
text: `${avatar} ${opinion.agentName} ${icon} ${opinion.stance}${suffix}: "${opinion.reasoning}"`,
|
|
5177
|
-
type: "opinion"
|
|
5178
|
-
};
|
|
5179
|
-
}
|
|
5180
|
-
function renderCrossReviewLine(review, agentNames) {
|
|
5181
|
-
const fromAvatar = getAgentAvatar(agentNames[review.fromAgentId] ?? "unknown");
|
|
5182
|
-
const fromName = agentNames[review.fromAgentId] ?? review.fromAgentId;
|
|
5183
|
-
const toAvatar = getAgentAvatar(agentNames[review.toAgentId] ?? "unknown");
|
|
5184
|
-
const toName = agentNames[review.toAgentId] ?? review.toAgentId;
|
|
5185
|
-
const verb = CROSS_REVIEW_VERBS[review.stance];
|
|
5186
|
-
return {
|
|
5187
|
-
text: `${fromAvatar} ${fromName} \u2192 ${toAvatar} ${toName} ${verb}: "${review.comment}"`,
|
|
5188
|
-
type: "cross-review"
|
|
5189
|
-
};
|
|
5190
|
-
}
|
|
5191
|
-
function renderConsensusLine(consensus) {
|
|
5192
|
-
const icon = consensus.reached ? "\u2705" : "\u274C";
|
|
5193
|
-
return {
|
|
5194
|
-
text: `${icon} Consensus: ${consensus.approveCount}/${consensus.totalAgents} | Critical: ${consensus.criticalCount}`,
|
|
5195
|
-
type: "consensus"
|
|
5196
|
-
};
|
|
5197
|
-
}
|
|
5198
|
-
function buildAgentNameMap(rounds) {
|
|
5199
|
-
const map = {};
|
|
5200
|
-
for (const round of rounds) {
|
|
5201
|
-
for (const opinion of round.opinions) {
|
|
5202
|
-
map[opinion.agentId] = opinion.agentName;
|
|
5203
|
-
}
|
|
5204
|
-
}
|
|
5205
|
-
return map;
|
|
5206
|
-
}
|
|
5207
|
-
function buildStanceHistories(rounds) {
|
|
5208
|
-
const histories = {};
|
|
5209
|
-
for (const round of rounds) {
|
|
5210
|
-
for (const opinion of round.opinions) {
|
|
5211
|
-
if (!histories[opinion.agentId]) {
|
|
5212
|
-
histories[opinion.agentId] = [];
|
|
5213
|
-
}
|
|
5214
|
-
histories[opinion.agentId].push(opinion.stance);
|
|
5215
|
-
}
|
|
5216
|
-
}
|
|
5217
|
-
return histories;
|
|
5218
|
-
}
|
|
5219
|
-
function renderDiscussionPanel(rounds, _width) {
|
|
5220
|
-
if (rounds.length === 0) {
|
|
5221
|
-
return [{ text: "No agent discussion yet", type: "empty" }];
|
|
5222
|
-
}
|
|
5223
|
-
const lines = [];
|
|
5224
|
-
const agentNames = buildAgentNameMap(rounds);
|
|
5225
|
-
const stanceHistories = buildStanceHistories(rounds);
|
|
5226
|
-
const latestRound = rounds[rounds.length - 1];
|
|
5227
|
-
lines.push({ text: `\u2500\u2500 Agent Discussion \u2500\u2500`, type: "header" });
|
|
5228
|
-
for (const opinion of latestRound.opinions) {
|
|
5229
|
-
lines.push(renderOpinionLine(opinion, stanceHistories[opinion.agentId]));
|
|
5230
|
-
}
|
|
5231
|
-
for (const review of latestRound.crossReviews) {
|
|
5232
|
-
lines.push(renderCrossReviewLine(review, agentNames));
|
|
5233
|
-
}
|
|
5234
|
-
const consensus = calculateConsensus(latestRound.opinions);
|
|
5235
|
-
lines.push(renderConsensusLine(consensus));
|
|
5236
|
-
return lines;
|
|
5908
|
+
// src/tui/components/ModeScreenRouter.tsx
|
|
5909
|
+
function resolveModeScreen(mode, hasDiscussionRounds, hasTddSteps, hasReviewResults) {
|
|
5910
|
+
if (mode === null) return "flow";
|
|
5911
|
+
if (mode === "AUTO") {
|
|
5912
|
+
if (hasReviewResults) return "eval";
|
|
5913
|
+
if (hasTddSteps) return "act";
|
|
5914
|
+
if (hasDiscussionRounds) return "plan";
|
|
5915
|
+
return "plan";
|
|
5916
|
+
}
|
|
5917
|
+
switch (mode) {
|
|
5918
|
+
case "PLAN":
|
|
5919
|
+
return "plan";
|
|
5920
|
+
case "ACT":
|
|
5921
|
+
return "act";
|
|
5922
|
+
case "EVAL":
|
|
5923
|
+
return "eval";
|
|
5924
|
+
}
|
|
5925
|
+
}
|
|
5926
|
+
function DisconnectBanner({
|
|
5927
|
+
status,
|
|
5928
|
+
width
|
|
5929
|
+
}) {
|
|
5930
|
+
if (status === "connected") return null;
|
|
5931
|
+
const icon = status === "reconnecting" ? "\u{1F504}" : "\u26A0\uFE0F";
|
|
5932
|
+
const msg = status === "reconnecting" ? "Reconnecting..." : "Disconnected";
|
|
5933
|
+
return /* @__PURE__ */ React7.createElement(Box7, { width, height: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "yellow", bold: true }, `${icon} Event Bridge: ${msg}`));
|
|
5237
5934
|
}
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
opinion: "white",
|
|
5242
|
-
"cross-review": "cyan",
|
|
5243
|
-
consensus: "green",
|
|
5244
|
-
header: "magenta",
|
|
5245
|
-
empty: "gray"
|
|
5246
|
-
};
|
|
5247
|
-
function AgentDiscussionPanel({
|
|
5248
|
-
rounds,
|
|
5935
|
+
function ModeScreenRouter({
|
|
5936
|
+
state,
|
|
5937
|
+
layoutMode,
|
|
5249
5938
|
width,
|
|
5250
|
-
height
|
|
5939
|
+
height,
|
|
5940
|
+
tick,
|
|
5941
|
+
now
|
|
5251
5942
|
}) {
|
|
5252
|
-
const
|
|
5253
|
-
|
|
5254
|
-
|
|
5943
|
+
const bannerHeight = state.connectionStatus !== "connected" ? 1 : 0;
|
|
5944
|
+
const contentHeight = height - bannerHeight;
|
|
5945
|
+
const screen = resolveModeScreen(
|
|
5946
|
+
state.currentMode,
|
|
5947
|
+
state.discussionRounds.length > 0,
|
|
5948
|
+
state.tddSteps.length > 0,
|
|
5949
|
+
state.reviewResults.length > 0
|
|
5255
5950
|
);
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
return /* @__PURE__ */ React3.createElement(
|
|
5259
|
-
Box3,
|
|
5951
|
+
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", width, height }, /* @__PURE__ */ React7.createElement(DisconnectBanner, { status: state.connectionStatus, width }), screen === "plan" && /* @__PURE__ */ React7.createElement(
|
|
5952
|
+
PlanModeScreen,
|
|
5260
5953
|
{
|
|
5261
|
-
|
|
5954
|
+
agents: state.agents,
|
|
5955
|
+
rounds: state.discussionRounds,
|
|
5262
5956
|
width,
|
|
5263
|
-
height
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
|
|
5957
|
+
height: contentHeight
|
|
5958
|
+
}
|
|
5959
|
+
), screen === "act" && /* @__PURE__ */ React7.createElement(
|
|
5960
|
+
ActModeScreen,
|
|
5961
|
+
{
|
|
5962
|
+
currentPhase: state.tddCurrentPhase,
|
|
5963
|
+
steps: state.tddSteps,
|
|
5964
|
+
agents: state.agents,
|
|
5965
|
+
width,
|
|
5966
|
+
height: contentHeight
|
|
5967
|
+
}
|
|
5968
|
+
), screen === "eval" && /* @__PURE__ */ React7.createElement(EvalModeScreen, { results: state.reviewResults, width, height: contentHeight }), screen === "flow" && /* @__PURE__ */ React7.createElement(
|
|
5969
|
+
FlowMap,
|
|
5970
|
+
{
|
|
5971
|
+
agents: state.agents,
|
|
5972
|
+
edges: state.edges,
|
|
5973
|
+
layoutMode,
|
|
5974
|
+
width,
|
|
5975
|
+
height: contentHeight,
|
|
5976
|
+
activeStage: state.currentMode,
|
|
5977
|
+
tick,
|
|
5978
|
+
now
|
|
5979
|
+
}
|
|
5980
|
+
));
|
|
5279
5981
|
}
|
|
5280
5982
|
|
|
5281
5983
|
// src/tui/components/FocusedAgentPanel.tsx
|
|
5282
|
-
import
|
|
5283
|
-
import { Box as
|
|
5984
|
+
import React9 from "react";
|
|
5985
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
5284
5986
|
|
|
5285
5987
|
// src/tui/components/focused-agent.pure.ts
|
|
5286
5988
|
function formatObjective(objectives, maxLines = 3) {
|
|
@@ -5326,8 +6028,8 @@ function formatEnhancedChecklist(tasks, maxItems = 6) {
|
|
|
5326
6028
|
}
|
|
5327
6029
|
|
|
5328
6030
|
// src/tui/components/ContextSection.tsx
|
|
5329
|
-
import
|
|
5330
|
-
import { Box as
|
|
6031
|
+
import React8 from "react";
|
|
6032
|
+
import { Box as Box8, Text as Text8 } from "ink";
|
|
5331
6033
|
|
|
5332
6034
|
// src/tui/components/context-section.pure.ts
|
|
5333
6035
|
function formatContextDecisions(decisions, maxItems = 5) {
|
|
@@ -5357,27 +6059,27 @@ function ContextSection({
|
|
|
5357
6059
|
const hasDecisions = decisions.length > 0;
|
|
5358
6060
|
const hasNotes = notes.length > 0;
|
|
5359
6061
|
if (!hasDecisions && !hasNotes) return null;
|
|
5360
|
-
return /* @__PURE__ */
|
|
6062
|
+
return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column" }, hasDecisions && /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text8, { dimColor: true, bold: true }, "Decisions"), formatContextDecisions(decisions)?.split("\n").map((line, i) => /* @__PURE__ */ React8.createElement(Text8, { key: i, color: "cyan" }, line))), hasNotes && /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text8, { dimColor: true, bold: true }, "Notes"), formatContextNotes(notes)?.split("\n").map((line, i) => /* @__PURE__ */ React8.createElement(Text8, { key: i, dimColor: true }, line))));
|
|
5361
6063
|
}
|
|
5362
6064
|
|
|
5363
6065
|
// src/tui/components/FocusedAgentPanel.tsx
|
|
5364
6066
|
function SectionDivider({ title }) {
|
|
5365
|
-
return /* @__PURE__ */
|
|
6067
|
+
return /* @__PURE__ */ React9.createElement(Text9, { color: "magenta" }, formatSectionDivider(title));
|
|
5366
6068
|
}
|
|
5367
6069
|
function LogSection({
|
|
5368
6070
|
logs,
|
|
5369
6071
|
eventLog
|
|
5370
6072
|
}) {
|
|
5371
|
-
if (!logs) return /* @__PURE__ */
|
|
6073
|
+
if (!logs) return /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "No events");
|
|
5372
6074
|
const logLines = logs.split("\n");
|
|
5373
6075
|
const offset = eventLog.length - logLines.length;
|
|
5374
|
-
return /* @__PURE__ */
|
|
6076
|
+
return /* @__PURE__ */ React9.createElement(React9.Fragment, null, logLines.map((line, i) => {
|
|
5375
6077
|
const ev = eventLog[offset + i];
|
|
5376
6078
|
const isError = ev?.level === "error";
|
|
5377
6079
|
const spaceIdx = line.indexOf(" ");
|
|
5378
6080
|
const timestamp = spaceIdx > 0 ? line.slice(0, spaceIdx) : line;
|
|
5379
6081
|
const message = spaceIdx > 0 ? line.slice(spaceIdx + 1) : "";
|
|
5380
|
-
return /* @__PURE__ */
|
|
6082
|
+
return /* @__PURE__ */ React9.createElement(Box9, { key: i, gap: 1 }, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, timestamp), /* @__PURE__ */ React9.createElement(Text9, { color: isError ? "red" : void 0 }, message));
|
|
5381
6083
|
}));
|
|
5382
6084
|
}
|
|
5383
6085
|
function FocusedAgentPanel({
|
|
@@ -5393,8 +6095,8 @@ function FocusedAgentPanel({
|
|
|
5393
6095
|
height
|
|
5394
6096
|
}) {
|
|
5395
6097
|
if (!agent) {
|
|
5396
|
-
return /* @__PURE__ */
|
|
5397
|
-
|
|
6098
|
+
return /* @__PURE__ */ React9.createElement(
|
|
6099
|
+
Box9,
|
|
5398
6100
|
{
|
|
5399
6101
|
borderStyle: "single",
|
|
5400
6102
|
borderColor: BORDER_COLORS.panel,
|
|
@@ -5402,7 +6104,7 @@ function FocusedAgentPanel({
|
|
|
5402
6104
|
width,
|
|
5403
6105
|
height
|
|
5404
6106
|
},
|
|
5405
|
-
/* @__PURE__ */
|
|
6107
|
+
/* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "No agent focused")
|
|
5406
6108
|
);
|
|
5407
6109
|
}
|
|
5408
6110
|
const avatar = getAgentAvatar(agent.name);
|
|
@@ -5415,8 +6117,8 @@ function FocusedAgentPanel({
|
|
|
5415
6117
|
const isRunning = agent.status === "running";
|
|
5416
6118
|
const showSpinner = isRunning && tick != null;
|
|
5417
6119
|
const showElapsed = isRunning && now != null && agent.startedAt != null;
|
|
5418
|
-
return /* @__PURE__ */
|
|
5419
|
-
|
|
6120
|
+
return /* @__PURE__ */ React9.createElement(
|
|
6121
|
+
Box9,
|
|
5420
6122
|
{
|
|
5421
6123
|
borderStyle: "single",
|
|
5422
6124
|
borderColor: BORDER_COLORS.panel,
|
|
@@ -5424,22 +6126,22 @@ function FocusedAgentPanel({
|
|
|
5424
6126
|
width,
|
|
5425
6127
|
height
|
|
5426
6128
|
},
|
|
5427
|
-
/* @__PURE__ */
|
|
5428
|
-
/* @__PURE__ */
|
|
5429
|
-
/* @__PURE__ */
|
|
5430
|
-
objective ? /* @__PURE__ */
|
|
5431
|
-
/* @__PURE__ */
|
|
5432
|
-
activeSkills.length > 0 ? activeSkills.map((s, i) => /* @__PURE__ */
|
|
5433
|
-
/* @__PURE__ */
|
|
5434
|
-
contextDecisions.length > 0 || contextNotes.length > 0 ? /* @__PURE__ */
|
|
5435
|
-
/* @__PURE__ */
|
|
5436
|
-
/* @__PURE__ */
|
|
6129
|
+
/* @__PURE__ */ React9.createElement(Box9, { gap: 2 }, /* @__PURE__ */ React9.createElement(Text9, null, avatar), /* @__PURE__ */ React9.createElement(Text9, { bold: true }, agent.name), showSpinner ? /* @__PURE__ */ React9.createElement(Text9, { color: "cyan" }, spinnerFrame(tick)) : /* @__PURE__ */ React9.createElement(Text9, { color: statusColor, bold: true }, icon), /* @__PURE__ */ React9.createElement(Text9, { color: statusColor }, statusLabel), showElapsed && /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, formatElapsed(agent.startedAt, now)), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, agent.stage)),
|
|
6130
|
+
/* @__PURE__ */ React9.createElement(Box9, { gap: 1 }, /* @__PURE__ */ React9.createElement(Text9, { color: "magenta" }, progressBar.bar), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, progressBar.label)),
|
|
6131
|
+
/* @__PURE__ */ React9.createElement(SectionDivider, { title: "Objective" }),
|
|
6132
|
+
objective ? /* @__PURE__ */ React9.createElement(Text9, null, objective) : /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "No objectives"),
|
|
6133
|
+
/* @__PURE__ */ React9.createElement(SectionDivider, { title: "Skills" }),
|
|
6134
|
+
activeSkills.length > 0 ? activeSkills.map((s, i) => /* @__PURE__ */ React9.createElement(Text9, { key: i }, " ", s)) : /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "No skills"),
|
|
6135
|
+
/* @__PURE__ */ React9.createElement(SectionDivider, { title: "Context" }),
|
|
6136
|
+
contextDecisions.length > 0 || contextNotes.length > 0 ? /* @__PURE__ */ React9.createElement(ContextSection, { decisions: contextDecisions, notes: contextNotes, width }) : /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "No context"),
|
|
6137
|
+
/* @__PURE__ */ React9.createElement(SectionDivider, { title: "Event Log" }),
|
|
6138
|
+
/* @__PURE__ */ React9.createElement(LogSection, { logs, eventLog })
|
|
5437
6139
|
);
|
|
5438
6140
|
}
|
|
5439
6141
|
|
|
5440
6142
|
// src/tui/components/ChecklistPanel.tsx
|
|
5441
|
-
import
|
|
5442
|
-
import { Box as
|
|
6143
|
+
import React10 from "react";
|
|
6144
|
+
import { Box as Box10, Text as Text10 } from "ink";
|
|
5443
6145
|
|
|
5444
6146
|
// src/tui/components/checklist-panel.pure.ts
|
|
5445
6147
|
function resolveChecklistTasks(tasks, contextDecisions, contextNotes) {
|
|
@@ -5467,8 +6169,8 @@ function ChecklistPanel({
|
|
|
5467
6169
|
}) {
|
|
5468
6170
|
const resolvedTasks = resolveChecklistTasks(tasks, contextDecisions, contextNotes);
|
|
5469
6171
|
const checklist = formatEnhancedChecklist(resolvedTasks);
|
|
5470
|
-
return /* @__PURE__ */
|
|
5471
|
-
|
|
6172
|
+
return /* @__PURE__ */ React10.createElement(
|
|
6173
|
+
Box10,
|
|
5472
6174
|
{
|
|
5473
6175
|
borderStyle: "single",
|
|
5474
6176
|
borderColor: BORDER_COLORS.panel,
|
|
@@ -5476,17 +6178,17 @@ function ChecklistPanel({
|
|
|
5476
6178
|
width,
|
|
5477
6179
|
height
|
|
5478
6180
|
},
|
|
5479
|
-
/* @__PURE__ */
|
|
6181
|
+
/* @__PURE__ */ React10.createElement(Text10, { bold: true, dimColor: true }, "\u2500\u2500\u2500 Checklist"),
|
|
5480
6182
|
checklist.split("\n").map((line, i) => {
|
|
5481
6183
|
const isCompleted = line.includes("\u2714");
|
|
5482
|
-
return /* @__PURE__ */
|
|
6184
|
+
return /* @__PURE__ */ React10.createElement(Text10, { key: i, color: isCompleted ? "green" : void 0 }, line);
|
|
5483
6185
|
})
|
|
5484
6186
|
);
|
|
5485
6187
|
}
|
|
5486
6188
|
|
|
5487
6189
|
// src/tui/components/StageHealthBar.tsx
|
|
5488
|
-
import
|
|
5489
|
-
import { Box as
|
|
6190
|
+
import React11 from "react";
|
|
6191
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
5490
6192
|
|
|
5491
6193
|
// src/tui/components/stage-health.pure.ts
|
|
5492
6194
|
function formatCount(n) {
|
|
@@ -5554,29 +6256,29 @@ function StageStatDisplay({
|
|
|
5554
6256
|
const parts = [];
|
|
5555
6257
|
if (stats.running > 0)
|
|
5556
6258
|
parts.push(
|
|
5557
|
-
/* @__PURE__ */
|
|
6259
|
+
/* @__PURE__ */ React11.createElement(Text11, { key: "r", color: "green" }, " ", "\u25CF ", stats.running, " running")
|
|
5558
6260
|
);
|
|
5559
6261
|
if (stats.blocked > 0)
|
|
5560
6262
|
parts.push(
|
|
5561
|
-
/* @__PURE__ */
|
|
6263
|
+
/* @__PURE__ */ React11.createElement(Text11, { key: "b", color: "yellow" }, " ", "\u23F8 ", stats.blocked, " blocked")
|
|
5562
6264
|
);
|
|
5563
6265
|
if (stats.waiting > 0)
|
|
5564
6266
|
parts.push(
|
|
5565
|
-
/* @__PURE__ */
|
|
6267
|
+
/* @__PURE__ */ React11.createElement(Text11, { key: "w", dimColor: true }, " ", "\u25CB ", stats.waiting, " waiting")
|
|
5566
6268
|
);
|
|
5567
6269
|
if (stats.done > 0)
|
|
5568
6270
|
parts.push(
|
|
5569
|
-
/* @__PURE__ */
|
|
6271
|
+
/* @__PURE__ */ React11.createElement(Text11, { key: "d", color: "green" }, " ", "\u2713 ", stats.done)
|
|
5570
6272
|
);
|
|
5571
6273
|
if (stats.error > 0)
|
|
5572
6274
|
parts.push(
|
|
5573
|
-
/* @__PURE__ */
|
|
6275
|
+
/* @__PURE__ */ React11.createElement(Text11, { key: "e", color: "red", bold: true }, " ", "! ", stats.error, " err")
|
|
5574
6276
|
);
|
|
5575
6277
|
if (parts.length === 0)
|
|
5576
6278
|
parts.push(
|
|
5577
|
-
/* @__PURE__ */
|
|
6279
|
+
/* @__PURE__ */ React11.createElement(Text11, { key: "idle", dimColor: true }, " ", "idle")
|
|
5578
6280
|
);
|
|
5579
|
-
return /* @__PURE__ */
|
|
6281
|
+
return /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Text11, { color, bold: true }, mode, ":"), parts);
|
|
5580
6282
|
}
|
|
5581
6283
|
function StageHealthBar({
|
|
5582
6284
|
stageHealth,
|
|
@@ -5590,24 +6292,24 @@ function StageHealthBar({
|
|
|
5590
6292
|
now: _now
|
|
5591
6293
|
}) {
|
|
5592
6294
|
const hasActivity = activityHistory && activityHistory.length > 0;
|
|
5593
|
-
return /* @__PURE__ */
|
|
5594
|
-
|
|
6295
|
+
return /* @__PURE__ */ React11.createElement(
|
|
6296
|
+
Box11,
|
|
5595
6297
|
{
|
|
5596
6298
|
borderStyle: "double",
|
|
5597
6299
|
borderColor: BORDER_COLORS.panel,
|
|
5598
6300
|
width,
|
|
5599
6301
|
flexDirection: "column"
|
|
5600
6302
|
},
|
|
5601
|
-
/* @__PURE__ */
|
|
6303
|
+
/* @__PURE__ */ React11.createElement(Box11, null, hasActivity && /* @__PURE__ */ React11.createElement(Box11, { gap: 1, marginRight: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "cyan" }, renderSparkline(
|
|
5602
6304
|
activityHistory.map((s) => s.toolCalls),
|
|
5603
6305
|
10
|
|
5604
|
-
)), /* @__PURE__ */
|
|
6306
|
+
)), /* @__PURE__ */ React11.createElement(Text11, { dimColor: true }, computeThroughput(activityHistory))), /* @__PURE__ */ React11.createElement(Box11, { gap: 2 }, ["PLAN", "ACT", "EVAL"].map((mode) => /* @__PURE__ */ React11.createElement(StageStatDisplay, { key: mode, mode, stats: stageHealth[mode] }))), /* @__PURE__ */ React11.createElement(Box11, { flexGrow: 1 }), /* @__PURE__ */ React11.createElement(Box11, { gap: 2 }, bottlenecks.length > 0 && /* @__PURE__ */ React11.createElement(Text11, { color: "red", bold: true }, "\u26A1 Bottlenecks: ", bottlenecks.join(" / ")), /* @__PURE__ */ React11.createElement(Text11, { dimColor: true }, "\u{1F916} ", formatCount(agentCount)), /* @__PURE__ */ React11.createElement(Text11, { dimColor: true }, "\u2699 ", formatCount(skillCount)), /* @__PURE__ */ React11.createElement(Text11, { dimColor: true }, "\u{1F527} ", formatCount(toolCount))))
|
|
5605
6307
|
);
|
|
5606
6308
|
}
|
|
5607
6309
|
|
|
5608
6310
|
// src/tui/components/ActivityVisualizer.tsx
|
|
5609
|
-
import
|
|
5610
|
-
import { Box as
|
|
6311
|
+
import React12, { useMemo as useMemo6 } from "react";
|
|
6312
|
+
import { Box as Box12, Text as Text12 } from "ink";
|
|
5611
6313
|
|
|
5612
6314
|
// src/tui/utils/display-width.ts
|
|
5613
6315
|
function isWide(code) {
|
|
@@ -5776,11 +6478,11 @@ function ActivityVisualizer({
|
|
|
5776
6478
|
const treeWidth = Math.floor(width * 0.6);
|
|
5777
6479
|
const cardWidth = width - treeWidth;
|
|
5778
6480
|
const contentHeight = Math.max(1, height - 2);
|
|
5779
|
-
const treeLines =
|
|
6481
|
+
const treeLines = useMemo6(
|
|
5780
6482
|
() => renderAgentTree(agents, edges, activeSkills, Math.max(1, treeWidth - 2), contentHeight),
|
|
5781
6483
|
[agents, edges, activeSkills, treeWidth, contentHeight]
|
|
5782
6484
|
);
|
|
5783
|
-
const cardLines =
|
|
6485
|
+
const cardLines = useMemo6(
|
|
5784
6486
|
() => renderAgentStatusCard(
|
|
5785
6487
|
focusedAgent,
|
|
5786
6488
|
currentMode,
|
|
@@ -5792,10 +6494,10 @@ function ActivityVisualizer({
|
|
|
5792
6494
|
[focusedAgent, currentMode, objectives, activeSkills, cardWidth, contentHeight]
|
|
5793
6495
|
);
|
|
5794
6496
|
if (width <= 0 || height <= 0) {
|
|
5795
|
-
return /* @__PURE__ */
|
|
6497
|
+
return /* @__PURE__ */ React12.createElement(Box12, null);
|
|
5796
6498
|
}
|
|
5797
|
-
return /* @__PURE__ */
|
|
5798
|
-
|
|
6499
|
+
return /* @__PURE__ */ React12.createElement(Box12, { flexDirection: "row", width, height }, /* @__PURE__ */ React12.createElement(
|
|
6500
|
+
Box12,
|
|
5799
6501
|
{
|
|
5800
6502
|
borderStyle: "single",
|
|
5801
6503
|
borderColor: BORDER_COLORS.panel,
|
|
@@ -5803,9 +6505,9 @@ function ActivityVisualizer({
|
|
|
5803
6505
|
width: treeWidth,
|
|
5804
6506
|
height
|
|
5805
6507
|
},
|
|
5806
|
-
treeLines.map((line, i) => /* @__PURE__ */
|
|
5807
|
-
), /* @__PURE__ */
|
|
5808
|
-
|
|
6508
|
+
treeLines.map((line, i) => /* @__PURE__ */ React12.createElement(Text12, { key: i }, line))
|
|
6509
|
+
), /* @__PURE__ */ React12.createElement(
|
|
6510
|
+
Box12,
|
|
5809
6511
|
{
|
|
5810
6512
|
borderStyle: "single",
|
|
5811
6513
|
borderColor: BORDER_COLORS.panel,
|
|
@@ -5813,7 +6515,7 @@ function ActivityVisualizer({
|
|
|
5813
6515
|
width: cardWidth,
|
|
5814
6516
|
height
|
|
5815
6517
|
},
|
|
5816
|
-
cardLines.map((line, i) => /* @__PURE__ */
|
|
6518
|
+
cardLines.map((line, i) => /* @__PURE__ */ React12.createElement(Text12, { key: i }, line))
|
|
5817
6519
|
));
|
|
5818
6520
|
}
|
|
5819
6521
|
|
|
@@ -5900,17 +6602,17 @@ function DashboardApp({
|
|
|
5900
6602
|
}) {
|
|
5901
6603
|
const { columns, rows, layoutMode } = useTerminalSize();
|
|
5902
6604
|
const tick = useTick(1e3);
|
|
5903
|
-
const now =
|
|
6605
|
+
const now = useMemo7(() => Date.now(), [tick]);
|
|
5904
6606
|
const internalState = useDashboardState(externalState ? void 0 : eventBus);
|
|
5905
6607
|
const state = externalState ?? internalState;
|
|
5906
6608
|
const focusedAgent = state.focusedAgentId ? state.agents.get(state.focusedAgentId) ?? null : null;
|
|
5907
|
-
const stageHealth =
|
|
5908
|
-
const bottlenecks =
|
|
5909
|
-
const grid =
|
|
6609
|
+
const stageHealth = useMemo7(() => computeStageHealth(state.agents), [state.agents]);
|
|
6610
|
+
const bottlenecks = useMemo7(() => detectBottlenecks(state.eventLog), [state.eventLog]);
|
|
6611
|
+
const grid = useMemo7(
|
|
5910
6612
|
() => computeGridLayout(columns, rows, layoutMode),
|
|
5911
6613
|
[columns, rows, layoutMode]
|
|
5912
6614
|
);
|
|
5913
|
-
return /* @__PURE__ */
|
|
6615
|
+
return /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", width: grid.total.width, height: grid.total.height }, /* @__PURE__ */ React13.createElement(
|
|
5914
6616
|
HeaderBar,
|
|
5915
6617
|
{
|
|
5916
6618
|
workspace: workspaceProp ?? state.workspace,
|
|
@@ -5921,7 +6623,7 @@ function DashboardApp({
|
|
|
5921
6623
|
tick,
|
|
5922
6624
|
now
|
|
5923
6625
|
}
|
|
5924
|
-
), layoutMode === "narrow" ? /* @__PURE__ */
|
|
6626
|
+
), layoutMode === "narrow" ? /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column" }, grid.checklistPanel.height > 0 && /* @__PURE__ */ React13.createElement(
|
|
5925
6627
|
ChecklistPanel,
|
|
5926
6628
|
{
|
|
5927
6629
|
tasks: state.tasks,
|
|
@@ -5930,7 +6632,7 @@ function DashboardApp({
|
|
|
5930
6632
|
width: grid.checklistPanel.width,
|
|
5931
6633
|
height: grid.checklistPanel.height
|
|
5932
6634
|
}
|
|
5933
|
-
), /* @__PURE__ */
|
|
6635
|
+
), /* @__PURE__ */ React13.createElement(
|
|
5934
6636
|
FocusedAgentPanel,
|
|
5935
6637
|
{
|
|
5936
6638
|
agent: focusedAgent,
|
|
@@ -5944,52 +6646,34 @@ function DashboardApp({
|
|
|
5944
6646
|
tick,
|
|
5945
6647
|
now
|
|
5946
6648
|
}
|
|
5947
|
-
),
|
|
5948
|
-
|
|
6649
|
+
), /* @__PURE__ */ React13.createElement(
|
|
6650
|
+
ModeScreenRouter,
|
|
5949
6651
|
{
|
|
5950
|
-
|
|
5951
|
-
width: grid.flowMap.width,
|
|
5952
|
-
height: grid.flowMap.height
|
|
5953
|
-
}
|
|
5954
|
-
) : /* @__PURE__ */ React9.createElement(
|
|
5955
|
-
FlowMap,
|
|
5956
|
-
{
|
|
5957
|
-
agents: state.agents,
|
|
5958
|
-
edges: state.edges,
|
|
6652
|
+
state,
|
|
5959
6653
|
layoutMode,
|
|
5960
6654
|
width: grid.flowMap.width,
|
|
5961
6655
|
height: grid.flowMap.height,
|
|
5962
|
-
activeStage: state.currentMode,
|
|
5963
6656
|
tick,
|
|
5964
6657
|
now
|
|
5965
6658
|
}
|
|
5966
|
-
)) : /* @__PURE__ */
|
|
5967
|
-
|
|
6659
|
+
)) : /* @__PURE__ */ React13.createElement(
|
|
6660
|
+
Box13,
|
|
5968
6661
|
{
|
|
5969
6662
|
flexDirection: "row",
|
|
5970
6663
|
width: grid.total.width,
|
|
5971
6664
|
height: grid.checklistPanel.height + grid.focusedAgent.height
|
|
5972
6665
|
},
|
|
5973
|
-
/* @__PURE__ */
|
|
5974
|
-
|
|
5975
|
-
{
|
|
5976
|
-
rounds: state.discussionRounds,
|
|
5977
|
-
width: grid.flowMap.width,
|
|
5978
|
-
height: grid.flowMap.height
|
|
5979
|
-
}
|
|
5980
|
-
) : /* @__PURE__ */ React9.createElement(
|
|
5981
|
-
FlowMap,
|
|
6666
|
+
/* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", width: grid.flowMap.width }, /* @__PURE__ */ React13.createElement(
|
|
6667
|
+
ModeScreenRouter,
|
|
5982
6668
|
{
|
|
5983
|
-
|
|
5984
|
-
edges: state.edges,
|
|
6669
|
+
state,
|
|
5985
6670
|
layoutMode,
|
|
5986
6671
|
width: grid.flowMap.width,
|
|
5987
6672
|
height: grid.flowMap.height,
|
|
5988
|
-
activeStage: state.currentMode,
|
|
5989
6673
|
tick,
|
|
5990
6674
|
now
|
|
5991
6675
|
}
|
|
5992
|
-
), /* @__PURE__ */
|
|
6676
|
+
), /* @__PURE__ */ React13.createElement(
|
|
5993
6677
|
ActivityVisualizer,
|
|
5994
6678
|
{
|
|
5995
6679
|
currentMode: state.currentMode,
|
|
@@ -6002,7 +6686,7 @@ function DashboardApp({
|
|
|
6002
6686
|
height: grid.monitorPanel.height
|
|
6003
6687
|
}
|
|
6004
6688
|
)),
|
|
6005
|
-
/* @__PURE__ */
|
|
6689
|
+
/* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", width: grid.checklistPanel.width }, /* @__PURE__ */ React13.createElement(
|
|
6006
6690
|
ChecklistPanel,
|
|
6007
6691
|
{
|
|
6008
6692
|
tasks: state.tasks,
|
|
@@ -6011,7 +6695,7 @@ function DashboardApp({
|
|
|
6011
6695
|
width: grid.checklistPanel.width,
|
|
6012
6696
|
height: grid.checklistPanel.height
|
|
6013
6697
|
}
|
|
6014
|
-
), /* @__PURE__ */
|
|
6698
|
+
), /* @__PURE__ */ React13.createElement(
|
|
6015
6699
|
FocusedAgentPanel,
|
|
6016
6700
|
{
|
|
6017
6701
|
agent: focusedAgent,
|
|
@@ -6026,7 +6710,7 @@ function DashboardApp({
|
|
|
6026
6710
|
now
|
|
6027
6711
|
}
|
|
6028
6712
|
))
|
|
6029
|
-
), /* @__PURE__ */
|
|
6713
|
+
), /* @__PURE__ */ React13.createElement(
|
|
6030
6714
|
StageHealthBar,
|
|
6031
6715
|
{
|
|
6032
6716
|
stageHealth,
|
|
@@ -6043,8 +6727,8 @@ function DashboardApp({
|
|
|
6043
6727
|
}
|
|
6044
6728
|
|
|
6045
6729
|
// src/tui/multi-session-app.tsx
|
|
6046
|
-
import
|
|
6047
|
-
import { Box as
|
|
6730
|
+
import React15, { useMemo as useMemo8, useCallback as useCallback2 } from "react";
|
|
6731
|
+
import { Box as Box15, useInput } from "ink";
|
|
6048
6732
|
import * as path8 from "path";
|
|
6049
6733
|
|
|
6050
6734
|
// src/tui/hooks/use-multi-session-state.ts
|
|
@@ -6200,8 +6884,8 @@ function useMultiSessionState(manager) {
|
|
|
6200
6884
|
}
|
|
6201
6885
|
|
|
6202
6886
|
// src/tui/components/SessionTabBar.tsx
|
|
6203
|
-
import
|
|
6204
|
-
import { Box as
|
|
6887
|
+
import React14 from "react";
|
|
6888
|
+
import { Box as Box14, Text as Text13 } from "ink";
|
|
6205
6889
|
|
|
6206
6890
|
// src/tui/components/session-tab-bar.pure.ts
|
|
6207
6891
|
var STATUS_ICONS2 = {
|
|
@@ -6255,14 +6939,14 @@ function SessionTabBar({
|
|
|
6255
6939
|
if (formatted === "") {
|
|
6256
6940
|
return null;
|
|
6257
6941
|
}
|
|
6258
|
-
return /* @__PURE__ */
|
|
6942
|
+
return /* @__PURE__ */ React14.createElement(Box14, { width, height: 1 }, /* @__PURE__ */ React14.createElement(Text13, null, formatted));
|
|
6259
6943
|
}
|
|
6260
6944
|
|
|
6261
6945
|
// src/tui/multi-session-app.tsx
|
|
6262
6946
|
function MultiSessionApp({ manager }) {
|
|
6263
6947
|
const { columns, layoutMode } = useTerminalSize();
|
|
6264
6948
|
const { sessions, activeSessionPid, switchNext, switchPrev, switchByIndex } = useMultiSessionState(manager);
|
|
6265
|
-
const tabs =
|
|
6949
|
+
const tabs = useMemo8(() => {
|
|
6266
6950
|
let index = 0;
|
|
6267
6951
|
const result = [];
|
|
6268
6952
|
for (const [pid, sessionState] of sessions) {
|
|
@@ -6277,13 +6961,13 @@ function MultiSessionApp({ manager }) {
|
|
|
6277
6961
|
}
|
|
6278
6962
|
return result;
|
|
6279
6963
|
}, [sessions, activeSessionPid]);
|
|
6280
|
-
const activeEventBus =
|
|
6964
|
+
const activeEventBus = useMemo8(() => {
|
|
6281
6965
|
if (activeSessionPid === null) return void 0;
|
|
6282
6966
|
const managedSessions = manager.getSessions();
|
|
6283
6967
|
const found = managedSessions.find((s) => s.instance.pid === activeSessionPid);
|
|
6284
6968
|
return found?.eventBus;
|
|
6285
6969
|
}, [manager, activeSessionPid]);
|
|
6286
|
-
const activeProjectRoot =
|
|
6970
|
+
const activeProjectRoot = useMemo8(() => {
|
|
6287
6971
|
if (activeSessionPid === null) return void 0;
|
|
6288
6972
|
return sessions.get(activeSessionPid)?.projectRoot;
|
|
6289
6973
|
}, [sessions, activeSessionPid]);
|
|
@@ -6305,7 +6989,7 @@ function MultiSessionApp({ manager }) {
|
|
|
6305
6989
|
[switchNext, switchPrev, switchByIndex]
|
|
6306
6990
|
);
|
|
6307
6991
|
useInput(handleInput);
|
|
6308
|
-
return /* @__PURE__ */
|
|
6992
|
+
return /* @__PURE__ */ React15.createElement(Box15, { flexDirection: "column" }, /* @__PURE__ */ React15.createElement(SessionTabBar, { sessions: tabs, width: columns, layoutMode }), /* @__PURE__ */ React15.createElement(
|
|
6309
6993
|
DashboardApp,
|
|
6310
6994
|
{
|
|
6311
6995
|
key: activeSessionPid ?? "none",
|
|
@@ -6353,19 +7037,22 @@ function createDefaultAgentState(params) {
|
|
|
6353
7037
|
// src/tui/index.tsx
|
|
6354
7038
|
function startTui(options) {
|
|
6355
7039
|
const renderOptions = options.stdout ? { stdout: options.stdout } : {};
|
|
6356
|
-
return render(/* @__PURE__ */
|
|
7040
|
+
return render(/* @__PURE__ */ React16.createElement(DashboardApp, { eventBus: options.eventBus }), renderOptions);
|
|
6357
7041
|
}
|
|
6358
7042
|
function renderMultiSession(options) {
|
|
6359
|
-
return render(/* @__PURE__ */
|
|
7043
|
+
return render(/* @__PURE__ */ React16.createElement(MultiSessionApp, { manager: options.manager }));
|
|
6360
7044
|
}
|
|
6361
7045
|
export {
|
|
6362
7046
|
AGENT_STATUSES,
|
|
6363
7047
|
DASHBOARD_NODE_STATUSES,
|
|
6364
7048
|
DashboardApp,
|
|
6365
7049
|
MultiSessionApp,
|
|
7050
|
+
TDD_PHASES,
|
|
6366
7051
|
TUI_EVENT_TYPES,
|
|
6367
7052
|
createDefaultAgentState,
|
|
6368
7053
|
createDefaultDashboardNode,
|
|
7054
|
+
createDefaultReviewResult,
|
|
7055
|
+
createDefaultTddStep,
|
|
6369
7056
|
createEmptyStageStats,
|
|
6370
7057
|
getLayoutMode,
|
|
6371
7058
|
renderMultiSession,
|