codingbuddy 4.5.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/agent/agent.module.js +3 -1
- package/dist/src/agent/agent.module.js.map +1 -1
- package/dist/src/agent/agent.service.d.ts +11 -4
- package/dist/src/agent/agent.service.js +81 -13
- package/dist/src/agent/agent.service.js.map +1 -1
- package/dist/src/agent/agent.types.d.ts +41 -1
- package/dist/src/agent/agent.types.js.map +1 -1
- package/dist/src/collaboration/discussion-engine.d.ts +14 -0
- package/dist/src/collaboration/discussion-engine.js +49 -0
- package/dist/src/collaboration/discussion-engine.js.map +1 -0
- package/dist/src/collaboration/index.d.ts +5 -0
- package/dist/src/collaboration/index.js +22 -0
- package/dist/src/collaboration/index.js.map +1 -0
- package/dist/src/collaboration/opinion-adapter.d.ts +14 -0
- package/dist/src/collaboration/opinion-adapter.js +56 -0
- package/dist/src/collaboration/opinion-adapter.js.map +1 -0
- package/dist/src/collaboration/terminal-formatter.d.ts +5 -0
- package/dist/src/collaboration/terminal-formatter.js +57 -0
- package/dist/src/collaboration/terminal-formatter.js.map +1 -0
- package/dist/src/collaboration/types.d.ts +50 -0
- package/dist/src/collaboration/types.js +53 -0
- package/dist/src/collaboration/types.js.map +1 -0
- package/dist/src/config/config.schema.d.ts +14 -0
- package/dist/src/config/config.schema.js +7 -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 +4 -2
- package/dist/src/context/context-document.service.js +24 -4
- package/dist/src/context/context-document.service.js.map +1 -1
- package/dist/src/context/context-document.types.d.ts +18 -0
- package/dist/src/context/context-document.types.js +13 -1
- package/dist/src/context/context-document.types.js.map +1 -1
- package/dist/src/context/context-parser.utils.js +32 -0
- package/dist/src/context/context-parser.utils.js.map +1 -1
- package/dist/src/context/context-serializer.utils.d.ts +3 -2
- package/dist/src/context/context-serializer.utils.js +25 -1
- package/dist/src/context/context-serializer.utils.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/explicit-pattern-matcher.d.ts +3 -0
- package/dist/src/keyword/explicit-pattern-matcher.js +34 -0
- package/dist/src/keyword/explicit-pattern-matcher.js.map +1 -0
- package/dist/src/keyword/keyword.module.js +17 -1
- 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 +33 -3
- package/dist/src/keyword/keyword.service.js.map +1 -1
- package/dist/src/keyword/keyword.types.d.ts +29 -1
- package/dist/src/keyword/keyword.types.js +34 -1
- package/dist/src/keyword/keyword.types.js.map +1 -1
- package/dist/src/keyword/primary-agent-resolver.d.ts +7 -3
- package/dist/src/keyword/primary-agent-resolver.js +24 -2
- package/dist/src/keyword/primary-agent-resolver.js.map +1 -1
- package/dist/src/keyword/strategies/act-agent.strategy.js +16 -0
- package/dist/src/keyword/strategies/act-agent.strategy.js.map +1 -1
- package/dist/src/keyword/strategies/index.d.ts +1 -1
- package/dist/src/keyword/strategies/index.js.map +1 -1
- package/dist/src/keyword/strategies/resolution-strategy.interface.d.ts +5 -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 +4 -1
- package/dist/src/mcp/handlers/agent.handler.js +59 -6
- 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 +6 -1
- package/dist/src/mcp/handlers/context-document.handler.js +113 -12
- package/dist/src/mcp/handlers/context-document.handler.js.map +1 -1
- package/dist/src/mcp/handlers/discussion.handler.d.ts +14 -0
- package/dist/src/mcp/handlers/discussion.handler.js +168 -0
- package/dist/src/mcp/handlers/discussion.handler.js.map +1 -0
- package/dist/src/mcp/handlers/discussion.types.d.ts +18 -0
- package/dist/src/mcp/handlers/discussion.types.js +11 -0
- package/dist/src/mcp/handlers/discussion.types.js.map +1 -0
- 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 +6 -0
- package/dist/src/mcp/handlers/index.js +13 -1
- package/dist/src/mcp/handlers/index.js.map +1 -1
- package/dist/src/mcp/handlers/mode.handler.d.ts +7 -1
- package/dist/src/mcp/handlers/mode.handler.js +109 -3
- package/dist/src/mcp/handlers/mode.handler.js.map +1 -1
- package/dist/src/mcp/handlers/pipeline.handler.d.ts +14 -0
- package/dist/src/mcp/handlers/pipeline.handler.js +137 -0
- package/dist/src/mcp/handlers/pipeline.handler.js.map +1 -0
- 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 +10 -0
- package/dist/src/mcp/mcp.module.js.map +1 -1
- package/dist/src/parallel-validation/extract-file-paths.d.ts +1 -0
- package/dist/src/parallel-validation/extract-file-paths.js +19 -0
- package/dist/src/parallel-validation/extract-file-paths.js.map +1 -0
- package/dist/src/parallel-validation/index.d.ts +5 -0
- package/dist/src/parallel-validation/index.js +12 -0
- package/dist/src/parallel-validation/index.js.map +1 -0
- package/dist/src/parallel-validation/overlap-matrix.d.ts +10 -0
- package/dist/src/parallel-validation/overlap-matrix.js +23 -0
- package/dist/src/parallel-validation/overlap-matrix.js.map +1 -0
- package/dist/src/parallel-validation/parallel-validation.handler.d.ts +8 -0
- package/dist/src/parallel-validation/parallel-validation.handler.js +84 -0
- package/dist/src/parallel-validation/parallel-validation.handler.js.map +1 -0
- package/dist/src/parallel-validation/parallel-validation.types.d.ts +12 -0
- package/dist/src/parallel-validation/parallel-validation.types.js +3 -0
- package/dist/src/parallel-validation/parallel-validation.types.js.map +1 -0
- package/dist/src/parallel-validation/wave-splitter.d.ts +2 -0
- package/dist/src/parallel-validation/wave-splitter.js +39 -0
- package/dist/src/parallel-validation/wave-splitter.js.map +1 -0
- package/dist/src/pipeline/index.d.ts +5 -0
- package/dist/src/pipeline/index.js +14 -0
- package/dist/src/pipeline/index.js.map +1 -0
- package/dist/src/pipeline/pipeline.executors.d.ts +2 -0
- package/dist/src/pipeline/pipeline.executors.js +79 -0
- package/dist/src/pipeline/pipeline.executors.js.map +1 -0
- package/dist/src/pipeline/pipeline.module.d.ts +2 -0
- package/dist/src/pipeline/pipeline.module.js +21 -0
- package/dist/src/pipeline/pipeline.module.js.map +1 -0
- package/dist/src/pipeline/pipeline.service.d.ts +8 -0
- package/dist/src/pipeline/pipeline.service.js +89 -0
- package/dist/src/pipeline/pipeline.service.js.map +1 -0
- package/dist/src/pipeline/pipeline.types.d.ts +47 -0
- package/dist/src/pipeline/pipeline.types.js +33 -0
- package/dist/src/pipeline/pipeline.types.js.map +1 -0
- 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/rule-tracker.d.ts +24 -0
- package/dist/src/rules/rule-tracker.js +74 -0
- package/dist/src/rules/rule-tracker.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/event-bridge-reader.d.ts +17 -0
- package/dist/src/shared/event-bridge-reader.js +56 -0
- package/dist/src/shared/event-bridge-reader.js.map +1 -0
- 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.d.ts +8 -0
- package/dist/src/tui/components/AgentDiscussionPanel.js +115 -0
- package/dist/src/tui/components/AgentDiscussionPanel.js.map +1 -0
- package/dist/src/tui/components/AgentDiscussionPanel.spec.d.ts +1 -0
- package/dist/src/tui/components/AgentDiscussionPanel.spec.js +229 -0
- package/dist/src/tui/components/AgentDiscussionPanel.spec.js.map +1 -0
- 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 +55 -0
- package/dist/src/tui/components/agent-discussion-panel.pure.js +201 -0
- package/dist/src/tui/components/agent-discussion-panel.pure.js.map +1 -0
- 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 +16 -0
- package/dist/src/tui/components/index.js +48 -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 -3
- package/dist/src/tui/dashboard-app.js.map +1 -1
- package/dist/src/tui/dashboard-types.d.ts +49 -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 +29 -1
- package/dist/src/tui/events/types.js +5 -0
- package/dist/src/tui/events/types.js.map +1 -1
- package/dist/src/tui/hooks/use-dashboard-state.d.ts +16 -1
- package/dist/src/tui/hooks/use-dashboard-state.js +70 -1
- package/dist/src/tui/hooks/use-dashboard-state.js.map +1 -1
- package/dist/src/tui-bundle.mjs +1023 -125
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +14 -14
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 };
|
|
@@ -1496,7 +1513,12 @@ var TUI_EVENTS = Object.freeze({
|
|
|
1496
1513
|
TOOL_INVOKED: "tool:invoked",
|
|
1497
1514
|
OBJECTIVE_SET: "objective:set",
|
|
1498
1515
|
SESSION_RESET: "session:reset",
|
|
1499
|
-
CONTEXT_UPDATED: "context:updated"
|
|
1516
|
+
CONTEXT_UPDATED: "context:updated",
|
|
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"
|
|
1500
1522
|
});
|
|
1501
1523
|
|
|
1502
1524
|
// src/tui/events/parse-agent.ts
|
|
@@ -2150,6 +2172,21 @@ var SUPPORTED_LANGUAGES = {
|
|
|
2150
2172
|
name: "Spanish",
|
|
2151
2173
|
nativeName: "Espa\xF1ol",
|
|
2152
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"
|
|
2153
2190
|
}
|
|
2154
2191
|
};
|
|
2155
2192
|
var SUPPORTED_LANGUAGE_CODES = Object.keys(
|
|
@@ -2629,11 +2666,106 @@ RulesService = __decorateClass([
|
|
|
2629
2666
|
Injectable4()
|
|
2630
2667
|
], RulesService);
|
|
2631
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
|
+
|
|
2632
2764
|
// src/custom/custom.module.ts
|
|
2633
2765
|
import { Module } from "@nestjs/common";
|
|
2634
2766
|
|
|
2635
2767
|
// src/custom/custom.service.ts
|
|
2636
|
-
import { Injectable as
|
|
2768
|
+
import { Injectable as Injectable6, Logger as Logger5 } from "@nestjs/common";
|
|
2637
2769
|
import * as fs from "fs/promises";
|
|
2638
2770
|
import * as path3 from "path";
|
|
2639
2771
|
|
|
@@ -2753,7 +2885,7 @@ var CustomService = class {
|
|
|
2753
2885
|
}
|
|
2754
2886
|
};
|
|
2755
2887
|
CustomService = __decorateClass([
|
|
2756
|
-
|
|
2888
|
+
Injectable6()
|
|
2757
2889
|
], CustomService);
|
|
2758
2890
|
|
|
2759
2891
|
// src/custom/custom.module.ts
|
|
@@ -2770,7 +2902,7 @@ CustomModule = __decorateClass([
|
|
|
2770
2902
|
import { Module as Module2 } from "@nestjs/common";
|
|
2771
2903
|
|
|
2772
2904
|
// src/config/config.service.ts
|
|
2773
|
-
import { Injectable as
|
|
2905
|
+
import { Injectable as Injectable7, Logger as Logger6 } from "@nestjs/common";
|
|
2774
2906
|
import { existsSync as existsSync5, statSync } from "fs";
|
|
2775
2907
|
import { stat, realpath } from "fs/promises";
|
|
2776
2908
|
import * as path7 from "path";
|
|
@@ -2837,6 +2969,22 @@ var TestStrategyConfigSchema = z3.object({
|
|
|
2837
2969
|
var AIConfigSchema = z3.object({
|
|
2838
2970
|
defaultModel: z3.string().optional(),
|
|
2839
2971
|
primaryAgent: z3.string().optional(),
|
|
2972
|
+
/**
|
|
2973
|
+
* Override default dispatch strength for parallel specialist agents.
|
|
2974
|
+
* - "auto": Always dispatch specialists automatically
|
|
2975
|
+
* - "recommend": Suggest dispatch (default for PLAN/ACT)
|
|
2976
|
+
* - "skip": Do not dispatch specialists
|
|
2977
|
+
*
|
|
2978
|
+
* Default varies by mode: EVAL="auto", PLAN/ACT="recommend"
|
|
2979
|
+
*
|
|
2980
|
+
* @example
|
|
2981
|
+
* ```javascript
|
|
2982
|
+
* ai: {
|
|
2983
|
+
* dispatchStrength: 'auto',
|
|
2984
|
+
* }
|
|
2985
|
+
* ```
|
|
2986
|
+
*/
|
|
2987
|
+
dispatchStrength: z3.enum(["auto", "recommend", "skip"]).optional(),
|
|
2840
2988
|
/**
|
|
2841
2989
|
* List of agent names to exclude from automatic resolution.
|
|
2842
2990
|
* Useful for project-specific exclusions (e.g., exclude mobile-developer for backend-only projects).
|
|
@@ -2862,7 +3010,27 @@ var AIConfigSchema = z3.object({
|
|
|
2862
3010
|
* }
|
|
2863
3011
|
* ```
|
|
2864
3012
|
*/
|
|
2865
|
-
maxIncludedSkills: z3.number().int().min(0).max(10).optional()
|
|
3013
|
+
maxIncludedSkills: z3.number().int().min(0).max(10).optional(),
|
|
3014
|
+
/**
|
|
3015
|
+
* Enable/disable automatic plan-reviewer gate after PLAN completion.
|
|
3016
|
+
* When enabled, parse_mode PLAN response includes a planReviewGate recommendation.
|
|
3017
|
+
* Default: true (enabled)
|
|
3018
|
+
*
|
|
3019
|
+
* @example
|
|
3020
|
+
* ```javascript
|
|
3021
|
+
* ai: {
|
|
3022
|
+
* planReviewGate: false, // disable plan review gate
|
|
3023
|
+
* }
|
|
3024
|
+
* ```
|
|
3025
|
+
*/
|
|
3026
|
+
planReviewGate: z3.boolean().optional(),
|
|
3027
|
+
/**
|
|
3028
|
+
* Enable/disable agent discussion integration in EVAL mode.
|
|
3029
|
+
* When enabled, parse_mode EVAL response includes agentDiscussion config
|
|
3030
|
+
* for structuring specialist findings as AgentOpinion protocol.
|
|
3031
|
+
* Default: true (enabled)
|
|
3032
|
+
*/
|
|
3033
|
+
agentDiscussion: z3.boolean().optional()
|
|
2866
3034
|
});
|
|
2867
3035
|
var AutoConfigSchema = z3.object({
|
|
2868
3036
|
maxIterations: z3.number().int().min(1).max(10).default(3)
|
|
@@ -2879,6 +3047,10 @@ var CodingBuddyConfigSchema = z3.object({
|
|
|
2879
3047
|
projectName: z3.string().optional(),
|
|
2880
3048
|
description: z3.string().optional(),
|
|
2881
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(),
|
|
2882
3054
|
// Technical Configuration
|
|
2883
3055
|
techStack: TechStackConfigSchema.optional(),
|
|
2884
3056
|
architecture: ArchitectureConfigSchema.optional(),
|
|
@@ -2890,6 +3062,8 @@ var CodingBuddyConfigSchema = z3.object({
|
|
|
2890
3062
|
auto: AutoConfigSchema.optional(),
|
|
2891
3063
|
// Context document limits (DoS prevention)
|
|
2892
3064
|
context: ContextConfigSchema.optional(),
|
|
3065
|
+
// Upstream Repository Mapping (for cross-repo issue creation)
|
|
3066
|
+
upstreamRepos: z3.record(z3.string(), z3.string()).optional(),
|
|
2893
3067
|
// Additional Context
|
|
2894
3068
|
keyFiles: z3.array(z3.string()).optional(),
|
|
2895
3069
|
avoid: z3.array(z3.string()).optional(),
|
|
@@ -3738,11 +3912,11 @@ var ConfigService = class {
|
|
|
3738
3912
|
}
|
|
3739
3913
|
};
|
|
3740
3914
|
ConfigService = __decorateClass([
|
|
3741
|
-
|
|
3915
|
+
Injectable7()
|
|
3742
3916
|
], ConfigService);
|
|
3743
3917
|
|
|
3744
3918
|
// src/config/config-diff.service.ts
|
|
3745
|
-
import { Injectable as
|
|
3919
|
+
import { Injectable as Injectable8 } from "@nestjs/common";
|
|
3746
3920
|
var ConfigDiffService = class {
|
|
3747
3921
|
/**
|
|
3748
3922
|
* Compare project analysis with current config
|
|
@@ -3914,7 +4088,7 @@ var ConfigDiffService = class {
|
|
|
3914
4088
|
}
|
|
3915
4089
|
};
|
|
3916
4090
|
ConfigDiffService = __decorateClass([
|
|
3917
|
-
|
|
4091
|
+
Injectable8()
|
|
3918
4092
|
], ConfigDiffService);
|
|
3919
4093
|
|
|
3920
4094
|
// src/config/config.module.ts
|
|
@@ -3933,8 +4107,8 @@ var RulesModule = class {
|
|
|
3933
4107
|
RulesModule = __decorateClass([
|
|
3934
4108
|
Module3({
|
|
3935
4109
|
imports: [CustomModule, CodingBuddyConfigModule],
|
|
3936
|
-
providers: [RulesService],
|
|
3937
|
-
exports: [RulesService]
|
|
4110
|
+
providers: [RulesService, RuleInsightsService],
|
|
4111
|
+
exports: [RulesService, RuleInsightsService]
|
|
3938
4112
|
})
|
|
3939
4113
|
], RulesModule);
|
|
3940
4114
|
|
|
@@ -3997,7 +4171,15 @@ function createInitialDashboardState() {
|
|
|
3997
4171
|
contextDecisions: [],
|
|
3998
4172
|
contextNotes: [],
|
|
3999
4173
|
contextMode: null,
|
|
4000
|
-
contextStatus: null
|
|
4174
|
+
contextStatus: null,
|
|
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 }
|
|
4001
4183
|
};
|
|
4002
4184
|
}
|
|
4003
4185
|
function cloneAgents(agents) {
|
|
@@ -4065,7 +4247,16 @@ function dashboardReducer(state, action) {
|
|
|
4065
4247
|
}
|
|
4066
4248
|
}
|
|
4067
4249
|
const focusedAgentId = selectFocusedAgent(agents, state.focusedAgentId);
|
|
4068
|
-
|
|
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
|
+
};
|
|
4069
4260
|
}
|
|
4070
4261
|
case "AGENT_RELATIONSHIP": {
|
|
4071
4262
|
const edge = {
|
|
@@ -4130,13 +4321,21 @@ function dashboardReducer(state, action) {
|
|
|
4130
4321
|
} else {
|
|
4131
4322
|
activityHistory = [...history.slice(-59), { timestamp: sec, toolCalls: 1 }];
|
|
4132
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
|
+
}
|
|
4133
4331
|
return {
|
|
4134
4332
|
...state,
|
|
4135
4333
|
agents,
|
|
4136
4334
|
eventLog: [...base, entry],
|
|
4137
4335
|
toolCalls: [...toolCallsBase, toolCall],
|
|
4138
4336
|
activityHistory,
|
|
4139
|
-
toolInvokeCount: state.toolInvokeCount + 1
|
|
4337
|
+
toolInvokeCount: state.toolInvokeCount + 1,
|
|
4338
|
+
fileChanges
|
|
4140
4339
|
};
|
|
4141
4340
|
}
|
|
4142
4341
|
case "OBJECTIVE_SET":
|
|
@@ -4180,6 +4379,12 @@ function dashboardReducer(state, action) {
|
|
|
4180
4379
|
contextStatus: status
|
|
4181
4380
|
};
|
|
4182
4381
|
}
|
|
4382
|
+
case "ADD_DISCUSSION_ROUND": {
|
|
4383
|
+
return {
|
|
4384
|
+
...state,
|
|
4385
|
+
discussionRounds: [...state.discussionRounds, action.payload.round]
|
|
4386
|
+
};
|
|
4387
|
+
}
|
|
4183
4388
|
case "SESSION_RESET":
|
|
4184
4389
|
return createInitialDashboardState();
|
|
4185
4390
|
case "CLEANUP_STALE_AGENTS": {
|
|
@@ -4197,6 +4402,24 @@ function dashboardReducer(state, action) {
|
|
|
4197
4402
|
const focusedAgentId = selectFocusedAgent(agents, state.focusedAgentId);
|
|
4198
4403
|
return { ...state, agents, focusedAgentId };
|
|
4199
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
|
+
}
|
|
4200
4423
|
// Reserved: no emitter currently produces PARALLEL_COMPLETED. Subscription kept for forward compatibility.
|
|
4201
4424
|
case "PARALLEL_COMPLETED":
|
|
4202
4425
|
case "AGENTS_LOADED":
|
|
@@ -4224,6 +4447,11 @@ function useDashboardState(eventBus) {
|
|
|
4224
4447
|
const onObjectiveSet = (p) => dispatch({ type: "OBJECTIVE_SET", payload: p });
|
|
4225
4448
|
const onSessionReset = (p) => dispatch({ type: "SESSION_RESET", payload: p });
|
|
4226
4449
|
const onContextUpdated = (p) => dispatch({ type: "CONTEXT_UPDATED", payload: p });
|
|
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 });
|
|
4227
4455
|
eventBus.on(TUI_EVENTS.AGENT_ACTIVATED, onActivated);
|
|
4228
4456
|
eventBus.on(TUI_EVENTS.AGENT_DEACTIVATED, onDeactivated);
|
|
4229
4457
|
eventBus.on(TUI_EVENTS.MODE_CHANGED, onModeChanged);
|
|
@@ -4237,6 +4465,11 @@ function useDashboardState(eventBus) {
|
|
|
4237
4465
|
eventBus.on(TUI_EVENTS.OBJECTIVE_SET, onObjectiveSet);
|
|
4238
4466
|
eventBus.on(TUI_EVENTS.SESSION_RESET, onSessionReset);
|
|
4239
4467
|
eventBus.on(TUI_EVENTS.CONTEXT_UPDATED, onContextUpdated);
|
|
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);
|
|
4240
4473
|
return () => {
|
|
4241
4474
|
eventBus.off(TUI_EVENTS.AGENT_ACTIVATED, onActivated);
|
|
4242
4475
|
eventBus.off(TUI_EVENTS.AGENT_DEACTIVATED, onDeactivated);
|
|
@@ -4251,6 +4484,11 @@ function useDashboardState(eventBus) {
|
|
|
4251
4484
|
eventBus.off(TUI_EVENTS.OBJECTIVE_SET, onObjectiveSet);
|
|
4252
4485
|
eventBus.off(TUI_EVENTS.SESSION_RESET, onSessionReset);
|
|
4253
4486
|
eventBus.off(TUI_EVENTS.CONTEXT_UPDATED, onContextUpdated);
|
|
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);
|
|
4254
4492
|
};
|
|
4255
4493
|
}, [eventBus]);
|
|
4256
4494
|
useEffect3(() => {
|
|
@@ -4490,10 +4728,596 @@ function HeaderBar({
|
|
|
4490
4728
|
);
|
|
4491
4729
|
}
|
|
4492
4730
|
|
|
4493
|
-
// 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
|
|
4494
4817
|
import React2, { useMemo } from "react";
|
|
4495
4818
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
4496
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
|
+
|
|
4497
5321
|
// src/tui/utils/color-buffer.ts
|
|
4498
5322
|
var DEFAULT_CELL = Object.freeze({ char: " ", style: Object.freeze({}) });
|
|
4499
5323
|
function stylesEqual(a, b) {
|
|
@@ -4989,13 +5813,13 @@ function trimTrailingSpaces(cells) {
|
|
|
4989
5813
|
}
|
|
4990
5814
|
return end === cells.length ? cells : cells.slice(0, end);
|
|
4991
5815
|
}
|
|
4992
|
-
var ColorRow =
|
|
5816
|
+
var ColorRow = React6.memo(function ColorRow2({
|
|
4993
5817
|
cells
|
|
4994
5818
|
}) {
|
|
4995
5819
|
const trimmed = trimTrailingSpaces(cells);
|
|
4996
|
-
if (trimmed.length === 0) return /* @__PURE__ */
|
|
5820
|
+
if (trimmed.length === 0) return /* @__PURE__ */ React6.createElement(Box6, null);
|
|
4997
5821
|
const segments = groupByStyle(trimmed);
|
|
4998
|
-
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)));
|
|
4999
5823
|
});
|
|
5000
5824
|
function FlowMap({
|
|
5001
5825
|
agents,
|
|
@@ -5009,22 +5833,22 @@ function FlowMap({
|
|
|
5009
5833
|
}) {
|
|
5010
5834
|
const contentWidth = Math.max(1, width - 2);
|
|
5011
5835
|
const contentHeight = Math.max(1, height - 3);
|
|
5012
|
-
const hasRunningAgents =
|
|
5836
|
+
const hasRunningAgents = useMemo5(
|
|
5013
5837
|
() => [...agents.values()].some((a) => a.status === "running"),
|
|
5014
5838
|
[agents]
|
|
5015
5839
|
);
|
|
5016
5840
|
const liveTick = hasRunningAgents ? tick ?? 0 : 0;
|
|
5017
5841
|
const liveNow = hasRunningAgents ? now : void 0;
|
|
5018
|
-
const compactContent =
|
|
5842
|
+
const compactContent = useMemo5(() => {
|
|
5019
5843
|
if (layoutMode !== "narrow") return null;
|
|
5020
5844
|
return renderFlowMapCompact(agents);
|
|
5021
5845
|
}, [agents, layoutMode]);
|
|
5022
|
-
const lines =
|
|
5846
|
+
const lines = useMemo5(() => {
|
|
5023
5847
|
if (layoutMode === "narrow") return null;
|
|
5024
5848
|
const buf = layoutMode === "wide" ? renderFlowMap(agents, edges, contentWidth, contentHeight, activeStage) : renderFlowMapSimplified(agents, contentWidth, contentHeight);
|
|
5025
5849
|
return buf.toLinesDirect();
|
|
5026
5850
|
}, [agents, edges, contentWidth, contentHeight, layoutMode, activeStage]);
|
|
5027
|
-
const liveOverlays =
|
|
5851
|
+
const liveOverlays = useMemo5(() => {
|
|
5028
5852
|
if (liveNow === void 0) return null;
|
|
5029
5853
|
const overlays = [];
|
|
5030
5854
|
for (const [id, agent] of agents) {
|
|
@@ -5039,8 +5863,8 @@ function FlowMap({
|
|
|
5039
5863
|
return overlays.length > 0 ? overlays : null;
|
|
5040
5864
|
}, [agents, liveTick, liveNow]);
|
|
5041
5865
|
if (layoutMode === "narrow") {
|
|
5042
|
-
return /* @__PURE__ */
|
|
5043
|
-
|
|
5866
|
+
return /* @__PURE__ */ React6.createElement(
|
|
5867
|
+
Box6,
|
|
5044
5868
|
{
|
|
5045
5869
|
borderStyle: "single",
|
|
5046
5870
|
borderColor: BORDER_COLORS.panel,
|
|
@@ -5048,14 +5872,14 @@ function FlowMap({
|
|
|
5048
5872
|
width,
|
|
5049
5873
|
height
|
|
5050
5874
|
},
|
|
5051
|
-
/* @__PURE__ */
|
|
5052
|
-
/* @__PURE__ */
|
|
5053
|
-
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))
|
|
5054
5878
|
);
|
|
5055
5879
|
}
|
|
5056
5880
|
if (!lines) {
|
|
5057
|
-
return /* @__PURE__ */
|
|
5058
|
-
|
|
5881
|
+
return /* @__PURE__ */ React6.createElement(
|
|
5882
|
+
Box6,
|
|
5059
5883
|
{
|
|
5060
5884
|
borderStyle: "single",
|
|
5061
5885
|
borderColor: BORDER_COLORS.panel,
|
|
@@ -5063,11 +5887,11 @@ function FlowMap({
|
|
|
5063
5887
|
width,
|
|
5064
5888
|
height
|
|
5065
5889
|
},
|
|
5066
|
-
/* @__PURE__ */
|
|
5890
|
+
/* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "FLOW MAP")
|
|
5067
5891
|
);
|
|
5068
5892
|
}
|
|
5069
|
-
return /* @__PURE__ */
|
|
5070
|
-
|
|
5893
|
+
return /* @__PURE__ */ React6.createElement(
|
|
5894
|
+
Box6,
|
|
5071
5895
|
{
|
|
5072
5896
|
borderStyle: "single",
|
|
5073
5897
|
borderColor: BORDER_COLORS.panel,
|
|
@@ -5075,15 +5899,90 @@ function FlowMap({
|
|
|
5075
5899
|
width,
|
|
5076
5900
|
height
|
|
5077
5901
|
},
|
|
5078
|
-
/* @__PURE__ */
|
|
5079
|
-
lines.map((row, y) => /* @__PURE__ */
|
|
5080
|
-
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))
|
|
5081
5905
|
);
|
|
5082
5906
|
}
|
|
5083
5907
|
|
|
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}`));
|
|
5934
|
+
}
|
|
5935
|
+
function ModeScreenRouter({
|
|
5936
|
+
state,
|
|
5937
|
+
layoutMode,
|
|
5938
|
+
width,
|
|
5939
|
+
height,
|
|
5940
|
+
tick,
|
|
5941
|
+
now
|
|
5942
|
+
}) {
|
|
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
|
|
5950
|
+
);
|
|
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,
|
|
5953
|
+
{
|
|
5954
|
+
agents: state.agents,
|
|
5955
|
+
rounds: state.discussionRounds,
|
|
5956
|
+
width,
|
|
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
|
+
));
|
|
5981
|
+
}
|
|
5982
|
+
|
|
5084
5983
|
// src/tui/components/FocusedAgentPanel.tsx
|
|
5085
|
-
import
|
|
5086
|
-
import { Box as
|
|
5984
|
+
import React9 from "react";
|
|
5985
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
5087
5986
|
|
|
5088
5987
|
// src/tui/components/focused-agent.pure.ts
|
|
5089
5988
|
function formatObjective(objectives, maxLines = 3) {
|
|
@@ -5129,8 +6028,8 @@ function formatEnhancedChecklist(tasks, maxItems = 6) {
|
|
|
5129
6028
|
}
|
|
5130
6029
|
|
|
5131
6030
|
// src/tui/components/ContextSection.tsx
|
|
5132
|
-
import
|
|
5133
|
-
import { Box as
|
|
6031
|
+
import React8 from "react";
|
|
6032
|
+
import { Box as Box8, Text as Text8 } from "ink";
|
|
5134
6033
|
|
|
5135
6034
|
// src/tui/components/context-section.pure.ts
|
|
5136
6035
|
function formatContextDecisions(decisions, maxItems = 5) {
|
|
@@ -5160,27 +6059,27 @@ function ContextSection({
|
|
|
5160
6059
|
const hasDecisions = decisions.length > 0;
|
|
5161
6060
|
const hasNotes = notes.length > 0;
|
|
5162
6061
|
if (!hasDecisions && !hasNotes) return null;
|
|
5163
|
-
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))));
|
|
5164
6063
|
}
|
|
5165
6064
|
|
|
5166
6065
|
// src/tui/components/FocusedAgentPanel.tsx
|
|
5167
6066
|
function SectionDivider({ title }) {
|
|
5168
|
-
return /* @__PURE__ */
|
|
6067
|
+
return /* @__PURE__ */ React9.createElement(Text9, { color: "magenta" }, formatSectionDivider(title));
|
|
5169
6068
|
}
|
|
5170
6069
|
function LogSection({
|
|
5171
6070
|
logs,
|
|
5172
6071
|
eventLog
|
|
5173
6072
|
}) {
|
|
5174
|
-
if (!logs) return /* @__PURE__ */
|
|
6073
|
+
if (!logs) return /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "No events");
|
|
5175
6074
|
const logLines = logs.split("\n");
|
|
5176
6075
|
const offset = eventLog.length - logLines.length;
|
|
5177
|
-
return /* @__PURE__ */
|
|
6076
|
+
return /* @__PURE__ */ React9.createElement(React9.Fragment, null, logLines.map((line, i) => {
|
|
5178
6077
|
const ev = eventLog[offset + i];
|
|
5179
6078
|
const isError = ev?.level === "error";
|
|
5180
6079
|
const spaceIdx = line.indexOf(" ");
|
|
5181
6080
|
const timestamp = spaceIdx > 0 ? line.slice(0, spaceIdx) : line;
|
|
5182
6081
|
const message = spaceIdx > 0 ? line.slice(spaceIdx + 1) : "";
|
|
5183
|
-
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));
|
|
5184
6083
|
}));
|
|
5185
6084
|
}
|
|
5186
6085
|
function FocusedAgentPanel({
|
|
@@ -5196,8 +6095,8 @@ function FocusedAgentPanel({
|
|
|
5196
6095
|
height
|
|
5197
6096
|
}) {
|
|
5198
6097
|
if (!agent) {
|
|
5199
|
-
return /* @__PURE__ */
|
|
5200
|
-
|
|
6098
|
+
return /* @__PURE__ */ React9.createElement(
|
|
6099
|
+
Box9,
|
|
5201
6100
|
{
|
|
5202
6101
|
borderStyle: "single",
|
|
5203
6102
|
borderColor: BORDER_COLORS.panel,
|
|
@@ -5205,7 +6104,7 @@ function FocusedAgentPanel({
|
|
|
5205
6104
|
width,
|
|
5206
6105
|
height
|
|
5207
6106
|
},
|
|
5208
|
-
/* @__PURE__ */
|
|
6107
|
+
/* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "No agent focused")
|
|
5209
6108
|
);
|
|
5210
6109
|
}
|
|
5211
6110
|
const avatar = getAgentAvatar(agent.name);
|
|
@@ -5218,8 +6117,8 @@ function FocusedAgentPanel({
|
|
|
5218
6117
|
const isRunning = agent.status === "running";
|
|
5219
6118
|
const showSpinner = isRunning && tick != null;
|
|
5220
6119
|
const showElapsed = isRunning && now != null && agent.startedAt != null;
|
|
5221
|
-
return /* @__PURE__ */
|
|
5222
|
-
|
|
6120
|
+
return /* @__PURE__ */ React9.createElement(
|
|
6121
|
+
Box9,
|
|
5223
6122
|
{
|
|
5224
6123
|
borderStyle: "single",
|
|
5225
6124
|
borderColor: BORDER_COLORS.panel,
|
|
@@ -5227,22 +6126,22 @@ function FocusedAgentPanel({
|
|
|
5227
6126
|
width,
|
|
5228
6127
|
height
|
|
5229
6128
|
},
|
|
5230
|
-
/* @__PURE__ */
|
|
5231
|
-
/* @__PURE__ */
|
|
5232
|
-
/* @__PURE__ */
|
|
5233
|
-
objective ? /* @__PURE__ */
|
|
5234
|
-
/* @__PURE__ */
|
|
5235
|
-
activeSkills.length > 0 ? activeSkills.map((s, i) => /* @__PURE__ */
|
|
5236
|
-
/* @__PURE__ */
|
|
5237
|
-
contextDecisions.length > 0 || contextNotes.length > 0 ? /* @__PURE__ */
|
|
5238
|
-
/* @__PURE__ */
|
|
5239
|
-
/* @__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 })
|
|
5240
6139
|
);
|
|
5241
6140
|
}
|
|
5242
6141
|
|
|
5243
6142
|
// src/tui/components/ChecklistPanel.tsx
|
|
5244
|
-
import
|
|
5245
|
-
import { Box as
|
|
6143
|
+
import React10 from "react";
|
|
6144
|
+
import { Box as Box10, Text as Text10 } from "ink";
|
|
5246
6145
|
|
|
5247
6146
|
// src/tui/components/checklist-panel.pure.ts
|
|
5248
6147
|
function resolveChecklistTasks(tasks, contextDecisions, contextNotes) {
|
|
@@ -5270,8 +6169,8 @@ function ChecklistPanel({
|
|
|
5270
6169
|
}) {
|
|
5271
6170
|
const resolvedTasks = resolveChecklistTasks(tasks, contextDecisions, contextNotes);
|
|
5272
6171
|
const checklist = formatEnhancedChecklist(resolvedTasks);
|
|
5273
|
-
return /* @__PURE__ */
|
|
5274
|
-
|
|
6172
|
+
return /* @__PURE__ */ React10.createElement(
|
|
6173
|
+
Box10,
|
|
5275
6174
|
{
|
|
5276
6175
|
borderStyle: "single",
|
|
5277
6176
|
borderColor: BORDER_COLORS.panel,
|
|
@@ -5279,17 +6178,17 @@ function ChecklistPanel({
|
|
|
5279
6178
|
width,
|
|
5280
6179
|
height
|
|
5281
6180
|
},
|
|
5282
|
-
/* @__PURE__ */
|
|
6181
|
+
/* @__PURE__ */ React10.createElement(Text10, { bold: true, dimColor: true }, "\u2500\u2500\u2500 Checklist"),
|
|
5283
6182
|
checklist.split("\n").map((line, i) => {
|
|
5284
6183
|
const isCompleted = line.includes("\u2714");
|
|
5285
|
-
return /* @__PURE__ */
|
|
6184
|
+
return /* @__PURE__ */ React10.createElement(Text10, { key: i, color: isCompleted ? "green" : void 0 }, line);
|
|
5286
6185
|
})
|
|
5287
6186
|
);
|
|
5288
6187
|
}
|
|
5289
6188
|
|
|
5290
6189
|
// src/tui/components/StageHealthBar.tsx
|
|
5291
|
-
import
|
|
5292
|
-
import { Box as
|
|
6190
|
+
import React11 from "react";
|
|
6191
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
5293
6192
|
|
|
5294
6193
|
// src/tui/components/stage-health.pure.ts
|
|
5295
6194
|
function formatCount(n) {
|
|
@@ -5357,29 +6256,29 @@ function StageStatDisplay({
|
|
|
5357
6256
|
const parts = [];
|
|
5358
6257
|
if (stats.running > 0)
|
|
5359
6258
|
parts.push(
|
|
5360
|
-
/* @__PURE__ */
|
|
6259
|
+
/* @__PURE__ */ React11.createElement(Text11, { key: "r", color: "green" }, " ", "\u25CF ", stats.running, " running")
|
|
5361
6260
|
);
|
|
5362
6261
|
if (stats.blocked > 0)
|
|
5363
6262
|
parts.push(
|
|
5364
|
-
/* @__PURE__ */
|
|
6263
|
+
/* @__PURE__ */ React11.createElement(Text11, { key: "b", color: "yellow" }, " ", "\u23F8 ", stats.blocked, " blocked")
|
|
5365
6264
|
);
|
|
5366
6265
|
if (stats.waiting > 0)
|
|
5367
6266
|
parts.push(
|
|
5368
|
-
/* @__PURE__ */
|
|
6267
|
+
/* @__PURE__ */ React11.createElement(Text11, { key: "w", dimColor: true }, " ", "\u25CB ", stats.waiting, " waiting")
|
|
5369
6268
|
);
|
|
5370
6269
|
if (stats.done > 0)
|
|
5371
6270
|
parts.push(
|
|
5372
|
-
/* @__PURE__ */
|
|
6271
|
+
/* @__PURE__ */ React11.createElement(Text11, { key: "d", color: "green" }, " ", "\u2713 ", stats.done)
|
|
5373
6272
|
);
|
|
5374
6273
|
if (stats.error > 0)
|
|
5375
6274
|
parts.push(
|
|
5376
|
-
/* @__PURE__ */
|
|
6275
|
+
/* @__PURE__ */ React11.createElement(Text11, { key: "e", color: "red", bold: true }, " ", "! ", stats.error, " err")
|
|
5377
6276
|
);
|
|
5378
6277
|
if (parts.length === 0)
|
|
5379
6278
|
parts.push(
|
|
5380
|
-
/* @__PURE__ */
|
|
6279
|
+
/* @__PURE__ */ React11.createElement(Text11, { key: "idle", dimColor: true }, " ", "idle")
|
|
5381
6280
|
);
|
|
5382
|
-
return /* @__PURE__ */
|
|
6281
|
+
return /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Text11, { color, bold: true }, mode, ":"), parts);
|
|
5383
6282
|
}
|
|
5384
6283
|
function StageHealthBar({
|
|
5385
6284
|
stageHealth,
|
|
@@ -5393,24 +6292,24 @@ function StageHealthBar({
|
|
|
5393
6292
|
now: _now
|
|
5394
6293
|
}) {
|
|
5395
6294
|
const hasActivity = activityHistory && activityHistory.length > 0;
|
|
5396
|
-
return /* @__PURE__ */
|
|
5397
|
-
|
|
6295
|
+
return /* @__PURE__ */ React11.createElement(
|
|
6296
|
+
Box11,
|
|
5398
6297
|
{
|
|
5399
6298
|
borderStyle: "double",
|
|
5400
6299
|
borderColor: BORDER_COLORS.panel,
|
|
5401
6300
|
width,
|
|
5402
6301
|
flexDirection: "column"
|
|
5403
6302
|
},
|
|
5404
|
-
/* @__PURE__ */
|
|
6303
|
+
/* @__PURE__ */ React11.createElement(Box11, null, hasActivity && /* @__PURE__ */ React11.createElement(Box11, { gap: 1, marginRight: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "cyan" }, renderSparkline(
|
|
5405
6304
|
activityHistory.map((s) => s.toolCalls),
|
|
5406
6305
|
10
|
|
5407
|
-
)), /* @__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))))
|
|
5408
6307
|
);
|
|
5409
6308
|
}
|
|
5410
6309
|
|
|
5411
6310
|
// src/tui/components/ActivityVisualizer.tsx
|
|
5412
|
-
import
|
|
5413
|
-
import { Box as
|
|
6311
|
+
import React12, { useMemo as useMemo6 } from "react";
|
|
6312
|
+
import { Box as Box12, Text as Text12 } from "ink";
|
|
5414
6313
|
|
|
5415
6314
|
// src/tui/utils/display-width.ts
|
|
5416
6315
|
function isWide(code) {
|
|
@@ -5579,11 +6478,11 @@ function ActivityVisualizer({
|
|
|
5579
6478
|
const treeWidth = Math.floor(width * 0.6);
|
|
5580
6479
|
const cardWidth = width - treeWidth;
|
|
5581
6480
|
const contentHeight = Math.max(1, height - 2);
|
|
5582
|
-
const treeLines =
|
|
6481
|
+
const treeLines = useMemo6(
|
|
5583
6482
|
() => renderAgentTree(agents, edges, activeSkills, Math.max(1, treeWidth - 2), contentHeight),
|
|
5584
6483
|
[agents, edges, activeSkills, treeWidth, contentHeight]
|
|
5585
6484
|
);
|
|
5586
|
-
const cardLines =
|
|
6485
|
+
const cardLines = useMemo6(
|
|
5587
6486
|
() => renderAgentStatusCard(
|
|
5588
6487
|
focusedAgent,
|
|
5589
6488
|
currentMode,
|
|
@@ -5595,10 +6494,10 @@ function ActivityVisualizer({
|
|
|
5595
6494
|
[focusedAgent, currentMode, objectives, activeSkills, cardWidth, contentHeight]
|
|
5596
6495
|
);
|
|
5597
6496
|
if (width <= 0 || height <= 0) {
|
|
5598
|
-
return /* @__PURE__ */
|
|
6497
|
+
return /* @__PURE__ */ React12.createElement(Box12, null);
|
|
5599
6498
|
}
|
|
5600
|
-
return /* @__PURE__ */
|
|
5601
|
-
|
|
6499
|
+
return /* @__PURE__ */ React12.createElement(Box12, { flexDirection: "row", width, height }, /* @__PURE__ */ React12.createElement(
|
|
6500
|
+
Box12,
|
|
5602
6501
|
{
|
|
5603
6502
|
borderStyle: "single",
|
|
5604
6503
|
borderColor: BORDER_COLORS.panel,
|
|
@@ -5606,9 +6505,9 @@ function ActivityVisualizer({
|
|
|
5606
6505
|
width: treeWidth,
|
|
5607
6506
|
height
|
|
5608
6507
|
},
|
|
5609
|
-
treeLines.map((line, i) => /* @__PURE__ */
|
|
5610
|
-
), /* @__PURE__ */
|
|
5611
|
-
|
|
6508
|
+
treeLines.map((line, i) => /* @__PURE__ */ React12.createElement(Text12, { key: i }, line))
|
|
6509
|
+
), /* @__PURE__ */ React12.createElement(
|
|
6510
|
+
Box12,
|
|
5612
6511
|
{
|
|
5613
6512
|
borderStyle: "single",
|
|
5614
6513
|
borderColor: BORDER_COLORS.panel,
|
|
@@ -5616,7 +6515,7 @@ function ActivityVisualizer({
|
|
|
5616
6515
|
width: cardWidth,
|
|
5617
6516
|
height
|
|
5618
6517
|
},
|
|
5619
|
-
cardLines.map((line, i) => /* @__PURE__ */
|
|
6518
|
+
cardLines.map((line, i) => /* @__PURE__ */ React12.createElement(Text12, { key: i }, line))
|
|
5620
6519
|
));
|
|
5621
6520
|
}
|
|
5622
6521
|
|
|
@@ -5703,17 +6602,17 @@ function DashboardApp({
|
|
|
5703
6602
|
}) {
|
|
5704
6603
|
const { columns, rows, layoutMode } = useTerminalSize();
|
|
5705
6604
|
const tick = useTick(1e3);
|
|
5706
|
-
const now =
|
|
6605
|
+
const now = useMemo7(() => Date.now(), [tick]);
|
|
5707
6606
|
const internalState = useDashboardState(externalState ? void 0 : eventBus);
|
|
5708
6607
|
const state = externalState ?? internalState;
|
|
5709
6608
|
const focusedAgent = state.focusedAgentId ? state.agents.get(state.focusedAgentId) ?? null : null;
|
|
5710
|
-
const stageHealth =
|
|
5711
|
-
const bottlenecks =
|
|
5712
|
-
const grid =
|
|
6609
|
+
const stageHealth = useMemo7(() => computeStageHealth(state.agents), [state.agents]);
|
|
6610
|
+
const bottlenecks = useMemo7(() => detectBottlenecks(state.eventLog), [state.eventLog]);
|
|
6611
|
+
const grid = useMemo7(
|
|
5713
6612
|
() => computeGridLayout(columns, rows, layoutMode),
|
|
5714
6613
|
[columns, rows, layoutMode]
|
|
5715
6614
|
);
|
|
5716
|
-
return /* @__PURE__ */
|
|
6615
|
+
return /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", width: grid.total.width, height: grid.total.height }, /* @__PURE__ */ React13.createElement(
|
|
5717
6616
|
HeaderBar,
|
|
5718
6617
|
{
|
|
5719
6618
|
workspace: workspaceProp ?? state.workspace,
|
|
@@ -5724,7 +6623,7 @@ function DashboardApp({
|
|
|
5724
6623
|
tick,
|
|
5725
6624
|
now
|
|
5726
6625
|
}
|
|
5727
|
-
), layoutMode === "narrow" ? /* @__PURE__ */
|
|
6626
|
+
), layoutMode === "narrow" ? /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column" }, grid.checklistPanel.height > 0 && /* @__PURE__ */ React13.createElement(
|
|
5728
6627
|
ChecklistPanel,
|
|
5729
6628
|
{
|
|
5730
6629
|
tasks: state.tasks,
|
|
@@ -5733,7 +6632,7 @@ function DashboardApp({
|
|
|
5733
6632
|
width: grid.checklistPanel.width,
|
|
5734
6633
|
height: grid.checklistPanel.height
|
|
5735
6634
|
}
|
|
5736
|
-
), /* @__PURE__ */
|
|
6635
|
+
), /* @__PURE__ */ React13.createElement(
|
|
5737
6636
|
FocusedAgentPanel,
|
|
5738
6637
|
{
|
|
5739
6638
|
agent: focusedAgent,
|
|
@@ -5747,38 +6646,34 @@ function DashboardApp({
|
|
|
5747
6646
|
tick,
|
|
5748
6647
|
now
|
|
5749
6648
|
}
|
|
5750
|
-
), /* @__PURE__ */
|
|
5751
|
-
|
|
6649
|
+
), /* @__PURE__ */ React13.createElement(
|
|
6650
|
+
ModeScreenRouter,
|
|
5752
6651
|
{
|
|
5753
|
-
|
|
5754
|
-
edges: state.edges,
|
|
6652
|
+
state,
|
|
5755
6653
|
layoutMode,
|
|
5756
6654
|
width: grid.flowMap.width,
|
|
5757
6655
|
height: grid.flowMap.height,
|
|
5758
|
-
activeStage: state.currentMode,
|
|
5759
6656
|
tick,
|
|
5760
6657
|
now
|
|
5761
6658
|
}
|
|
5762
|
-
)) : /* @__PURE__ */
|
|
5763
|
-
|
|
6659
|
+
)) : /* @__PURE__ */ React13.createElement(
|
|
6660
|
+
Box13,
|
|
5764
6661
|
{
|
|
5765
6662
|
flexDirection: "row",
|
|
5766
6663
|
width: grid.total.width,
|
|
5767
6664
|
height: grid.checklistPanel.height + grid.focusedAgent.height
|
|
5768
6665
|
},
|
|
5769
|
-
/* @__PURE__ */
|
|
5770
|
-
|
|
6666
|
+
/* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", width: grid.flowMap.width }, /* @__PURE__ */ React13.createElement(
|
|
6667
|
+
ModeScreenRouter,
|
|
5771
6668
|
{
|
|
5772
|
-
|
|
5773
|
-
edges: state.edges,
|
|
6669
|
+
state,
|
|
5774
6670
|
layoutMode,
|
|
5775
6671
|
width: grid.flowMap.width,
|
|
5776
6672
|
height: grid.flowMap.height,
|
|
5777
|
-
activeStage: state.currentMode,
|
|
5778
6673
|
tick,
|
|
5779
6674
|
now
|
|
5780
6675
|
}
|
|
5781
|
-
), /* @__PURE__ */
|
|
6676
|
+
), /* @__PURE__ */ React13.createElement(
|
|
5782
6677
|
ActivityVisualizer,
|
|
5783
6678
|
{
|
|
5784
6679
|
currentMode: state.currentMode,
|
|
@@ -5791,7 +6686,7 @@ function DashboardApp({
|
|
|
5791
6686
|
height: grid.monitorPanel.height
|
|
5792
6687
|
}
|
|
5793
6688
|
)),
|
|
5794
|
-
/* @__PURE__ */
|
|
6689
|
+
/* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", width: grid.checklistPanel.width }, /* @__PURE__ */ React13.createElement(
|
|
5795
6690
|
ChecklistPanel,
|
|
5796
6691
|
{
|
|
5797
6692
|
tasks: state.tasks,
|
|
@@ -5800,7 +6695,7 @@ function DashboardApp({
|
|
|
5800
6695
|
width: grid.checklistPanel.width,
|
|
5801
6696
|
height: grid.checklistPanel.height
|
|
5802
6697
|
}
|
|
5803
|
-
), /* @__PURE__ */
|
|
6698
|
+
), /* @__PURE__ */ React13.createElement(
|
|
5804
6699
|
FocusedAgentPanel,
|
|
5805
6700
|
{
|
|
5806
6701
|
agent: focusedAgent,
|
|
@@ -5815,7 +6710,7 @@ function DashboardApp({
|
|
|
5815
6710
|
now
|
|
5816
6711
|
}
|
|
5817
6712
|
))
|
|
5818
|
-
), /* @__PURE__ */
|
|
6713
|
+
), /* @__PURE__ */ React13.createElement(
|
|
5819
6714
|
StageHealthBar,
|
|
5820
6715
|
{
|
|
5821
6716
|
stageHealth,
|
|
@@ -5832,8 +6727,8 @@ function DashboardApp({
|
|
|
5832
6727
|
}
|
|
5833
6728
|
|
|
5834
6729
|
// src/tui/multi-session-app.tsx
|
|
5835
|
-
import
|
|
5836
|
-
import { Box as
|
|
6730
|
+
import React15, { useMemo as useMemo8, useCallback as useCallback2 } from "react";
|
|
6731
|
+
import { Box as Box15, useInput } from "ink";
|
|
5837
6732
|
import * as path8 from "path";
|
|
5838
6733
|
|
|
5839
6734
|
// src/tui/hooks/use-multi-session-state.ts
|
|
@@ -5989,8 +6884,8 @@ function useMultiSessionState(manager) {
|
|
|
5989
6884
|
}
|
|
5990
6885
|
|
|
5991
6886
|
// src/tui/components/SessionTabBar.tsx
|
|
5992
|
-
import
|
|
5993
|
-
import { Box as
|
|
6887
|
+
import React14 from "react";
|
|
6888
|
+
import { Box as Box14, Text as Text13 } from "ink";
|
|
5994
6889
|
|
|
5995
6890
|
// src/tui/components/session-tab-bar.pure.ts
|
|
5996
6891
|
var STATUS_ICONS2 = {
|
|
@@ -6044,14 +6939,14 @@ function SessionTabBar({
|
|
|
6044
6939
|
if (formatted === "") {
|
|
6045
6940
|
return null;
|
|
6046
6941
|
}
|
|
6047
|
-
return /* @__PURE__ */
|
|
6942
|
+
return /* @__PURE__ */ React14.createElement(Box14, { width, height: 1 }, /* @__PURE__ */ React14.createElement(Text13, null, formatted));
|
|
6048
6943
|
}
|
|
6049
6944
|
|
|
6050
6945
|
// src/tui/multi-session-app.tsx
|
|
6051
6946
|
function MultiSessionApp({ manager }) {
|
|
6052
6947
|
const { columns, layoutMode } = useTerminalSize();
|
|
6053
6948
|
const { sessions, activeSessionPid, switchNext, switchPrev, switchByIndex } = useMultiSessionState(manager);
|
|
6054
|
-
const tabs =
|
|
6949
|
+
const tabs = useMemo8(() => {
|
|
6055
6950
|
let index = 0;
|
|
6056
6951
|
const result = [];
|
|
6057
6952
|
for (const [pid, sessionState] of sessions) {
|
|
@@ -6066,13 +6961,13 @@ function MultiSessionApp({ manager }) {
|
|
|
6066
6961
|
}
|
|
6067
6962
|
return result;
|
|
6068
6963
|
}, [sessions, activeSessionPid]);
|
|
6069
|
-
const activeEventBus =
|
|
6964
|
+
const activeEventBus = useMemo8(() => {
|
|
6070
6965
|
if (activeSessionPid === null) return void 0;
|
|
6071
6966
|
const managedSessions = manager.getSessions();
|
|
6072
6967
|
const found = managedSessions.find((s) => s.instance.pid === activeSessionPid);
|
|
6073
6968
|
return found?.eventBus;
|
|
6074
6969
|
}, [manager, activeSessionPid]);
|
|
6075
|
-
const activeProjectRoot =
|
|
6970
|
+
const activeProjectRoot = useMemo8(() => {
|
|
6076
6971
|
if (activeSessionPid === null) return void 0;
|
|
6077
6972
|
return sessions.get(activeSessionPid)?.projectRoot;
|
|
6078
6973
|
}, [sessions, activeSessionPid]);
|
|
@@ -6094,7 +6989,7 @@ function MultiSessionApp({ manager }) {
|
|
|
6094
6989
|
[switchNext, switchPrev, switchByIndex]
|
|
6095
6990
|
);
|
|
6096
6991
|
useInput(handleInput);
|
|
6097
|
-
return /* @__PURE__ */
|
|
6992
|
+
return /* @__PURE__ */ React15.createElement(Box15, { flexDirection: "column" }, /* @__PURE__ */ React15.createElement(SessionTabBar, { sessions: tabs, width: columns, layoutMode }), /* @__PURE__ */ React15.createElement(
|
|
6098
6993
|
DashboardApp,
|
|
6099
6994
|
{
|
|
6100
6995
|
key: activeSessionPid ?? "none",
|
|
@@ -6142,19 +7037,22 @@ function createDefaultAgentState(params) {
|
|
|
6142
7037
|
// src/tui/index.tsx
|
|
6143
7038
|
function startTui(options) {
|
|
6144
7039
|
const renderOptions = options.stdout ? { stdout: options.stdout } : {};
|
|
6145
|
-
return render(/* @__PURE__ */
|
|
7040
|
+
return render(/* @__PURE__ */ React16.createElement(DashboardApp, { eventBus: options.eventBus }), renderOptions);
|
|
6146
7041
|
}
|
|
6147
7042
|
function renderMultiSession(options) {
|
|
6148
|
-
return render(/* @__PURE__ */
|
|
7043
|
+
return render(/* @__PURE__ */ React16.createElement(MultiSessionApp, { manager: options.manager }));
|
|
6149
7044
|
}
|
|
6150
7045
|
export {
|
|
6151
7046
|
AGENT_STATUSES,
|
|
6152
7047
|
DASHBOARD_NODE_STATUSES,
|
|
6153
7048
|
DashboardApp,
|
|
6154
7049
|
MultiSessionApp,
|
|
7050
|
+
TDD_PHASES,
|
|
6155
7051
|
TUI_EVENT_TYPES,
|
|
6156
7052
|
createDefaultAgentState,
|
|
6157
7053
|
createDefaultDashboardNode,
|
|
7054
|
+
createDefaultReviewResult,
|
|
7055
|
+
createDefaultTddStep,
|
|
6158
7056
|
createEmptyStageStats,
|
|
6159
7057
|
getLayoutMode,
|
|
6160
7058
|
renderMultiSession,
|