agileflow 2.79.0 → 2.80.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/package.json +1 -1
- package/scripts/agileflow-configure.js +126 -17
- package/scripts/agileflow-welcome.js +48 -16
- package/scripts/damage-control/bash-tool-damage-control.js +7 -6
- package/scripts/damage-control/edit-tool-damage-control.js +4 -24
- package/scripts/damage-control/patterns.yaml +32 -32
- package/scripts/damage-control/write-tool-damage-control.js +4 -24
- package/scripts/damage-control-bash.js +28 -22
- package/scripts/damage-control-edit.js +6 -12
- package/scripts/damage-control-write.js +6 -12
- package/scripts/get-env.js +6 -6
- package/scripts/obtain-context.js +47 -36
- package/scripts/ralph-loop.js +14 -6
- package/scripts/screenshot-verifier.js +4 -2
- package/src/core/commands/configure.md +46 -9
- package/src/core/experts/documentation/expertise.yaml +25 -0
- package/tools/cli/commands/start.js +19 -21
- package/tools/cli/installers/ide/claude-code.js +32 -19
- package/tools/cli/tui/Dashboard.js +3 -4
- package/tools/postinstall.js +1 -9
|
@@ -114,27 +114,9 @@ function parsePathRules(content) {
|
|
|
114
114
|
*/
|
|
115
115
|
function getDefaultPathRules() {
|
|
116
116
|
return {
|
|
117
|
-
zeroAccessPaths: [
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
'.env',
|
|
121
|
-
'.env.local',
|
|
122
|
-
'.env.production',
|
|
123
|
-
],
|
|
124
|
-
readOnlyPaths: [
|
|
125
|
-
'/etc/',
|
|
126
|
-
'~/.bashrc',
|
|
127
|
-
'~/.zshrc',
|
|
128
|
-
'package-lock.json',
|
|
129
|
-
'yarn.lock',
|
|
130
|
-
'.git/',
|
|
131
|
-
],
|
|
132
|
-
noDeletePaths: [
|
|
133
|
-
'.agileflow/',
|
|
134
|
-
'.claude/',
|
|
135
|
-
'docs/09-agents/status.json',
|
|
136
|
-
'CLAUDE.md',
|
|
137
|
-
],
|
|
117
|
+
zeroAccessPaths: ['~/.ssh/', '~/.aws/credentials', '.env', '.env.local', '.env.production'],
|
|
118
|
+
readOnlyPaths: ['/etc/', '~/.bashrc', '~/.zshrc', 'package-lock.json', 'yarn.lock', '.git/'],
|
|
119
|
+
noDeletePaths: ['.agileflow/', '.claude/', 'docs/09-agents/status.json', 'CLAUDE.md'],
|
|
138
120
|
};
|
|
139
121
|
}
|
|
140
122
|
|
|
@@ -247,9 +229,7 @@ function main() {
|
|
|
247
229
|
}
|
|
248
230
|
|
|
249
231
|
// Resolve to absolute path
|
|
250
|
-
const absolutePath = path.isAbsolute(filePath)
|
|
251
|
-
? filePath
|
|
252
|
-
: path.join(projectDir, filePath);
|
|
232
|
+
const absolutePath = path.isAbsolute(filePath) ? filePath : path.join(projectDir, filePath);
|
|
253
233
|
|
|
254
234
|
// Load rules
|
|
255
235
|
const rules = loadPathRules(projectDir);
|
|
@@ -17,14 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
const fs = require('fs');
|
|
19
19
|
const path = require('path');
|
|
20
|
-
|
|
21
|
-
// Color codes for output
|
|
22
|
-
const c = {
|
|
23
|
-
red: '\x1b[38;5;203m',
|
|
24
|
-
yellow: '\x1b[38;5;215m',
|
|
25
|
-
reset: '\x1b[0m',
|
|
26
|
-
dim: '\x1b[2m'
|
|
27
|
-
};
|
|
20
|
+
const { c } = require('../lib/colors');
|
|
28
21
|
|
|
29
22
|
/**
|
|
30
23
|
* Find project root by looking for .agileflow directory
|
|
@@ -48,7 +41,7 @@ function parseSimpleYAML(content) {
|
|
|
48
41
|
const config = {
|
|
49
42
|
bashToolPatterns: [],
|
|
50
43
|
askPatterns: [],
|
|
51
|
-
agileflowProtections: []
|
|
44
|
+
agileflowProtections: [],
|
|
52
45
|
};
|
|
53
46
|
|
|
54
47
|
let currentSection = null;
|
|
@@ -76,13 +69,22 @@ function parseSimpleYAML(content) {
|
|
|
76
69
|
currentPattern = null;
|
|
77
70
|
} else if (trimmed.startsWith('- pattern:') && currentSection) {
|
|
78
71
|
// New pattern entry
|
|
79
|
-
const patternValue = trimmed
|
|
72
|
+
const patternValue = trimmed
|
|
73
|
+
.replace('- pattern:', '')
|
|
74
|
+
.trim()
|
|
75
|
+
.replace(/^["']|["']$/g, '');
|
|
80
76
|
currentPattern = { pattern: patternValue };
|
|
81
77
|
config[currentSection].push(currentPattern);
|
|
82
78
|
} else if (trimmed.startsWith('reason:') && currentPattern) {
|
|
83
|
-
currentPattern.reason = trimmed
|
|
79
|
+
currentPattern.reason = trimmed
|
|
80
|
+
.replace('reason:', '')
|
|
81
|
+
.trim()
|
|
82
|
+
.replace(/^["']|["']$/g, '');
|
|
84
83
|
} else if (trimmed.startsWith('flags:') && currentPattern) {
|
|
85
|
-
currentPattern.flags = trimmed
|
|
84
|
+
currentPattern.flags = trimmed
|
|
85
|
+
.replace('flags:', '')
|
|
86
|
+
.trim()
|
|
87
|
+
.replace(/^["']|["']$/g, '');
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
|
|
@@ -96,7 +98,7 @@ function loadPatterns(projectRoot) {
|
|
|
96
98
|
const configPaths = [
|
|
97
99
|
path.join(projectRoot, '.agileflow/config/damage-control-patterns.yaml'),
|
|
98
100
|
path.join(projectRoot, '.agileflow/config/damage-control-patterns.yml'),
|
|
99
|
-
path.join(projectRoot, '.agileflow/templates/damage-control-patterns.yaml')
|
|
101
|
+
path.join(projectRoot, '.agileflow/templates/damage-control-patterns.yaml'),
|
|
100
102
|
];
|
|
101
103
|
|
|
102
104
|
for (const configPath of configPaths) {
|
|
@@ -135,14 +137,14 @@ function validateCommand(command, config) {
|
|
|
135
137
|
// Check blocked patterns (bashToolPatterns + agileflowProtections)
|
|
136
138
|
const blockedPatterns = [
|
|
137
139
|
...(config.bashToolPatterns || []),
|
|
138
|
-
...(config.agileflowProtections || [])
|
|
140
|
+
...(config.agileflowProtections || []),
|
|
139
141
|
];
|
|
140
142
|
|
|
141
143
|
for (const rule of blockedPatterns) {
|
|
142
144
|
if (matchesPattern(command, rule)) {
|
|
143
145
|
return {
|
|
144
146
|
action: 'block',
|
|
145
|
-
reason: rule.reason || 'Command blocked by damage control'
|
|
147
|
+
reason: rule.reason || 'Command blocked by damage control',
|
|
146
148
|
};
|
|
147
149
|
}
|
|
148
150
|
}
|
|
@@ -152,7 +154,7 @@ function validateCommand(command, config) {
|
|
|
152
154
|
if (matchesPattern(command, rule)) {
|
|
153
155
|
return {
|
|
154
156
|
action: 'ask',
|
|
155
|
-
reason: rule.reason || 'Please confirm this command'
|
|
157
|
+
reason: rule.reason || 'Please confirm this command',
|
|
156
158
|
};
|
|
157
159
|
}
|
|
158
160
|
}
|
|
@@ -192,17 +194,21 @@ function main() {
|
|
|
192
194
|
switch (result.action) {
|
|
193
195
|
case 'block':
|
|
194
196
|
// Output error message and block
|
|
195
|
-
console.error(`${c.
|
|
196
|
-
console.error(
|
|
197
|
+
console.error(`${c.coral}[BLOCKED]${c.reset} ${result.reason}`);
|
|
198
|
+
console.error(
|
|
199
|
+
`${c.dim}Command: ${command.substring(0, 100)}${command.length > 100 ? '...' : ''}${c.reset}`
|
|
200
|
+
);
|
|
197
201
|
process.exit(2);
|
|
198
202
|
break;
|
|
199
203
|
|
|
200
204
|
case 'ask':
|
|
201
205
|
// Output JSON to trigger user confirmation
|
|
202
|
-
console.log(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
+
console.log(
|
|
207
|
+
JSON.stringify({
|
|
208
|
+
result: 'ask',
|
|
209
|
+
message: result.reason,
|
|
210
|
+
})
|
|
211
|
+
);
|
|
206
212
|
process.exit(0);
|
|
207
213
|
break;
|
|
208
214
|
|
|
@@ -15,13 +15,7 @@
|
|
|
15
15
|
const fs = require('fs');
|
|
16
16
|
const path = require('path');
|
|
17
17
|
const os = require('os');
|
|
18
|
-
|
|
19
|
-
// Color codes for output
|
|
20
|
-
const c = {
|
|
21
|
-
red: '\x1b[38;5;203m',
|
|
22
|
-
reset: '\x1b[0m',
|
|
23
|
-
dim: '\x1b[2m'
|
|
24
|
-
};
|
|
18
|
+
const { c } = require('../lib/colors');
|
|
25
19
|
|
|
26
20
|
/**
|
|
27
21
|
* Find project root by looking for .agileflow directory
|
|
@@ -54,7 +48,7 @@ function parseSimpleYAML(content) {
|
|
|
54
48
|
const config = {
|
|
55
49
|
zeroAccessPaths: [],
|
|
56
50
|
readOnlyPaths: [],
|
|
57
|
-
noDeletePaths: []
|
|
51
|
+
noDeletePaths: [],
|
|
58
52
|
};
|
|
59
53
|
|
|
60
54
|
let currentSection = null;
|
|
@@ -92,7 +86,7 @@ function loadPatterns(projectRoot) {
|
|
|
92
86
|
const configPaths = [
|
|
93
87
|
path.join(projectRoot, '.agileflow/config/damage-control-patterns.yaml'),
|
|
94
88
|
path.join(projectRoot, '.agileflow/config/damage-control-patterns.yml'),
|
|
95
|
-
path.join(projectRoot, '.agileflow/templates/damage-control-patterns.yaml')
|
|
89
|
+
path.join(projectRoot, '.agileflow/templates/damage-control-patterns.yaml'),
|
|
96
90
|
];
|
|
97
91
|
|
|
98
92
|
for (const configPath of configPaths) {
|
|
@@ -168,7 +162,7 @@ function validatePath(filePath, config) {
|
|
|
168
162
|
return {
|
|
169
163
|
action: 'block',
|
|
170
164
|
reason: `Zero-access path: ${zeroMatch}`,
|
|
171
|
-
detail: 'This file is protected and cannot be accessed'
|
|
165
|
+
detail: 'This file is protected and cannot be accessed',
|
|
172
166
|
};
|
|
173
167
|
}
|
|
174
168
|
|
|
@@ -178,7 +172,7 @@ function validatePath(filePath, config) {
|
|
|
178
172
|
return {
|
|
179
173
|
action: 'block',
|
|
180
174
|
reason: `Read-only path: ${readOnlyMatch}`,
|
|
181
|
-
detail: 'This file is read-only and cannot be edited'
|
|
175
|
+
detail: 'This file is read-only and cannot be edited',
|
|
182
176
|
};
|
|
183
177
|
}
|
|
184
178
|
|
|
@@ -215,7 +209,7 @@ function main() {
|
|
|
215
209
|
const result = validatePath(filePath, config);
|
|
216
210
|
|
|
217
211
|
if (result.action === 'block') {
|
|
218
|
-
console.error(`${c.
|
|
212
|
+
console.error(`${c.coral}[BLOCKED]${c.reset} ${result.reason}`);
|
|
219
213
|
console.error(`${c.dim}${result.detail}${c.reset}`);
|
|
220
214
|
console.error(`${c.dim}File: ${filePath}${c.reset}`);
|
|
221
215
|
process.exit(2);
|
|
@@ -15,13 +15,7 @@
|
|
|
15
15
|
const fs = require('fs');
|
|
16
16
|
const path = require('path');
|
|
17
17
|
const os = require('os');
|
|
18
|
-
|
|
19
|
-
// Color codes for output
|
|
20
|
-
const c = {
|
|
21
|
-
red: '\x1b[38;5;203m',
|
|
22
|
-
reset: '\x1b[0m',
|
|
23
|
-
dim: '\x1b[2m'
|
|
24
|
-
};
|
|
18
|
+
const { c } = require('../lib/colors');
|
|
25
19
|
|
|
26
20
|
/**
|
|
27
21
|
* Find project root by looking for .agileflow directory
|
|
@@ -54,7 +48,7 @@ function parseSimpleYAML(content) {
|
|
|
54
48
|
const config = {
|
|
55
49
|
zeroAccessPaths: [],
|
|
56
50
|
readOnlyPaths: [],
|
|
57
|
-
noDeletePaths: []
|
|
51
|
+
noDeletePaths: [],
|
|
58
52
|
};
|
|
59
53
|
|
|
60
54
|
let currentSection = null;
|
|
@@ -92,7 +86,7 @@ function loadPatterns(projectRoot) {
|
|
|
92
86
|
const configPaths = [
|
|
93
87
|
path.join(projectRoot, '.agileflow/config/damage-control-patterns.yaml'),
|
|
94
88
|
path.join(projectRoot, '.agileflow/config/damage-control-patterns.yml'),
|
|
95
|
-
path.join(projectRoot, '.agileflow/templates/damage-control-patterns.yaml')
|
|
89
|
+
path.join(projectRoot, '.agileflow/templates/damage-control-patterns.yaml'),
|
|
96
90
|
];
|
|
97
91
|
|
|
98
92
|
for (const configPath of configPaths) {
|
|
@@ -168,7 +162,7 @@ function validatePath(filePath, config) {
|
|
|
168
162
|
return {
|
|
169
163
|
action: 'block',
|
|
170
164
|
reason: `Zero-access path: ${zeroMatch}`,
|
|
171
|
-
detail: 'This file is protected and cannot be accessed'
|
|
165
|
+
detail: 'This file is protected and cannot be accessed',
|
|
172
166
|
};
|
|
173
167
|
}
|
|
174
168
|
|
|
@@ -178,7 +172,7 @@ function validatePath(filePath, config) {
|
|
|
178
172
|
return {
|
|
179
173
|
action: 'block',
|
|
180
174
|
reason: `Read-only path: ${readOnlyMatch}`,
|
|
181
|
-
detail: 'This file is read-only and cannot be written to'
|
|
175
|
+
detail: 'This file is read-only and cannot be written to',
|
|
182
176
|
};
|
|
183
177
|
}
|
|
184
178
|
|
|
@@ -215,7 +209,7 @@ function main() {
|
|
|
215
209
|
const result = validatePath(filePath, config);
|
|
216
210
|
|
|
217
211
|
if (result.action === 'block') {
|
|
218
|
-
console.error(`${c.
|
|
212
|
+
console.error(`${c.coral}[BLOCKED]${c.reset} ${result.reason}`);
|
|
219
213
|
console.error(`${c.dim}${result.detail}${c.reset}`);
|
|
220
214
|
console.error(`${c.dim}File: ${filePath}${c.reset}`);
|
|
221
215
|
process.exit(2);
|
package/scripts/get-env.js
CHANGED
|
@@ -156,12 +156,12 @@ function formatOutput(info, asJson = false, compact = false) {
|
|
|
156
156
|
brand: '\x1b[38;2;232;104;58m', // #e8683a - AgileFlow brand orange
|
|
157
157
|
|
|
158
158
|
// Vibrant 256-color palette (modern, sleek look)
|
|
159
|
-
mintGreen: '\x1b[38;5;158m',
|
|
160
|
-
peach: '\x1b[38;5;215m',
|
|
161
|
-
coral: '\x1b[38;5;203m',
|
|
162
|
-
lightGreen: '\x1b[38;5;194m',
|
|
163
|
-
skyBlue: '\x1b[38;5;117m',
|
|
164
|
-
lavender: '\x1b[38;5;147m',
|
|
159
|
+
mintGreen: '\x1b[38;5;158m', // Healthy/success states
|
|
160
|
+
peach: '\x1b[38;5;215m', // Warning states
|
|
161
|
+
coral: '\x1b[38;5;203m', // Critical/error states
|
|
162
|
+
lightGreen: '\x1b[38;5;194m', // Session healthy
|
|
163
|
+
skyBlue: '\x1b[38;5;117m', // Directories/paths
|
|
164
|
+
lavender: '\x1b[38;5;147m', // Model info
|
|
165
165
|
};
|
|
166
166
|
|
|
167
167
|
// Beautiful compact colorful format (using vibrant 256-color palette)
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
const fs = require('fs');
|
|
19
19
|
const path = require('path');
|
|
20
20
|
const { execSync } = require('child_process');
|
|
21
|
+
const { c: C, box } = require('../lib/colors');
|
|
21
22
|
|
|
22
23
|
const DISPLAY_LIMIT = 30000; // Claude Code's Bash tool display limit
|
|
23
24
|
|
|
@@ -44,8 +45,10 @@ if (commandName) {
|
|
|
44
45
|
state: {},
|
|
45
46
|
});
|
|
46
47
|
|
|
47
|
-
//
|
|
48
|
-
state.active_command
|
|
48
|
+
// Remove legacy active_command field (only use active_commands array now)
|
|
49
|
+
if (state.active_command !== undefined) {
|
|
50
|
+
delete state.active_command;
|
|
51
|
+
}
|
|
49
52
|
|
|
50
53
|
fs.writeFileSync(sessionStatePath, JSON.stringify(state, null, 2) + '\n');
|
|
51
54
|
} catch (e) {
|
|
@@ -54,33 +57,6 @@ if (commandName) {
|
|
|
54
57
|
}
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
// ANSI colors
|
|
58
|
-
const C = {
|
|
59
|
-
reset: '\x1b[0m',
|
|
60
|
-
dim: '\x1b[2m',
|
|
61
|
-
bold: '\x1b[1m',
|
|
62
|
-
cyan: '\x1b[36m',
|
|
63
|
-
yellow: '\x1b[33m',
|
|
64
|
-
green: '\x1b[32m',
|
|
65
|
-
red: '\x1b[31m',
|
|
66
|
-
magenta: '\x1b[35m',
|
|
67
|
-
blue: '\x1b[34m',
|
|
68
|
-
brightCyan: '\x1b[96m',
|
|
69
|
-
brightYellow: '\x1b[93m',
|
|
70
|
-
brightGreen: '\x1b[92m',
|
|
71
|
-
brand: '\x1b[38;2;232;104;58m', // AgileFlow brand orange
|
|
72
|
-
|
|
73
|
-
// Vibrant 256-color palette (modern, sleek look)
|
|
74
|
-
mintGreen: '\x1b[38;5;158m', // Healthy/success states
|
|
75
|
-
peach: '\x1b[38;5;215m', // Warning states
|
|
76
|
-
coral: '\x1b[38;5;203m', // Critical/error states
|
|
77
|
-
lightGreen: '\x1b[38;5;194m', // Session healthy
|
|
78
|
-
lightYellow: '\x1b[38;5;228m', // Session warning
|
|
79
|
-
skyBlue: '\x1b[38;5;117m', // Directories/paths
|
|
80
|
-
lavender: '\x1b[38;5;147m', // Model info
|
|
81
|
-
softGold: '\x1b[38;5;222m', // Cost/money
|
|
82
|
-
};
|
|
83
|
-
|
|
84
60
|
function safeRead(filePath) {
|
|
85
61
|
try {
|
|
86
62
|
return fs.readFileSync(filePath, 'utf8');
|
|
@@ -225,7 +201,8 @@ function generateSummary() {
|
|
|
225
201
|
|
|
226
202
|
// Header row (full width, no column divider)
|
|
227
203
|
const title = commandName ? `Context [${commandName}]` : 'Context Summary';
|
|
228
|
-
const branchColor =
|
|
204
|
+
const branchColor =
|
|
205
|
+
branch === 'main' ? C.mintGreen : branch.startsWith('fix') ? C.coral : C.skyBlue;
|
|
229
206
|
const maxBranchLen = 20;
|
|
230
207
|
const branchDisplay =
|
|
231
208
|
branch.length > maxBranchLen ? branch.substring(0, maxBranchLen - 2) + '..' : branch;
|
|
@@ -300,7 +277,12 @@ function generateSummary() {
|
|
|
300
277
|
|
|
301
278
|
// Research
|
|
302
279
|
const researchText = researchFiles.length > 0 ? `${researchFiles.length} notes` : 'none';
|
|
303
|
-
summary += row(
|
|
280
|
+
summary += row(
|
|
281
|
+
'Research',
|
|
282
|
+
researchText,
|
|
283
|
+
C.lavender,
|
|
284
|
+
researchFiles.length > 0 ? C.skyBlue : C.dim
|
|
285
|
+
);
|
|
304
286
|
|
|
305
287
|
// Epics
|
|
306
288
|
const epicText = epicFiles.length > 0 ? `${epicFiles.length} epics` : 'none';
|
|
@@ -396,7 +378,36 @@ function generateFullContent() {
|
|
|
396
378
|
content += `${C.dim}No session-state.json found${C.reset}\n`;
|
|
397
379
|
}
|
|
398
380
|
|
|
399
|
-
// 4.
|
|
381
|
+
// 4. INTERACTION MODE (AskUserQuestion guidance)
|
|
382
|
+
const metadata = safeReadJSON('docs/00-meta/agileflow-metadata.json');
|
|
383
|
+
const askUserQuestionConfig = metadata?.features?.askUserQuestion;
|
|
384
|
+
|
|
385
|
+
if (askUserQuestionConfig?.enabled) {
|
|
386
|
+
content += `\n${C.brand}${C.bold}═══ ⚡ INTERACTION MODE: AskUserQuestion ENABLED ═══${C.reset}\n`;
|
|
387
|
+
content += `${C.dim}${'─'.repeat(60)}${C.reset}\n`;
|
|
388
|
+
content += `${C.bold}CRITICAL RULE:${C.reset} End ${C.skyBlue}EVERY${C.reset} response with the AskUserQuestion tool.\n\n`;
|
|
389
|
+
content += `${C.mintGreen}✓ CORRECT:${C.reset} Call the actual AskUserQuestion tool\n`;
|
|
390
|
+
content += `${C.coral}✗ WRONG:${C.reset} Text like "Want me to continue?" or "What's next?"\n\n`;
|
|
391
|
+
content += `${C.lavender}Required format:${C.reset}\n`;
|
|
392
|
+
content += `${C.dim}\`\`\`xml
|
|
393
|
+
<invoke name="AskUserQuestion">
|
|
394
|
+
<parameter name="questions">[{
|
|
395
|
+
"question": "What would you like to do next?",
|
|
396
|
+
"header": "Next step",
|
|
397
|
+
"multiSelect": false,
|
|
398
|
+
"options": [
|
|
399
|
+
{"label": "Option A (Recommended)", "description": "Why this is best"},
|
|
400
|
+
{"label": "Option B", "description": "Alternative approach"},
|
|
401
|
+
{"label": "Pause", "description": "Stop here for now"}
|
|
402
|
+
]
|
|
403
|
+
}]</parameter>
|
|
404
|
+
</invoke>
|
|
405
|
+
\`\`\`${C.reset}\n`;
|
|
406
|
+
content += `${C.dim}${'─'.repeat(60)}${C.reset}\n`;
|
|
407
|
+
content += `${C.dim}Mode: ${askUserQuestionConfig.mode || 'all'} | Configure: /agileflow:configure${C.reset}\n\n`;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// 5. DOCS STRUCTURE (using vibrant 256-color palette)
|
|
400
411
|
content += `\n${C.skyBlue}${C.bold}═══ Documentation ═══${C.reset}\n`;
|
|
401
412
|
const docsDir = 'docs';
|
|
402
413
|
const docFolders = safeLs(docsDir).filter(f => {
|
|
@@ -420,7 +431,7 @@ function generateFullContent() {
|
|
|
420
431
|
});
|
|
421
432
|
}
|
|
422
433
|
|
|
423
|
-
//
|
|
434
|
+
// 6. RESEARCH NOTES - List + Full content of most recent (using vibrant 256-color palette)
|
|
424
435
|
content += `\n${C.skyBlue}${C.bold}═══ Research Notes ═══${C.reset}\n`;
|
|
425
436
|
const researchDir = 'docs/10-research';
|
|
426
437
|
const researchFiles = safeLs(researchDir).filter(f => f.endsWith('.md') && f !== 'README.md');
|
|
@@ -443,7 +454,7 @@ function generateFullContent() {
|
|
|
443
454
|
content += `${C.dim}No research notes${C.reset}\n`;
|
|
444
455
|
}
|
|
445
456
|
|
|
446
|
-
//
|
|
457
|
+
// 7. BUS MESSAGES (using vibrant 256-color palette)
|
|
447
458
|
content += `\n${C.skyBlue}${C.bold}═══ Recent Agent Messages ═══${C.reset}\n`;
|
|
448
459
|
const busPath = 'docs/09-agents/bus/log.jsonl';
|
|
449
460
|
const busContent = safeRead(busPath);
|
|
@@ -467,7 +478,7 @@ function generateFullContent() {
|
|
|
467
478
|
content += `${C.dim}No bus log found${C.reset}\n`;
|
|
468
479
|
}
|
|
469
480
|
|
|
470
|
-
//
|
|
481
|
+
// 8. KEY FILES - Full content
|
|
471
482
|
content += `\n${C.cyan}${C.bold}═══ Key Context Files (Full Content) ═══${C.reset}\n`;
|
|
472
483
|
|
|
473
484
|
const keyFilesToRead = [
|
|
@@ -493,7 +504,7 @@ function generateFullContent() {
|
|
|
493
504
|
const settingsExists = fs.existsSync('.claude/settings.json');
|
|
494
505
|
content += `\n ${settingsExists ? `${C.green}✓${C.reset}` : `${C.dim}○${C.reset}`} .claude/settings.json\n`;
|
|
495
506
|
|
|
496
|
-
//
|
|
507
|
+
// 9. EPICS FOLDER
|
|
497
508
|
content += `\n${C.cyan}${C.bold}═══ Epic Files ═══${C.reset}\n`;
|
|
498
509
|
const epicFiles = safeLs('docs/05-epics').filter(f => f.endsWith('.md') && f !== 'README.md');
|
|
499
510
|
if (epicFiles.length > 0) {
|
package/scripts/ralph-loop.js
CHANGED
|
@@ -134,7 +134,7 @@ function verifyScreenshots(rootDir) {
|
|
|
134
134
|
const imageExtensions = ['.png', '.jpg', '.jpeg', '.webp', '.gif'];
|
|
135
135
|
let files;
|
|
136
136
|
try {
|
|
137
|
-
files = fs.readdirSync(fullPath).filter(
|
|
137
|
+
files = fs.readdirSync(fullPath).filter(file => {
|
|
138
138
|
const ext = path.extname(file).toLowerCase();
|
|
139
139
|
return imageExtensions.includes(ext);
|
|
140
140
|
});
|
|
@@ -320,11 +320,13 @@ function handleLoop(rootDir) {
|
|
|
320
320
|
console.log(`${c.yellow}⚠ ${screenshotResult.output}${c.reset}`);
|
|
321
321
|
if (screenshotResult.unverified.length > 0) {
|
|
322
322
|
console.log(`${c.dim}Unverified screenshots:${c.reset}`);
|
|
323
|
-
screenshotResult.unverified.slice(0, 5).forEach(
|
|
323
|
+
screenshotResult.unverified.slice(0, 5).forEach(file => {
|
|
324
324
|
console.log(` ${c.yellow}- ${file}${c.reset}`);
|
|
325
325
|
});
|
|
326
326
|
if (screenshotResult.unverified.length > 5) {
|
|
327
|
-
console.log(
|
|
327
|
+
console.log(
|
|
328
|
+
` ${c.dim}... and ${screenshotResult.unverified.length - 5} more${c.reset}`
|
|
329
|
+
);
|
|
328
330
|
}
|
|
329
331
|
}
|
|
330
332
|
state.ralph_loop.screenshots_verified = false;
|
|
@@ -334,8 +336,12 @@ function handleLoop(rootDir) {
|
|
|
334
336
|
// Visual Mode: Enforce minimum iterations
|
|
335
337
|
if (visualMode && iteration < minIterations) {
|
|
336
338
|
console.log('');
|
|
337
|
-
console.log(
|
|
338
|
-
|
|
339
|
+
console.log(
|
|
340
|
+
`${c.yellow}⚠ Visual Mode requires ${minIterations}+ iterations for confirmation${c.reset}`
|
|
341
|
+
);
|
|
342
|
+
console.log(
|
|
343
|
+
`${c.dim}Current: iteration ${iteration}. Let loop run once more to confirm.${c.reset}`
|
|
344
|
+
);
|
|
339
345
|
|
|
340
346
|
state.ralph_loop.iteration = iteration;
|
|
341
347
|
saveSessionState(rootDir, state);
|
|
@@ -458,7 +464,9 @@ function handleCLI() {
|
|
|
458
464
|
console.log(` Current Story: ${loop.current_story}`);
|
|
459
465
|
console.log(` Iteration: ${loop.iteration || 0}/${loop.max_iterations || 20}`);
|
|
460
466
|
if (loop.visual_mode) {
|
|
461
|
-
const verified = loop.screenshots_verified
|
|
467
|
+
const verified = loop.screenshots_verified
|
|
468
|
+
? `${c.green}yes${c.reset}`
|
|
469
|
+
: `${c.yellow}no${c.reset}`;
|
|
462
470
|
console.log(` Screenshots Verified: ${verified}`);
|
|
463
471
|
}
|
|
464
472
|
}
|
|
@@ -97,7 +97,7 @@ function getImageFiles(dir) {
|
|
|
97
97
|
|
|
98
98
|
try {
|
|
99
99
|
const files = fs.readdirSync(dir);
|
|
100
|
-
return files.filter(
|
|
100
|
+
return files.filter(file => {
|
|
101
101
|
const ext = path.extname(file).toLowerCase();
|
|
102
102
|
return imageExtensions.includes(ext);
|
|
103
103
|
});
|
|
@@ -172,7 +172,9 @@ function formatResult(result, options) {
|
|
|
172
172
|
|
|
173
173
|
if (result.success) {
|
|
174
174
|
console.log(`${c.green}${c.bold}All screenshots verified${c.reset}`);
|
|
175
|
-
console.log(
|
|
175
|
+
console.log(
|
|
176
|
+
`${c.dim}${result.verified}/${result.total} screenshots have 'verified-' prefix${c.reset}`
|
|
177
|
+
);
|
|
176
178
|
} else {
|
|
177
179
|
console.log(`${c.red}${c.bold}Unverified screenshots found${c.reset}`);
|
|
178
180
|
console.log(`${c.dim}${result.verified}/${result.total} verified${c.reset}`);
|
|
@@ -10,7 +10,7 @@ compact_context:
|
|
|
10
10
|
- "CRITICAL: If 🔄 OUTDATED shown → offer --upgrade to re-deploy latest scripts"
|
|
11
11
|
- "MUST backup created on migrate: .claude/settings.json.backup"
|
|
12
12
|
- "MUST show RED RESTART banner after ANY changes (quit, wait 5s, restart)"
|
|
13
|
-
- "Features: sessionstart, precompact, ralphloop, selfimprove, archival, statusline, autoupdate"
|
|
13
|
+
- "Features: sessionstart, precompact, ralphloop, selfimprove, archival, statusline, autoupdate, askuserquestion"
|
|
14
14
|
- "Stop hooks (ralphloop, selfimprove) run when Claude completes or pauses"
|
|
15
15
|
state_fields:
|
|
16
16
|
- detection_status
|
|
@@ -52,7 +52,7 @@ node .agileflow/scripts/agileflow-configure.js --repair=statusline # Fix specif
|
|
|
52
52
|
|
|
53
53
|
### Features
|
|
54
54
|
|
|
55
|
-
`sessionstart`, `precompact`, `ralphloop`, `selfimprove`, `archival`, `statusline`, `autoupdate`
|
|
55
|
+
`sessionstart`, `precompact`, `ralphloop`, `selfimprove`, `archival`, `statusline`, `autoupdate`, `askuserquestion`
|
|
56
56
|
|
|
57
57
|
**Stop hooks** (ralphloop, selfimprove) run when Claude completes or pauses work.
|
|
58
58
|
|
|
@@ -180,12 +180,12 @@ node .agileflow/scripts/agileflow-configure.js --enable=archival --archival-days
|
|
|
180
180
|
|
|
181
181
|
## Profile Details
|
|
182
182
|
|
|
183
|
-
| Profile | SessionStart | PreCompact | RalphLoop | SelfImprove | Archival | StatusLine |
|
|
184
|
-
|
|
185
|
-
| `full` | ✅ | ✅ | ✅ | ✅ | ✅ 30 days | ✅ |
|
|
186
|
-
| `basic` | ✅ | ✅ | ❌ | ❌ | ✅ 30 days | ❌ |
|
|
187
|
-
| `minimal` | ✅ | ❌ | ❌ | ❌ | ✅ 30 days | ❌ |
|
|
188
|
-
| `none` | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
|
183
|
+
| Profile | SessionStart | PreCompact | RalphLoop | SelfImprove | Archival | StatusLine | AskUserQuestion |
|
|
184
|
+
|---------|-------------|------------|-----------|-------------|----------|------------|-----------------|
|
|
185
|
+
| `full` | ✅ | ✅ | ✅ | ✅ | ✅ 30 days | ✅ | ✅ |
|
|
186
|
+
| `basic` | ✅ | ✅ | ❌ | ❌ | ✅ 30 days | ❌ | ✅ |
|
|
187
|
+
| `minimal` | ✅ | ❌ | ❌ | ❌ | ✅ 30 days | ❌ | ❌ |
|
|
188
|
+
| `none` | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
|
189
189
|
|
|
190
190
|
## Interactive Mode (via /configure command)
|
|
191
191
|
|
|
@@ -226,7 +226,8 @@ Based on selection, run appropriate command.
|
|
|
226
226
|
{"label": "SelfImprove (Stop Hook)", "description": "Auto-update agent expertise from work"},
|
|
227
227
|
{"label": "Archival", "description": "Auto-archive old completed stories"},
|
|
228
228
|
{"label": "Status Line", "description": "Custom status bar"},
|
|
229
|
-
{"label": "Auto-Update", "description": "Automatically update AgileFlow on session start"}
|
|
229
|
+
{"label": "Auto-Update", "description": "Automatically update AgileFlow on session start"},
|
|
230
|
+
{"label": "AskUserQuestion Mode", "description": "End all responses with AskUserQuestion tool for guided interaction"}
|
|
230
231
|
]
|
|
231
232
|
}]</parameter>
|
|
232
233
|
</invoke>
|
|
@@ -240,6 +241,7 @@ Map selections:
|
|
|
240
241
|
- "Archival" → `archival`
|
|
241
242
|
- "Status Line" → `statusline`
|
|
242
243
|
- "Auto-Update" → `autoupdate`
|
|
244
|
+
- "AskUserQuestion Mode" → `askuserquestion`
|
|
243
245
|
|
|
244
246
|
## Auto-Update Configuration
|
|
245
247
|
|
|
@@ -263,6 +265,41 @@ node .agileflow/scripts/agileflow-configure.js --enable=autoupdate
|
|
|
263
265
|
|
|
264
266
|
**Check frequencies:** `hourly`, `daily`, `weekly`, `never`
|
|
265
267
|
|
|
268
|
+
## AskUserQuestion Mode
|
|
269
|
+
|
|
270
|
+
Enable AskUserQuestion to have all commands end with guided options:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
# Enable AskUserQuestion mode
|
|
274
|
+
node .agileflow/scripts/agileflow-configure.js --enable=askuserquestion
|
|
275
|
+
|
|
276
|
+
# Disable AskUserQuestion mode
|
|
277
|
+
node .agileflow/scripts/agileflow-configure.js --disable=askuserquestion
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**What it does:**
|
|
281
|
+
- When enabled: All commands end with AskUserQuestion tool call (guided options)
|
|
282
|
+
- When disabled: Commands can end with natural text questions
|
|
283
|
+
|
|
284
|
+
**Storage in metadata:**
|
|
285
|
+
```json
|
|
286
|
+
{
|
|
287
|
+
"features": {
|
|
288
|
+
"askUserQuestion": {
|
|
289
|
+
"enabled": true,
|
|
290
|
+
"mode": "all"
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Modes:**
|
|
297
|
+
- `all`: All commands use AskUserQuestion (default)
|
|
298
|
+
- `interactive`: Only interactive commands (babysit, mentor, configure, epic-planner)
|
|
299
|
+
- `none`: Disabled
|
|
300
|
+
|
|
301
|
+
The guidance is injected via `obtain-context.js` when commands run.
|
|
302
|
+
|
|
266
303
|
## Stop Hook Features
|
|
267
304
|
|
|
268
305
|
Stop hooks run when Claude completes a task or pauses for user input. These enable autonomous workflows.
|
|
@@ -150,3 +150,28 @@ learnings:
|
|
|
150
150
|
total_lines: 2009
|
|
151
151
|
source: "packages/cli/src/core/commands/*.md"
|
|
152
152
|
notes: "All files follow consistent documentation template: frontmatter, quick start, purpose, parameters table, examples with explanations, workflow steps, output/files, and related commands"
|
|
153
|
+
|
|
154
|
+
- date: 2026-01-09
|
|
155
|
+
context: "Created IDE Integrations documentation for AgileFlow"
|
|
156
|
+
insight: "IDE handler system supports 4 IDEs (Claude Code, Cursor, Windsurf, Codex CLI) through plugin architecture. Each IDE has custom config directory (.claude/, .cursor/, .windsurf/, .codex/) and different installation models. Claude Code most advanced (damage control, spawnable agents), Codex CLI unique (per-repo skills, user-level prompts, AGENTS.md instructions)"
|
|
157
|
+
created_files:
|
|
158
|
+
- "apps/docs/content/docs/features/ide-integrations.mdx (700+ lines)"
|
|
159
|
+
- "apps/docs/content/docs/features/index.mdx (updated with IDE section)"
|
|
160
|
+
total_lines: 700
|
|
161
|
+
source: "packages/cli/tools/cli/installers/ide/ (_base-ide.js, claude-code.js, cursor.js, windsurf.js, codex.js, manager.js)"
|
|
162
|
+
coverage:
|
|
163
|
+
- "IDE overview table with config dirs, types, status"
|
|
164
|
+
- "Quick start for Claude Code (default IDE)"
|
|
165
|
+
- "Multi-IDE installation instructions"
|
|
166
|
+
- "Detailed setup for each IDE with directory structure"
|
|
167
|
+
- "Command access patterns by IDE"
|
|
168
|
+
- "Claude Code subagent spawning, damage control hooks"
|
|
169
|
+
- "Cursor unique features, differences from Claude Code"
|
|
170
|
+
- "Windsurf workflow management, VSCode integration"
|
|
171
|
+
- "Codex CLI dual installation model (per-repo skills, user-level prompts, AGENTS.md)"
|
|
172
|
+
- "Dynamic IDE handler system, extensibility guide"
|
|
173
|
+
- "Content injection system explanation"
|
|
174
|
+
- "Troubleshooting guide for common issues"
|
|
175
|
+
- "Best practices for IDE selection and multi-IDE usage"
|
|
176
|
+
- "Configuration management and version control"
|
|
177
|
+
notes: "Comprehensive 700+ line documentation covering all 4 IDEs with detailed setup, command access, and unique features. Includes handler architecture for IDE developers extending with new IDEs."
|