agileflow 2.86.0 → 2.87.0
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/CHANGELOG.md +5 -0
- package/package.json +1 -1
- package/scripts/agileflow-statusline.sh +22 -6
- package/scripts/agileflow-welcome.js +14 -0
- package/scripts/obtain-context.js +81 -71
- package/scripts/session-manager.js +36 -10
- package/src/core/commands/babysit.md +82 -22
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.87.0] - 2026-01-13
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Multi-session visibility with cleanup notifications and status line indicators
|
|
14
|
+
|
|
10
15
|
## [2.86.0] - 2026-01-13
|
|
11
16
|
|
|
12
17
|
### Added
|
package/package.json
CHANGED
|
@@ -510,8 +510,9 @@ fi
|
|
|
510
510
|
# ============================================================================
|
|
511
511
|
# Session Info (Multi-session awareness)
|
|
512
512
|
# ============================================================================
|
|
513
|
-
# Show current session
|
|
513
|
+
# Show current session info for ALL sessions (main and non-main)
|
|
514
514
|
SESSION_INFO=""
|
|
515
|
+
OTHER_SESSIONS=""
|
|
515
516
|
SHOW_SESSION=true # New component - default enabled
|
|
516
517
|
|
|
517
518
|
# Check component setting
|
|
@@ -531,17 +532,28 @@ if [ "$SHOW_SESSION" = "true" ]; then
|
|
|
531
532
|
{id: .key, nickname: .value.nickname, is_main: .value.is_main}
|
|
532
533
|
' "$REGISTRY_FILE" 2>/dev/null)
|
|
533
534
|
|
|
535
|
+
# Count total sessions and other active sessions (sessions with lock files)
|
|
536
|
+
TOTAL_SESSIONS=$(jq '.sessions | length' "$REGISTRY_FILE" 2>/dev/null)
|
|
537
|
+
|
|
534
538
|
if [ -n "$SESSION_DATA" ]; then
|
|
535
539
|
SESSION_NUM=$(echo "$SESSION_DATA" | jq -r '.id')
|
|
536
540
|
SESSION_NICK=$(echo "$SESSION_DATA" | jq -r '.nickname // empty')
|
|
537
541
|
IS_MAIN=$(echo "$SESSION_DATA" | jq -r '.is_main // false')
|
|
538
542
|
|
|
539
|
-
# Only show for non-main sessions
|
|
540
|
-
if [ "$
|
|
543
|
+
# Only show session info for non-main sessions (main is default, no need to show)
|
|
544
|
+
if [ -n "$SESSION_NUM" ] && [ "$IS_MAIN" != "true" ]; then
|
|
541
545
|
if [ -n "$SESSION_NICK" ] && [ "$SESSION_NICK" != "null" ]; then
|
|
542
|
-
|
|
546
|
+
# With nickname
|
|
547
|
+
SESSION_INFO="${DIM}⎇${RESET} ${MAGENTA}Session ${SESSION_NUM}${RESET}${DIM}:${RESET}${SESSION_NICK}"
|
|
543
548
|
else
|
|
544
|
-
|
|
549
|
+
# Without nickname - show simple
|
|
550
|
+
SESSION_INFO="${DIM}⎇${RESET} ${MAGENTA}Session ${SESSION_NUM}${RESET}"
|
|
551
|
+
fi
|
|
552
|
+
|
|
553
|
+
# Show other sessions count if > 1 (only relevant for non-main)
|
|
554
|
+
if [ -n "$TOTAL_SESSIONS" ] && [ "$TOTAL_SESSIONS" -gt 1 ] 2>/dev/null; then
|
|
555
|
+
OTHER_COUNT=$((TOTAL_SESSIONS - 1))
|
|
556
|
+
OTHER_SESSIONS="${DIM} +${OTHER_COUNT}${RESET}"
|
|
545
557
|
fi
|
|
546
558
|
fi
|
|
547
559
|
fi
|
|
@@ -561,10 +573,14 @@ if [ "$SHOW_AGILEFLOW" = "true" ] && [ -n "$AGILEFLOW_DISPLAY" ]; then
|
|
|
561
573
|
OUTPUT="${AGILEFLOW_DISPLAY}"
|
|
562
574
|
fi
|
|
563
575
|
|
|
564
|
-
# Session info (
|
|
576
|
+
# Session info (always show when available, with other sessions count)
|
|
565
577
|
if [ "$SHOW_SESSION" = "true" ] && [ -n "$SESSION_INFO" ]; then
|
|
566
578
|
[ -n "$OUTPUT" ] && OUTPUT="${OUTPUT}${SEP}"
|
|
567
579
|
OUTPUT="${OUTPUT}${SESSION_INFO}"
|
|
580
|
+
# Append other sessions count if there are parallel sessions
|
|
581
|
+
if [ -n "$OTHER_SESSIONS" ]; then
|
|
582
|
+
OUTPUT="${OUTPUT}${OTHER_SESSIONS}"
|
|
583
|
+
fi
|
|
568
584
|
fi
|
|
569
585
|
|
|
570
586
|
# Model with subtle styling (if enabled and available)
|
|
@@ -341,6 +341,7 @@ function checkParallelSessions(rootDir) {
|
|
|
341
341
|
otherActive: 0,
|
|
342
342
|
currentId: null,
|
|
343
343
|
cleaned: 0,
|
|
344
|
+
cleanedSessions: [], // Detailed info about cleaned sessions
|
|
344
345
|
// Extended session info for non-main sessions
|
|
345
346
|
isMain: true,
|
|
346
347
|
nickname: null,
|
|
@@ -374,6 +375,7 @@ function checkParallelSessions(rootDir) {
|
|
|
374
375
|
result.currentId = data.id;
|
|
375
376
|
result.otherActive = data.otherActive || 0;
|
|
376
377
|
result.cleaned = data.cleaned || 0;
|
|
378
|
+
result.cleanedSessions = data.cleanedSessions || [];
|
|
377
379
|
|
|
378
380
|
if (data.current) {
|
|
379
381
|
result.isMain = data.current.is_main === true;
|
|
@@ -1277,6 +1279,18 @@ async function main() {
|
|
|
1277
1279
|
);
|
|
1278
1280
|
}
|
|
1279
1281
|
|
|
1282
|
+
// Show detailed message if sessions were cleaned (VISIBLE - not hidden!)
|
|
1283
|
+
if (parallelSessions.cleaned > 0 && parallelSessions.cleanedSessions) {
|
|
1284
|
+
console.log('');
|
|
1285
|
+
console.log(`${c.amber}📋 Cleaned ${parallelSessions.cleaned} inactive session(s):${c.reset}`);
|
|
1286
|
+
parallelSessions.cleanedSessions.forEach((sess) => {
|
|
1287
|
+
const name = sess.nickname ? `${sess.id} "${sess.nickname}"` : `Session ${sess.id}`;
|
|
1288
|
+
const reason = sess.reason === 'pid_dead' ? 'process ended' : sess.reason;
|
|
1289
|
+
console.log(` ${c.dim}└─ ${name} (${reason}, PID ${sess.pid})${c.reset}`);
|
|
1290
|
+
});
|
|
1291
|
+
console.log(` ${c.slate}Sessions are cleaned when their Claude Code process is no longer running.${c.reset}`);
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1280
1294
|
// Story claiming: cleanup stale claims and show warnings
|
|
1281
1295
|
if (storyClaiming) {
|
|
1282
1296
|
try {
|
|
@@ -386,6 +386,67 @@ function generateFullContent() {
|
|
|
386
386
|
content += `${C.lavender}${C.bold}${title}${C.reset}\n`;
|
|
387
387
|
content += `${C.dim}Generated: ${new Date().toISOString()}${C.reset}\n`;
|
|
388
388
|
|
|
389
|
+
// 0.5 SESSION CONTEXT BANNER (FIRST - before everything else)
|
|
390
|
+
// This is critical for multi-session awareness - agents need to know which session they're in
|
|
391
|
+
const sessionManagerPath = path.join(__dirname, 'session-manager.js');
|
|
392
|
+
const altSessionManagerPath = '.agileflow/scripts/session-manager.js';
|
|
393
|
+
|
|
394
|
+
if (fs.existsSync(sessionManagerPath) || fs.existsSync(altSessionManagerPath)) {
|
|
395
|
+
const managerPath = fs.existsSync(sessionManagerPath)
|
|
396
|
+
? sessionManagerPath
|
|
397
|
+
: altSessionManagerPath;
|
|
398
|
+
const sessionStatus = safeExec(`node "${managerPath}" status`);
|
|
399
|
+
|
|
400
|
+
if (sessionStatus) {
|
|
401
|
+
try {
|
|
402
|
+
const statusData = JSON.parse(sessionStatus);
|
|
403
|
+
if (statusData.current) {
|
|
404
|
+
const session = statusData.current;
|
|
405
|
+
const isMain = session.is_main === true;
|
|
406
|
+
const sessionName = session.nickname
|
|
407
|
+
? `Session ${session.id} "${session.nickname}"`
|
|
408
|
+
: `Session ${session.id}`;
|
|
409
|
+
|
|
410
|
+
content += `\n${C.teal}${C.bold}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}\n`;
|
|
411
|
+
content += `${C.teal}${C.bold}📍 SESSION CONTEXT${C.reset}\n`;
|
|
412
|
+
content += `${C.teal}${C.bold}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}\n`;
|
|
413
|
+
|
|
414
|
+
if (isMain) {
|
|
415
|
+
content += `${C.mintGreen}${C.bold}${sessionName}${C.reset} ${C.dim}(main project)${C.reset}\n`;
|
|
416
|
+
} else {
|
|
417
|
+
content += `${C.peach}${C.bold}🔀 ${sessionName}${C.reset} ${C.dim}(worktree)${C.reset}\n`;
|
|
418
|
+
content += `Branch: ${C.skyBlue}${session.branch || 'unknown'}${C.reset}\n`;
|
|
419
|
+
content += `${C.dim}Path: ${session.path || process.cwd()}${C.reset}\n`;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Show other active sessions prominently
|
|
423
|
+
if (statusData.otherActive > 0) {
|
|
424
|
+
content += `${C.amber}⚠️ ${statusData.otherActive} other active session(s)${C.reset} - check story claims below\n`;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
content += `${C.teal}${C.bold}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}\n\n`;
|
|
428
|
+
}
|
|
429
|
+
} catch (e) {
|
|
430
|
+
// Silently ignore session parse errors - will still show detailed session context later
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// 0.7 INTERACTION MODE (AskUserQuestion) - EARLY for visibility
|
|
436
|
+
// This MUST appear before other content to ensure Claude sees it
|
|
437
|
+
const earlyMetadata = safeReadJSON('docs/00-meta/agileflow-metadata.json');
|
|
438
|
+
const askUserQuestionConfig = earlyMetadata?.features?.askUserQuestion;
|
|
439
|
+
|
|
440
|
+
if (askUserQuestionConfig?.enabled) {
|
|
441
|
+
content += `${C.coral}${C.bold}┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓${C.reset}\n`;
|
|
442
|
+
content += `${C.coral}${C.bold}┃ 🔔 MANDATORY: AskUserQuestion After EVERY Response ┃${C.reset}\n`;
|
|
443
|
+
content += `${C.coral}${C.bold}┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛${C.reset}\n`;
|
|
444
|
+
content += `${C.bold}After completing ANY task${C.reset} (implementation, fix, etc.):\n`;
|
|
445
|
+
content += `${C.mintGreen}→ ALWAYS${C.reset} call ${C.skyBlue}AskUserQuestion${C.reset} tool to offer next steps\n`;
|
|
446
|
+
content += `${C.coral}→ NEVER${C.reset} end with text like "Done!" or "What's next?"\n\n`;
|
|
447
|
+
content += `${C.dim}Balance: Use at natural pause points. Don't ask permission for routine work.${C.reset}\n\n`;
|
|
448
|
+
}
|
|
449
|
+
|
|
389
450
|
// 0. PROGRESSIVE DISCLOSURE (section activation)
|
|
390
451
|
if (activeSections.length > 0) {
|
|
391
452
|
content += `\n${C.cyan}${C.bold}═══ 📖 Progressive Disclosure: Active Sections ═══${C.reset}\n`;
|
|
@@ -490,58 +551,35 @@ function generateFullContent() {
|
|
|
490
551
|
content += `${C.dim}No session-state.json found${C.reset}\n`;
|
|
491
552
|
}
|
|
492
553
|
|
|
493
|
-
// 4. SESSION CONTEXT (
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
const
|
|
554
|
+
// 4. SESSION CONTEXT (details - banner shown above)
|
|
555
|
+
// Note: Prominent SESSION CONTEXT banner is shown at the top of output
|
|
556
|
+
// This section provides additional details for non-main sessions
|
|
557
|
+
const sessionMgrPath = path.join(__dirname, 'session-manager.js');
|
|
558
|
+
const altSessionMgrPath = '.agileflow/scripts/session-manager.js';
|
|
497
559
|
|
|
498
|
-
if (fs.existsSync(
|
|
499
|
-
const
|
|
500
|
-
|
|
501
|
-
: altSessionManagerPath;
|
|
502
|
-
const sessionStatus = safeExec(`node "${managerPath}" status`);
|
|
560
|
+
if (fs.existsSync(sessionMgrPath) || fs.existsSync(altSessionMgrPath)) {
|
|
561
|
+
const mgrPath = fs.existsSync(sessionMgrPath) ? sessionMgrPath : altSessionMgrPath;
|
|
562
|
+
const sessionStatusStr = safeExec(`node "${mgrPath}" status`);
|
|
503
563
|
|
|
504
|
-
if (
|
|
564
|
+
if (sessionStatusStr) {
|
|
505
565
|
try {
|
|
506
|
-
const statusData = JSON.parse(
|
|
507
|
-
if (statusData.current) {
|
|
566
|
+
const statusData = JSON.parse(sessionStatusStr);
|
|
567
|
+
if (statusData.current && !statusData.current.is_main) {
|
|
568
|
+
// Only show additional details for non-main sessions
|
|
569
|
+
content += `\n${C.skyBlue}${C.bold}═══ Session Details ═══${C.reset}\n`;
|
|
508
570
|
const session = statusData.current;
|
|
509
|
-
const isMain = session.is_main === true;
|
|
510
571
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
// NON-MAIN SESSION - Show prominent banner
|
|
515
|
-
const sessionName = session.nickname
|
|
516
|
-
? `${session.id} "${session.nickname}"`
|
|
517
|
-
: `${session.id}`;
|
|
518
|
-
content += `${C.teal}${C.bold}🔀 SESSION ${sessionName} (worktree)${C.reset}\n`;
|
|
519
|
-
content += `Branch: ${C.skyBlue}${session.branch || 'unknown'}${C.reset}\n`;
|
|
520
|
-
content += `Path: ${C.dim}${session.path || process.cwd()}${C.reset}\n`;
|
|
521
|
-
|
|
522
|
-
// Calculate relative path to main
|
|
523
|
-
const mainPath = process.cwd().replace(/-[^/]+$/, ''); // Heuristic: strip session suffix
|
|
524
|
-
content += `Main project: ${C.dim}${mainPath}${C.reset}\n`;
|
|
525
|
-
|
|
526
|
-
// Remind about merge flow
|
|
527
|
-
content += `${C.lavender}💡 When done: /agileflow:session:end → merge to main${C.reset}\n`;
|
|
528
|
-
}
|
|
572
|
+
// Calculate relative path to main
|
|
573
|
+
const mainPath = process.cwd().replace(/-[^/]+$/, ''); // Heuristic: strip session suffix
|
|
574
|
+
content += `Main project: ${C.dim}${mainPath}${C.reset}\n`;
|
|
529
575
|
|
|
530
|
-
//
|
|
531
|
-
|
|
532
|
-
content += `${C.peach}⚠️ ${statusData.otherActive} other session(s) active${C.reset}\n`;
|
|
533
|
-
}
|
|
534
|
-
} else {
|
|
535
|
-
content += `${C.dim}No session registered${C.reset}\n`;
|
|
576
|
+
// Remind about merge flow
|
|
577
|
+
content += `${C.lavender}💡 When done: /agileflow:session:end → merge to main${C.reset}\n`;
|
|
536
578
|
}
|
|
537
579
|
} catch (e) {
|
|
538
|
-
|
|
580
|
+
// Silently ignore - banner above has basic info
|
|
539
581
|
}
|
|
540
|
-
} else {
|
|
541
|
-
content += `${C.dim}Session manager available${C.reset}\n`;
|
|
542
582
|
}
|
|
543
|
-
} else {
|
|
544
|
-
content += `${C.dim}Multi-session not configured${C.reset}\n`;
|
|
545
583
|
}
|
|
546
584
|
|
|
547
585
|
// 5. STORY CLAIMS (inter-session coordination)
|
|
@@ -662,35 +700,7 @@ function generateFullContent() {
|
|
|
662
700
|
content += `${C.dim} /agileflow:configure → Visual E2E testing${C.reset}\n\n`;
|
|
663
701
|
}
|
|
664
702
|
|
|
665
|
-
//
|
|
666
|
-
const askUserQuestionConfig = metadata?.features?.askUserQuestion;
|
|
667
|
-
|
|
668
|
-
if (askUserQuestionConfig?.enabled) {
|
|
669
|
-
content += `\n${C.brand}${C.bold}═══ ⚡ INTERACTION MODE: AskUserQuestion ENABLED ═══${C.reset}\n`;
|
|
670
|
-
content += `${C.dim}${'─'.repeat(60)}${C.reset}\n`;
|
|
671
|
-
content += `${C.bold}CRITICAL RULE:${C.reset} End ${C.skyBlue}EVERY${C.reset} response with the AskUserQuestion tool.\n\n`;
|
|
672
|
-
content += `${C.mintGreen}✓ CORRECT:${C.reset} Call the actual AskUserQuestion tool\n`;
|
|
673
|
-
content += `${C.coral}✗ WRONG:${C.reset} Text like "Want me to continue?" or "What's next?"\n\n`;
|
|
674
|
-
content += `${C.lavender}Required format:${C.reset}\n`;
|
|
675
|
-
content += `${C.dim}\`\`\`xml
|
|
676
|
-
<invoke name="AskUserQuestion">
|
|
677
|
-
<parameter name="questions">[{
|
|
678
|
-
"question": "What would you like to do next?",
|
|
679
|
-
"header": "Next step",
|
|
680
|
-
"multiSelect": false,
|
|
681
|
-
"options": [
|
|
682
|
-
{"label": "Option A (Recommended)", "description": "Why this is best"},
|
|
683
|
-
{"label": "Option B", "description": "Alternative approach"},
|
|
684
|
-
{"label": "Pause", "description": "Stop here for now"}
|
|
685
|
-
]
|
|
686
|
-
}]</parameter>
|
|
687
|
-
</invoke>
|
|
688
|
-
\`\`\`${C.reset}\n`;
|
|
689
|
-
content += `${C.dim}${'─'.repeat(60)}${C.reset}\n`;
|
|
690
|
-
content += `${C.dim}Mode: ${askUserQuestionConfig.mode || 'all'} | Configure: /agileflow:configure${C.reset}\n\n`;
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
// 5. DOCS STRUCTURE (using vibrant 256-color palette)
|
|
703
|
+
// DOCS STRUCTURE (using vibrant 256-color palette)
|
|
694
704
|
content += `\n${C.skyBlue}${C.bold}═══ Documentation ═══${C.reset}\n`;
|
|
695
705
|
const docsDir = 'docs';
|
|
696
706
|
const docFolders = safeLs(docsDir).filter(f => {
|
|
@@ -117,19 +117,39 @@ function isSessionActive(sessionId) {
|
|
|
117
117
|
return isPidAlive(parseInt(lock.pid, 10));
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
// Clean up stale locks
|
|
121
|
-
function cleanupStaleLocks(registry) {
|
|
120
|
+
// Clean up stale locks (with detailed tracking)
|
|
121
|
+
function cleanupStaleLocks(registry, options = {}) {
|
|
122
|
+
const { verbose = false, dryRun = false } = options;
|
|
122
123
|
let cleaned = 0;
|
|
124
|
+
const cleanedSessions = [];
|
|
123
125
|
|
|
124
126
|
for (const [id, session] of Object.entries(registry.sessions)) {
|
|
125
127
|
const lock = readLock(id);
|
|
126
|
-
if (lock
|
|
127
|
-
|
|
128
|
-
|
|
128
|
+
if (lock) {
|
|
129
|
+
const pid = parseInt(lock.pid, 10);
|
|
130
|
+
const isAlive = isPidAlive(pid);
|
|
131
|
+
|
|
132
|
+
if (!isAlive) {
|
|
133
|
+
// Track what we're cleaning and why
|
|
134
|
+
cleanedSessions.push({
|
|
135
|
+
id,
|
|
136
|
+
nickname: session.nickname,
|
|
137
|
+
branch: session.branch,
|
|
138
|
+
pid,
|
|
139
|
+
reason: 'pid_dead',
|
|
140
|
+
path: session.path,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
if (!dryRun) {
|
|
144
|
+
removeLock(id);
|
|
145
|
+
}
|
|
146
|
+
cleaned++;
|
|
147
|
+
}
|
|
129
148
|
}
|
|
130
149
|
}
|
|
131
150
|
|
|
132
|
-
|
|
151
|
+
// Return detailed info for display
|
|
152
|
+
return { count: cleaned, sessions: cleanedSessions };
|
|
133
153
|
}
|
|
134
154
|
|
|
135
155
|
// Get current git branch
|
|
@@ -342,7 +362,7 @@ function createSession(options = {}) {
|
|
|
342
362
|
// Get all sessions with status
|
|
343
363
|
function getSessions() {
|
|
344
364
|
const registry = loadRegistry();
|
|
345
|
-
const
|
|
365
|
+
const cleanupResult = cleanupStaleLocks(registry);
|
|
346
366
|
|
|
347
367
|
const sessions = [];
|
|
348
368
|
for (const [id, session] of Object.entries(registry.sessions)) {
|
|
@@ -357,7 +377,12 @@ function getSessions() {
|
|
|
357
377
|
// Sort by ID (numeric)
|
|
358
378
|
sessions.sort((a, b) => parseInt(a.id) - parseInt(b.id));
|
|
359
379
|
|
|
360
|
-
|
|
380
|
+
// Return count for backward compat, plus detailed info
|
|
381
|
+
return {
|
|
382
|
+
sessions,
|
|
383
|
+
cleaned: cleanupResult.count,
|
|
384
|
+
cleanedSessions: cleanupResult.sessions,
|
|
385
|
+
};
|
|
361
386
|
}
|
|
362
387
|
|
|
363
388
|
// Get count of active sessions (excluding current)
|
|
@@ -989,7 +1014,7 @@ function main() {
|
|
|
989
1014
|
|
|
990
1015
|
// Register in single pass (combines register + count + status)
|
|
991
1016
|
const registry = loadRegistry();
|
|
992
|
-
const
|
|
1017
|
+
const cleanupResult = cleanupStaleLocks(registry);
|
|
993
1018
|
const branch = getCurrentBranch();
|
|
994
1019
|
const story = getCurrentStory();
|
|
995
1020
|
const pid = process.ppid || process.pid;
|
|
@@ -1055,7 +1080,8 @@ function main() {
|
|
|
1055
1080
|
current,
|
|
1056
1081
|
otherActive,
|
|
1057
1082
|
total: sessions.length,
|
|
1058
|
-
cleaned,
|
|
1083
|
+
cleaned: cleanupResult.count,
|
|
1084
|
+
cleanedSessions: cleanupResult.sessions,
|
|
1059
1085
|
})
|
|
1060
1086
|
);
|
|
1061
1087
|
break;
|
|
@@ -5,16 +5,21 @@ compact_context:
|
|
|
5
5
|
priority: critical
|
|
6
6
|
preserve_rules:
|
|
7
7
|
- "ACTIVE COMMAND: /agileflow-babysit - Mentor mode with expert delegation"
|
|
8
|
+
- "🔔 MANDATORY: Call AskUserQuestion tool at END of EVERY response - especially after completing tasks"
|
|
9
|
+
- "NEVER end with text like 'Done!' or 'What's next?' - ALWAYS use AskUserQuestion tool instead"
|
|
8
10
|
- "MUST use EnterPlanMode FIRST for ANY non-trivial task (explore codebase, design approach, get approval)"
|
|
9
11
|
- "MUST delegate complex work to domain experts (don't do everything yourself)"
|
|
10
|
-
- "MUST use AskUserQuestion for decisions, TodoWrite for tracking"
|
|
11
12
|
- "Simple task → do yourself | Complex single-domain → spawn expert | Multi-domain → spawn orchestrator"
|
|
12
13
|
- "STUCK DETECTION: If same error 2+ times, suggest /agileflow:research:ask with 200+ line detailed prompt"
|
|
13
14
|
- "Research prompts MUST include: 50+ lines actual code, exact error, what was tried, 3+ specific questions"
|
|
15
|
+
- "STORY CLAIMING: Run 'node .agileflow/scripts/lib/story-claiming.js claim <id>' IMMEDIATELY after user selects story"
|
|
16
|
+
- "STORY CLAIMING: Run 'node .agileflow/scripts/lib/story-claiming.js others' BEFORE suggesting stories, exclude 🔒 claimed"
|
|
17
|
+
- "STORY CLAIMING: Run 'node .agileflow/scripts/lib/story-claiming.js release <id>' when story marked done"
|
|
14
18
|
state_fields:
|
|
15
19
|
- current_story
|
|
16
20
|
- current_epic
|
|
17
21
|
- delegation_mode
|
|
22
|
+
- claimed_story_id
|
|
18
23
|
---
|
|
19
24
|
|
|
20
25
|
# /agileflow-babysit
|
|
@@ -224,6 +229,17 @@ node scripts/ralph-loop.js --reset # Reset loop state
|
|
|
224
229
|
|
|
225
230
|
**EVERY response MUST end with the AskUserQuestion tool.** Not text like "Want me to...?" - the ACTUAL TOOL CALL.
|
|
226
231
|
|
|
232
|
+
**This applies (natural pause points):**
|
|
233
|
+
- ✅ After completing a task (ESPECIALLY important - don't leave user hanging)
|
|
234
|
+
- ✅ After spawning an agent and receiving results
|
|
235
|
+
- ✅ When presenting options or decisions
|
|
236
|
+
- ✅ Even when you think you're "done" - ask what's next
|
|
237
|
+
|
|
238
|
+
**Don't be annoying - DON'T ask for:**
|
|
239
|
+
- ❌ Permission to read files, spawn experts, or do routine work
|
|
240
|
+
- ❌ Confirmation of obvious next steps you should just do
|
|
241
|
+
- ❌ Every micro-step in a workflow
|
|
242
|
+
|
|
227
243
|
**Required format:**
|
|
228
244
|
```xml
|
|
229
245
|
<function_calls>
|
|
@@ -242,8 +258,8 @@ node scripts/ralph-loop.js --reset # Reset loop state
|
|
|
242
258
|
</function_calls>
|
|
243
259
|
```
|
|
244
260
|
|
|
245
|
-
**❌ WRONG:** "Want me to continue?" / "Should I proceed?" / "Let me know what
|
|
246
|
-
**✅ RIGHT:** Call the AskUserQuestion tool with actual options
|
|
261
|
+
**❌ WRONG:** "Want me to continue?" / "Should I proceed?" / "Done! Let me know what's next"
|
|
262
|
+
**✅ RIGHT:** Call the AskUserQuestion tool with actual options - NEVER end without it
|
|
247
263
|
|
|
248
264
|
---
|
|
249
265
|
|
|
@@ -320,23 +336,32 @@ Use TodoWrite for any task with 3+ steps. Update status as you complete each ste
|
|
|
320
336
|
|
|
321
337
|
**Phase 1: Context & Task Selection**
|
|
322
338
|
1. Run context script (obtain-context.js babysit)
|
|
323
|
-
2.
|
|
324
|
-
3.
|
|
339
|
+
2. Check for stories claimed by OTHER sessions (filter from suggestions)
|
|
340
|
+
3. Present task options using AskUserQuestion (with 🔒 badges for claimed)
|
|
341
|
+
4. User selects task
|
|
342
|
+
5. **CLAIM THE STORY immediately after selection:**
|
|
343
|
+
```bash
|
|
344
|
+
node .agileflow/scripts/lib/story-claiming.js claim <story-id>
|
|
345
|
+
```
|
|
325
346
|
|
|
326
347
|
**Phase 2: Plan Mode (for non-trivial tasks)**
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
348
|
+
6. Call `EnterPlanMode` tool
|
|
349
|
+
7. Explore codebase with Glob, Grep, Read
|
|
350
|
+
8. Design approach, write to plan file
|
|
351
|
+
9. Call `ExitPlanMode` for user approval
|
|
331
352
|
|
|
332
353
|
**Phase 3: Execution**
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
354
|
+
10. Delegate to experts based on scope
|
|
355
|
+
11. Collect results if async (TaskOutput)
|
|
356
|
+
12. Verify tests pass
|
|
336
357
|
|
|
337
358
|
**Phase 4: Completion**
|
|
338
|
-
|
|
339
|
-
|
|
359
|
+
13. Update status.json (mark story done)
|
|
360
|
+
14. **RELEASE THE STORY claim:**
|
|
361
|
+
```bash
|
|
362
|
+
node .agileflow/scripts/lib/story-claiming.js release <story-id>
|
|
363
|
+
```
|
|
364
|
+
15. Present next steps via AskUserQuestion
|
|
340
365
|
|
|
341
366
|
---
|
|
342
367
|
|
|
@@ -352,12 +377,35 @@ Use TodoWrite for any task with 3+ steps. Update status as you complete each ste
|
|
|
352
377
|
|
|
353
378
|
### SUGGESTIONS PRIORITY (for task selection)
|
|
354
379
|
|
|
380
|
+
**BEFORE suggesting stories, check for claims:**
|
|
381
|
+
```bash
|
|
382
|
+
node .agileflow/scripts/lib/story-claiming.js others
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
**Story badges in suggestions:**
|
|
386
|
+
| Badge | Meaning | Include in suggestions? |
|
|
387
|
+
|-------|---------|------------------------|
|
|
388
|
+
| ⭐ | Ready, available | YES - prioritize these |
|
|
389
|
+
| 🔒 | Claimed by other session | NO - exclude or show disabled |
|
|
390
|
+
| ✓ | Claimed by this session | YES - show as "continue" |
|
|
391
|
+
|
|
392
|
+
**Priority order (for unclaimed stories):**
|
|
355
393
|
1. ⭐ READY stories (all AC complete, no blockers)
|
|
356
394
|
2. Blocked with simple unblock
|
|
357
395
|
3. Near-complete epics (80%+ done)
|
|
358
396
|
4. README TODOs
|
|
359
397
|
5. New features
|
|
360
398
|
|
|
399
|
+
**Example with claim filtering:**
|
|
400
|
+
```json
|
|
401
|
+
[
|
|
402
|
+
{"label": "US-0042: Auth API ⭐ (Recommended)", "description": "Ready to implement"},
|
|
403
|
+
{"label": "US-0038: User Profile ✓", "description": "Continue your work"},
|
|
404
|
+
{"label": "US-0041: Settings 🔒", "description": "Claimed by Session 2 - skip"},
|
|
405
|
+
{"label": "Other", "description": "Tell me what you want"}
|
|
406
|
+
]
|
|
407
|
+
```
|
|
408
|
+
|
|
361
409
|
Present top 3-5 via AskUserQuestion, always include "Other" option.
|
|
362
410
|
|
|
363
411
|
---
|
|
@@ -377,12 +425,17 @@ Present top 3-5 via AskUserQuestion, always include "Other" option.
|
|
|
377
425
|
### REMEMBER AFTER COMPACTION
|
|
378
426
|
|
|
379
427
|
- `/agileflow:babysit` IS ACTIVE - follow these rules
|
|
380
|
-
-
|
|
428
|
+
- **🔔 AskUserQuestion AFTER EVERY RESPONSE** - especially after task completion!
|
|
429
|
+
- Don't say "Done!" and stop - call AskUserQuestion with next step options
|
|
430
|
+
- Don't leave user waiting - proactively suggest what to do next
|
|
381
431
|
- Plan mode FIRST for non-trivial tasks
|
|
382
432
|
- Delegate complex work to experts
|
|
383
433
|
- If stuck 2+ times → research prompt
|
|
384
434
|
- Use state narration markers (📍🔀🔄⚠️✅) for visibility
|
|
385
|
-
- **STORY CLAIMING
|
|
435
|
+
- **STORY CLAIMING - CRITICAL:**
|
|
436
|
+
1. BEFORE suggesting: `node .agileflow/scripts/lib/story-claiming.js others` → exclude 🔒
|
|
437
|
+
2. AFTER user selects: `node .agileflow/scripts/lib/story-claiming.js claim <id>`
|
|
438
|
+
3. WHEN done: `node .agileflow/scripts/lib/story-claiming.js release <id>`
|
|
386
439
|
|
|
387
440
|
<!-- COMPACT_SUMMARY_END -->
|
|
388
441
|
|
|
@@ -795,12 +848,19 @@ User: "Fix the typo in README"
|
|
|
795
848
|
- Initial task selection
|
|
796
849
|
- Choosing between approaches
|
|
797
850
|
- Architectural decisions
|
|
798
|
-
- End of every response
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
-
|
|
803
|
-
-
|
|
851
|
+
- End of every response (to keep user engaged)
|
|
852
|
+
- After completing a task (offer next steps)
|
|
853
|
+
|
|
854
|
+
**DON'T use for (avoid being annoying):**
|
|
855
|
+
- Routine operations ("Can I read this file?" → just read it)
|
|
856
|
+
- Spawning experts ("Should I spawn the API expert?" → just spawn it)
|
|
857
|
+
- Obvious next steps that don't need confirmation
|
|
858
|
+
- Asking the same question repeatedly
|
|
859
|
+
- Interrupting workflow when you already know what to do
|
|
860
|
+
- Asking permission for every small action
|
|
861
|
+
|
|
862
|
+
**Balance:**
|
|
863
|
+
Use AskUserQuestion at natural pause points (task completion, decision needed) but NOT for every micro-step. If you know the next action, do it. Ask only when user input genuinely helps.
|
|
804
864
|
|
|
805
865
|
**Format:**
|
|
806
866
|
```xml
|