agileflow 2.92.1 → 2.93.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.
Files changed (115) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +3 -3
  3. package/package.json +1 -1
  4. package/scripts/agileflow-statusline.sh +106 -0
  5. package/scripts/agileflow-welcome.js +57 -0
  6. package/scripts/document-repl.js +793 -0
  7. package/scripts/session-manager.js +195 -12
  8. package/scripts/spawn-parallel.js +41 -14
  9. package/src/core/agents/accessibility.md +19 -125
  10. package/src/core/agents/adr-writer.md +18 -1
  11. package/src/core/agents/analytics.md +19 -125
  12. package/src/core/agents/api.md +5 -130
  13. package/src/core/agents/ci.md +26 -131
  14. package/src/core/agents/compliance.md +21 -125
  15. package/src/core/agents/database.md +20 -125
  16. package/src/core/agents/datamigration.md +20 -125
  17. package/src/core/agents/design.md +19 -125
  18. package/src/core/agents/devops.md +12 -129
  19. package/src/core/agents/documentation.md +18 -1
  20. package/src/core/agents/epic-planner.md +31 -10
  21. package/src/core/agents/integrations.md +19 -125
  22. package/src/core/agents/mobile.md +19 -125
  23. package/src/core/agents/monitoring.md +19 -125
  24. package/src/core/agents/performance.md +19 -125
  25. package/src/core/agents/product.md +18 -1
  26. package/src/core/agents/qa.md +21 -125
  27. package/src/core/agents/readme-updater.md +18 -1
  28. package/src/core/agents/refactor.md +19 -125
  29. package/src/core/agents/research.md +3 -1
  30. package/src/core/agents/rlm-subcore.md +202 -0
  31. package/src/core/agents/security.md +7 -125
  32. package/src/core/agents/testing.md +20 -125
  33. package/src/core/agents/ui.md +14 -135
  34. package/src/core/commands/adr/list.md +20 -0
  35. package/src/core/commands/adr/update.md +24 -1
  36. package/src/core/commands/adr/view.md +23 -1
  37. package/src/core/commands/adr.md +2 -2
  38. package/src/core/commands/agent.md +11 -1
  39. package/src/core/commands/assign.md +15 -6
  40. package/src/core/commands/auto.md +11 -1
  41. package/src/core/commands/babysit.md +15 -4
  42. package/src/core/commands/baseline.md +11 -1
  43. package/src/core/commands/batch.md +11 -1
  44. package/src/core/commands/blockers.md +11 -1
  45. package/src/core/commands/board.md +11 -1
  46. package/src/core/commands/changelog.md +11 -0
  47. package/src/core/commands/choose.md +16 -1
  48. package/src/core/commands/ci.md +11 -1
  49. package/src/core/commands/configure.md +73 -2
  50. package/src/core/commands/context/export.md +8 -0
  51. package/src/core/commands/context/full.md +8 -0
  52. package/src/core/commands/context/note.md +8 -0
  53. package/src/core/commands/debt.md +11 -0
  54. package/src/core/commands/deploy.md +10 -0
  55. package/src/core/commands/deps.md +11 -1
  56. package/src/core/commands/diagnose.md +10 -0
  57. package/src/core/commands/docs.md +12 -2
  58. package/src/core/commands/epic/list.md +20 -0
  59. package/src/core/commands/epic/view.md +25 -0
  60. package/src/core/commands/epic.md +5 -6
  61. package/src/core/commands/feedback.md +11 -0
  62. package/src/core/commands/handoff.md +12 -2
  63. package/src/core/commands/help.md +10 -0
  64. package/src/core/commands/ideate.md +10 -0
  65. package/src/core/commands/impact.md +11 -1
  66. package/src/core/commands/metrics.md +11 -1
  67. package/src/core/commands/multi-expert.md +11 -1
  68. package/src/core/commands/packages.md +11 -0
  69. package/src/core/commands/pr.md +10 -0
  70. package/src/core/commands/readme-sync.md +10 -5
  71. package/src/core/commands/research/analyze.md +60 -3
  72. package/src/core/commands/research/ask.md +9 -1
  73. package/src/core/commands/research/import.md +8 -0
  74. package/src/core/commands/research/list.md +8 -0
  75. package/src/core/commands/research/synthesize.md +9 -1
  76. package/src/core/commands/research/view.md +8 -0
  77. package/src/core/commands/retro.md +12 -2
  78. package/src/core/commands/review.md +11 -1
  79. package/src/core/commands/rlm.md +363 -0
  80. package/src/core/commands/roadmap/analyze.md +1 -1
  81. package/src/core/commands/rpi.md +9 -1
  82. package/src/core/commands/session/cleanup.md +250 -0
  83. package/src/core/commands/session/end.md +10 -0
  84. package/src/core/commands/session/history.md +11 -1
  85. package/src/core/commands/session/init.md +10 -0
  86. package/src/core/commands/session/new.md +113 -13
  87. package/src/core/commands/session/resume.md +10 -0
  88. package/src/core/commands/session/spawn.md +8 -0
  89. package/src/core/commands/session/status.md +10 -0
  90. package/src/core/commands/skill/create.md +1 -1
  91. package/src/core/commands/skill/delete.md +11 -1
  92. package/src/core/commands/skill/edit.md +11 -1
  93. package/src/core/commands/skill/test.md +11 -1
  94. package/src/core/commands/skill/upgrade.md +11 -1
  95. package/src/core/commands/sprint.md +14 -3
  96. package/src/core/commands/status.md +15 -6
  97. package/src/core/commands/story/list.md +23 -0
  98. package/src/core/commands/story/view.md +24 -0
  99. package/src/core/commands/story.md +4 -5
  100. package/src/core/commands/template.md +10 -0
  101. package/src/core/commands/tests.md +10 -0
  102. package/src/core/commands/update.md +10 -0
  103. package/src/core/commands/validate-expertise.md +10 -1
  104. package/src/core/commands/velocity.md +11 -1
  105. package/src/core/commands/verify.md +13 -1
  106. package/src/core/commands/whats-new.md +8 -0
  107. package/src/core/commands/workflow.md +16 -1
  108. package/src/core/templates/agent-coordination-pattern.md +38 -0
  109. package/src/core/templates/agileflow-metadata.json +25 -0
  110. package/src/core/templates/preserve-rules-common.md +107 -0
  111. package/src/core/templates/preserve-rules.json +42 -0
  112. package/src/core/templates/proactive-action-spec.md +29 -0
  113. package/src/core/templates/quality-gate-priorities.md +34 -0
  114. package/src/core/templates/session-harness-protocol.md +128 -0
  115. package/tools/cli/lib/content-injector.js +336 -0
