agileflow 2.90.7 → 2.92.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 (144) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +6 -6
  3. package/lib/README.md +178 -0
  4. package/lib/codebase-indexer.js +818 -0
  5. package/lib/colors.js +190 -12
  6. package/lib/consent.js +232 -0
  7. package/lib/correlation.js +277 -0
  8. package/lib/error-codes.js +46 -0
  9. package/lib/errors.js +48 -6
  10. package/lib/file-cache.js +182 -0
  11. package/lib/format-error.js +156 -0
  12. package/lib/path-resolver.js +155 -7
  13. package/lib/paths.js +212 -20
  14. package/lib/placeholder-registry.js +205 -0
  15. package/lib/registry-di.js +358 -0
  16. package/lib/result-schema.js +363 -0
  17. package/lib/result.js +210 -0
  18. package/lib/session-registry.js +13 -0
  19. package/lib/session-state-machine.js +465 -0
  20. package/lib/validate-commands.js +308 -0
  21. package/lib/validate-names.js +3 -3
  22. package/lib/validate.js +116 -52
  23. package/package.json +4 -1
  24. package/scripts/af +34 -0
  25. package/scripts/agent-loop.js +63 -9
  26. package/scripts/agileflow-configure.js +2 -2
  27. package/scripts/agileflow-welcome.js +435 -23
  28. package/scripts/archive-completed-stories.sh +57 -11
  29. package/scripts/claude-tmux.sh +102 -0
  30. package/scripts/damage-control-bash.js +3 -70
  31. package/scripts/damage-control-edit.js +3 -20
  32. package/scripts/damage-control-write.js +3 -20
  33. package/scripts/dependency-check.js +310 -0
  34. package/scripts/get-env.js +11 -4
  35. package/scripts/lib/configure-detect.js +23 -1
  36. package/scripts/lib/configure-features.js +43 -2
  37. package/scripts/lib/context-formatter.js +771 -0
  38. package/scripts/lib/context-loader.js +699 -0
  39. package/scripts/lib/damage-control-utils.js +107 -0
  40. package/scripts/lib/json-utils.sh +162 -0
  41. package/scripts/lib/state-migrator.js +353 -0
  42. package/scripts/lib/story-state-machine.js +437 -0
  43. package/scripts/obtain-context.js +118 -1048
  44. package/scripts/pre-push-check.sh +46 -0
  45. package/scripts/precompact-context.sh +36 -11
  46. package/scripts/query-codebase.js +538 -0
  47. package/scripts/ralph-loop.js +5 -5
  48. package/scripts/session-manager.js +220 -42
  49. package/scripts/spawn-parallel.js +651 -0
  50. package/scripts/tui/blessed/data/watcher.js +180 -0
  51. package/scripts/tui/blessed/index.js +244 -0
  52. package/scripts/tui/blessed/panels/output.js +101 -0
  53. package/scripts/tui/blessed/panels/sessions.js +150 -0
  54. package/scripts/tui/blessed/panels/trace.js +97 -0
  55. package/scripts/tui/blessed/ui/help.js +77 -0
  56. package/scripts/tui/blessed/ui/screen.js +52 -0
  57. package/scripts/tui/blessed/ui/statusbar.js +47 -0
  58. package/scripts/tui/blessed/ui/tabbar.js +99 -0
  59. package/scripts/tui/index.js +38 -30
  60. package/scripts/validators/README.md +143 -0
  61. package/scripts/validators/component-validator.js +239 -0
  62. package/scripts/validators/json-schema-validator.js +186 -0
  63. package/scripts/validators/markdown-validator.js +152 -0
  64. package/scripts/validators/migration-validator.js +129 -0
  65. package/scripts/validators/security-validator.js +380 -0
  66. package/scripts/validators/story-format-validator.js +197 -0
  67. package/scripts/validators/test-result-validator.js +114 -0
  68. package/scripts/validators/workflow-validator.js +247 -0
  69. package/src/core/agents/accessibility.md +6 -0
  70. package/src/core/agents/adr-writer.md +6 -0
  71. package/src/core/agents/analytics.md +6 -0
  72. package/src/core/agents/api.md +6 -0
  73. package/src/core/agents/ci.md +6 -0
  74. package/src/core/agents/codebase-query.md +261 -0
  75. package/src/core/agents/compliance.md +6 -0
  76. package/src/core/agents/configuration-damage-control.md +6 -0
  77. package/src/core/agents/configuration-visual-e2e.md +6 -0
  78. package/src/core/agents/database.md +10 -0
  79. package/src/core/agents/datamigration.md +6 -0
  80. package/src/core/agents/design.md +6 -0
  81. package/src/core/agents/devops.md +6 -0
  82. package/src/core/agents/documentation.md +6 -0
  83. package/src/core/agents/epic-planner.md +6 -0
  84. package/src/core/agents/integrations.md +6 -0
  85. package/src/core/agents/mentor.md +6 -0
  86. package/src/core/agents/mobile.md +6 -0
  87. package/src/core/agents/monitoring.md +6 -0
  88. package/src/core/agents/multi-expert.md +6 -0
  89. package/src/core/agents/performance.md +6 -0
  90. package/src/core/agents/product.md +6 -0
  91. package/src/core/agents/qa.md +6 -0
  92. package/src/core/agents/readme-updater.md +6 -0
  93. package/src/core/agents/refactor.md +6 -0
  94. package/src/core/agents/research.md +6 -0
  95. package/src/core/agents/security.md +6 -0
  96. package/src/core/agents/testing.md +10 -0
  97. package/src/core/agents/ui.md +6 -0
  98. package/src/core/commands/adr.md +114 -0
  99. package/src/core/commands/agent.md +120 -0
  100. package/src/core/commands/assign.md +145 -0
  101. package/src/core/commands/audit.md +401 -0
  102. package/src/core/commands/babysit.md +32 -5
  103. package/src/core/commands/board.md +1 -0
  104. package/src/core/commands/changelog.md +118 -0
  105. package/src/core/commands/configure.md +42 -6
  106. package/src/core/commands/diagnose.md +114 -0
  107. package/src/core/commands/epic.md +205 -1
  108. package/src/core/commands/handoff.md +128 -0
  109. package/src/core/commands/help.md +76 -0
  110. package/src/core/commands/metrics.md +1 -0
  111. package/src/core/commands/pr.md +96 -0
  112. package/src/core/commands/research/analyze.md +1 -0
  113. package/src/core/commands/research/ask.md +2 -0
  114. package/src/core/commands/research/import.md +1 -0
  115. package/src/core/commands/research/list.md +2 -0
  116. package/src/core/commands/research/synthesize.md +584 -0
  117. package/src/core/commands/research/view.md +2 -0
  118. package/src/core/commands/roadmap/analyze.md +400 -0
  119. package/src/core/commands/session/new.md +113 -6
  120. package/src/core/commands/session/spawn.md +197 -0
  121. package/src/core/commands/sprint.md +22 -0
  122. package/src/core/commands/status.md +200 -1
  123. package/src/core/commands/story/list.md +9 -9
  124. package/src/core/commands/story/view.md +1 -0
  125. package/src/core/commands/story.md +143 -4
  126. package/src/core/experts/codebase-query/expertise.yaml +190 -0
  127. package/src/core/experts/codebase-query/question.md +73 -0
  128. package/src/core/experts/codebase-query/self-improve.md +105 -0
  129. package/src/core/templates/agileflow-metadata.json +55 -2
  130. package/src/core/templates/plan-template.md +125 -0
  131. package/src/core/templates/story-lifecycle.md +213 -0
  132. package/src/core/templates/story-template.md +4 -0
  133. package/src/core/templates/tdd-test-template.js +241 -0
  134. package/tools/cli/commands/setup.js +86 -0
  135. package/tools/cli/installers/core/installer.js +94 -0
  136. package/tools/cli/installers/ide/_base-ide.js +20 -11
  137. package/tools/cli/installers/ide/codex.js +29 -47
  138. package/tools/cli/lib/config-manager.js +17 -2
  139. package/tools/cli/lib/content-transformer.js +271 -0
  140. package/tools/cli/lib/error-handler.js +14 -22
  141. package/tools/cli/lib/ide-error-factory.js +421 -0
  142. package/tools/cli/lib/ide-health-monitor.js +364 -0
  143. package/tools/cli/lib/ide-registry.js +114 -1
  144. package/tools/cli/lib/ui.js +14 -25
