orchestrix-yuri 4.8.5 → 4.8.7
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.
|
@@ -679,10 +679,17 @@ class PhaseOrchestrator {
|
|
|
679
679
|
this._lastActiveAgent = progress.currentAgent;
|
|
680
680
|
}
|
|
681
681
|
|
|
682
|
-
// Check if all stories done
|
|
682
|
+
// Check if all stories done — but ONLY if no agent is actively working.
|
|
683
|
+
// If an agent is busy (e.g., SM drafting new stories), story counts are stale.
|
|
683
684
|
if (progress.totalStories > 0 && progress.doneStories >= progress.totalStories) {
|
|
684
|
-
|
|
685
|
-
|
|
685
|
+
if (progress.currentAgent) {
|
|
686
|
+
// Agent still working — stories may be in flux (new ones being created)
|
|
687
|
+
log.engine(`All ${progress.doneStories}/${progress.totalStories} stories done but ${progress.currentAgent} is still active — waiting`);
|
|
688
|
+
} else {
|
|
689
|
+
// No active agent + all stories done → truly complete
|
|
690
|
+
this._completeDev();
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
686
693
|
}
|
|
687
694
|
|
|
688
695
|
// Periodic progress report
|
|
@@ -841,10 +848,10 @@ class PhaseOrchestrator {
|
|
|
841
848
|
}
|
|
842
849
|
|
|
843
850
|
_progressBar(pct) {
|
|
851
|
+
const clamped = Math.min(100, Math.max(0, pct));
|
|
844
852
|
const total = 20;
|
|
845
|
-
const filled = Math.round(
|
|
846
|
-
|
|
847
|
-
return '▓'.repeat(filled) + '░'.repeat(empty) + ` ${pct}%`;
|
|
853
|
+
const filled = Math.min(total, Math.round(clamped / 100 * total));
|
|
854
|
+
return '▓'.repeat(filled) + '░'.repeat(total - filled) + ` ${clamped}%`;
|
|
848
855
|
}
|
|
849
856
|
|
|
850
857
|
_formatDuration(ms) {
|
package/lib/gateway/router.js
CHANGED
|
@@ -38,7 +38,7 @@ const META_COMMANDS = {
|
|
|
38
38
|
// All natural language ("怎么样了", "进度如何") goes through dispatcher
|
|
39
39
|
// so Claude's understanding ability decides the routing.
|
|
40
40
|
const STATUS_PATTERNS = [
|
|
41
|
-
|
|
41
|
+
/^[*/]status\b/i,
|
|
42
42
|
];
|
|
43
43
|
|
|
44
44
|
/**
|
|
@@ -652,10 +652,24 @@ Reply with ONLY one word: small, medium, or large. Nothing else.`;
|
|
|
652
652
|
try {
|
|
653
653
|
const focus = yaml.load(fs.readFileSync(focusPath, 'utf8')) || {};
|
|
654
654
|
|
|
655
|
-
|
|
655
|
+
// Always check for live dev session first — it's the ground truth.
|
|
656
|
+
// focus.yaml may be stale (e.g., still says phase 4 after dev restarted).
|
|
657
|
+
let hasLiveDevSession = false;
|
|
658
|
+
try {
|
|
659
|
+
const { execSync } = require('child_process');
|
|
660
|
+
const sessions = execSync('tmux list-sessions -F "#{session_name}" 2>/dev/null', { encoding: 'utf8' }).trim();
|
|
661
|
+
const projectName = path.basename(projectRoot).toLowerCase();
|
|
662
|
+
const devSession = sessions.split('\n').find((s) =>
|
|
663
|
+
s.startsWith('orchestrix-') && s.toLowerCase().includes(projectName)
|
|
664
|
+
) || sessions.split('\n').find((s) => s.startsWith('orchestrix-'));
|
|
665
|
+
if (devSession) {
|
|
666
|
+
const tmx = require('./engine/tmux-utils');
|
|
667
|
+
hasLiveDevSession = tmx.hasSession(devSession);
|
|
668
|
+
}
|
|
669
|
+
} catch { /* no tmux */ }
|
|
656
670
|
|
|
657
|
-
//
|
|
658
|
-
if (
|
|
671
|
+
// If live dev session exists, show dev progress card regardless of focus.yaml phase
|
|
672
|
+
if (hasLiveDevSession) {
|
|
659
673
|
try {
|
|
660
674
|
const card = this._buildStatusCard(projectRoot, focus);
|
|
661
675
|
if (card) parts.push(card);
|
|
@@ -664,8 +678,10 @@ Reply with ONLY one word: small, medium, or large. Nothing else.`;
|
|
|
664
678
|
}
|
|
665
679
|
}
|
|
666
680
|
|
|
667
|
-
|
|
668
|
-
|
|
681
|
+
const phaseNum = parseInt(focus.phase, 10);
|
|
682
|
+
|
|
683
|
+
// Test phase: only show if no live dev session and no card yet
|
|
684
|
+
if (phaseNum === 4 && parts.length === 0 && !hasLiveDevSession) {
|
|
669
685
|
try {
|
|
670
686
|
const card = this._buildTestStatusCard(projectRoot);
|
|
671
687
|
if (card) parts.push(card);
|
|
@@ -1060,9 +1076,9 @@ Reply with ONLY one word: small, medium, or large. Nothing else.`;
|
|
|
1060
1076
|
|
|
1061
1077
|
// 6. Build card
|
|
1062
1078
|
const total = totalPlanned || createdStories; // prefer planned, fallback to created
|
|
1063
|
-
const pct = total > 0 ? Math.round(doneStories / total * 100) : 0;
|
|
1079
|
+
const pct = total > 0 ? Math.min(100, Math.round(doneStories / total * 100)) : 0;
|
|
1064
1080
|
const barLen = 20;
|
|
1065
|
-
const filled = Math.round(pct / 100 * barLen);
|
|
1081
|
+
const filled = Math.min(barLen, Math.round(pct / 100 * barLen));
|
|
1066
1082
|
const bar = '▓'.repeat(filled) + '░'.repeat(barLen - filled);
|
|
1067
1083
|
|
|
1068
1084
|
const lines = ['📊 **Dev Progress Report**', '━━━━━━━━━━━━━━━━━━━━━'];
|
|
@@ -1111,10 +1127,10 @@ Reply with ONLY one word: small, medium, or large. Nothing else.`;
|
|
|
1111
1127
|
const passed = state.epics.filter((e) => e.status === 'passed').length;
|
|
1112
1128
|
const failed = state.epics.filter((e) => e.status === 'failed').length;
|
|
1113
1129
|
const tested = passed + failed;
|
|
1114
|
-
const pct = total > 0 ? Math.round((tested / total) * 100) : 0;
|
|
1130
|
+
const pct = total > 0 ? Math.min(100, Math.round((tested / total) * 100)) : 0;
|
|
1115
1131
|
|
|
1116
1132
|
const barTotal = 20;
|
|
1117
|
-
const filled = Math.round(pct / 100 * barTotal);
|
|
1133
|
+
const filled = Math.min(barTotal, Math.round(pct / 100 * barTotal));
|
|
1118
1134
|
const bar = '▓'.repeat(filled) + '░'.repeat(barTotal - filled) + ` ${pct}%`;
|
|
1119
1135
|
|
|
1120
1136
|
const lines = [
|