agileflow 3.3.0 → 3.4.1

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 (210) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +6 -6
  3. package/lib/skill-loader.js +0 -1
  4. package/package.json +1 -1
  5. package/scripts/agileflow-statusline.sh +81 -0
  6. package/scripts/agileflow-welcome.js +79 -0
  7. package/scripts/claude-tmux.sh +90 -23
  8. package/scripts/claude-watchdog.sh +225 -0
  9. package/scripts/generators/agent-registry.js +14 -1
  10. package/scripts/generators/inject-babysit.js +22 -9
  11. package/scripts/generators/inject-help.js +19 -9
  12. package/scripts/lib/ac-test-matcher.js +452 -0
  13. package/scripts/lib/audit-cleanup.js +250 -0
  14. package/scripts/lib/audit-registry.js +304 -0
  15. package/scripts/lib/configure-features.js +35 -0
  16. package/scripts/lib/feature-catalog.js +3 -3
  17. package/scripts/lib/gate-enforcer.js +295 -0
  18. package/scripts/lib/model-profiles.js +118 -0
  19. package/scripts/lib/quality-gates.js +163 -0
  20. package/scripts/lib/signal-detectors.js +44 -1
  21. package/scripts/lib/skill-catalog.js +557 -0
  22. package/scripts/lib/skill-recommender.js +311 -0
  23. package/scripts/lib/status-writer.js +255 -0
  24. package/scripts/lib/story-claiming.js +128 -45
  25. package/scripts/lib/task-sync.js +32 -38
  26. package/scripts/lib/tdd-phase-manager.js +455 -0
  27. package/scripts/lib/team-events.js +34 -3
  28. package/scripts/lib/tmux-audit-monitor.js +611 -0
  29. package/scripts/lib/tmux-group-colors.js +113 -0
  30. package/scripts/lib/tool-registry.yaml +241 -0
  31. package/scripts/lib/tool-shed.js +441 -0
  32. package/scripts/messaging-bridge.js +209 -1
  33. package/scripts/native-team-observer.js +219 -0
  34. package/scripts/obtain-context.js +14 -0
  35. package/scripts/ralph-loop.js +30 -5
  36. package/scripts/smart-detect.js +21 -0
  37. package/scripts/spawn-audit-sessions.js +877 -0
  38. package/scripts/team-manager.js +56 -16
  39. package/scripts/tmux-close-windows.sh +180 -0
  40. package/src/core/agents/a11y-analyzer-aria.md +155 -0
  41. package/src/core/agents/a11y-analyzer-forms.md +162 -0
  42. package/src/core/agents/a11y-analyzer-keyboard.md +175 -0
  43. package/src/core/agents/a11y-analyzer-semantic.md +153 -0
  44. package/src/core/agents/a11y-analyzer-visual.md +158 -0
  45. package/src/core/agents/a11y-consensus.md +248 -0
  46. package/src/core/agents/ads-audit-budget.md +181 -0
  47. package/src/core/agents/ads-audit-compliance.md +169 -0
  48. package/src/core/agents/ads-audit-creative.md +164 -0
  49. package/src/core/agents/ads-audit-google.md +226 -0
  50. package/src/core/agents/ads-audit-meta.md +183 -0
  51. package/src/core/agents/ads-audit-tracking.md +197 -0
  52. package/src/core/agents/ads-consensus.md +396 -0
  53. package/src/core/agents/ads-generate.md +145 -0
  54. package/src/core/agents/ads-performance-tracker.md +197 -0
  55. package/src/core/agents/api-quality-analyzer-conventions.md +148 -0
  56. package/src/core/agents/api-quality-analyzer-docs.md +176 -0
  57. package/src/core/agents/api-quality-analyzer-errors.md +183 -0
  58. package/src/core/agents/api-quality-analyzer-pagination.md +171 -0
  59. package/src/core/agents/api-quality-analyzer-versioning.md +143 -0
  60. package/src/core/agents/api-quality-consensus.md +214 -0
  61. package/src/core/agents/arch-analyzer-circular.md +148 -0
  62. package/src/core/agents/arch-analyzer-complexity.md +171 -0
  63. package/src/core/agents/arch-analyzer-coupling.md +146 -0
  64. package/src/core/agents/arch-analyzer-layering.md +151 -0
  65. package/src/core/agents/arch-analyzer-patterns.md +162 -0
  66. package/src/core/agents/arch-consensus.md +227 -0
  67. package/src/core/agents/brainstorm-analyzer-features.md +169 -0
  68. package/src/core/agents/brainstorm-analyzer-growth.md +161 -0
  69. package/src/core/agents/brainstorm-analyzer-integration.md +172 -0
  70. package/src/core/agents/brainstorm-analyzer-market.md +147 -0
  71. package/src/core/agents/brainstorm-analyzer-ux.md +167 -0
  72. package/src/core/agents/brainstorm-consensus.md +237 -0
  73. package/src/core/agents/completeness-consensus.md +5 -5
  74. package/src/core/agents/perf-consensus.md +2 -2
  75. package/src/core/agents/security-consensus.md +2 -2
  76. package/src/core/agents/seo-analyzer-content.md +167 -0
  77. package/src/core/agents/seo-analyzer-images.md +187 -0
  78. package/src/core/agents/seo-analyzer-performance.md +206 -0
  79. package/src/core/agents/seo-analyzer-schema.md +176 -0
  80. package/src/core/agents/seo-analyzer-sitemap.md +172 -0
  81. package/src/core/agents/seo-analyzer-technical.md +144 -0
  82. package/src/core/agents/seo-consensus.md +289 -0
  83. package/src/core/agents/test-consensus.md +2 -2
  84. package/src/core/commands/adr.md +1 -0
  85. package/src/core/commands/ads/audit.md +375 -0
  86. package/src/core/commands/ads/budget.md +97 -0
  87. package/src/core/commands/ads/competitor.md +112 -0
  88. package/src/core/commands/ads/creative.md +85 -0
  89. package/src/core/commands/ads/generate.md +238 -0
  90. package/src/core/commands/ads/google.md +112 -0
  91. package/src/core/commands/ads/health.md +327 -0
  92. package/src/core/commands/ads/landing.md +119 -0
  93. package/src/core/commands/ads/linkedin.md +112 -0
  94. package/src/core/commands/ads/meta.md +91 -0
  95. package/src/core/commands/ads/microsoft.md +115 -0
  96. package/src/core/commands/ads/plan.md +321 -0
  97. package/src/core/commands/ads/test-plan.md +317 -0
  98. package/src/core/commands/ads/tiktok.md +129 -0
  99. package/src/core/commands/ads/track.md +288 -0
  100. package/src/core/commands/ads/youtube.md +124 -0
  101. package/src/core/commands/ads.md +140 -0
  102. package/src/core/commands/assign.md +1 -0
  103. package/src/core/commands/audit.md +43 -6
  104. package/src/core/commands/babysit.md +315 -1266
  105. package/src/core/commands/baseline.md +1 -0
  106. package/src/core/commands/blockers.md +1 -0
  107. package/src/core/commands/board.md +1 -0
  108. package/src/core/commands/changelog.md +1 -0
  109. package/src/core/commands/choose.md +1 -0
  110. package/src/core/commands/ci.md +1 -0
  111. package/src/core/commands/code/accessibility.md +347 -0
  112. package/src/core/commands/code/api.md +297 -0
  113. package/src/core/commands/code/architecture.md +297 -0
  114. package/src/core/commands/{audit → code}/completeness.md +72 -25
  115. package/src/core/commands/{audit → code}/legal.md +63 -16
  116. package/src/core/commands/{audit → code}/logic.md +64 -16
  117. package/src/core/commands/{audit → code}/performance.md +67 -20
  118. package/src/core/commands/{audit → code}/security.md +69 -19
  119. package/src/core/commands/{audit → code}/test.md +67 -20
  120. package/src/core/commands/configure.md +1 -0
  121. package/src/core/commands/council.md +1 -0
  122. package/src/core/commands/deploy.md +1 -0
  123. package/src/core/commands/diagnose.md +1 -0
  124. package/src/core/commands/docs.md +1 -0
  125. package/src/core/commands/epic/edit.md +213 -0
  126. package/src/core/commands/epic.md +1 -0
  127. package/src/core/commands/export.md +238 -0
  128. package/src/core/commands/help.md +16 -1
  129. package/src/core/commands/{discovery → ideate}/brief.md +12 -12
  130. package/src/core/commands/{discovery/new.md → ideate/discover.md} +20 -16
  131. package/src/core/commands/ideate/features.md +496 -0
  132. package/src/core/commands/ideate/new.md +158 -124
  133. package/src/core/commands/impact.md +1 -0
  134. package/src/core/commands/learn/explain.md +118 -0
  135. package/src/core/commands/learn/glossary.md +135 -0
  136. package/src/core/commands/learn/patterns.md +138 -0
  137. package/src/core/commands/learn/tour.md +126 -0
  138. package/src/core/commands/migrate/codemods.md +151 -0
  139. package/src/core/commands/migrate/plan.md +131 -0
  140. package/src/core/commands/migrate/scan.md +114 -0
  141. package/src/core/commands/migrate/validate.md +119 -0
  142. package/src/core/commands/multi-expert.md +1 -0
  143. package/src/core/commands/pr.md +1 -0
  144. package/src/core/commands/review.md +1 -0
  145. package/src/core/commands/seo/audit.md +373 -0
  146. package/src/core/commands/seo/competitor.md +174 -0
  147. package/src/core/commands/seo/content.md +107 -0
  148. package/src/core/commands/seo/geo.md +229 -0
  149. package/src/core/commands/seo/hreflang.md +140 -0
  150. package/src/core/commands/seo/images.md +96 -0
  151. package/src/core/commands/seo/page.md +198 -0
  152. package/src/core/commands/seo/plan.md +163 -0
  153. package/src/core/commands/seo/programmatic.md +131 -0
  154. package/src/core/commands/seo/references/cwv-thresholds.md +64 -0
  155. package/src/core/commands/seo/references/eeat-framework.md +110 -0
  156. package/src/core/commands/seo/references/quality-gates.md +91 -0
  157. package/src/core/commands/seo/references/schema-types.md +102 -0
  158. package/src/core/commands/seo/schema.md +183 -0
  159. package/src/core/commands/seo/sitemap.md +97 -0
  160. package/src/core/commands/seo/technical.md +100 -0
  161. package/src/core/commands/seo.md +107 -0
  162. package/src/core/commands/skill/list.md +68 -212
  163. package/src/core/commands/skill/recommend.md +216 -0
  164. package/src/core/commands/sprint.md +1 -0
  165. package/src/core/commands/status/undo.md +191 -0
  166. package/src/core/commands/status.md +1 -0
  167. package/src/core/commands/story/edit.md +204 -0
  168. package/src/core/commands/story/view.md +29 -7
  169. package/src/core/commands/story-validate.md +1 -0
  170. package/src/core/commands/story.md +1 -0
  171. package/src/core/commands/tdd-next.md +238 -0
  172. package/src/core/commands/tdd.md +211 -0
  173. package/src/core/commands/team/start.md +10 -6
  174. package/src/core/commands/tests.md +1 -0
  175. package/src/core/commands/verify.md +27 -1
  176. package/src/core/commands/workflow.md +2 -0
  177. package/src/core/experts/_core-expertise.yaml +105 -0
  178. package/src/core/experts/analytics/expertise.yaml +5 -99
  179. package/src/core/experts/codebase-query/expertise.yaml +3 -72
  180. package/src/core/experts/compliance/expertise.yaml +6 -72
  181. package/src/core/experts/database/expertise.yaml +9 -52
  182. package/src/core/experts/documentation/expertise.yaml +7 -140
  183. package/src/core/experts/integrations/expertise.yaml +7 -127
  184. package/src/core/experts/mentor/expertise.yaml +8 -35
  185. package/src/core/experts/monitoring/expertise.yaml +7 -49
  186. package/src/core/experts/performance/expertise.yaml +1 -26
  187. package/src/core/experts/security/expertise.yaml +9 -34
  188. package/src/core/experts/ui/expertise.yaml +6 -36
  189. package/src/core/knowledge/ads/ad-audit-checklist-scoring.md +424 -0
  190. package/src/core/knowledge/ads/ad-optimization-logic.md +590 -0
  191. package/src/core/knowledge/ads/ad-technical-specifications.md +385 -0
  192. package/src/core/knowledge/ads/definitive-advertising-reference-2026.md +506 -0
  193. package/src/core/knowledge/ads/paid-advertising-research-2026.md +445 -0
  194. package/src/core/teams/backend.json +41 -0
  195. package/src/core/teams/frontend.json +41 -0
  196. package/src/core/teams/qa.json +41 -0
  197. package/src/core/teams/solo.json +35 -0
  198. package/src/core/templates/agileflow-metadata.json +20 -1
  199. package/tools/cli/commands/setup.js +85 -3
  200. package/tools/cli/commands/update.js +42 -0
  201. package/tools/cli/installers/ide/_base-ide.js +42 -5
  202. package/tools/cli/installers/ide/claude-code.js +71 -3
  203. package/tools/cli/lib/content-injector.js +160 -12
  204. package/tools/cli/lib/docs-setup.js +1 -1
  205. package/src/core/commands/skill/create.md +0 -698
  206. package/src/core/commands/skill/delete.md +0 -316
  207. package/src/core/commands/skill/edit.md +0 -359
  208. package/src/core/commands/skill/test.md +0 -394
  209. package/src/core/commands/skill/upgrade.md +0 -552
  210. package/src/core/templates/skill-template.md +0 -117