@@ -0,0 +1,97 @@
1
+ 'use strict';
2
+
3
+ const blessed = require('blessed');
4
+
5
+ /**
6
+ * Create the trace panel showing execution steps
7
+ */
8
+ module.exports = function createTracePanel(grid, state) {
9
+ const box = blessed.box({
10
+ parent: grid.screen,
11
+ top: 3,
12
+ left: 0,
13
+ width: '100%',
14
+ height: '100%-4',
15
+ label: ' {yellow-fg}{bold}Trace{/bold}{/yellow-fg} ',
16
+ tags: true,
17
+ border: {
18
+ type: 'line',
19
+ fg: 'yellow',
20
+ },
21
+ style: {
22
+ fg: 'white',
23
+ bg: 'black',
24
+ border: { fg: 'yellow' },
25
+ },
26
+ scrollable: true,
27
+ alwaysScroll: true,
28
+ scrollbar: {
29
+ ch: '│',
30
+ style: { fg: 'yellow' },
31
+ },
32
+ keys: true,
33
+ vi: true,
34
+ });
35
+
36
+ let traces = [];
37
+
38
+ function render() {
39
+ if (traces.length === 0) {
40
+ box.setContent(`
41
+ {gray-fg}No trace data{/}
42
+
43
+ {yellow-fg}What shows here:{/}
44
+ • Active command execution
45
+ • Step-by-step agent workflow
46
+ • Tool calls and responses
47
+ • Timing information
48
+
49
+ {gray-fg}Trace data comes from .agileflow/session-state.json{/}
50
+ `);
51
+ return;
52
+ }
53
+
54
+ let lines = [];
55
+ traces.forEach((t, i) => {
56
+ // Status indicator
57
+ let statusIcon = '{gray-fg}○{/}';
58
+ if (t.status === 'running') statusIcon = '{yellow-fg}◉{/}';
59
+ else if (t.status === 'completed') statusIcon = '{green-fg}●{/}';
60
+ else if (t.status === 'error') statusIcon = '{red-fg}✖{/}';
61
+
62
+ const stepNum = String(i + 1).padStart(2, '0');
63
+ const action = (t.action || 'Unknown').substring(0, 40);
64
+ const duration = t.duration || '--';
65
+
66
+ lines.push(` ${statusIcon} Step ${stepNum}: {bold}${action}{/}`);
67
+ if (t.details) {
68
+ lines.push(` {gray-fg}${t.details.substring(0, 60)}{/}`);
69
+ }
70
+ lines.push(` {gray-fg}Duration: ${duration}{/}`);
71
+ lines.push('');
72
+ });
73
+
74
+ box.setContent(lines.join('\n'));
75
+ }
76
+
77
+ return {
78
+ element: box,
79
+ show() {
80
+ box.show();
81
+ },
82
+ hide() {
83
+ box.hide();
84
+ },
85
+ focus() {
86
+ box.focus();
87
+ },
88
+ setData(data) {
89
+ traces = data || [];
90
+ render();
91
+ },
92
+ addStep(action, status = 'running', details = '') {
93
+ traces.push({ action, status, details, duration: '--' });
94
+ render();
95
+ },
96
+ };
97
+ };
@@ -0,0 +1,77 @@
1
+ 'use strict';
2
+
3
+ const blessed = require('blessed');
4
+
5
+ /**
6
+ * Create the help overlay that shows all available commands
7
+ * Toggled with ? or h key
8
+ */
9
+ module.exports = function createHelpOverlay(screen, state) {
10
+ const help = blessed.box({
11
+ parent: screen,
12
+ top: 'center',
13
+ left: 'center',
14
+ width: 55,
15
+ height: 22,
16
+ tags: true,
17
+ border: { type: 'line', fg: 'yellow' },
18
+ style: {
19
+ fg: 'white',
20
+ bg: 'black',
21
+ border: { fg: 'yellow' },
22
+ },
23
+ label: ' {yellow-fg}Help{/yellow-fg} ',
24
+ hidden: true,
25
+ content: `
26
+ {bold}Navigation{/bold}
27
+ {cyan-fg}1{/} Sessions tab
28
+ {cyan-fg}2{/} Output tab
29
+ {cyan-fg}3{/} Trace tab
30
+ {cyan-fg}Tab{/} Next tab
31
+ {cyan-fg}j/k or {/}{cyan-fg}arrow-down/arrow-up{/} Navigate list items
32
+ {cyan-fg}Enter{/} Select item
33
+
34
+ {bold}Actions{/bold}
35
+ {cyan-fg}r{/} Refresh data
36
+ {cyan-fg}s{/} Start loop on current story
37
+ {cyan-fg}p{/} Pause active loop
38
+
39
+ {bold}Display{/bold}
40
+ {cyan-fg}?{/} or {cyan-fg}h{/} Toggle this help
41
+ {cyan-fg}Escape{/} Close help/dialogs
42
+
43
+ {bold}Exit{/bold}
44
+ {cyan-fg}q{/} Quit TUI
45
+ {cyan-fg}Ctrl+C{/} Force quit
46
+
47
+ {gray-fg}Press Escape or ? to close{/gray-fg}`,
48
+ });
49
+
50
+ // Close help on various keys
51
+ help.key(['escape', 'q', '?', 'h', 'enter', 'space'], () => {
52
+ help.hide();
53
+ screen.render();
54
+ });
55
+
56
+ return {
57
+ element: help,
58
+ toggle() {
59
+ if (help.hidden) {
60
+ help.show();
61
+ help.focus();
62
+ } else {
63
+ help.hide();
64
+ }
65
+ },
66
+ show() {
67
+ help.show();
68
+ help.focus();
69
+ },
70
+ hide() {
71
+ help.hide();
72
+ },
73
+ isVisible() {
74
+ return !help.hidden;
75
+ },
76
+ };
77
+ };
@@ -0,0 +1,52 @@
1
+ 'use strict';
2
+
3
+ const blessed = require('blessed');
4
+
5
+ /**
6
+ * Create the main blessed screen with flicker-free rendering
7
+ *
8
+ * Key settings:
9
+ * - smartCSR: Enable differential rendering (only update changed cells)
10
+ * - fullUnicode: Support Unicode characters like box drawing
11
+ */
12
+ module.exports = function createScreen() {
13
+ const screen = blessed.screen({
14
+ smartCSR: true, // Key for flicker-free differential rendering
15
+ fullUnicode: true, // Support Unicode characters
16
+ title: 'AgileFlow TUI',
17
+ cursor: {
18
+ artificial: true,
19
+ blink: true,
20
+ shape: 'line',
21
+ },
22
+ debug: false,
23
+ warnings: false,
24
+ autoPadding: true,
25
+ dockBorders: true,
26
+ });
27
+
28
+ // Enable synchronized output mode for atomic updates
29
+ // This batches all screen updates and flushes them at once
30
+ // Note: Not all terminals support this, but it gracefully degrades
31
+ try {
32
+ process.stdout.write('\x1b[?2026h');
33
+ } catch (e) {
34
+ // Ignore if terminal doesn't support
35
+ }
36
+
37
+ // Disable synchronized output on exit
38
+ process.on('exit', () => {
39
+ try {
40
+ process.stdout.write('\x1b[?2026l');
41
+ } catch (e) {
42
+ // Ignore
43
+ }
44
+ });
45
+
46
+ // Handle resize gracefully
47
+ screen.on('resize', () => {
48
+ screen.render();
49
+ });
50
+
51
+ return screen;
52
+ };
@@ -0,0 +1,47 @@
1
+ 'use strict';
2
+
3
+ const blessed = require('blessed');
4
+
5
+ /**
6
+ * Create the status bar at the bottom with always-visible key hints
7
+ * nano-style: users can always see what keys are available
8
+ */
9
+ module.exports = function createStatusBar(screen, state) {
10
+ const statusBar = blessed.box({
11
+ parent: screen,
12
+ bottom: 0,
13
+ left: 0,
14
+ width: '100%',
15
+ height: 1,
16
+ tags: true,
17
+ style: {
18
+ fg: 'white',
19
+ bg: 'blue',
20
+ },
21
+ });
22
+
23
+ // Always-visible key hints (nano-style for user-friendliness)
24
+ const hints = [
25
+ '{bold}1-3{/bold}:Tab',
26
+ '{bold}Tab{/bold}:Next',
27
+ '{bold}j/k{/bold}:Nav',
28
+ '{bold}r{/bold}:Refresh',
29
+ '{bold}?{/bold}:Help',
30
+ '{bold}q{/bold}:Quit',
31
+ ];
32
+
33
+ const hintText = ' ' + hints.join(' ');
34
+ statusBar.setContent(hintText);
35
+
36
+ return {
37
+ element: statusBar,
38
+ setStatus(text) {
39
+ // Show custom status with key hints
40
+ const shortHints = ['{bold}r{/bold}:Refresh', '{bold}?{/bold}:Help', '{bold}q{/bold}:Quit'];
41
+ statusBar.setContent(` ${text} | ${shortHints.join(' ')}`);
42
+ },
43
+ resetHints() {
44
+ statusBar.setContent(hintText);
45
+ },
46
+ };
47
+ };
@@ -0,0 +1,99 @@
1
+ 'use strict';
2
+
3
+ const blessed = require('blessed');
4
+
5
+ /**
6
+ * Create a proper styled tab bar with visual distinction
7
+ */
8
+ module.exports = function createTabBar(screen, state) {
9
+ // Header bar background
10
+ const header = blessed.box({
11
+ parent: screen,
12
+ top: 0,
13
+ left: 0,
14
+ width: '100%',
15
+ height: 3,
16
+ style: {
17
+ bg: 'black',
18
+ },
19
+ });
20
+
21
+ // Logo/title
22
+ blessed.box({
23
+ parent: header,
24
+ top: 0,
25
+ left: 0,
26
+ width: 20,
27
+ height: 3,
28
+ content: '{bold}{#e8683a-fg}▄▀▄ AgileFlow{/}',
29
+ tags: true,
30
+ style: {
31
+ bg: 'black',
32
+ },
33
+ });
34
+
35
+ // Tab container
36
+ const tabContainer = blessed.box({
37
+ parent: header,
38
+ top: 0,
39
+ left: 20,
40
+ width: '100%-20',
41
+ height: 3,
42
+ style: {
43
+ bg: 'black',
44
+ },
45
+ });
46
+
47
+ // Create styled tabs
48
+ const tabs = state.tabs.map((name, i) => {
49
+ const tab = blessed.box({
50
+ parent: tabContainer,
51
+ top: 1,
52
+ left: i * 18,
53
+ width: 16,
54
+ height: 1,
55
+ content: `[${i + 1}] ${name}`,
56
+ tags: true,
57
+ style: {
58
+ fg: 'white',
59
+ bg: 'black',
60
+ },
61
+ });
62
+ return tab;
63
+ });
64
+
65
+ // Version info on right
66
+ blessed.box({
67
+ parent: header,
68
+ top: 1,
69
+ right: 1,
70
+ width: 12,
71
+ height: 1,
72
+ content: '{gray-fg}v2.90.7{/}',
73
+ tags: true,
74
+ style: {
75
+ bg: 'black',
76
+ },
77
+ });
78
+
79
+ return {
80
+ element: header,
81
+ setTab(index) {
82
+ tabs.forEach((tab, i) => {
83
+ if (i === index) {
84
+ // Active tab - cyan background, black text, with brackets
85
+ tab.style.fg = 'black';
86
+ tab.style.bg = 'cyan';
87
+ tab.style.bold = true;
88
+ tab.setContent(`▶ ${state.tabs[i]} ◀`);
89
+ } else {
90
+ // Inactive tabs
91
+ tab.style.fg = 'gray';
92
+ tab.style.bg = 'black';
93
+ tab.style.bold = false;
94
+ tab.setContent(`[${i + 1}] ${state.tabs[i]}`);
95
+ }
96
+ });
97
+ },
98
+ };
99
+ };
@@ -4,50 +4,58 @@
4
4
  /**
5
5
  * AgileFlow TUI - Terminal User Interface
6
6
  *
7
- * Real-time visualization for session monitoring, multi-agent orchestration,
8
- * and interactive loop control.
7
+ * Full-screen, flicker-free dashboard for session monitoring, multi-agent
8
+ * orchestration, and interactive workflow control.
9
9
  *
10
10
  * Usage:
11
11
  * node scripts/tui/index.js
12
12
  * npx agileflow tui
13
+ * npx agileflow tui --fallback (use simple ANSI version)
13
14
  *
14
15
  * Key bindings:
15
- * q - Quit TUI
16
- * s - Start loop on current story
17
- * p - Pause active loop
18
- * r - Resume paused loop
19
- * t - Toggle trace panel
20
- * 1-9 - Switch session focus
16
+ * 1-3 Switch tabs (Sessions, Output, Trace)
17
+ * Tab Next tab
18
+ * j/k Navigate list items
19
+ * r Refresh data
20
+ * ?/h Toggle help overlay
21
+ * q Quit TUI
21
22
  */
