orchestrix-yuri 4.2.0 → 4.2.1

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.
@@ -594,6 +594,8 @@ class Router {
594
594
  else if (key === 'StatusReview') byStatus.Review = (byStatus.Review || 0) + 1;
595
595
  else if (key === 'StatusBlocked') byStatus.Blocked = (byStatus.Blocked || 0) + 1;
596
596
  else if (key === 'StatusApproved') byStatus.Approved = (byStatus.Approved || 0) + 1;
597
+ else if (key === 'StatusDraft') byStatus.Draft = (byStatus.Draft || 0) + 1;
598
+ else if (key === 'StatusNoStatus') byStatus.NoStatus = (byStatus.NoStatus || 0) + 1;
597
599
  else if (key === 'StatusOther') byStatus.Other = (byStatus.Other || 0) + 1;
598
600
  }
599
601
  }
@@ -617,17 +619,27 @@ class Router {
617
619
  const tmx = require('./engine/tmux-utils');
618
620
  if (devSession && tmx.hasSession(devSession)) {
619
621
  const windowNames = ['Architect', 'SM', 'Dev', 'QA'];
622
+ // Pass 1: find window with active spinner
620
623
  for (let w = 0; w < 4; w++) {
621
- const pane = tmx.capturePane(devSession, w, 5);
622
- const lines = pane.split('\n').filter((l) => l.trim());
624
+ const pane = tmx.capturePane(devSession, w, 10);
623
625
  if (/●|⠋|⠙|⠹|⠸|⠼|⠴|⠦|⠧|⠇|⠏/.test(pane)) {
624
626
  currentAgent = windowNames[w];
625
627
  currentWindow = w;
626
- const storyMatch = pane.match(/story[_-]?\d+[\._-]\d+/i) || pane.match(/\d+\.\d+/);
627
- if (storyMatch) currentStory = storyMatch[0];
628
628
  break;
629
629
  }
630
630
  }
631
+ // Pass 2: if no spinner, find window with most output (likely active)
632
+ if (!currentAgent) {
633
+ for (let w = 0; w < 4; w++) {
634
+ const pane = tmx.capturePane(devSession, w, 10);
635
+ const contentLines = pane.split('\n').filter((l) => l.trim() && !/^❯\s*$/.test(l));
636
+ if (contentLines.length > 3) {
637
+ currentAgent = windowNames[w];
638
+ currentWindow = w;
639
+ break;
640
+ }
641
+ }
642
+ }
631
643
  }
632
644
 
633
645
  // 4. Count epics from docs/prd/ (epic YAML files)
@@ -665,7 +677,7 @@ class Router {
665
677
  lines.push('━━━━━━━━━━━━━━━━━━━━━');
666
678
 
667
679
  // Status breakdown
668
- const icons = { Done: '✅', InProgress: '🔄', Review: '👀', Blocked: '🚫', Approved: '', AwaitingArchReview: '🏛️', RequiresRevision: '🔧', Escalated: '⚠️' };
680
+ const icons = { Done: '✅', InProgress: '🔄', Review: '👀', Blocked: '🚫', Approved: '📋', Draft: '📝', NoStatus: '', Other: '·' };
669
681
  const statusEntries = Object.entries(byStatus).filter(([, v]) => v > 0);
670
682
  if (statusEntries.length > 0) {
671
683
  for (const [s, n] of statusEntries) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orchestrix-yuri",
3
- "version": "4.2.0",
3
+ "version": "4.2.1",
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": {
@@ -63,12 +63,14 @@ for f in "$STORIES_DIR"/*.md; do
63
63
  status_lower=$(echo "$status" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')
64
64
 
65
65
  case "$status_lower" in
66
- done) echo "StatusDone:$fname" ;;
67
- inprogress|in_progress|in-progress) echo "StatusInProgress:$fname"; in_progress_story="$fname" ;;
68
- review|inreview|in_review) echo "StatusReview:$fname" ;;
66
+ done|complete|completed) echo "StatusDone:$fname" ;;
67
+ inprogress|in_progress|in-progress|wip) echo "StatusInProgress:$fname"; in_progress_story="$fname" ;;
68
+ review|inreview|in_review|underreview) echo "StatusReview:$fname" ;;
69
69
  blocked) echo "StatusBlocked:$fname" ;;
70
- approved) echo "StatusApproved:$fname" ;;
71
- *) echo "StatusOther:$fname" ;;
70
+ approved|ready) echo "StatusApproved:$fname" ;;
71
+ draft|new|todo|pending|open) echo "StatusDraft:$fname" ;;
72
+ "") echo "StatusNoStatus:$fname" ;;
73
+ *) echo "StatusOther:$fname:$status" ;;
72
74
  esac
73
75
  done
74
76
 
@@ -80,18 +82,29 @@ else
80
82
  echo "Epics:0"
81
83
  fi
82
84
 
83
- # ── CurrentEpic: max prefix from story filenames ──
84
- current_epic=$(ls "$STORIES_DIR" 2>/dev/null | grep -oE '^[0-9]+' | sort -n | tail -1)
85
- echo "CurrentEpic:${current_epic:-0}"
86
-
87
- # ── CurrentStory: InProgress or highest numbered ──
85
+ # ── CurrentEpic + CurrentStory: based on InProgress story ──
86
+ # Priority: InProgress story > last non-Done story > highest numbered
88
87
  if [ -n "$in_progress_story" ]; then
89
88
  echo "CurrentStory:$in_progress_story"
89
+ current_epic=$(echo "$in_progress_story" | grep -oE '^[0-9]+')
90
+ echo "CurrentEpic:${current_epic:-0}"
90
91
  else
91
- latest=$(ls "$STORIES_DIR"/*.md 2>/dev/null | sort -V | tail -1)
92
- if [ -n "$latest" ]; then
93
- echo "CurrentStory:$(basename "$latest" .md)"
92
+ # Find last non-Done story (most likely being worked on next)
93
+ last_non_done=""
94
+ for f in $(ls "$STORIES_DIR"/*.md 2>/dev/null | sort -V); do
95
+ [ -f "$f" ] || continue
96
+ s=$(awk '/^## Status/{found=1; next} found && /^[[:space:]]*$/{next} found{print; exit}' "$f" 2>/dev/null)
97
+ s_lower=$(echo "$s" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')
98
+ if [ "$s_lower" != "done" ]; then
99
+ last_non_done=$(basename "$f" .md)
100
+ fi
101
+ done
102
+ if [ -n "$last_non_done" ]; then
103
+ echo "CurrentStory:$last_non_done"
104
+ current_epic=$(echo "$last_non_done" | grep -oE '^[0-9]+')
105
+ echo "CurrentEpic:${current_epic:-0}"
94
106
  else
95
107
  echo "CurrentStory:none"
108
+ echo "CurrentEpic:0"
96
109
  fi
97
110
  fi