orchestrix-yuri 4.7.5 → 4.7.7
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.
|
@@ -705,17 +705,26 @@ class PhaseOrchestrator {
|
|
|
705
705
|
|
|
706
706
|
if (output && output !== 'NO_STORIES_DIR') {
|
|
707
707
|
for (const line of output.split('\n')) {
|
|
708
|
-
|
|
709
|
-
const
|
|
710
|
-
|
|
711
|
-
|
|
708
|
+
if (!line.includes(':')) continue;
|
|
709
|
+
const colonIdx = line.indexOf(':');
|
|
710
|
+
const key = line.slice(0, colonIdx);
|
|
711
|
+
const value = line.slice(colonIdx + 1);
|
|
712
|
+
|
|
713
|
+
if (key === 'Total') {
|
|
714
|
+
result.totalStories = parseInt(value, 10) || 0;
|
|
715
|
+
} else if (key === 'Epics') {
|
|
716
|
+
result.totalEpics = parseInt(value, 10) || 0;
|
|
712
717
|
} else if (key === 'CurrentEpic') {
|
|
713
|
-
result.currentEpic =
|
|
714
|
-
} else if (key
|
|
715
|
-
result.
|
|
716
|
-
|
|
717
|
-
|
|
718
|
+
result.currentEpic = parseInt(value, 10) || 0;
|
|
719
|
+
} else if (key === 'CurrentStory') {
|
|
720
|
+
if (!result.currentStory) result.currentStory = value;
|
|
721
|
+
} else if (key.startsWith('Status')) {
|
|
722
|
+
// Per-file status: StatusDone:1.1-name → count as 'Done'
|
|
723
|
+
const statusName = key.slice(6); // strip 'Status' prefix
|
|
724
|
+
result.byStatus[statusName] = (result.byStatus[statusName] || 0) + 1;
|
|
725
|
+
if (statusName === 'Done') result.doneStories++;
|
|
718
726
|
}
|
|
727
|
+
// 'Created' is metadata — skip (Total is the authoritative count)
|
|
719
728
|
}
|
|
720
729
|
}
|
|
721
730
|
} catch { /* fallback to phase3.yaml */ }
|
|
@@ -798,7 +807,8 @@ class PhaseOrchestrator {
|
|
|
798
807
|
if (statusEntries.length > 0) {
|
|
799
808
|
const statusIcons = {
|
|
800
809
|
Done: '✅', InProgress: '🔄', Review: '👀', Blocked: '🚫',
|
|
801
|
-
Approved: '
|
|
810
|
+
Approved: '📋', Draft: '📝', NoStatus: '❓',
|
|
811
|
+
AwaitingArchReview: '🏛️', RequiresRevision: '🔧', Escalated: '⚠️',
|
|
802
812
|
};
|
|
803
813
|
for (const [status, count] of statusEntries) {
|
|
804
814
|
lines.push(`${statusIcons[status] || '·'} ${status}: ${count}`);
|
package/lib/gateway/router.js
CHANGED
|
@@ -358,8 +358,16 @@ class Router {
|
|
|
358
358
|
case 'iterate':
|
|
359
359
|
case 'deploy':
|
|
360
360
|
return this._handlePhaseCommand(classified.action, msg);
|
|
361
|
-
case 'status':
|
|
361
|
+
case 'status': {
|
|
362
|
+
// Agent-specific or decision queries need Claude reasoning with tmux context,
|
|
363
|
+
// not a canned status card. Fall through to conversation handler.
|
|
364
|
+
const agentRe = /\b(sm|architect|dev|qa|po|pm|ux)\b/i;
|
|
365
|
+
const decisionRe = /决策|决定|确认|需要我|block|decide|should i|approve/i;
|
|
366
|
+
if (agentRe.test(msg.text) || decisionRe.test(msg.text)) {
|
|
367
|
+
return null; // → conversation handler (Claude with tmux context)
|
|
368
|
+
}
|
|
362
369
|
return this._handleStatusQuery(msg);
|
|
370
|
+
}
|
|
363
371
|
default:
|
|
364
372
|
return null;
|
|
365
373
|
}
|
|
@@ -540,13 +548,19 @@ Reply with ONLY one word: small, medium, or large. Nothing else.`;
|
|
|
540
548
|
|
|
541
549
|
const projectRoot = engine.resolveProjectRoot();
|
|
542
550
|
|
|
543
|
-
//
|
|
551
|
+
// Inject tmux pane context so Claude can see agent state
|
|
544
552
|
let prompt = engine.composePrompt(msg.text);
|
|
545
553
|
if (this.orchestrator.isRunning()) {
|
|
546
554
|
const agentContext = this.orchestrator.captureCurrentAgentContext();
|
|
547
555
|
if (agentContext) {
|
|
548
556
|
prompt = `${agentContext}\n\n---\n\nUser message: ${msg.text}`;
|
|
549
557
|
}
|
|
558
|
+
} else if (projectRoot) {
|
|
559
|
+
// Even without active orchestrator, check for live dev sessions
|
|
560
|
+
const tmxContext = this._captureLiveDevContext(projectRoot);
|
|
561
|
+
if (tmxContext) {
|
|
562
|
+
prompt = `${tmxContext}\n\n---\n\nUser message: ${msg.text}`;
|
|
563
|
+
}
|
|
550
564
|
}
|
|
551
565
|
|
|
552
566
|
log.router(`Processing: "${msg.text.slice(0, 80)}..." → cwd: ${projectRoot || '~'}`);
|
|
@@ -970,6 +984,31 @@ Reply with ONLY one word: small, medium, or large. Nothing else.`;
|
|
|
970
984
|
return lines.join('\n');
|
|
971
985
|
}
|
|
972
986
|
|
|
987
|
+
// ── Live Dev Context (for conversation when orchestrator is not tracking) ─────
|
|
988
|
+
|
|
989
|
+
_captureLiveDevContext(projectRoot) {
|
|
990
|
+
const { execSync } = require('child_process');
|
|
991
|
+
const tmx = require('./engine/tmux-utils');
|
|
992
|
+
try {
|
|
993
|
+
const sessions = execSync('tmux list-sessions -F "#{session_name}" 2>/dev/null', { encoding: 'utf8' }).trim();
|
|
994
|
+
const projectName = path.basename(projectRoot).toLowerCase();
|
|
995
|
+
const devSession = sessions.split('\n').find((s) =>
|
|
996
|
+
s.startsWith('orchestrix-') && s.toLowerCase().includes(projectName)
|
|
997
|
+
) || sessions.split('\n').find((s) => s.startsWith('orchestrix-'));
|
|
998
|
+
if (!devSession || !tmx.hasSession(devSession)) return null;
|
|
999
|
+
|
|
1000
|
+
const windows = ['Architect', 'SM', 'Dev', 'QA'];
|
|
1001
|
+
const summaries = [];
|
|
1002
|
+
for (let w = 0; w < 4; w++) {
|
|
1003
|
+
const tail = tmx.capturePane(devSession, w, 10);
|
|
1004
|
+
const lines = tail.split('\n').filter((l) => l.trim());
|
|
1005
|
+
const last = lines.slice(-3).map((l) => l.trim().slice(0, 100)).join('\n ');
|
|
1006
|
+
summaries.push(` Window ${w} (${windows[w]}):\n ${last || '(idle)'}`);
|
|
1007
|
+
}
|
|
1008
|
+
return `[LIVE DEV SESSION] ${devSession} (orchestrator not actively tracking)\n${summaries.join('\n')}`;
|
|
1009
|
+
} catch { return null; }
|
|
1010
|
+
}
|
|
1011
|
+
|
|
973
1012
|
// ── Help ──────────────────────────────────────────────────────────────────────
|
|
974
1013
|
|
|
975
1014
|
_buildHelpText() {
|