@@ -231,6 +231,161 @@ async function cleanupStaleLocksAsync(registry, options = {}) {
231
231
  return { count: cleanedSessions.length, sessions: cleanedSessions };
232
232
  }
233
233
 
234
+ /**
235
+ * Get detailed file information for a session's changes
236
+ * @param {string} sessionPath - Path to session worktree
237
+ * @param {string[]} changes - Array of git status lines
238
+ * @returns {Object[]} Array of file details with analysis
239
+ */
240
+ function getFileDetails(sessionPath, changes) {
241
+ return changes.map((change) => {
242
+ const status = change.substring(0, 2).trim();
243
+ const file = change.substring(3);
244
+
245
+ const detail = { status, file, trivial: false, existsInMain: false, diffLines: 0 };
246
+
247
+ // For modified files, get diff stats
248
+ if (status === 'M') {
249
+ try {
250
+ const diffStat = spawnSync('git', ['diff', '--numstat', file], {
251
+ cwd: sessionPath,
252
+ encoding: 'utf8',
253
+ timeout: 3000,
254
+ });
255
+ if (diffStat.stdout) {
256
+ const parts = diffStat.stdout.trim().split('\t');
257
+ const added = parseInt(parts[0], 10) || 0;
258
+ const removed = parseInt(parts[1], 10) || 0;
259
+ detail.diffLines = added + removed;
260
+ // Trivial if only 1-2 lines changed (likely whitespace)
261
+ detail.trivial = detail.diffLines <= 2;
262
+ }
263
+ } catch (e) {
264
+ // Can't get diff, assume not trivial
265
+ }
266
+ }
267
+
268
+ // For untracked files, check if exists in main
269
+ if (status === '??') {
270
+ detail.existsInMain = fs.existsSync(path.join(ROOT, file));
271
+ // Trivial if it's a duplicate
272
+ detail.trivial = detail.existsInMain;
273
+ }
274
+
275
+ // Config/cache files are trivial
276
+ if (file.includes('.claude/') || file.includes('.agileflow/cache')) {
277
+ detail.trivial = true;
278
+ }
279
+
280
+ return detail;
281
+ });
282
+ }
283
+
284
+ /**
285
+ * Get health status for all sessions
286
+ * Detects: stale sessions, uncommitted changes, orphaned entries
287
+ * @param {Object} options - { staleDays: 7, detailed: false }
288
+ * @returns {Object} Health report
289
+ */
290
+ function getSessionsHealth(options = {}) {
291
+ const { staleDays = 7, detailed = false } = options;
292
+ const registry = loadRegistry();
293
+ const now = Date.now();
294
+ const staleThreshold = staleDays * 24 * 60 * 60 * 1000;
295
+
296
+ const health = {
297
+ stale: [], // Sessions with no activity > staleDays
298
+ uncommitted: [], // Sessions with uncommitted git changes
299
+ orphanedRegistry: [], // Registry entries where path doesn't exist
300
+ orphanedWorktrees: [], // Worktrees not in registry
301
+ healthy: 0,
302
+ };
303
+
304
+ // Check each registered session
305
+ for (const [id, session] of Object.entries(registry.sessions)) {
306
+ if (session.is_main) continue; // Skip main session
307
+
308
+ const age = now - new Date(session.last_active).getTime();
309
+ const pathExists = fs.existsSync(session.path);
310
+
311
+ // Check for orphaned registry entry (path missing)
312
+ if (!pathExists) {
313
+ health.orphanedRegistry.push({ id, ...session, reason: 'path_missing' });
314
+ continue;
315
+ }
316
+
317
+ // Check for stale session
318
+ if (age > staleThreshold) {
319
+ health.stale.push({
320
+ id,
321
+ ...session,
322
+ ageDays: Math.floor(age / (24 * 60 * 60 * 1000)),
323
+ });
324
+ }
325
+
326
+ // Check for uncommitted changes
327
+ try {
328
+ const result = spawnSync('git', ['status', '--porcelain'], {
329
+ cwd: session.path,
330
+ encoding: 'utf8',
331
+ timeout: 5000,
332
+ });
333
+ if (result.stdout && result.stdout.trim()) {
334
+ // Don't use trim() on the whole string - it removes leading space from first status
335
+ // Split by newline and filter empty lines instead
336
+ const changes = result.stdout.split('\n').filter((line) => line.length > 0);
337
+ const sessionData = {
338
+ id,
339
+ ...session,
340
+ changeCount: changes.length,
341
+ changes: detailed ? changes : changes.slice(0, 5), // All or first 5
342
+ };
343
+
344
+ // Add detailed file analysis if requested
345
+ if (detailed) {
346
+ sessionData.fileDetails = getFileDetails(session.path, changes);
347
+ // Calculate if session is safe to delete (all changes trivial)
348
+ sessionData.allTrivial = sessionData.fileDetails.every((f) => f.trivial);
349
+ }
350
+
351
+ health.uncommitted.push(sessionData);
352
+ } else {
353
+ health.healthy++;
354
+ }
355
+ } catch (e) {
356
+ // Can't check, skip
357
+ }
358
+ }
359
+
360
+ // Check for orphaned worktrees (directories not in registry)
361
+ try {
362
+ const worktreeList = spawnSync('git', ['worktree', 'list', '--porcelain'], {
363
+ encoding: 'utf8',
364
+ });
365
+ if (worktreeList.stdout) {
366
+ const worktrees = worktreeList.stdout
367
+ .split('\n')
368
+ .filter((line) => line.startsWith('worktree '))
369
+ .map((line) => line.replace('worktree ', ''));
370
+
371
+ const mainPath = ROOT;
372
+ for (const wtPath of worktrees) {
373
+ const inRegistry = Object.values(registry.sessions).some((s) => s.path === wtPath);
374
+ if (!inRegistry && wtPath !== mainPath) {
375
+ // Check if it's an AgileFlow worktree (has .agileflow folder)
376
+ if (fs.existsSync(path.join(wtPath, '.agileflow'))) {
377
+ health.orphanedWorktrees.push({ path: wtPath });
378
+ }
379
+ }
380
+ }
381
+ }
382
+ } catch (e) {
383
+ // Can't list worktrees, skip
384
+ }
385
+
386
+ return health;
387
+ }
388
+
234
389
  // Git command cache (10 second TTL to avoid stale data)
