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.
- package/lib/gateway/router.js +17 -5
- package/package.json +1 -1
- package/skill/scripts/scan-stories.sh +26 -13
package/lib/gateway/router.js
CHANGED
|
@@ -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,
|
|
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: '
|
|
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
|
@@ -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
|
-
|
|
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:
|
|
84
|
-
|
|
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
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|