orchestrix-yuri 4.2.0 → 4.2.2
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 +23 -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,33 @@ 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
|
+
// Detect active agent: an agent showing the Command table or
|
|
623
|
+
// "How can I assist" is IDLE (waiting). A window WITHOUT these
|
|
624
|
+
// patterns is actively executing a task.
|
|
625
|
+
const idlePatterns = /Command.*Description|How can I assist|assist you today/i;
|
|
626
|
+
|
|
627
|
+
// Pass 1: find window with spinner (definitely working)
|
|
620
628
|
for (let w = 0; w < 4; w++) {
|
|
621
|
-
const pane = tmx.capturePane(devSession, w,
|
|
622
|
-
const lines = pane.split('\n').filter((l) => l.trim());
|
|
629
|
+
const pane = tmx.capturePane(devSession, w, 10);
|
|
623
630
|
if (/●|⠋|⠙|⠹|⠸|⠼|⠴|⠦|⠧|⠇|⠏/.test(pane)) {
|
|
624
631
|
currentAgent = windowNames[w];
|
|
625
632
|
currentWindow = w;
|
|
626
|
-
const storyMatch = pane.match(/story[_-]?\d+[\._-]\d+/i) || pane.match(/\d+\.\d+/);
|
|
627
|
-
if (storyMatch) currentStory = storyMatch[0];
|
|
628
633
|
break;
|
|
629
634
|
}
|
|
630
635
|
}
|
|
636
|
+
|
|
637
|
+
// Pass 2: find window that is NOT idle (no Command table)
|
|
638
|
+
if (!currentAgent) {
|
|
639
|
+
for (let w = 0; w < 4; w++) {
|
|
640
|
+
const pane = tmx.capturePane(devSession, w, 15);
|
|
641
|
+
const hasContent = pane.split('\n').filter((l) => l.trim()).length > 2;
|
|
642
|
+
if (hasContent && !idlePatterns.test(pane)) {
|
|
643
|
+
currentAgent = windowNames[w];
|
|
644
|
+
currentWindow = w;
|
|
645
|
+
break;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
631
649
|
}
|
|
632
650
|
|
|
633
651
|
// 4. Count epics from docs/prd/ (epic YAML files)
|
|
@@ -665,7 +683,7 @@ class Router {
|
|
|
665
683
|
lines.push('━━━━━━━━━━━━━━━━━━━━━');
|
|
666
684
|
|
|
667
685
|
// Status breakdown
|
|
668
|
-
const icons = { Done: '✅', InProgress: '🔄', Review: '👀', Blocked: '🚫', Approved: '
|
|
686
|
+
const icons = { Done: '✅', InProgress: '🔄', Review: '👀', Blocked: '🚫', Approved: '📋', Draft: '📝', NoStatus: '❓', Other: '·' };
|
|
669
687
|
const statusEntries = Object.entries(byStatus).filter(([, v]) => v > 0);
|
|
670
688
|
if (statusEntries.length > 0) {
|
|
671
689
|
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
|