235
390
  const gitCache = {
236
391
  data: new Map(),
@@ -432,7 +587,11 @@ function progressIndicator(message) {
432
587
  * @param {number} timeoutMs - Timeout in milliseconds
433
588
  * @returns {Promise<{stdout: string, stderr: string}>}
434
589
  */
435
- function createWorktreeWithTimeout(worktreePath, branchName, timeoutMs = DEFAULT_WORKTREE_TIMEOUT_MS) {
590
+ function createWorktreeWithTimeout(
591
+ worktreePath,
592
+ branchName,
593
+ timeoutMs = DEFAULT_WORKTREE_TIMEOUT_MS
594
+ ) {
436
595
  return new Promise((resolve, reject) => {
437
596
  let stdout = '';
438
597
  let stderr = '';
@@ -455,15 +614,15 @@ function createWorktreeWithTimeout(worktreePath, branchName, timeoutMs = DEFAULT
455
614
  }, 1000);
456
615
  }, timeoutMs);
457
616
 
458
- proc.stdout.on('data', (data) => {
617
+ proc.stdout.on('data', data => {
459
618
  stdout += data.toString();
460
619
  });
461
620
 
462
- proc.stderr.on('data', (data) => {
621
+ proc.stderr.on('data', data => {
463
622
  stderr += data.toString();
464
623
  });
465
624
 
466
- proc.on('error', (err) => {
625
+ proc.on('error', err => {
467
626
  clearTimeout(timer);
468
627
  reject(new Error(`Failed to spawn git: ${err.message}`));
469
628
  });
@@ -472,7 +631,11 @@ function createWorktreeWithTimeout(worktreePath, branchName, timeoutMs = DEFAULT
472
631
  clearTimeout(timer);
473
632
 
474
633
  if (timedOut) {
475
- reject(new Error(`Worktree creation timed out after ${timeoutMs / 1000}s. Try increasing timeout or check disk space.`));
634
+ reject(
635
+ new Error(
636
+ `Worktree creation timed out after ${timeoutMs / 1000}s. Try increasing timeout or check disk space.`
637
+ )
638
+ );
476
639
  return;
477
640
  }
478
641
 
@@ -601,7 +764,9 @@ async function createSession(options = {}) {
601
764
  const timeoutMs = options.timeout || DEFAULT_WORKTREE_TIMEOUT_MS;
602
765
 
603
766
  // Create worktree with timeout and progress feedback
604
- const stopProgress = progressIndicator('Creating worktree (this may take a while for large repos)');
767
+ const stopProgress = progressIndicator(
768
+ 'Creating worktree (this may take a while for large repos)'
769
+ );
605
770
  try {
606
771
  await createWorktreeWithTimeout(worktreePath, branchName, timeoutMs);
607
772
  stopProgress();
@@ -1300,16 +1465,23 @@ function main() {
1300
1465
  if (options.timeout) {
1301
1466
  options.timeout = parseInt(options.timeout, 10);
1302
1467
  if (isNaN(options.timeout) || options.timeout < 1000) {
1303
- console.log(JSON.stringify({ success: false, error: 'Timeout must be a number >= 1000 (milliseconds)' }));
1468
+ console.log(
1469
+ JSON.stringify({
1470
+ success: false,
1471
+ error: 'Timeout must be a number >= 1000 (milliseconds)',
1472
+ })
1473
+ );
1304
1474
  return;
1305
1475
  }
1306
1476
  }
1307
1477
  // Handle async createSession
1308
- createSession(options).then(result => {
1309
- console.log(JSON.stringify(result));
1310
- }).catch(err => {
1311
- console.log(JSON.stringify({ success: false, error: err.message }));
1312
- });
1478
+ createSession(options)
1479
+ .then(result => {
1480
+ console.log(JSON.stringify(result));
1481
+ })
1482
+ .catch(err => {
1483
+ console.log(JSON.stringify({ success: false, error: err.message }));
1484
+ });
1313
1485
  break;
1314
1486
  }
1315
1487
 
@@ -1361,6 +1533,17 @@ function main() {
1361
1533
  break;
1362
1534
  }
1363
1535
 
1536
+ case 'health': {
1537
+ // Get health status for all sessions
1538
+ // Usage: health [staleDays] [--detailed]
1539
+ const staleDaysArg = args.find((a) => /^\d+$/.test(a));
1540
+ const staleDays = staleDaysArg ? parseInt(staleDaysArg, 10) : 7;
1541
+ const detailed = args.includes('--detailed');
1542
+ const health = getSessionsHealth({ staleDays, detailed });
1543
+ console.log(JSON.stringify(health));
1544
+ break;
1545
+ }
1546
+
1364
1547
  case 'get': {
1365
1548
  const sessionId = args[1];
1366
1549
  if (!sessionId) {
@@ -64,16 +64,24 @@ function hasScreen() {
64
64
  * Build the Claude command for a session
65
65
  */
66
66
  function buildClaudeCommand(sessionPath, options = {}) {
67
- const { init = false, dangerous = false, prompt = null } = options;
67
+ const { init = false, dangerous = false, prompt = null, claudeArgs = null, noClaude = false } = options;
68
68
  const parts = [`cd "${sessionPath}"`];
69
69
 
70
70
  if (init) {
71
71
  parts.push('claude init --yes 2>/dev/null || true');
72
72
  }
73
73
 
74
+ // If noClaude is true, just return cd command (no claude startup)
75
+ if (noClaude) {
76
+ return parts.join(' && ');
77
+ }
78
+
74
79
  let claudeCmd = 'claude';
75
80
  if (dangerous) {
76
- claudeCmd = 'claude --dangerouslySkipPermissions';
81
+ claudeCmd = 'claude --dangerously-skip-permissions';
82
+ } else if (claudeArgs) {
83
+ // Custom claude arguments (e.g., --permission-mode acceptEdits)
84
+ claudeCmd = `claude ${claudeArgs}`;
77
85
  }
78
86
 
79
87
  if (prompt) {
@@ -215,7 +223,7 @@ function getReadyStoriesFromEpic(epicId) {
215
223
  /**
216
224
  * Main spawn command
217
225
  */
218
- function spawn(args) {
226
+ async function spawn(args) {
219
227
  const count = args.count ? parseInt(args.count, 10) : null;
220
228
  const branches = args.branches ? args.branches.split(',').map(b => b.trim()) : null;
221
229
  const fromEpic = args['from-epic'] || args.fromEpic;
@@ -223,6 +231,8 @@ function spawn(args) {
223
231
  const init = args.init || false;
224
232
  const dangerous = args.dangerous || false;
225
233
  const prompt = args.prompt || null;
234
+ const claudeArgs = args['claude-args'] || args.claudeArgs || null;
235
+ const noClaude = args['no-claude'] || args.noClaude || false;
226
236
 
227
237
  // Determine what to create
228
238
  let sessionsToCreate = [];
@@ -276,7 +286,7 @@ function spawn(args) {
276
286
 
277
287
  const createdSessions = [];
278
288
  for (const sessionSpec of sessionsToCreate) {
279
- const result = sessionManager.createSession({
289
+ const result = await sessionManager.createSession({
280
290
  nickname: sessionSpec.nickname,
281
291
  branch: sessionSpec.branch,
282
292
  });
@@ -311,10 +321,10 @@ function spawn(args) {
311
321
  // Spawn in tmux or output commands
312
322
  if (noTmux) {
313
323
  // User explicitly requested manual mode
314
- outputCommands(createdSessions, { init, dangerous, prompt });
324
+ outputCommands(createdSessions, { init, dangerous, prompt, claudeArgs, noClaude });
315
325
  } else if (hasTmux()) {
316
326
  // Tmux available - use it
317
- const tmuxResult = spawnInTmux(createdSessions, { init, dangerous, prompt });
327
+ const tmuxResult = spawnInTmux(createdSessions, { init, dangerous, prompt, claudeArgs, noClaude });
318
328
 
319
329
  if (tmuxResult.success) {
320
330
  console.log(success(`\n✅ Tmux session created: ${tmuxResult.sessionName}`));
@@ -326,7 +336,7 @@ function spawn(args) {
326
336
  console.log('');
327
337
  } else {
328
338
  console.error(error(`Failed to create tmux session: ${tmuxResult.error}`));
329
- outputCommands(createdSessions, { init, dangerous, prompt });
339
+ outputCommands(createdSessions, { init, dangerous, prompt, claudeArgs, noClaude });
330
340
  }
331
341
  } else {
332
342
  // Tmux NOT available - require it or use --no-tmux
@@ -392,9 +402,12 @@ function list() {
392
402
  /**
393
403
  * Add a new window to an existing tmux session
394
404
  */
395
- function addWindow(args) {
405
+ async function addWindow(args) {
396
406
  const nickname = args.nickname || args.name || null;
397
407
  const branch = args.branch || null;
408
+ const dangerous = args.dangerous || false;
409
+ const claudeArgs = args['claude-args'] || args.claudeArgs || null;
410
+ const noClaude = args['no-claude'] || args.noClaude || false;
398
411
 
399
412
  // Check if we're inside a tmux session
400
413
  const tmuxEnv = process.env.TMUX;
@@ -427,7 +440,7 @@ function addWindow(args) {
427
440
  branch: branch || `parallel-${Date.now()}`,
428
441
  };
429
442
 
430
- const result = sessionManager.createSession({
443
+ const result = await sessionManager.createSession({
431
444
  nickname: sessionSpec.nickname,
432
445
  branch: sessionSpec.branch,
433
446
  });
@@ -438,7 +451,7 @@ function addWindow(args) {
438
451
  }
439
452
 
440
453
  const windowName = sessionSpec.nickname;
441
- const cmd = buildClaudeCommand(result.path, {});
454
+ const cmd = buildClaudeCommand(result.path, { dangerous, claudeArgs, noClaude });
442
455
 
443
456
  // Create new window in current tmux session
444
457
  const newWindowResult = spawnSync(
@@ -551,7 +564,9 @@ ${c.cyan}SPAWN OPTIONS:${c.reset}
551
564
  --branches "a,b,c" Create worktrees for specific branch names
552
565
  --from-epic EP-XXX Create worktrees for ready stories in epic
553
566
  --init Run 'claude init' in each worktree
554
- --dangerous Use --dangerouslySkipPermissions
567
+ --dangerous Use --dangerously-skip-permissions
568
+ --claude-args "..." Custom arguments for claude command
569
+ --no-claude Create worktree but don't start claude
555
570
  --no-tmux Output commands without spawning in tmux
556
571
  --prompt "TEXT" Initial prompt to send to each Claude instance
557
572
 
@@ -575,6 +590,9 @@ ${c.cyan}ADD-WINDOW OPTIONS:${c.reset}
575
590
  --name NAME Name for the new session/window
576
591
  --nickname NAME Alias for --name
577
592
  --branch BRANCH Use specific branch name
593
+ --dangerous Use --dangerously-skip-permissions
594
+ --claude-args "..." Custom arguments for claude command
595
+ --no-claude Create worktree but don't start claude
578
596
 
579
597
  ${c.cyan}ADD-WINDOW EXAMPLES:${c.reset}
580
598
  ${dim('# Add window with auto-generated name (when in tmux)')}
@@ -582,6 +600,15 @@ ${c.cyan}ADD-WINDOW EXAMPLES:${c.reset}
582
600
 
583
601
  ${dim('# Add named window')}
584
602
  node scripts/spawn-parallel.js add-window --name auth
603
+
604
+ ${dim('# Add window without starting claude')}
605
+ node scripts/spawn-parallel.js add-window --name research --no-claude
606
+
607
+ ${dim('# Add window with skip permissions')}
608
+ node scripts/spawn-parallel.js add-window --name trusted --dangerous
609
+
610
+ ${dim('# Add window with custom claude args')}
611
+ node scripts/spawn-parallel.js add-window --name safe --claude-args "--permission-mode acceptEdits"
585
612
  `);
586
613
  }
587
614
 
@@ -616,16 +643,16 @@ function parseArgs(argv) {
616
643
  /**
617
644
  * Main entry point
618
645
  */
619
- function main() {
646
+ async function main() {
620
647
  const { command, args } = parseArgs(process.argv.slice(2));
621
648
 
622
649
  switch (command) {
623
650
  case 'spawn':
624
- spawn(args);
651
+ await spawn(args);
625
652
  break;
626
653
  case 'add-window':
627
654
  case 'add':
628
- addWindow(args);
655
+ await addWindow(args);
629
656
  break;
630
657
  case 'list':
631
658
  list();
@@ -189,131 +189,8 @@ BOUNDARIES
189
189
  - Always prioritize real user needs over technical convenience
190
190
 
191
191
 
192
- SESSION HARNESS & VERIFICATION PROTOCOL (v2.25.0+)
192
+ <!-- {{SESSION_HARNESS}} -->
193
193
 
194
- **CRITICAL**: Session Harness System prevents agents from breaking functionality, claiming work is done when tests fail, or losing context between sessions.
195
-
196
- **PRE-IMPLEMENTATION VERIFICATION**
197
-
198
- Before starting work on ANY story:
199
-
200
- 1. **Check Session Harness**:
201
- - Look for `docs/00-meta/environment.json`
202
- - If exists → Session harness is active ✅
203
- - If missing → Suggest `/agileflow:session:init` to user
204
-
205
- 2. **Test Baseline Check**:
206
- - Read `test_status` from story in `docs/09-agents/status.json`
207
- - If `"passing"` → Proceed with implementation ✅
208
- - If `"failing"` → STOP. Cannot start new work with failing baseline ⚠️
209
- - If `"not_run"` → Run `/agileflow:verify` first to establish baseline
210
- - If `"skipped"` → Check why tests are skipped, document override decision
211
-
212
- 3. **Environment Verification** (if session harness active):
213
- - Run `/agileflow:session:resume` to verify environment and load context
214
- - Check for regressions (tests were passing, now failing)
215
- - If regression detected → Fix before proceeding with new story
216
-
217
- **DURING IMPLEMENTATION**
218
-
219
- 1. **Incremental Testing**:
220
- - Run tests frequently during development (not just at end)
221
- - Fix test failures immediately (don't accumulate debt)
222
- - Use `/agileflow:verify US-XXXX` to check specific story tests
223
-
224
- 2. **Real-time Status Updates**:
225
- - Update `test_status` in status.json as tests are written/fixed
226
- - Append bus messages when tests pass milestone checkpoints
227
-
228
- **POST-IMPLEMENTATION VERIFICATION**
229
-
230
- After completing ANY changes:
231
-
232
- 1. **Run Full Test Suite**:
233
- - Execute `/agileflow:verify US-XXXX` to run tests for the story
234
- - Check exit code (0 = success required for completion)
235
- - Review test output for warnings or flaky tests
236
-
237
- 2. **Update Test Status**:
238
- - `/agileflow:verify` automatically updates `test_status` in status.json
239
- - Verify the update was successful
240
- - Expected: `test_status: "passing"` with test results metadata
241
-
242
- 3. **Regression Check**:
243
- - Compare test results to baseline (initial test status)
244
- - If new failures introduced → Fix before marking complete
245
- - If test count decreased → Investigate deleted tests
246
-
247
- 4. **Story Completion Requirements**:
248
- - Story can ONLY be marked `"in-review"` if `test_status: "passing"` ✅
249
- - If tests failing → Story remains `"in-progress"` until fixed ⚠️
250
- - No exceptions unless documented override (see below)
251
-
252
- **OVERRIDE PROTOCOL** (Use with extreme caution)
253
-
254
- If tests are failing but you need to proceed:
255
-
256
- 1. **Document Override Decision**:
257
- - Append bus message with full explanation (include agent ID, story ID, reason, tracking issue)
258
-
259
- 2. **Update Story Dev Agent Record**:
260
- - Add note to "Issues Encountered" section explaining override
261
- - Link to tracking issue for the failing test
262
- - Document risk and mitigation plan
263
-
264
- 3. **Create Follow-up Story**:
265
- - If test failure is real but out of scope → Create new story
266
- - Link dependency in status.json
267
- - Notify user of the override and follow-up story
268
-
269
- **BASELINE MANAGEMENT**
270
-
271
- After completing major milestones (epic complete, sprint end):
272
-
273
- 1. **Establish Baseline**:
274
- - Suggest `/agileflow:baseline "Epic EP-XXXX complete"` to user
275
- - Requires: All tests passing, git working tree clean
276
- - Creates git tag + metadata for reset point
277
-
278
- 2. **Baseline Benefits**:
279
- - Known-good state to reset to if needed
280
- - Regression detection reference point
281
- - Deployment readiness checkpoint
282
- - Sprint/epic completion marker
283
-
284
- **INTEGRATION WITH WORKFLOW**
285
-
286
- The verification protocol integrates into the standard workflow:
287
-
288
- 1. **Before creating feature branch**: Run pre-implementation verification
289
- 2. **Before marking in-review**: Run post-implementation verification
290
- 3. **After merge**: Verify baseline is still passing
291
-
292
- **ERROR HANDLING**
293
-
294
- If `/agileflow:verify` fails:
295
- - Read error output carefully
296
- - Check if test command is configured in `docs/00-meta/environment.json`
297
- - Verify test dependencies are installed
298
- - If project has no tests → Suggest `/agileflow:session:init` to set up testing
299
- - If tests are misconfigured → Coordinate with AG-CI
300
-
301
- **SESSION RESUME PROTOCOL**
302
-
303
- When resuming work after context loss:
304
-
305
- 1. **Run Resume Command**: `/agileflow:session:resume` loads context automatically
306
- 2. **Check Session State**: Review `docs/09-agents/session-state.json`
307
- 3. **Verify Test Status**: Ensure no regressions occurred
308
- 4. **Load Previous Insights**: Check Dev Agent Record from previous stories
309
-
310
- **KEY PRINCIPLES**
311
-
312
- - **Tests are the contract**: Passing tests = feature works as specified
313
- - **Fail fast**: Catch regressions immediately, not at PR review
314
- - **Context preservation**: Session harness maintains progress across context windows
315
- - **Transparency**: Document all override decisions fully
316
- - **Accountability**: test_status field creates audit trail
317
194
 
318
195
  WCAG 2.1 STANDARDS
319
196
 
@@ -554,7 +431,9 @@ WORKFLOW
554
431
 
555
432
  10. Sync externally if enabled
556
433
 
557
- QUALITY CHECKLIST
434
+ <!-- {{QUALITY_GATE_PRIORITIES}} -->
435
+
436
+ QUALITY CHECKLIST (AG-ACCESSIBILITY Specific)
558
437
 
559
438
  Before approval:
560
439
  - [ ] WCAG 2.1 Level AA compliance verified
@@ -568,6 +447,21 @@ Before approval:
568
447
  - [ ] Motion respects prefers-reduced-motion
569
448
  - [ ] Accessibility documentation complete
570
449
 
450
+ AGENT COORDINATION
451
+
452
+ **Coordinates with**:
453
+ - **AG-UI**: Accessibility in UI components (send a11y findings, receive implementation questions)
454
+ - **AG-DESIGN**: Design system accessibility (send contrast/focus requirements, coordinate on design tokens)
455
+ - **AG-QA**: Accessibility testing (send test criteria, receive test results)
456
+
457
+ **Bus Messages** (append to `docs/09-agents/bus/log.jsonl`):
458
+ ```jsonl
459
+ {"ts":"<ISO>","from":"AG-ACCESSIBILITY","type":"finding","story":"<US-ID>","text":"Finding: Component [X] missing keyboard navigation"}
460
+ {"ts":"<ISO>","from":"AG-ACCESSIBILITY","type":"status","story":"<US-ID>","text":"A11y audit complete: WCAG AA compliance verified"}
461
+ ```
462
+
463
+ **On invocation**: Check bus for AG-UI requests for accessibility review.
464
+
571
465
  FIRST ACTION
572
466
 
573
467
  **CRITICAL: Load Expertise First (Agent Expert Protocol)**
@@ -362,7 +362,9 @@ ADR TEMPLATE STRUCTURE
362
362
  - [Title](URL) - Description
363
363
  ```
364
364
 
365
- QUALITY CHECKLIST
365
+ <!-- {{QUALITY_GATE_PRIORITIES}} -->
366
+
367
+ QUALITY CHECKLIST (AG-ADR-WRITER Specific)
366
368
  Before creating ADR:
367
369
  - [ ] Context explains why decision is needed now
368
370
  - [ ] At least 2 alternatives documented
@@ -388,6 +390,21 @@ TONE
388
390
  - Avoid advocacy (document, don't persuade)
389
391
  - Focus on context and reasoning, not implementation details
390
392
 
393
+ AGENT COORDINATION
394
+
395
+ **Coordinates with**:
396
+ - **AG-RESEARCH**: Technical research (receive research findings, document decisions)
397
+ - **AG-PRODUCT**: Product decisions (receive feature requirements, document trade-offs)
398
+ - **AG-EPIC-PLANNER**: Epic planning (send architectural constraints, receive epic context)
399
+
400
+ **Bus Messages** (append to `docs/09-agents/bus/log.jsonl`):
401
+ ```jsonl
402
+ {"ts":"<ISO>","from":"AG-ADR-WRITER","type":"status","story":"<US-ID>","text":"ADR-XXXX created: [decision title]"}
403
+ {"ts":"<ISO>","from":"AG-ADR-WRITER","type":"finding","story":"<US-ID>","text":"Finding: Existing ADR-YYYY conflicts with proposed approach"}
404
+ ```
405
+
406
+ **On invocation**: Check bus for architectural decisions that need documentation.
407
+
391
408
  FIRST ACTION
392
409
 
393
410
  **CRITICAL: Load Expertise First (Agent Expert Protocol)**