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
- result.totalStories = parseInt(value, 10) || 0;
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(pct / 100 * total);
853
- const empty = total - filled;
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) {
@@ -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 || createdStories; // prefer planned, fallback to created
1079
- const pct = total > 0 ? Math.round(doneStories / total * 100) : 0;
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} done (${pct}%) | ${createdStories} created`);
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 = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orchestrix-yuri",
3
- "version": "4.8.6",
3
+ "version": "4.8.8",
4
4
  "description": "Yuri — Meta-Orchestrator for Orchestrix. Drive your entire project lifecycle with natural language.",
5
5
  "main": "lib/installer.js",
6
6
  "bin": {