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.
- package/CHANGELOG.md +10 -0
- package/README.md +6 -6
- package/lib/README.md +178 -0
- package/lib/codebase-indexer.js +818 -0
- package/lib/colors.js +190 -12
- package/lib/consent.js +232 -0
- package/lib/correlation.js +277 -0
- package/lib/error-codes.js +46 -0
- package/lib/errors.js +48 -6
- package/lib/file-cache.js +182 -0
- package/lib/format-error.js +156 -0
- package/lib/path-resolver.js +155 -7
- package/lib/paths.js +212 -20
- package/lib/placeholder-registry.js +205 -0
- package/lib/registry-di.js +358 -0
- package/lib/result-schema.js +363 -0
- package/lib/result.js +210 -0
- package/lib/session-registry.js +13 -0
- package/lib/session-state-machine.js +465 -0
- package/lib/validate-commands.js +308 -0
- package/lib/validate-names.js +3 -3
- package/lib/validate.js +116 -52
- package/package.json +4 -1
- package/scripts/af +34 -0
- package/scripts/agent-loop.js +63 -9
- package/scripts/agileflow-configure.js +2 -2
- package/scripts/agileflow-welcome.js +435 -23
- package/scripts/archive-completed-stories.sh +57 -11
- package/scripts/claude-tmux.sh +102 -0
- package/scripts/damage-control-bash.js +3 -70
- package/scripts/damage-control-edit.js +3 -20
- package/scripts/damage-control-write.js +3 -20
- package/scripts/dependency-check.js +310 -0
- package/scripts/get-env.js +11 -4
- package/scripts/lib/configure-detect.js +23 -1
- package/scripts/lib/configure-features.js +43 -2
- package/scripts/lib/context-formatter.js +771 -0
- package/scripts/lib/context-loader.js +699 -0
- package/scripts/lib/damage-control-utils.js +107 -0
- package/scripts/lib/json-utils.sh +162 -0
- package/scripts/lib/state-migrator.js +353 -0
- package/scripts/lib/story-state-machine.js +437 -0
- package/scripts/obtain-context.js +118 -1048
- package/scripts/pre-push-check.sh +46 -0
- package/scripts/precompact-context.sh +36 -11
- package/scripts/query-codebase.js +538 -0
- package/scripts/ralph-loop.js +5 -5
- package/scripts/session-manager.js +220 -42
- package/scripts/spawn-parallel.js +651 -0
- package/scripts/tui/blessed/data/watcher.js +180 -0
- package/scripts/tui/blessed/index.js +244 -0
- package/scripts/tui/blessed/panels/output.js +101 -0
- package/scripts/tui/blessed/panels/sessions.js +150 -0
- package/scripts/tui/blessed/panels/trace.js +97 -0
- package/scripts/tui/blessed/ui/help.js +77 -0
- package/scripts/tui/blessed/ui/screen.js +52 -0
- package/scripts/tui/blessed/ui/statusbar.js +47 -0
- package/scripts/tui/blessed/ui/tabbar.js +99 -0
- package/scripts/tui/index.js +38 -30
- package/scripts/validators/README.md +143 -0
- package/scripts/validators/component-validator.js +239 -0
- package/scripts/validators/json-schema-validator.js +186 -0
- package/scripts/validators/markdown-validator.js +152 -0
- package/scripts/validators/migration-validator.js +129 -0
- package/scripts/validators/security-validator.js +380 -0
- package/scripts/validators/story-format-validator.js +197 -0
- package/scripts/validators/test-result-validator.js +114 -0
- package/scripts/validators/workflow-validator.js +247 -0
- package/src/core/agents/accessibility.md +6 -0
- package/src/core/agents/adr-writer.md +6 -0
- package/src/core/agents/analytics.md +6 -0
- package/src/core/agents/api.md +6 -0
- package/src/core/agents/ci.md +6 -0
- package/src/core/agents/codebase-query.md +261 -0
- package/src/core/agents/compliance.md +6 -0
- package/src/core/agents/configuration-damage-control.md +6 -0
- package/src/core/agents/configuration-visual-e2e.md +6 -0
- package/src/core/agents/database.md +10 -0
- package/src/core/agents/datamigration.md +6 -0
- package/src/core/agents/design.md +6 -0
- package/src/core/agents/devops.md +6 -0
- package/src/core/agents/documentation.md +6 -0
- package/src/core/agents/epic-planner.md +6 -0
- package/src/core/agents/integrations.md +6 -0
- package/src/core/agents/mentor.md +6 -0
- package/src/core/agents/mobile.md +6 -0
- package/src/core/agents/monitoring.md +6 -0
- package/src/core/agents/multi-expert.md +6 -0
- package/src/core/agents/performance.md +6 -0
- package/src/core/agents/product.md +6 -0
- package/src/core/agents/qa.md +6 -0
- package/src/core/agents/readme-updater.md +6 -0
- package/src/core/agents/refactor.md +6 -0
- package/src/core/agents/research.md +6 -0
- package/src/core/agents/security.md +6 -0
- package/src/core/agents/testing.md +10 -0
- package/src/core/agents/ui.md +6 -0
- package/src/core/commands/adr.md +114 -0
- package/src/core/commands/agent.md +120 -0
- package/src/core/commands/assign.md +145 -0
- package/src/core/commands/audit.md +401 -0
- package/src/core/commands/babysit.md +32 -5
- package/src/core/commands/board.md +1 -0
- package/src/core/commands/changelog.md +118 -0
- package/src/core/commands/configure.md +42 -6
- package/src/core/commands/diagnose.md +114 -0
- package/src/core/commands/epic.md +205 -1
- package/src/core/commands/handoff.md +128 -0
- package/src/core/commands/help.md +76 -0
- package/src/core/commands/metrics.md +1 -0
- package/src/core/commands/pr.md +96 -0
- package/src/core/commands/research/analyze.md +1 -0
- package/src/core/commands/research/ask.md +2 -0
- package/src/core/commands/research/import.md +1 -0
- package/src/core/commands/research/list.md +2 -0
- package/src/core/commands/research/synthesize.md +584 -0
- package/src/core/commands/research/view.md +2 -0
- package/src/core/commands/roadmap/analyze.md +400 -0
- package/src/core/commands/session/new.md +113 -6
- package/src/core/commands/session/spawn.md +197 -0
- package/src/core/commands/sprint.md +22 -0
- package/src/core/commands/status.md +200 -1
- package/src/core/commands/story/list.md +9 -9
- package/src/core/commands/story/view.md +1 -0
- package/src/core/commands/story.md +143 -4
- package/src/core/experts/codebase-query/expertise.yaml +190 -0
- package/src/core/experts/codebase-query/question.md +73 -0
- package/src/core/experts/codebase-query/self-improve.md +105 -0
- package/src/core/templates/agileflow-metadata.json +55 -2
- package/src/core/templates/plan-template.md +125 -0
- package/src/core/templates/story-lifecycle.md +213 -0
- package/src/core/templates/story-template.md +4 -0
- package/src/core/templates/tdd-test-template.js +241 -0
- package/tools/cli/commands/setup.js +86 -0
- package/tools/cli/installers/core/installer.js +94 -0
- package/tools/cli/installers/ide/_base-ide.js +20 -11
- package/tools/cli/installers/ide/codex.js +29 -47
- package/tools/cli/lib/config-manager.js +17 -2
- package/tools/cli/lib/content-transformer.js +271 -0
- package/tools/cli/lib/error-handler.js +14 -22
- package/tools/cli/lib/ide-error-factory.js +421 -0
- package/tools/cli/lib/ide-health-monitor.js +364 -0
- package/tools/cli/lib/ide-registry.js +114 -1
- 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
|
+
};
|
package/scripts/tui/index.js
CHANGED
|
@@ -4,50 +4,58 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* AgileFlow TUI - Terminal User Interface
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* and interactive
|
|
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
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* r
|
|
19
|
-
*
|
|
20
|
-
*
|
|
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
|
-
//
|
|
24
|
-
const
|
|
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 (
|
|
31
|
-
// Use
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
49
|
-
|
|
50
|
-
|
|
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
|
+
```
|