@@ -81,6 +81,19 @@ function getMessagingBridge() {
81
81
  return _messagingBridge;
82
82
  }
83
83
 
84
+ // Lazy-load team events for dual-write (session-state + JSONL bus)
85
+ let _teamEvents;
86
+ function getTeamEvents() {
87
+ if (!_teamEvents) {
88
+ try {
89
+ _teamEvents = require('./lib/team-events');
90
+ } catch (e) {
91
+ _teamEvents = null;
92
+ }
93
+ }
94
+ return _teamEvents;
95
+ }
96
+
84
97
  /**
85
98
  * Find the teams directory
86
99
  */
@@ -344,17 +357,14 @@ function startTeam(rootDir, templateName) {
344
357
  // Non-critical - team can still function without state tracking
345
358
  }
346
359
 
347
- // Log team_created event to bus
360
+ // Log team_created event to session-state + JSONL bus (dual-write)
348
361
  try {
349
- const bridge = getMessagingBridge();
350
- if (bridge) {
351
- bridge.sendMessage(rootDir, {
352
- from: 'team-manager',
353
- to: 'team-lead',
354
- type: 'team_created',
362
+ const teamEvents = getTeamEvents();
363
+ if (teamEvents) {
364
+ teamEvents.trackEvent(rootDir, 'team_created', {
365
+ trace_id: traceId,
355
366
  template: templateName,
356
367
  mode,
357
- trace_id: traceId,
358
368
  teammate_count: template.teammates.length,
359
369
  });
360
370
  }
@@ -439,17 +449,14 @@ function stopTeam(rootDir) {
439
449
  fs.writeFileSync(sessionStatePath, JSON.stringify(state, null, 2) + '\n');
440
450
  }
441
451
 
442
- // Log team_stopped event
452
+ // Log team_stopped event to session-state + JSONL bus (dual-write)
443
453
  try {
444
- const bridge = getMessagingBridge();
445
- if (bridge) {
446
- bridge.sendMessage(rootDir, {
447
- from: 'team-manager',
448
- to: 'system',
449
- type: 'team_stopped',
454
+ const teamEvents = getTeamEvents();
455
+ if (teamEvents) {
456
+ teamEvents.trackEvent(rootDir, 'team_stopped', {
457
+ trace_id: team.trace_id,
450
458
  template: team.template,
451
459
  mode: team.mode,
452
- trace_id: team.trace_id,
453
460
  duration_ms: duration,
454
461
  tasks_completed: state.team_metrics ? state.team_metrics.tasks_completed : 0,
455
462
  });
@@ -458,6 +465,20 @@ function stopTeam(rootDir) {
458
465
  // Non-critical
459
466
  }
460
467
 
468
+ // Log team_completed event for observability parity (AC3)
469
+ try {
470
+ const teamEvents = require('./lib/team-events');
471
+ teamEvents.trackEvent(rootDir, 'team_completed', {
472
+ trace_id: team.trace_id,
473
+ template: team.template,
474
+ mode: team.mode,
475
+ duration_ms: duration,
476
+ tasks_completed: state.team_metrics ? state.team_metrics.tasks_completed : 0,
477
+ });
478
+ } catch (e) {
479
+ // Non-critical
480
+ }
481
+
461
482
  // Aggregate and save team metrics by trace_id
462
483
  try {
463
484
  if (team.trace_id) {
@@ -471,6 +492,25 @@ function stopTeam(rootDir) {
471
492
  // Non-critical - metrics aggregation is best-effort
472
493
  }
473
494
 
495
+ // Reconcile teammate final states to status.json (AC2/AC3)
496
+ try {
497
+ const taskSync = require('./lib/task-sync');
498
+ const nativeTasks = (team.teammates || [])
499
+ .filter(t => t.status === 'completed' || t.status === 'done')
500
+ .map(t => ({
501
+ id: t.agent,
502
+ status: 'completed',
503
+ metadata: { story_id: t.story_id },
504
+ }))
505
+ .filter(t => t.metadata.story_id);
506
+
507
+ if (nativeTasks.length > 0) {
508
+ taskSync.reconcile(rootDir, nativeTasks);
509
+ }
510
+ } catch (e) {
511
+ // Non-critical - reconciliation is best-effort
512
+ }
513
+
474
514
  return {
475
515
  ok: true,
476
516
  template: team.template,
@@ -0,0 +1,180 @@
1
+ #!/bin/bash
2
+ # tmux-close-windows.sh - Batch close tmux windows via multi-select picker
3
+ #
4
+ # Called by Alt+W (Shift+Alt+w) keybind. Opens an fzf multi-select picker
5
+ # (or bash fallback) to close multiple windows at once. Each closed window
6
+ # is saved to the restore stack for Alt+T recovery.
7
+ #
8
+ # Usage: Run inside a tmux popup (display-popup -E)
9
+
10
+ STACK_FILE="$HOME/.tmux_closed_windows.log"
11
+ MAX_ENTRIES=20
12
+ SESSION=$(tmux display-message -p '#{session_name}' 2>/dev/null)
13
+ CURRENT_IDX=$(tmux display-message -p '#{window_index}' 2>/dev/null)
14
+
15
+ if [ -z "$SESSION" ]; then
16
+ echo "Error: not in a tmux session"
17
+ exit 1
18
+ fi
19
+
20
+ # Build window list (excluding current window)
21
+ WINDOWS=()
22
+ while IFS=$'\t' read -r idx name path pane_count; do
23
+ [ "$idx" = "$CURRENT_IDX" ] && continue
24
+ WINDOWS+=("$idx"$'\t'"$name"$'\t'"$path"$'\t'"$pane_count")
25
+ done < <(tmux list-windows -t "$SESSION" -F '#{window_index} #{window_name} #{pane_current_path} #{window_panes}' 2>/dev/null)
26
+
27
+ if [ "${#WINDOWS[@]}" -eq 0 ]; then
28
+ echo "No other windows to close"
29
+ sleep 1
30
+ exit 0
31
+ fi
32
+
33
+ # Save a window's state to the restore stack (same format as tmux-save-closed-window.sh)
34
+ save_window() {
35
+ local idx="$1"
36
+ local win_name pane_path claude_uuid timestamp
37
+
38
+ win_name=$(tmux display-message -t "$SESSION:$idx" -p '#{window_name}' 2>/dev/null || echo '')
39
+ pane_path=$(tmux display-message -t "$SESSION:$idx" -p '#{pane_current_path}' 2>/dev/null || echo "$HOME")
40
+ claude_uuid=$(tmux show-options -p -t "$SESSION:$idx" -qv @claude_uuid 2>/dev/null || echo '')
41
+ timestamp=$(date +%s)
42
+
43
+ echo "${win_name}|${pane_path}|${claude_uuid}|${timestamp}" >> "$STACK_FILE"
44
+
45
+ # Prune to MAX_ENTRIES
46
+ if [ -f "$STACK_FILE" ]; then
47
+ local line_count
48
+ line_count=$(wc -l < "$STACK_FILE")
49
+ if [ "$line_count" -gt "$MAX_ENTRIES" ]; then
50
+ tail -n "$MAX_ENTRIES" "$STACK_FILE" > "${STACK_FILE}.tmp" && mv "${STACK_FILE}.tmp" "$STACK_FILE"
51
+ fi
52
+ fi
53
+ }
54
+
55
+ # Format window list for display
56
+ format_entry() {
57
+ local idx="$1" name="$2" path="$3"
58
+ local short_path
59
+ short_path=$(echo "$path" | sed "s|^$HOME|~|")
60
+ printf '[%s] %-14s %s' "$idx" "$name" "$short_path"
61
+ }
62
+
63
+ # ── fzf path ────────────────────────────────────────────────────────────────
64
+ if command -v fzf &>/dev/null; then
65
+ # Build fzf input
66
+ FZF_INPUT=""
67
+ for entry in "${WINDOWS[@]}"; do
68
+ IFS=$'\t' read -r idx name path pane_count <<< "$entry"
69
+ FZF_INPUT+="$(format_entry "$idx" "$name" "$path")"$'\n'
70
+ done
71
+
72
+ SELECTED=$(printf '%s' "$FZF_INPUT" | fzf --multi \
73
+ --header="TAB=select ENTER=close selected ESC=cancel" \
74
+ --prompt="Close windows> " \
75
+ --color="fg:#a9b1d6,bg:#1a1b26,hl:#e8683a,fg+:#e0e0e0,bg+:#2d2f3a,hl+:#e8683a,pointer:#e8683a,marker:#e8683a,prompt:#7aa2f7" \
76
+ 2>/dev/null)
77
+
78
+ if [ -z "$SELECTED" ]; then
79
+ exit 0
80
+ fi
81
+
82
+ # Extract window indices from selection, sort descending to avoid renumbering
83
+ INDICES=()
84
+ while IFS= read -r line; do
85
+ idx=$(echo "$line" | sed 's/^\[//' | sed 's/\].*//')
86
+ INDICES+=("$idx")
87
+ done <<< "$SELECTED"
88
+
89
+ # Sort indices in reverse order (highest first)
90
+ IFS=$'\n' SORTED=($(printf '%s\n' "${INDICES[@]}" | sort -rn)); unset IFS
91
+
92
+ CLOSED=0
93
+ for idx in "${SORTED[@]}"; do
94
+ save_window "$idx"
95
+ tmux kill-window -t "$SESSION:$idx" 2>/dev/null && CLOSED=$((CLOSED + 1))
96
+ done
97
+
98
+ tmux display-message "Closed $CLOSED window(s)"
99
+ exit 0
100
+ fi
101
+
102
+ # ── Bash fallback (no fzf) ──────────────────────────────────────────────────
103
+ SELECTED_FLAGS=()
104
+ for _ in "${WINDOWS[@]}"; do
105
+ SELECTED_FLAGS+=(0)
106
+ done
107
+
108
+ while true; do
109
+ clear
110
+ printf '\n \033[1;38;5;208mClose Windows\033[0m (type numbers to toggle, Enter=close, q=cancel)\n\n'
111
+
112
+ i=0
113
+ for entry in "${WINDOWS[@]}"; do
114
+ IFS=$'\t' read -r idx name path pane_count <<< "$entry"
115
+ short_path=$(echo "$path" | sed "s|^$HOME|~|")
116
+ if [ "${SELECTED_FLAGS[$i]}" = "1" ]; then
117
+ printf ' \033[38;5;208m%d) [x] %-14s %s\033[0m\n' "$((i + 1))" "$name" "$short_path"
118
+ else
119
+ printf ' %d) [ ] %-14s %s\n' "$((i + 1))" "$name" "$short_path"
120
+ fi
121
+ i=$((i + 1))
122
+ done
123
+
124
+ # Count selected
125
+ SEL_COUNT=0
126
+ for f in "${SELECTED_FLAGS[@]}"; do
127
+ [ "$f" = "1" ] && SEL_COUNT=$((SEL_COUNT + 1))
128
+ done
129
+
130
+ printf '\n Selected: %d\n' "$SEL_COUNT"
131
+ printf ' Toggle> '
132
+ read -r INPUT
133
+
134
+ if [ "$INPUT" = "q" ] || [ "$INPUT" = "Q" ]; then
135
+ exit 0
136
+ fi
137
+
138
+ if [ -z "$INPUT" ]; then
139
+ # Enter pressed — close selected windows
140
+ if [ "$SEL_COUNT" -eq 0 ]; then
141
+ printf ' No windows selected.\n'
142
+ sleep 1
143
+ continue
144
+ fi
145
+
146
+ # Collect selected indices in reverse order
147
+ INDICES=()
148
+ i=0
149
+ for entry in "${WINDOWS[@]}"; do
150
+ if [ "${SELECTED_FLAGS[$i]}" = "1" ]; then
151
+ IFS=$'\t' read -r idx _ _ _ <<< "$entry"
152
+ INDICES+=("$idx")
153
+ fi
154
+ i=$((i + 1))
155
+ done
156
+
157
+ IFS=$'\n' SORTED=($(printf '%s\n' "${INDICES[@]}" | sort -rn)); unset IFS
158
+
159
+ CLOSED=0
160
+ for idx in "${SORTED[@]}"; do
161
+ save_window "$idx"
162
+ tmux kill-window -t "$SESSION:$idx" 2>/dev/null && CLOSED=$((CLOSED + 1))
163
+ done
164
+
165
+ tmux display-message "Closed $CLOSED window(s)"
166
+ exit 0
167
+ fi
168
+
169
+ # Toggle numbers from input (space-separated)
170
+ for num in $INPUT; do
171
+ if [[ "$num" =~ ^[0-9]+$ ]] && [ "$num" -ge 1 ] && [ "$num" -le "${#WINDOWS[@]}" ]; then
172
+ idx=$((num - 1))
173
+ if [ "${SELECTED_FLAGS[$idx]}" = "0" ]; then
174
+ SELECTED_FLAGS[$idx]=1
175
+ else
176
+ SELECTED_FLAGS[$idx]=0
177
+ fi
178
+ fi
179
+ done
180
+ done
@@ -0,0 +1,155 @@
1
+ ---
2
+ name: a11y-analyzer-aria
3
+ description: ARIA usage analyzer for roles, states, properties, live regions, and widget patterns in web components
4
+ tools: Read, Glob, Grep
5
+ model: haiku
6
+ team_role: utility
7
+ ---
8
+
9
+
10
+ # Accessibility Analyzer: ARIA Usage
11
+
12
+ You are a specialized accessibility analyzer focused on **ARIA (Accessible Rich Internet Applications)** usage. Your job is to find incorrect, missing, or redundant ARIA attributes that create barriers or confusion for assistive technology users.
13
+
14
+ ---
15
+
16
+ ## Your Focus Areas
17
+
18
+ 1. **Invalid ARIA roles**: Misspelled roles, roles on wrong elements, abstract roles used directly
19
+ 2. **Missing required ARIA properties**: Widgets missing required states (e.g., `aria-expanded` on disclosure)
20
+ 3. **ARIA on wrong elements**: Roles that conflict with native semantics
21
+ 4. **Live regions**: Missing or incorrect `aria-live`, `aria-atomic`, `aria-relevant` for dynamic content
22
+ 5. **Widget patterns**: Custom widgets missing expected ARIA pattern (tabs, menus, dialogs, combobox)
23
+ 6. **Redundant ARIA**: ARIA that duplicates native semantics (e.g., `role="button"` on `<button>`)
24
+ 7. **aria-hidden misuse**: Interactive elements hidden from AT but visible on screen
25
+
26
+ ---
27
+
28
+ ## Analysis Process
29
+
30
+ ### Step 1: Read the Target Code
31
+
32
+ Read the files you're asked to analyze. Focus on:
33
+ - Custom interactive components (dropdowns, modals, tabs, accordions)
34
+ - Dynamic content areas (notifications, chat, live feeds)
35
+ - Custom form controls (date pickers, sliders, toggles)
36
+ - Overlay patterns (modals, drawers, popovers)
37
+
38
+ ### Step 2: Look for These Patterns
39
+
40
+ **Pattern 1: Missing aria-expanded on toggleable content**
41
+ ```jsx
42
+ // VULN: No aria-expanded state
43
+ <button onClick={() => setOpen(!open)}>Menu</button>
44
+ {open && <div className="dropdown">...</div>}
45
+ // Needs: aria-expanded={open} on the button
46
+ ```
47
+
48
+ **Pattern 2: Custom tabs without ARIA pattern**
49
+ ```jsx
50
+ // VULN: Tab pattern without proper roles
51
+ <div className="tabs">
52
+ <div className="tab active" onClick={() => setTab(0)}>Tab 1</div>
53
+ <div className="tab" onClick={() => setTab(1)}>Tab 2</div>
54
+ </div>
55
+ // Needs: role="tablist", role="tab", aria-selected, role="tabpanel"
56
+ ```
57
+
58
+ **Pattern 3: Modal without dialog role**
59
+ ```jsx
60
+ // VULN: Modal overlay without dialog semantics
61
+ <div className="modal-overlay" style={{ display: isOpen ? 'flex' : 'none' }}>
62
+ <div className="modal-content">
63
+ <h2>Confirm</h2>
64
+ <p>Are you sure?</p>
65
+ </div>
66
+ </div>
67
+ // Needs: role="dialog", aria-modal="true", aria-labelledby
68
+ ```
69
+
70
+ **Pattern 4: Dynamic content without live region**
71
+ ```jsx
72
+ // VULN: Toast notification not announced to screen readers
73
+ {toast && <div className="toast">{toast.message}</div>}
74
+ // Needs: aria-live="polite" or role="status"
75
+ ```
76
+
77
+ **Pattern 5: aria-hidden on focusable element**
78
+ ```jsx
79
+ // VULN: Button hidden from AT but still focusable
80
+ <button aria-hidden="true" onClick={handleClose}>X</button>
81
+ // aria-hidden removes from AT but button is still tabbable
82
+ ```
83
+
84
+ **Pattern 6: Redundant ARIA**
85
+ ```jsx
86
+ // ISSUE: Redundant - <nav> already has navigation role
87
+ <nav role="navigation">...</nav>
88
+
89
+ // ISSUE: Redundant - <button> already has button role
90
+ <button role="button">Click</button>
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Output Format
96
+
97
+ For each potential issue found, output:
98
+
99
+ ```markdown
100
+ ### FINDING-{N}: {Brief Title}
101
+
102
+ **Location**: `{file}:{line}`
103
+ **Severity**: BLOCKER (AT crash/confusion) | MAJOR (missing critical info) | MINOR (degraded) | ENHANCEMENT
104
+ **Confidence**: HIGH | MEDIUM | LOW
105
+ **WCAG**: SC {number} ({name}) - Level {A/AA/AAA}
106
+
107
+ **Code**:
108
+ \`\`\`{language}
109
+ {relevant code snippet, 3-7 lines}
110
+ \`\`\`
111
+
112
+ **Issue**: {Clear explanation of the ARIA problem}
113
+
114
+ **Impact**:
115
+ - Assistive technology: {what AT does with this code}
116
+ - User experience: {what the user perceives}
117
+
118
+ **Remediation**:
119
+ - {Specific fix with code example}
120
+ ```
121
+
122
+ ---
123
+
124
+ ## WCAG Reference
125
+
126
+ | Issue | WCAG SC | Level | Typical Severity |
127
+ |-------|---------|-------|-----------------|
128
+ | Missing ARIA states | SC 4.1.2 | A | BLOCKER |
129
+ | Invalid ARIA roles | SC 4.1.2 | A | MAJOR |
130
+ | Missing live region | SC 4.1.3 | AA | MAJOR |
131
+ | aria-hidden on focusable | SC 4.1.2 | A | BLOCKER |
132
+ | Missing dialog semantics | SC 4.1.2 | A | BLOCKER |
133
+ | Redundant ARIA | SC 4.1.2 | A | ENHANCEMENT |
134
+ | Missing widget pattern | SC 4.1.2 | A | MAJOR |
135
+
136
+ ---
137
+
138
+ ## Important Rules
139
+
140
+ 1. **Be SPECIFIC**: Include exact file paths and line numbers
141
+ 2. **Check for headless UI**: Libraries like Radix, Headless UI, React Aria handle ARIA automatically
142
+ 3. **Verify component output**: A component wrapping a headless library may already have correct ARIA
143
+ 4. **First rule of ARIA**: Don't use ARIA if native HTML can do the job
144
+ 5. **Check for aria-label vs visible text**: Prefer visible labels over aria-label when possible
145
+
146
+ ---
147
+
148
+ ## What NOT to Report
149
+
150
+ - Components using Radix UI, Headless UI, React Aria, or Reach UI (they handle ARIA correctly)
151
+ - Native HTML elements with correct implicit roles
152
+ - Server-only code that doesn't render UI
153
+ - Color contrast (visual analyzer handles those)
154
+ - Heading hierarchy (semantic analyzer handles those)
155
+ - Focus management (keyboard analyzer handles those)
@@ -0,0 +1,162 @@
1
+ ---
2
+ name: a11y-analyzer-forms
3
+ description: Forms accessibility analyzer for labels, error messages, autocomplete, validation feedback, and form control associations
4
+ tools: Read, Glob, Grep
5
+ model: haiku
6
+ team_role: utility
7
+ ---
8
+
9
+
10
+ # Accessibility Analyzer: Forms Accessibility
11
+
12
+ You are a specialized accessibility analyzer focused on **forms accessibility**. Your job is to find code patterns where form controls lack proper labels, error handling is inaccessible, or form interactions create barriers for assistive technology users.
13
+
14
+ ---
15
+
16
+ ## Your Focus Areas
17
+
18
+ 1. **Missing labels**: Inputs without associated `<label>`, missing `aria-label` or `aria-labelledby`
19
+ 2. **Error messages**: Errors not programmatically associated with inputs, missing `aria-describedby`
20
+ 3. **Autocomplete**: Missing `autocomplete` attributes on identity/payment fields
21
+ 4. **Validation feedback**: Client-side validation that's not announced to screen readers
22
+ 5. **Required fields**: Missing `aria-required` or `required` attribute, unclear required indication
23
+ 6. **Fieldset/legend**: Related controls (radio groups, checkbox groups) not grouped with `<fieldset>`/`<legend>`
24
+
25
+ ---
26
+
27
+ ## Analysis Process
28
+
29
+ ### Step 1: Read the Target Code
30
+
31
+ Read the files you're asked to analyze. Focus on:
32
+ - Form components and form handlers
33
+ - Input, select, textarea, and custom form control components
34
+ - Validation logic and error display
35
+ - Login, registration, checkout, and settings forms
36
+ - Search inputs and filter controls
37
+
38
+ ### Step 2: Look for These Patterns
39
+
40
+ **Pattern 1: Input without label**
41
+ ```jsx
42
+ // VULN: Input with no associated label
43
+ <input type="text" placeholder="Enter email" />
44
+ // placeholder is NOT a label substitute
45
+
46
+ // VULN: Label not associated with input
47
+ <label>Email</label>
48
+ <input type="email" id="email-input" />
49
+ // Missing htmlFor="email-input" on label
50
+ ```
51
+
52
+ **Pattern 2: Error message not associated**
53
+ ```jsx
54
+ // VULN: Error shown visually but not linked to input
55
+ <input type="email" value={email} onChange={setEmail} />
56
+ {error && <span className="error">{error}</span>}
57
+ // Needs: aria-describedby on input pointing to error span's id
58
+ // Also needs: aria-invalid="true" on the input
59
+ ```
60
+
61
+ **Pattern 3: Missing autocomplete on identity fields**
62
+ ```jsx
63
+ // VULN: Login form without autocomplete hints
64
+ <form>
65
+ <input type="text" name="username" /> // needs autocomplete="username"
66
+ <input type="password" name="password" /> // needs autocomplete="current-password"
67
+ </form>
68
+ ```
69
+
70
+ **Pattern 4: Required fields without programmatic indication**
71
+ ```jsx
72
+ // VULN: Visual asterisk but no programmatic required
73
+ <label>Name <span className="required">*</span></label>
74
+ <input type="text" name="name" />
75
+ // Needs: required attribute or aria-required="true"
76
+ ```
77
+
78
+ **Pattern 5: Radio/checkbox group without fieldset**
79
+ ```jsx
80
+ // VULN: Related radio buttons not grouped
81
+ <label><input type="radio" name="plan" value="free" /> Free</label>
82
+ <label><input type="radio" name="plan" value="pro" /> Pro</label>
83
+ <label><input type="radio" name="plan" value="enterprise" /> Enterprise</label>
84
+ // Needs: <fieldset><legend>Choose a plan</legend>...</fieldset>
85
+ ```
86
+
87
+ **Pattern 6: Custom validation without announcement**
88
+ ```jsx
89
+ // VULN: Validation error appears but isn't announced
90
+ const [errors, setErrors] = useState({});
91
+ const validate = () => {
92
+ if (!email) setErrors({ email: 'Email is required' });
93
+ };
94
+ // Error state changes aren't announced to screen readers
95
+ // Needs: aria-live region or role="alert" on error container
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Output Format
101
+
102
+ For each potential issue found, output:
103
+
104
+ ```markdown
105
+ ### FINDING-{N}: {Brief Title}
106
+
107
+ **Location**: `{file}:{line}`
108
+ **Severity**: BLOCKER (form unusable) | MAJOR (significant barrier) | MINOR (degraded) | ENHANCEMENT
109
+ **Confidence**: HIGH | MEDIUM | LOW
110
+ **WCAG**: SC {number} ({name}) - Level {A/AA/AAA}
111
+
112
+ **Code**:
113
+ \`\`\`{language}
114
+ {relevant code snippet, 3-7 lines}
115
+ \`\`\`
116
+
117
+ **Issue**: {Clear explanation of the forms accessibility barrier}
118
+
119
+ **Impact**:
120
+ - Users affected: {screen reader users, voice control, cognitive disabilities}
121
+ - Barrier: {what they cannot do or understand}
122
+
123
+ **Remediation**:
124
+ - {Specific fix with code example}
125
+ ```
126
+
127
+ ---
128
+
129
+ ## WCAG Reference
130
+
131
+ | Issue | WCAG SC | Level | Typical Severity |
132
+ |-------|---------|-------|-----------------|
133
+ | Missing label | SC 1.3.1, 4.1.2 | A | BLOCKER |
134
+ | Missing error association | SC 3.3.1 | A | MAJOR |
135
+ | Missing autocomplete | SC 1.3.5 | AA | MINOR |
136
+ | Missing required indication | SC 3.3.2 | A | MAJOR |
137
+ | Missing fieldset/legend | SC 1.3.1 | A | MAJOR |
138
+ | Error prevention | SC 3.3.4 | AA | MINOR |
139
+ | Validation not announced | SC 4.1.3 | AA | MAJOR |
140
+ | Missing input purpose | SC 1.3.5 | AA | MINOR |
141
+
142
+ ---
143
+
144
+ ## Important Rules
145
+
146
+ 1. **Be SPECIFIC**: Include exact file paths and line numbers
147
+ 2. **Check for form libraries**: React Hook Form, Formik, and Zod may handle some a11y automatically
148
+ 3. **Verify aria-label**: `aria-label` is valid even without a visible label
149
+ 4. **Check label wrapping**: `<label><input /> Text</label>` is a valid implicit association
150
+ 5. **Consider UI libraries**: shadcn/ui, MUI, Chakra UI often include label associations
151
+
152
+ ---
153
+
154
+ ## What NOT to Report
155
+
156
+ - Inputs wrapped in `<label>` elements (implicit association is valid)
157
+ - Inputs with `aria-label` or `aria-labelledby`
158
+ - Form libraries that auto-generate error associations
159
+ - Search inputs with `role="search"` on the form and clear visual context
160
+ - Hidden inputs (`type="hidden"`) that don't need labels
161
+ - Focus management issues (keyboard analyzer handles those)
162
+ - Color-only error indicators (visual analyzer handles those)