orchestrix-yuri 4.8.6 → 4.8.8
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.
|
@@ -722,6 +722,8 @@ class PhaseOrchestrator {
|
|
|
722
722
|
}).trim();
|
|
723
723
|
|
|
724
724
|
if (output && output !== 'NO_STORIES_DIR') {
|
|
725
|
+
let planned = 0;
|
|
726
|
+
let created = 0;
|
|
725
727
|
for (const line of output.split('\n')) {
|
|
726
728
|
if (!line.includes(':')) continue;
|
|
727
729
|
const colonIdx = line.indexOf(':');
|
|
@@ -729,7 +731,9 @@ class PhaseOrchestrator {
|
|
|
729
731
|
const value = line.slice(colonIdx + 1);
|
|
730
732
|
|
|
731
733
|
if (key === 'Total') {
|
|
732
|
-
|
|
734
|
+
planned = parseInt(value, 10) || 0;
|
|
735
|
+
} else if (key === 'Created') {
|
|
736
|
+
created = parseInt(value, 10) || 0;
|
|
733
737
|
} else if (key === 'Epics') {
|
|
734
738
|
result.totalEpics = parseInt(value, 10) || 0;
|
|
735
739
|
} else if (key === 'CurrentEpic') {
|
|
@@ -742,8 +746,11 @@ class PhaseOrchestrator {
|
|
|
742
746
|
result.byStatus[statusName] = (result.byStatus[statusName] || 0) + 1;
|
|
743
747
|
if (statusName === 'Done') result.doneStories++;
|
|
744
748
|
}
|
|
745
|
-
// 'Created' is metadata — skip (Total is the authoritative count)
|
|
746
749
|
}
|
|
750
|
+
// Use actual story files as ground truth — YAML plans can be stale
|
|
751
|
+
result.totalStories = Math.max(planned, created);
|
|
752
|
+
// Ensure current epic is counted in total
|
|
753
|
+
if (result.currentEpic > result.totalEpics) result.totalEpics = result.currentEpic;
|
|
747
754
|
}
|
|
748
755
|
} catch { /* fallback to phase3.yaml */ }
|
|
749
756
|
}
|
|
@@ -848,10 +855,10 @@ class PhaseOrchestrator {
|
|
|
848
855
|
}
|
|
849
856
|
|
|
850
857
|
_progressBar(pct) {
|
|
858
|
+
const clamped = Math.min(100, Math.max(0, pct));
|
|
851
859
|
const total = 20;
|
|
852
|
-
const filled = Math.round(
|
|
853
|
-
|
|
854
|
-
return '▓'.repeat(filled) + '░'.repeat(empty) + ` ${pct}%`;
|
|
860
|
+
const filled = Math.min(total, Math.round(clamped / 100 * total));
|
|
861
|
+
return '▓'.repeat(filled) + '░'.repeat(total - filled) + ` ${clamped}%`;
|
|
855
862
|
}
|
|
856
863
|
|
|
857
864
|
_formatDuration(ms) {
|
package/lib/gateway/router.js
CHANGED
|
@@ -1074,18 +1074,19 @@ Reply with ONLY one word: small, medium, or large. Nothing else.`;
|
|
|
1074
1074
|
const runMin = Math.floor(runMs / 60000);
|
|
1075
1075
|
const elapsed = runMin < 60 ? `${runMin}min` : `${Math.floor(runMin / 60)}h ${runMin % 60}min`;
|
|
1076
1076
|
|
|
1077
|
-
// 6. Build card
|
|
1078
|
-
const total = totalPlanned
|
|
1079
|
-
|
|
1077
|
+
// 6. Build card — use actual story files as ground truth, not stale YAML
|
|
1078
|
+
const total = Math.max(totalPlanned, createdStories);
|
|
1079
|
+
if (currentEpic > totalEpics) totalEpics = currentEpic; // ensure current epic counted
|
|
1080
|
+
const pct = total > 0 ? Math.min(100, Math.round(doneStories / total * 100)) : 0;
|
|
1080
1081
|
const barLen = 20;
|
|
1081
|
-
const filled = Math.round(pct / 100 * barLen);
|
|
1082
|
+
const filled = Math.min(barLen, Math.round(pct / 100 * barLen));
|
|
1082
1083
|
const bar = '▓'.repeat(filled) + '░'.repeat(barLen - filled);
|
|
1083
1084
|
|
|
1084
1085
|
const lines = ['📊 **Dev Progress Report**', '━━━━━━━━━━━━━━━━━━━━━'];
|
|
1085
1086
|
if (totalEpics > 0) {
|
|
1086
1087
|
lines.push(`Epic: ${currentEpic}/${totalEpics}`);
|
|
1087
1088
|
}
|
|
1088
|
-
lines.push(`Story: ${doneStories}/${total}
|
|
1089
|
+
lines.push(`Story: ${doneStories}/${total} (${pct}%)`);
|
|
1089
1090
|
lines.push(`${bar} ${pct}%`);
|
|
1090
1091
|
lines.push('━━━━━━━━━━━━━━━━━━━━━');
|
|
1091
1092
|
|
|
@@ -1127,10 +1128,10 @@ Reply with ONLY one word: small, medium, or large. Nothing else.`;
|
|
|
1127
1128
|
const passed = state.epics.filter((e) => e.status === 'passed').length;
|
|
1128
1129
|
const failed = state.epics.filter((e) => e.status === 'failed').length;
|
|
1129
1130
|
const tested = passed + failed;
|
|
1130
|
-
const pct = total > 0 ? Math.round((tested / total) * 100) : 0;
|
|
1131
|
+
const pct = total > 0 ? Math.min(100, Math.round((tested / total) * 100)) : 0;
|
|
1131
1132
|
|
|
1132
1133
|
const barTotal = 20;
|
|
1133
|
-
const filled = Math.round(pct / 100 * barTotal);
|
|
1134
|
+
const filled = Math.min(barTotal, Math.round(pct / 100 * barTotal));
|
|
1134
1135
|
const bar = '▓'.repeat(filled) + '░'.repeat(barTotal - filled) + ` ${pct}%`;
|
|
1135
1136
|
|
|
1136
1137
|
const lines = [
|