agileflow 2.92.1 → 2.94.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 +10 -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 +54 -0
  6. package/scripts/document-repl.js +793 -0
  7. package/scripts/session-manager.js +230 -16
  8. package/scripts/spawn-parallel.js +53 -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 +338 -0
@@ -12,6 +12,11 @@
12
12
  * <!-- {{AGENT_LIST}} --> - Full formatted agent list
13
13
  * <!-- {{COMMAND_LIST}} --> - Full formatted command list
14
14
  *
15
+ * TEMPLATES:
16
+ * <!-- {{SESSION_HARNESS}} --> - Session harness protocol (generic)
17
+ * <!-- {{SESSION_HARNESS:AG-API}} --> - Session harness protocol (with agent ID)
18
+ * <!-- {{QUALITY_GATE_PRIORITIES}} --> - Quality gate priorities (CRITICAL/HIGH/MEDIUM)
19
+ *
15
20
  * METADATA:
16
21
  * {{VERSION}} - AgileFlow version from package.json
17
22
  * {{INSTALL_DATE}} - Date of installation (YYYY-MM-DD)
@@ -225,6 +230,239 @@ function generateCommandList(commandsDir) {
225
230
  return output;
226
231
  }
227
232
 
233
+ // =============================================================================
234
+ // Template Generation Functions
235
+ // =============================================================================
236
+
237
+ /**
238
+ * Session harness template cache
239
+ * @type {string|null}
240
+ */
241
+ let sessionHarnessTemplateCache = null;
242
+
243
+ /**
244
+ * Quality gate priorities template cache
245
+ * @type {string|null}
246
+ */
247
+ let qualityGatePrioritiesCache = null;
248
+
249
+ /**
250
+ * Load session harness template from templates directory
251
+ * @param {string} coreDir - Path to core directory
252
+ * @returns {string} Template content or empty string if not found
253
+ */
254
+ function loadSessionHarnessTemplate(coreDir) {
255
+ // Return cached template if available
256
+ if (sessionHarnessTemplateCache !== null) {
257
+ return sessionHarnessTemplateCache;
258
+ }
259
+
260
+ const templatePath = path.join(coreDir, 'templates', 'session-harness-protocol.md');
261
+
262
+ if (!fs.existsSync(templatePath)) {
263
+ // Template not found, return empty string
264
+ sessionHarnessTemplateCache = '';
265
+ return sessionHarnessTemplateCache;
266
+ }
267
+
268
+ // Validate path is within core directory (security)
269
+ if (!isPathSafe(templatePath, coreDir)) {
270
+ sessionHarnessTemplateCache = '';
271
+ return sessionHarnessTemplateCache;
272
+ }
273
+
274
+ try {
275
+ sessionHarnessTemplateCache = fs.readFileSync(templatePath, 'utf8');
276
+ return sessionHarnessTemplateCache;
277
+ } catch (err) {
278
+ sessionHarnessTemplateCache = '';
279
+ return sessionHarnessTemplateCache;
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Generate session harness protocol content for a specific agent
285
+ * @param {string} coreDir - Path to core directory
286
+ * @param {string} agentId - Agent ID (e.g., "AG-API", "AG-UI")
287
+ * @returns {string} Session harness content with agent ID substituted
288
+ */
289
+ function generateSessionHarnessContent(coreDir, agentId = 'AGENT') {
290
+ const template = loadSessionHarnessTemplate(coreDir);
291
+
292
+ if (!template) {
293
+ return '';
294
+ }
295
+
296
+ // Substitute agent ID in the template
297
+ // The template uses {AGENT_ID} as placeholder
298
+ return template.replace(/\{AGENT_ID\}/g, agentId);
299
+ }
300
+
301
+ /**
302
+ * Clear the session harness template cache
303
+ * Useful for testing or when template file changes
304
+ */
305
+ function clearSessionHarnessCache() {
306
+ sessionHarnessTemplateCache = null;
307
+ }
308
+
309
+ /**
310
+ * Load quality gate priorities template from templates directory
311
+ * @param {string} coreDir - Path to core directory
312
+ * @returns {string} Template content or empty string if not found
313
+ */
314
+ function loadQualityGatePrioritiesTemplate(coreDir) {
315
+ // Return cached template if available
316
+ if (qualityGatePrioritiesCache !== null) {
317
+ return qualityGatePrioritiesCache;
318
+ }
319
+
320
+ const templatePath = path.join(coreDir, 'templates', 'quality-gate-priorities.md');
321
+
322
+ if (!fs.existsSync(templatePath)) {
323
+ qualityGatePrioritiesCache = '';
324
+ return qualityGatePrioritiesCache;
325
+ }
326
+
327
+ // Validate path is within core directory (security)
328
+ if (!isPathSafe(templatePath, coreDir)) {
329
+ qualityGatePrioritiesCache = '';
330
+ return qualityGatePrioritiesCache;
331
+ }
332
+
333
+ try {
334
+ qualityGatePrioritiesCache = fs.readFileSync(templatePath, 'utf8');
335
+ return qualityGatePrioritiesCache;
336
+ } catch (err) {
337
+ qualityGatePrioritiesCache = '';
338
+ return qualityGatePrioritiesCache;
339
+ }
340
+ }
341
+
342
+ /**
343
+ * Generate quality gate priorities content for a specific agent
344
+ * @param {string} coreDir - Path to core directory
345
+ * @param {string} agentId - Agent ID (e.g., "AG-API", "AG-UI")
346
+ * @returns {string} Quality gate priorities content with agent ID substituted
347
+ */
348
+ function generateQualityGatePrioritiesContent(coreDir, agentId = 'AGENT') {
349
+ const template = loadQualityGatePrioritiesTemplate(coreDir);
350
+
351
+ if (!template) {
352
+ return '';
353
+ }
354
+
355
+ // Substitute placeholders in the template
356
+ return template
357
+ .replace(/\{AGENT_ID\}/g, agentId)
358
+ .replace(/\{TIMESTAMP\}/g, new Date().toISOString())
359
+ .replace(/\{STORY_ID\}/g, 'US-XXXX');
360
+ }
361
+
362
+ /**
363
+ * Clear the quality gate priorities template cache
364
+ * Useful for testing or when template file changes
365
+ */
366
+ function clearQualityGatePrioritiesCache() {
367
+ qualityGatePrioritiesCache = null;
368
+ }
369
+
370
+ // =============================================================================
371
+ // Preserve Rules Expansion Functions
372
+ // =============================================================================
373
+
374
+ /**
375
+ * Preserve rules template cache
376
+ * @type {Object|null}
377
+ */
378
+ let preserveRulesCache = null;
379
+
380
+ /**
381
+ * Load preserve rules definitions from templates directory
382
+ * @param {string} coreDir - Path to core directory
383
+ * @returns {Object} Rules object with category keys and rule arrays
384
+ */
385
+ function loadPreserveRules(coreDir) {
386
+ // Return cached rules if available
387
+ if (preserveRulesCache !== null) {
388
+ return preserveRulesCache;
389
+ }
390
+
391
+ const rulesPath = path.join(coreDir, 'templates', 'preserve-rules.json');
392
+
393
+ if (!fs.existsSync(rulesPath)) {
394
+ preserveRulesCache = {};
395
+ return preserveRulesCache;
396
+ }
397
+
398
+ // Validate path is within core directory (security)
399
+ if (!isPathSafe(rulesPath, coreDir)) {
400
+ preserveRulesCache = {};
401
+ return preserveRulesCache;
402
+ }
403
+
404
+ try {
405
+ const content = fs.readFileSync(rulesPath, 'utf8');
406
+ preserveRulesCache = JSON.parse(content);
407
+ return preserveRulesCache;
408
+ } catch (err) {
409
+ preserveRulesCache = {};
410
+ return preserveRulesCache;
411
+ }
412
+ }
413
+
414
+ /**
415
+ * Expand preserve rules placeholders in content
416
+ * Replaces "{{RULES:category}}" with actual rule strings from the template
417
+ *
418
+ * @param {string} content - Content with preserve rules placeholders
419
+ * @param {string} coreDir - Path to core directory
420
+ * @returns {string} Content with rules expanded
421
+ */
422
+ function expandPreserveRules(content, coreDir) {
423
+ const rules = loadPreserveRules(coreDir);
424
+
425
+ if (!rules || Object.keys(rules).length === 0) {
426
+ return content;
427
+ }
428
+
429
+ // Pattern matches: - "{{RULES:category}}" in YAML preserve_rules arrays
430
+ // We need to handle the YAML list context carefully
431
+ const pattern = /- "\{\{RULES:(\w+)\}\}"/g;
432
+
433
+ return content.replace(pattern, (match, category) => {
434
+ const ruleList = rules[category];
435
+
436
+ if (!ruleList || !Array.isArray(ruleList) || ruleList.length === 0) {
437
+ // Unknown category or empty, keep original placeholder as warning
438
+ return match;
439
+ }
440
+
441
+ // Sanitize rules before injecting
442
+ const sanitizedRules = ruleList.map(rule => {
443
+ // Escape double quotes in rule text
444
+ const escaped = String(rule).replace(/"/g, '\\"');
445
+ // Validate it's a reasonable rule string
446
+ if (escaped.length > 500) {
447
+ return escaped.substring(0, 500);
448
+ }
449
+ return escaped;
450
+ });
451
+
452
+ // Return expanded rules as YAML list items with proper indentation
453
+ // Each rule becomes: - "rule text"
454
+ return sanitizedRules.map(rule => `- "${rule}"`).join('\n ');
455
+ });
456
+ }
457
+
458
+ /**
459
+ * Clear the preserve rules template cache
460
+ * Useful for testing or when template file changes
461
+ */
462
+ function clearPreserveRulesCache() {
463
+ preserveRulesCache = null;
464
+ }
465
+
228
466
  // =============================================================================
229
467
  // Main Injection Function
230
468
  // =============================================================================
@@ -243,6 +481,11 @@ function injectContent(content, context = {}) {
243
481
 
244
482
  let result = content;
245
483
 
484
+ // Expand preserve rules placeholders first (YAML frontmatter processing)
485
+ if (coreDir && fs.existsSync(coreDir) && result.includes('{{RULES:')) {
486
+ result = expandPreserveRules(result, coreDir);
487
+ }
488
+
246
489
  // Get counts if core directory is available
247
490
  let counts = { commands: 0, agents: 0, skills: 0 };
248
491
  if (coreDir && fs.existsSync(coreDir)) {
@@ -283,6 +526,69 @@ function injectContent(content, context = {}) {
283
526
  result = result.replace(/<!-- \{\{COMMAND_LIST\}\} -->/g, commandList);
284
527
  result = result.replace(/\{\{COMMAND_LIST\}\}/g, commandList);
285
528
  }
529
+
530
+ // Replace session harness template placeholder
531
+ // Supports two formats:
532
+ // <!-- {{SESSION_HARNESS}} --> - Uses default agent ID
533
+ // <!-- {{SESSION_HARNESS:AG-API}} --> - Uses specified agent ID
534
+ if (result.includes('SESSION_HARNESS')) {
535
+ // First, handle agent-specific format: <!-- {{SESSION_HARNESS:AG-XXX}} -->
536
+ const agentSpecificPattern = /<!-- \{\{SESSION_HARNESS:(AG-[A-Z]+)\}\} -->/g;
537
+ result = result.replace(agentSpecificPattern, (match, agentId) => {
538
+ return generateSessionHarnessContent(coreDir, agentId);
539
+ });
540
+
541
+ // Then, handle generic format: <!-- {{SESSION_HARNESS}} -->
542
+ // Try to extract agent ID from frontmatter name field if available
543
+ const genericPattern = /<!-- \{\{SESSION_HARNESS\}\} -->/g;
544
+ result = result.replace(genericPattern, () => {
545
+ // Try to get agent ID from frontmatter 'name' field
546
+ // Look for "name: agileflow-xxx" pattern in the content
547
+ const frontmatterMatch = result.match(/^---[\s\S]*?name:\s*(agileflow-)?(\w+)[\s\S]*?---/m);
548
+ let agentId = 'AGENT';
549
+ if (frontmatterMatch && frontmatterMatch[2]) {
550
+ // Convert agent name to uppercase agent ID format
551
+ // e.g., "api" -> "AG-API", "ui" -> "AG-UI"
552
+ agentId = `AG-${frontmatterMatch[2].toUpperCase()}`;
553
+ }
554
+ return generateSessionHarnessContent(coreDir, agentId);
555
+ });
556
+
557
+ // Also handle non-comment format: {{SESSION_HARNESS}}
558
+ result = result.replace(/\{\{SESSION_HARNESS\}\}/g, () => {
559
+ const frontmatterMatch = result.match(/^---[\s\S]*?name:\s*(agileflow-)?(\w+)[\s\S]*?---/m);
560
+ let agentId = 'AGENT';
561
+ if (frontmatterMatch && frontmatterMatch[2]) {
562
+ agentId = `AG-${frontmatterMatch[2].toUpperCase()}`;
563
+ }
564
+ return generateSessionHarnessContent(coreDir, agentId);
565
+ });
566
+ }
567
+
568
+ // Replace quality gate priorities template placeholder
569
+ // Supports: <!-- {{QUALITY_GATE_PRIORITIES}} -->
570
+ if (result.includes('QUALITY_GATE_PRIORITIES')) {
571
+ // Handle comment format: <!-- {{QUALITY_GATE_PRIORITIES}} -->
572
+ const qualityGatePattern = /<!-- \{\{QUALITY_GATE_PRIORITIES\}\} -->/g;
573
+ result = result.replace(qualityGatePattern, () => {
574
+ const frontmatterMatch = result.match(/^---[\s\S]*?name:\s*(agileflow-)?(\w+)[\s\S]*?---/m);
575
+ let agentId = 'AGENT';
576
+ if (frontmatterMatch && frontmatterMatch[2]) {
577
+ agentId = `AG-${frontmatterMatch[2].toUpperCase()}`;
578
+ }
579
+ return generateQualityGatePrioritiesContent(coreDir, agentId);
580
+ });
581
+
582
+ // Also handle non-comment format: {{QUALITY_GATE_PRIORITIES}}
583
+ result = result.replace(/\{\{QUALITY_GATE_PRIORITIES\}\}/g, () => {
584
+ const frontmatterMatch = result.match(/^---[\s\S]*?name:\s*(agileflow-)?(\w+)[\s\S]*?---/m);
585
+ let agentId = 'AGENT';
586
+ if (frontmatterMatch && frontmatterMatch[2]) {
587
+ agentId = `AG-${frontmatterMatch[2].toUpperCase()}`;
588
+ }
589
+ return generateQualityGatePrioritiesContent(coreDir, agentId);
590
+ });
591
+ }
286
592
  }
287
593
 
288
594
  // Replace folder placeholders with sanitized values
@@ -380,6 +686,9 @@ function hasPlaceholders(content) {
380
686
  /\{\{INSTALL_DATE\}\}/,
381
687
  /\{\{AGENT_LIST\}\}/,
382
688
  /\{\{COMMAND_LIST\}\}/,
689
+ /\{\{SESSION_HARNESS\}\}/,
690
+ /\{\{QUALITY_GATE_PRIORITIES\}\}/,
691
+ /\{\{RULES:\w+\}\}/,
383
692
  /\{agileflow_folder\}/,
384
693
  ];
385
694
 
@@ -401,6 +710,25 @@ function getPlaceholderDocs() {
401
710
  '<!-- {{AGENT_LIST}} -->': 'Full formatted agent list with details',
402
711
  '<!-- {{COMMAND_LIST}} -->': 'Full formatted command list',
403
712
  },
713
+ templates: {
714
+ '<!-- {{SESSION_HARNESS}} -->':
715
+ 'Session harness protocol (auto-detects agent ID from frontmatter)',
716
+ '<!-- {{SESSION_HARNESS:AG-API}} -->': 'Session harness protocol with explicit agent ID',
717
+ '<!-- {{QUALITY_GATE_PRIORITIES}} -->':
718
+ 'Quality gate priorities with CRITICAL/HIGH/MEDIUM levels',
719
+ },
720
+ preserve_rules: {
721
+ '{{RULES:json_operations}}': 'Rules for safe JSON file modifications',
722
+ '{{RULES:file_preview}}': 'Rules for showing previews before writing',
723
+ '{{RULES:user_confirmation}}': 'Rules for using AskUserQuestion tool',
724
+ '{{RULES:todo_tracking}}': 'Rules for using TodoWrite tool',
725
+ '{{RULES:bus_messaging}}': 'Rules for bus message logging',
726
+ '{{RULES:plan_mode}}': 'Rules for using EnterPlanMode',
727
+ '{{RULES:commit_approval}}': 'Rules about git commits',
728
+ '{{RULES:delegation}}': 'Rules for expert delegation',
729
+ '{{RULES:research_first}}': 'Rules for checking research before starting',
730
+ '{{RULES:status_updates}}': 'Rules for updating status.json',
731
+ },
404
732
  metadata: {
405
733
  '{{VERSION}}': 'AgileFlow version from package.json',
406
734
  '{{INSTALL_DATE}}': 'Installation date (YYYY-MM-DD)',
@@ -423,6 +751,16 @@ module.exports = {
423
751
  generateAgentList,
424
752
  generateCommandList,
425
753
 
754
+ // Template generation
755
+ generateSessionHarnessContent,
756
+ clearSessionHarnessCache,
757
+ generateQualityGatePrioritiesContent,
758
+ clearQualityGatePrioritiesCache,
759
+
760
+ // Preserve rules expansion
761
+ expandPreserveRules,
762
+ clearPreserveRulesCache,
763
+
426
764
  // Main injection
427
765
  injectContent,
428
766
  hasPlaceholders,