22
23
 
23
- // Use simple-tui (pure Node.js) - Ink has React version conflicts in monorepo
24
- const useInk = false;
24
+ // Check for --fallback flag
25
+ const useFallback = process.argv.includes('--fallback') || process.argv.includes('--simple');
25
26
 
26
27
  /**
27
28
  * Main entry point
28
29
  */
29
30
  async function main() {
30
- if (useInk) {
31
- // Use the React/Ink-based Dashboard for modern terminals
32
- const React = require('react');
33
- const { render } = require('ink');
34
- const { Dashboard } = require('./Dashboard');
35
-
36
- // Handle actions from the dashboard
37
- const handleAction = action => {
38
- // TODO: Implement loop control actions
39
- // console.log('Action:', action);
40
- };
41
-
42
- // Render the dashboard
43
- const { waitUntilExit } = render(React.createElement(Dashboard, { onAction: handleAction }));
44
-
45
- // Wait for exit
46
- await waitUntilExit();
31
+ if (useFallback) {
32
+ // Use simple TUI (pure Node.js ANSI codes, no dependencies)
33
+ try {
34
+ const { main: simpleTuiMain } = require('./simple-tui');
35
+ simpleTuiMain();
36
+ } catch (err) {
37
+ console.error('Simple TUI Error:', err.message);
38
+ process.exit(1);
39
+ }
47
40
  } else {
48
- // Use simple TUI (pure Node.js, no React dependencies)
49
- const { main: simpleTuiMain } = require('./simple-tui');
50
- simpleTuiMain();
41
+ // Use blessed TUI (professional full-screen interface)
42
+ try {
43
+ const { main: blessedMain } = require('./blessed');
44
+ blessedMain();
45
+ } catch (err) {
46
+ // If blessed fails (missing deps, terminal issues), fall back to simple
47
+ console.error('Blessed TUI failed to load:', err.message);
48
+ console.error('Falling back to simple TUI...\n');
49
+
50
+ try {
51
+ const { main: simpleTuiMain } = require('./simple-tui');
52
+ simpleTuiMain();
53
+ } catch (fallbackErr) {
54
+ console.error('Fallback TUI also failed:', fallbackErr.message);
55
+ console.error('\nTry running with: npx agileflow status');
56
+ process.exit(1);
57
+ }
58
+ }
51
59
  }
52
60
  }
53
61
 
@@ -0,0 +1,143 @@
1
+ # Validators
2
+
3
+ Specialized self-validation scripts for AgileFlow agents.
4
+
5
+ ## Overview
6
+
7
+ Validators are Node.js scripts that run via hooks to verify agent output. They enable **closed-loop prompts** where validation is guaranteed, not optional.
8
+
9
+ **Research**: See [ADR-0009](../../../docs/03-decisions/adr-0009-specialized-self-validating-agents.md)
10
+
11
+ ---
12
+
13
+ ## Exit Codes
14
+
15
+ | Code | Meaning | Behavior |
16
+ |------|---------|----------|
17
+ | `0` | Success | Proceed normally |
18
+ | `2` | Error (blocking) | Stderr sent to Claude for self-correction |
19
+ | Other | Warning | Log but continue |
20
+
21
+ **Exit code 2 is special**: Claude receives stderr output and automatically attempts to fix the issue.
22
+
23
+ ---
24
+
25
+ ## Input Format
26
+
27
+ Validators receive JSON via stdin with tool context:
28
+
29
+ ```json
30
+ {
31
+ "tool_name": "Write",
32
+ "tool_input": {
33
+ "file_path": "/path/to/file.json",
34
+ "content": "..."
35
+ },
36
+ "result": "File written successfully"
37
+ }
38
+ ```
39
+
40
+ ---
41
+
42
+ ## Validator Template
43
+
44
+ ```javascript
45
+ #!/usr/bin/env node
46
+ const fs = require('fs');
47
+
48
+ let input = '';
49
+ process.stdin.on('data', chunk => input += chunk);
50
+ process.stdin.on('end', () => {
51
+ try {
52
+ const context = JSON.parse(input);
53
+ const filePath = context.tool_input?.file_path;
54
+
55
+ if (!filePath) {
56
+ console.log('No file path in context, skipping');
57
+ process.exit(0);
58
+ }
59
+
60
+ // Your validation logic here
61
+ const issues = validate(filePath);
62
+
63
+ if (issues.length > 0) {
64
+ // Exit 2 = Claude will try to fix these
65
+ console.error(`Resolve these issues in ${filePath}:`);
66
+ issues.forEach(i => console.error(` - ${i}`));
67
+ process.exit(2);
68
+ }
69
+
70
+ console.log(`Validation passed: ${filePath}`);
71
+ process.exit(0);
72
+ } catch (e) {
73
+ // Exit 1 = warning, don't block
74
+ console.error(`Validator error: ${e.message}`);
75
+ process.exit(1);
76
+ }
77
+ });
78
+
79
+ function validate(filePath) {
80
+ const issues = [];
81
+ // Add your checks here
82
+ return issues;
83
+ }
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Hook Configuration
89
+
90
+ Add hooks to agent/command frontmatter:
91
+
92
+ ### PostToolUse (after each tool call)
93
+
94
+ ```yaml
95
+ hooks:
96
+ PostToolUse:
97
+ - matcher: "Write"
98
+ hooks:
99
+ - type: command
100
+ command: "node .agileflow/hooks/validators/your-validator.js"
101
+ ```
102
+
103
+ ### Stop (when agent finishes)
104
+
105
+ ```yaml
106
+ hooks:
107
+ Stop:
108
+ - hooks:
109
+ - type: command
110
+ command: "node .agileflow/hooks/validators/final-validator.js"
111
+ ```
112
+
113
+ ---
114
+
115
+ ## Best Practices
116
+
117
+ 1. **Keep validators fast** (< 100ms) - they run on every matching tool call
118
+ 2. **Use specific matchers** - `"Write"` not `"Write|Edit|Read"`
119
+ 3. **Return helpful errors** - Claude uses stderr to fix issues
120
+ 4. **Test standalone first** - `echo '{"tool_input":{"file_path":"test.json"}}' | node validator.js`
121
+ 5. **Log success too** - helps debugging hook chains
122
+
123
+ ---
124
+
125
+ ## Available Validators
126
+
127
+ | Validator | Purpose | Matcher |
128
+ |-----------|---------|---------|
129
+ | `json-schema-validator.js` | Validate JSON structure | Write (*.json) |
130
+ | `markdown-validator.js` | Validate markdown format | Write (*.md) |
131
+ | `story-format-validator.js` | Validate story structure | Write (status.json) |
132
+
133
+ ---
134
+
135
+ ## Testing Validators
136
+
137
+ ```bash
138
+ # Test with sample input
139
+ echo '{"tool_name":"Write","tool_input":{"file_path":"test.json","content":"{}"}}' | node json-schema-validator.js
140
+
141
+ # Check exit code
142
+ echo $?
143
+ ```