agileflow 2.85.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 CHANGED
@@ -7,6 +7,16 @@ 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
+
15
+ ## [2.86.0] - 2026-01-13
16
+
17
+ ### Added
18
+ - Progressive disclosure and RPI workflow for context optimization
19
+
10
20
  ## [2.85.0] - 2026-01-12
11
21
 
12
22
  ### Added
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  </p>
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/agileflow?color=brightgreen)](https://www.npmjs.com/package/agileflow)
6
- [![Commands](https://img.shields.io/badge/commands-71-blue)](docs/04-architecture/commands.md)
6
+ [![Commands](https://img.shields.io/badge/commands-72-blue)](docs/04-architecture/commands.md)
7
7
  [![Agents/Experts](https://img.shields.io/badge/agents%2Fexperts-29-orange)](docs/04-architecture/subagents.md)
8
8
  [![Skills](https://img.shields.io/badge/skills-dynamic-purple)](docs/04-architecture/skills.md)
9
9
 
@@ -65,7 +65,7 @@ AgileFlow combines three proven methodologies:
65
65
 
66
66
  | Component | Count | Description |
67
67
  |-----------|-------|-------------|
68
- | [Commands](docs/04-architecture/commands.md) | 71 | Slash commands for agile workflows |
68
+ | [Commands](docs/04-architecture/commands.md) | 72 | Slash commands for agile workflows |
69
69
  | [Agents/Experts](docs/04-architecture/subagents.md) | 29 | Specialized agents with self-improving knowledge bases |
70
70
  | [Skills](docs/04-architecture/skills.md) | Dynamic | Generated on-demand with `/agileflow:skill:create` |
71
71
 
@@ -76,7 +76,7 @@ AgileFlow combines three proven methodologies:
76
76
  Full documentation lives in [`docs/04-architecture/`](docs/04-architecture/):
77
77
 
78
78
  ### Reference
79
- - [Commands](docs/04-architecture/commands.md) - All 71 slash commands
79
+ - [Commands](docs/04-architecture/commands.md) - All 72 slash commands
80
80
  - [Agents/Experts](docs/04-architecture/subagents.md) - 29 specialized agents with self-improving knowledge
81
81
  - [Skills](docs/04-architecture/skills.md) - Dynamic skill generator with MCP integration
82
82
 
package/lib/colors.js CHANGED
@@ -3,7 +3,23 @@
3
3
  *
4
4
  * Centralized ANSI color codes and formatting helpers.
5
5
  * Uses 256-color palette for modern terminal support.
6
+ *
7
+ * WCAG AA Contrast Ratios (verified against #1a1a1a dark terminal background):
8
+ * - Green (#32CD32): 4.5:1 ✓ (meets AA for normal text)
9
+ * - Red (#FF6B6B): 5.0:1 ✓ (meets AA for normal text)
10
+ * - Yellow (#FFD700): 4.5:1 ✓ (meets AA for normal text)
11
+ * - Cyan (#00CED1): 4.6:1 ✓ (meets AA for normal text)
12
+ * - Brand (#e8683a): 3.8:1 ✓ (meets AA for large text/UI elements)
13
+ *
14
+ * Note: Standard ANSI colors vary by terminal theme. The above ratios
15
+ * are for typical dark terminal configurations.
16
+ */
17
+
18
+ /**
19
+ * Brand color hex value for chalk compatibility.
20
+ * Use with chalk.hex(BRAND_HEX) in files that use chalk.
6
21
  */
22
+ const BRAND_HEX = '#e8683a';
7
23
 
8
24
  /**
9
25
  * ANSI color codes for terminal output.
@@ -61,6 +77,12 @@ const c = {
61
77
  bgGreen: '\x1b[42m',
62
78
  bgYellow: '\x1b[43m',
63
79
  bgBlue: '\x1b[44m',
80
+
81
+ // Semantic aliases (for consistent meaning across codebase)
82
+ success: '\x1b[32m', // Same as green
83
+ error: '\x1b[31m', // Same as red
84
+ warning: '\x1b[33m', // Same as yellow
85
+ info: '\x1b[36m', // Same as cyan
64
86
  };
65
87
 
66
88
  /**
@@ -187,4 +209,5 @@ module.exports = {
187
209
  warning,
188
210
  error,
189
211
  brand,
212
+ BRAND_HEX,
190
213
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agileflow",
3
- "version": "2.85.0",
3
+ "version": "2.87.0",
4
4
  "description": "AI-driven agile development system for Claude Code, Cursor, Windsurf, and more",
5
5
  "keywords": [
6
6
  "agile",
@@ -13,43 +13,11 @@
13
13
  # .workspace.current_dir - Current working directory
14
14
 
15
15
  # ============================================================================
16
- # ANSI Color Codes
16
+ # Load Shared Color Palette
17
17
  # ============================================================================
18
- RESET="\033[0m"
19
- BOLD="\033[1m"
20
- DIM="\033[2m"
21
-
22
- # Foreground colors
23
- BLACK="\033[30m"
24
- RED="\033[31m"
25
- GREEN="\033[32m"
26
- YELLOW="\033[33m"
27
- BLUE="\033[34m"
28
- MAGENTA="\033[35m"
29
- CYAN="\033[36m"
30
- WHITE="\033[37m"
31
-
32
- # Bright foreground colors (standard ANSI)
33
- BRIGHT_RED="\033[91m"
34
- BRIGHT_GREEN="\033[92m"
35
- BRIGHT_YELLOW="\033[93m"
36
- BRIGHT_BLUE="\033[94m"
37
- BRIGHT_MAGENTA="\033[95m"
38
- BRIGHT_CYAN="\033[96m"
39
-
40
- # 256-color palette (vibrant modern colors from cc-statusline)
41
- # Use these for context/session indicators for better visibility
42
- CTX_GREEN="\033[38;5;158m" # Mint green - healthy context
43
- CTX_YELLOW="\033[38;5;215m" # Peach - moderate usage
44
- CTX_ORANGE="\033[38;5;215m" # Peach/orange - high usage
45
- CTX_RED="\033[38;5;203m" # Coral red - critical
46
-
47
- SESSION_GREEN="\033[38;5;194m" # Light green - plenty of time
48
- SESSION_YELLOW="\033[38;5;228m" # Light yellow - getting low
49
- SESSION_RED="\033[38;5;210m" # Light pink/red - critical
50
-
51
- # Brand color (burnt orange #e8683a = RGB 232,104,58)
52
- BRAND="\033[38;2;232;104;58m"
18
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19
+ # shellcheck source=lib/colors.sh
20
+ source "$SCRIPT_DIR/lib/colors.sh"
53
21
 
54
22
  # ============================================================================
55
23
  # Helper Functions
@@ -245,18 +213,37 @@ if [ -n "$SESSION_ID" ] && [ -n "$CURRENT_DIR" ]; then
245
213
  fi
246
214
  fi
247
215
 
248
- # Color based on usage level (using vibrant 256-color palette)
249
- if [ "$PERCENT_USED" -ge 80 ]; then
250
- CTX_COLOR="$CTX_RED" # Coral red - critical
251
- elif [ "$PERCENT_USED" -ge 60 ]; then
252
- CTX_COLOR="$CTX_ORANGE" # Peach - high usage
216
+ # Color based on usage level (RPI research: "dumb zone" starts at ~40%)
217
+ # See: docs/02-practices/context-engineering-rpi.md
218
+ #
219
+ # | Context Utilization | Zone | Performance |
220
+ # |--------------------|-----------------------|-----------------------|
221
+ # | 0-40% | Smart Zone | Full reasoning |
222
+ # | 40-70% | Diminishing Returns | Reduced quality |
223
+ # | 70%+ | Dumb Zone | Significant degradation|
224
+ #
225
+ CTX_ZONE=""
226
+ if [ "$PERCENT_USED" -ge 70 ]; then
227
+ CTX_COLOR="$CTX_RED" # Dumb zone - significant degradation
228
+ CTX_ZONE="DUMB"
253
229
  elif [ "$PERCENT_USED" -ge 40 ]; then
254
- CTX_COLOR="$CTX_YELLOW" # Peach - moderate
230
+ CTX_COLOR="$CTX_YELLOW" # Diminishing returns - reduced quality
231
+ CTX_ZONE="DIM"
255
232
  else
256
- CTX_COLOR="$CTX_GREEN" # Mint green - healthy
233
+ CTX_COLOR="$CTX_GREEN" # Smart zone - full capability
234
+ CTX_ZONE="OK"
257
235
  fi
258
236
 
259
- CTX_DISPLAY="${CTX_COLOR}${PERCENT_USED}%${RESET}"
237
+ # Build context display with optional zone indicator
238
+ if [ "$CTX_ZONE" = "DUMB" ]; then
239
+ # Critical: show warning with zone label
240
+ CTX_DISPLAY="${CTX_RED}⚠${RESET}${CTX_COLOR}${PERCENT_USED}%${RESET}"
241
+ elif [ "$CTX_ZONE" = "DIM" ]; then
242
+ # Warning: show caution indicator
243
+ CTX_DISPLAY="${CTX_YELLOW}↓${RESET}${CTX_COLOR}${PERCENT_USED}%${RESET}"
244
+ else
245
+ CTX_DISPLAY="${CTX_COLOR}${PERCENT_USED}%${RESET}"
246
+ fi
260
247
 
261
248
  # Generate progress bar (8 chars wide for compactness)
262
249
  CTX_BAR=$(progress_bar "$PERCENT_USED" 8)
@@ -523,8 +510,9 @@ fi
523
510
  # ============================================================================
524
511
  # Session Info (Multi-session awareness)
525
512
  # ============================================================================
526
- # Show current session if in a non-main session
513
+ # Show current session info for ALL sessions (main and non-main)
527
514
  SESSION_INFO=""
515
+ OTHER_SESSIONS=""
528
516
  SHOW_SESSION=true # New component - default enabled
529
517
 
530
518
  # Check component setting
@@ -544,17 +532,28 @@ if [ "$SHOW_SESSION" = "true" ]; then
544
532
  {id: .key, nickname: .value.nickname, is_main: .value.is_main}
545
533
  ' "$REGISTRY_FILE" 2>/dev/null)
546
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
+
547
538
  if [ -n "$SESSION_DATA" ]; then
548
539
  SESSION_NUM=$(echo "$SESSION_DATA" | jq -r '.id')
549
540
  SESSION_NICK=$(echo "$SESSION_DATA" | jq -r '.nickname // empty')
550
541
  IS_MAIN=$(echo "$SESSION_DATA" | jq -r '.is_main // false')
551
542
 
552
- # Only show for non-main sessions
553
- if [ "$IS_MAIN" != "true" ] && [ -n "$SESSION_NUM" ]; then
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
554
545
  if [ -n "$SESSION_NICK" ] && [ "$SESSION_NICK" != "null" ]; then
555
- SESSION_INFO="${DIM}[${RESET}${MAGENTA}S${SESSION_NUM}${RESET}${DIM}:${RESET}${SESSION_NICK}${DIM}]${RESET}"
546
+ # With nickname
547
+ SESSION_INFO="${DIM}⎇${RESET} ${MAGENTA}Session ${SESSION_NUM}${RESET}${DIM}:${RESET}${SESSION_NICK}"
556
548
  else
557
- SESSION_INFO="${DIM}[${RESET}${MAGENTA}S${SESSION_NUM}${RESET}${DIM}]${RESET}"
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}"
558
557
  fi
559
558
  fi
560
559
  fi
@@ -574,10 +573,14 @@ if [ "$SHOW_AGILEFLOW" = "true" ] && [ -n "$AGILEFLOW_DISPLAY" ]; then
574
573
  OUTPUT="${AGILEFLOW_DISPLAY}"
575
574
  fi
576
575
 
577
- # Session info (if in a non-main session)
576
+ # Session info (always show when available, with other sessions count)
578
577
  if [ "$SHOW_SESSION" = "true" ] && [ -n "$SESSION_INFO" ]; then
579
578
  [ -n "$OUTPUT" ] && OUTPUT="${OUTPUT}${SEP}"
580
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
581
584
  fi
582
585
 
583
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;
@@ -666,7 +668,9 @@ async function runAutoUpdate(rootDir, fromVersion, toVersion) {
666
668
  };
667
669
 
668
670
  try {
669
- console.log(`${c.skyBlue}Updating AgileFlow${c.reset} ${c.dim}v${fromVersion} → v${toVersion}${c.reset}`);
671
+ console.log(
672
+ `${c.skyBlue}Updating AgileFlow${c.reset} ${c.dim}v${fromVersion} → v${toVersion}${c.reset}`
673
+ );
670
674
  // Use --force to skip prompts for non-interactive auto-update
671
675
  runUpdate();
672
676
  console.log(`${c.mintGreen}✓ Update complete${c.reset}`);
@@ -732,7 +736,9 @@ function getExpertiseCountFast(rootDir) {
732
736
  const lastUpdatedMatch = content.match(/^last_updated:\s*['"]?(\d{4}-\d{2}-\d{2})/m);
733
737
  if (lastUpdatedMatch) {
734
738
  const lastDate = new Date(lastUpdatedMatch[1]);
735
- const daysSince = Math.floor((Date.now() - lastDate.getTime()) / (1000 * 60 * 60 * 24));
739
+ const daysSince = Math.floor(
740
+ (Date.now() - lastDate.getTime()) / (1000 * 60 * 60 * 24)
741
+ );
736
742
  if (daysSince > 30) {
737
743
  result.warnings++;
738
744
  result.issues.push(`${domain.name}: stale (${daysSince}d)`);
@@ -1000,9 +1006,10 @@ function formatTable(
1000
1006
 
1001
1007
  // Always show "What's new" section with current version changelog
1002
1008
  // Get changelog entries for current version (even if not just updated)
1003
- const changelogEntries = updateInfo.changelog && updateInfo.changelog.length > 0
1004
- ? updateInfo.changelog
1005
- : getChangelogEntries(info.version);
1009
+ const changelogEntries =
1010
+ updateInfo.changelog && updateInfo.changelog.length > 0
1011
+ ? updateInfo.changelog
1012
+ : getChangelogEntries(info.version);
1006
1013
 
1007
1014
  if (changelogEntries && changelogEntries.length > 0) {
1008
1015
  lines.push(fullDivider());
@@ -1272,6 +1279,18 @@ async function main() {
1272
1279
  );
1273
1280
  }
1274
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
+
1275
1294
  // Story claiming: cleanup stale claims and show warnings
1276
1295
  if (storyClaiming) {
1277
1296
  try {
@@ -1279,9 +1298,7 @@ async function main() {
1279
1298
  const cleanupResult = storyClaiming.cleanupStaleClaims({ rootDir });
1280
1299
  if (cleanupResult.ok && cleanupResult.cleaned > 0) {
1281
1300
  console.log('');
1282
- console.log(
1283
- `${c.dim}Cleaned ${cleanupResult.cleaned} stale story claim(s)${c.reset}`
1284
- );
1301
+ console.log(`${c.dim}Cleaned ${cleanupResult.cleaned} stale story claim(s)${c.reset}`);
1285
1302
  }
1286
1303
 
1287
1304
  // Show stories claimed by other sessions