agileflow 2.84.2 → 2.86.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 +3 -3
- package/lib/colors.js +23 -0
- package/package.json +1 -1
- package/scripts/agileflow-statusline.sh +31 -44
- package/scripts/agileflow-welcome.js +378 -132
- package/scripts/batch-pmap-loop.js +528 -0
- package/scripts/lib/colors.sh +106 -0
- package/scripts/lib/file-tracking.js +5 -3
- package/scripts/obtain-context.js +132 -20
- package/scripts/session-boundary.js +138 -0
- package/scripts/session-manager.js +526 -7
- package/scripts/test-session-boundary.js +80 -0
- package/src/core/agents/mentor.md +40 -2
- package/src/core/agents/orchestrator.md +35 -2
- package/src/core/commands/babysit.md +198 -674
- package/src/core/commands/batch.md +117 -2
- package/src/core/commands/metrics.md +62 -9
- package/src/core/commands/rpi.md +500 -0
- package/src/core/commands/session/new.md +90 -51
- package/src/core/commands/session/resume.md +40 -16
- package/src/core/commands/session/status.md +35 -2
- package/src/core/templates/session-state.json +32 -3
- package/tools/cli/commands/config.js +43 -21
- package/tools/cli/commands/doctor.js +8 -5
- package/tools/cli/commands/setup.js +14 -7
- package/tools/cli/commands/uninstall.js +8 -5
- package/tools/cli/commands/update.js +20 -10
- package/tools/cli/lib/content-injector.js +80 -0
- package/tools/cli/lib/error-handler.js +173 -0
- package/tools/cli/lib/ui.js +3 -2
|
@@ -10,6 +10,7 @@ const fs = require('fs-extra');
|
|
|
10
10
|
const { Installer } = require('../installers/core/installer');
|
|
11
11
|
const { IdeManager } = require('../installers/ide/manager');
|
|
12
12
|
const { displayLogo, displaySection, success, warning, error, confirm } = require('../lib/ui');
|
|
13
|
+
const { ErrorHandler } = require('../lib/error-handler');
|
|
13
14
|
|
|
14
15
|
const installer = new Installer();
|
|
15
16
|
const ideManager = new IdeManager();
|
|
@@ -138,11 +139,13 @@ module.exports = {
|
|
|
138
139
|
|
|
139
140
|
process.exit(0);
|
|
140
141
|
} catch (err) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
const handler = new ErrorHandler('uninstall');
|
|
143
|
+
handler.critical(
|
|
144
|
+
'Uninstall failed',
|
|
145
|
+
'Check file permissions',
|
|
146
|
+
'sudo npx agileflow uninstall --force',
|
|
147
|
+
err
|
|
148
|
+
);
|
|
146
149
|
}
|
|
147
150
|
},
|
|
148
151
|
};
|
|
@@ -22,6 +22,7 @@ const {
|
|
|
22
22
|
} = require('../lib/ui');
|
|
23
23
|
const { createDocsStructure, getDocsFolderName } = require('../lib/docs-setup');
|
|
24
24
|
const { getLatestVersion } = require('../lib/npm-utils');
|
|
25
|
+
const { ErrorHandler } = require('../lib/error-handler');
|
|
25
26
|
|
|
26
27
|
const installer = new Installer();
|
|
27
28
|
const ideManager = new IdeManager();
|
|
@@ -76,9 +77,12 @@ module.exports = {
|
|
|
76
77
|
const status = await installer.getStatus(directory);
|
|
77
78
|
|
|
78
79
|
if (!status.installed) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
const handler = new ErrorHandler('update');
|
|
81
|
+
handler.warning(
|
|
82
|
+
'No AgileFlow installation found',
|
|
83
|
+
'Initialize AgileFlow first',
|
|
84
|
+
'npx agileflow setup'
|
|
85
|
+
);
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
displaySection('Updating AgileFlow', `Current version: ${status.version}`);
|
|
@@ -179,8 +183,12 @@ module.exports = {
|
|
|
179
183
|
const coreResult = await installer.install(config, { force: options.force });
|
|
180
184
|
|
|
181
185
|
if (!coreResult.success) {
|
|
182
|
-
|
|
183
|
-
|
|
186
|
+
const handler = new ErrorHandler('update');
|
|
187
|
+
handler.warning(
|
|
188
|
+
'Update failed',
|
|
189
|
+
'Try running doctor to diagnose issues',
|
|
190
|
+
'npx agileflow doctor --fix'
|
|
191
|
+
);
|
|
184
192
|
}
|
|
185
193
|
|
|
186
194
|
success('Updated core content');
|
|
@@ -237,11 +245,13 @@ module.exports = {
|
|
|
237
245
|
|
|
238
246
|
process.exit(0);
|
|
239
247
|
} catch (err) {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
248
|
+
const handler = new ErrorHandler('update');
|
|
249
|
+
handler.critical(
|
|
250
|
+
'Update failed',
|
|
251
|
+
'Check network connection and disk space',
|
|
252
|
+
'npx agileflow doctor',
|
|
253
|
+
err
|
|
254
|
+
);
|
|
245
255
|
}
|
|
246
256
|
},
|
|
247
257
|
};
|
|
@@ -202,6 +202,80 @@ function injectContent(content, context = {}) {
|
|
|
202
202
|
return result;
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
// =============================================================================
|
|
206
|
+
// Section Processing Functions (Progressive Disclosure)
|
|
207
|
+
// =============================================================================
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Extract section names from content
|
|
211
|
+
* @param {string} content - Content with section markers
|
|
212
|
+
* @returns {string[]} Array of section names
|
|
213
|
+
*/
|
|
214
|
+
function extractSectionNames(content) {
|
|
215
|
+
const sectionPattern = /<!-- SECTION: (\w+[-\w]*) -->/g;
|
|
216
|
+
const sections = [];
|
|
217
|
+
let match;
|
|
218
|
+
while ((match = sectionPattern.exec(content)) !== null) {
|
|
219
|
+
sections.push(match[1]);
|
|
220
|
+
}
|
|
221
|
+
return sections;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Filter content to only include specified sections
|
|
226
|
+
* Sections are marked with: <!-- SECTION: name --> ... <!-- END_SECTION -->
|
|
227
|
+
*
|
|
228
|
+
* @param {string} content - Content with section markers
|
|
229
|
+
* @param {string[]} activeSections - Sections to include (empty = include all)
|
|
230
|
+
* @returns {string} Content with only active sections
|
|
231
|
+
*/
|
|
232
|
+
function filterSections(content, activeSections = []) {
|
|
233
|
+
// If no active sections specified, include all content
|
|
234
|
+
if (!activeSections || activeSections.length === 0) {
|
|
235
|
+
return content;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Pattern matches: <!-- SECTION: name --> content <!-- END_SECTION -->
|
|
239
|
+
const sectionPattern = /<!-- SECTION: (\w+[-\w]*) -->([\s\S]*?)<!-- END_SECTION -->/g;
|
|
240
|
+
|
|
241
|
+
return content.replace(sectionPattern, (match, sectionName, sectionContent) => {
|
|
242
|
+
if (activeSections.includes(sectionName)) {
|
|
243
|
+
// Keep the section content, remove the markers
|
|
244
|
+
return sectionContent;
|
|
245
|
+
}
|
|
246
|
+
// Remove the entire section
|
|
247
|
+
return '';
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Remove all section markers but keep content
|
|
253
|
+
* Used when no filtering is needed but markers should be cleaned
|
|
254
|
+
*
|
|
255
|
+
* @param {string} content - Content with section markers
|
|
256
|
+
* @returns {string} Content without section markers
|
|
257
|
+
*/
|
|
258
|
+
function stripSectionMarkers(content) {
|
|
259
|
+
// Remove section start markers
|
|
260
|
+
let result = content.replace(/<!-- SECTION: \w+[-\w]* -->\n?/g, '');
|
|
261
|
+
// Remove section end markers
|
|
262
|
+
result = result.replace(/<!-- END_SECTION -->\n?/g, '');
|
|
263
|
+
return result;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Check if content has section markers
|
|
268
|
+
* @param {string} content - Content to check
|
|
269
|
+
* @returns {boolean} True if content has sections
|
|
270
|
+
*/
|
|
271
|
+
function hasSections(content) {
|
|
272
|
+
return /<!-- SECTION: \w+[-\w]* -->/.test(content);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// =============================================================================
|
|
276
|
+
// Utility Functions
|
|
277
|
+
// =============================================================================
|
|
278
|
+
|
|
205
279
|
/**
|
|
206
280
|
* Check if content has any template variables
|
|
207
281
|
* @param {string} content - Content to check
|
|
@@ -263,4 +337,10 @@ module.exports = {
|
|
|
263
337
|
injectContent,
|
|
264
338
|
hasPlaceholders,
|
|
265
339
|
getPlaceholderDocs,
|
|
340
|
+
|
|
341
|
+
// Section processing (progressive disclosure)
|
|
342
|
+
extractSectionNames,
|
|
343
|
+
filterSections,
|
|
344
|
+
stripSectionMarkers,
|
|
345
|
+
hasSections,
|
|
266
346
|
};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* error-handler.js - Centralized Error Handling with Actionable Guidance
|
|
3
|
+
*
|
|
4
|
+
* Provides three-tier error handling:
|
|
5
|
+
* - INFO: Non-blocking issues (does not exit)
|
|
6
|
+
* - WARNING: Issues that should be addressed (exit 1)
|
|
7
|
+
* - CRITICAL: Severe errors (exit 1 + stack trace if DEBUG=1)
|
|
8
|
+
*
|
|
9
|
+
* Error output format: "X <problem> | Action: <what to do> | Run: <command>"
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { c } = require('../../../lib/colors');
|
|
13
|
+
|
|
14
|
+
class ErrorHandler {
|
|
15
|
+
/**
|
|
16
|
+
* Create an ErrorHandler instance
|
|
17
|
+
* @param {string} commandName - Name of the command using this handler
|
|
18
|
+
*/
|
|
19
|
+
constructor(commandName = 'agileflow') {
|
|
20
|
+
this.commandName = commandName;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Format error with actionable guidance
|
|
25
|
+
* Output: "X <problem> | Action: <what to do> | Run: <command>"
|
|
26
|
+
*
|
|
27
|
+
* @param {string} message - The error message describing the problem
|
|
28
|
+
* @param {string} [actionText] - What the user should do to fix it
|
|
29
|
+
* @param {string} [commandHint] - Command to run to fix it
|
|
30
|
+
* @returns {string} Formatted error string
|
|
31
|
+
*/
|
|
32
|
+
formatError(message, actionText, commandHint) {
|
|
33
|
+
let output = `${c.red}\u2716${c.reset} ${message}`;
|
|
34
|
+
if (actionText) {
|
|
35
|
+
output += ` ${c.dim}|${c.reset} ${c.cyan}Action:${c.reset} ${actionText}`;
|
|
36
|
+
}
|
|
37
|
+
if (commandHint) {
|
|
38
|
+
output += ` ${c.dim}|${c.reset} ${c.green}Run:${c.reset} ${c.bold}${commandHint}${c.reset}`;
|
|
39
|
+
}
|
|
40
|
+
return output;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Format warning message (yellow indicator)
|
|
45
|
+
* @param {string} message - The warning message
|
|
46
|
+
* @param {string} [actionText] - What the user should do
|
|
47
|
+
* @param {string} [commandHint] - Command to run
|
|
48
|
+
* @returns {string} Formatted warning string
|
|
49
|
+
*/
|
|
50
|
+
formatWarning(message, actionText, commandHint) {
|
|
51
|
+
let output = `${c.yellow}\u26A0${c.reset} ${message}`;
|
|
52
|
+
if (actionText) {
|
|
53
|
+
output += ` ${c.dim}|${c.reset} ${c.cyan}Action:${c.reset} ${actionText}`;
|
|
54
|
+
}
|
|
55
|
+
if (commandHint) {
|
|
56
|
+
output += ` ${c.dim}|${c.reset} ${c.green}Run:${c.reset} ${c.bold}${commandHint}${c.reset}`;
|
|
57
|
+
}
|
|
58
|
+
return output;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* INFO: Non-blocking issue, continue execution (does NOT exit)
|
|
63
|
+
* Use for informational messages about issues that don't prevent operation.
|
|
64
|
+
*
|
|
65
|
+
* @param {string} message - The info message
|
|
66
|
+
* @param {string} [actionText] - Optional action hint
|
|
67
|
+
* @param {string} [commandHint] - Optional command hint
|
|
68
|
+
*/
|
|
69
|
+
info(message, actionText, commandHint) {
|
|
70
|
+
console.log(this.formatWarning(message, actionText, commandHint));
|
|
71
|
+
// Does NOT exit - allows continuation
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* WARNING: Issue that should be addressed (exit 1)
|
|
76
|
+
* Use for problems that prevent the operation from completing properly.
|
|
77
|
+
*
|
|
78
|
+
* @param {string} message - The warning message
|
|
79
|
+
* @param {string} [actionText] - What the user should do
|
|
80
|
+
* @param {string} [commandHint] - Command to run to fix it
|
|
81
|
+
*/
|
|
82
|
+
warning(message, actionText, commandHint) {
|
|
83
|
+
console.error(this.formatError(message, actionText, commandHint));
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* CRITICAL: Severe error (exit 1 + stack trace if DEBUG=1)
|
|
89
|
+
* Use for unexpected errors, crashes, or severe failures.
|
|
90
|
+
*
|
|
91
|
+
* @param {string} message - The error message
|
|
92
|
+
* @param {string} [actionText] - What the user should do
|
|
93
|
+
* @param {string} [commandHint] - Command to run
|
|
94
|
+
* @param {Error} [error] - Original error object for stack trace
|
|
95
|
+
*/
|
|
96
|
+
critical(message, actionText, commandHint, error) {
|
|
97
|
+
console.error(this.formatError(message, actionText, commandHint));
|
|
98
|
+
if (process.env.DEBUG === '1' && error?.stack) {
|
|
99
|
+
console.error(`\n${c.dim}Stack trace:${c.reset}`);
|
|
100
|
+
console.error(c.dim + error.stack + c.reset);
|
|
101
|
+
}
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Convenience method: Get formatted error string without exiting
|
|
107
|
+
* Useful for collecting multiple errors before displaying.
|
|
108
|
+
*
|
|
109
|
+
* @param {string} message - The error message
|
|
110
|
+
* @param {string} [actionText] - What the user should do
|
|
111
|
+
* @param {string} [commandHint] - Command to run
|
|
112
|
+
* @returns {string} Formatted error string
|
|
113
|
+
*/
|
|
114
|
+
errorWithAction(message, actionText, commandHint) {
|
|
115
|
+
return this.formatError(message, actionText, commandHint);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Convenience method: Get formatted warning string without exiting
|
|
120
|
+
*
|
|
121
|
+
* @param {string} message - The warning message
|
|
122
|
+
* @param {string} [actionText] - What the user should do
|
|
123
|
+
* @param {string} [commandHint] - Command to run
|
|
124
|
+
* @returns {string} Formatted warning string
|
|
125
|
+
*/
|
|
126
|
+
warningWithAction(message, actionText, commandHint) {
|
|
127
|
+
return this.formatWarning(message, actionText, commandHint);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Display multiple issues at once, then exit with appropriate code
|
|
132
|
+
* Useful for validation that collects all errors before reporting.
|
|
133
|
+
*
|
|
134
|
+
* @param {Array<{type: 'info'|'warning'|'error', message: string, action?: string, command?: string}>} issues
|
|
135
|
+
* @returns {boolean} True if there were errors/warnings (would normally exit)
|
|
136
|
+
*/
|
|
137
|
+
reportIssues(issues) {
|
|
138
|
+
let hasErrors = false;
|
|
139
|
+
let hasWarnings = false;
|
|
140
|
+
|
|
141
|
+
for (const issue of issues) {
|
|
142
|
+
if (issue.type === 'error') {
|
|
143
|
+
console.error(this.formatError(issue.message, issue.action, issue.command));
|
|
144
|
+
hasErrors = true;
|
|
145
|
+
} else if (issue.type === 'warning') {
|
|
146
|
+
console.error(this.formatWarning(issue.message, issue.action, issue.command));
|
|
147
|
+
hasWarnings = true;
|
|
148
|
+
} else {
|
|
149
|
+
console.log(this.formatWarning(issue.message, issue.action, issue.command));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (hasErrors || hasWarnings) {
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return hasErrors || hasWarnings;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Create a pre-configured ErrorHandler instance
|
|
163
|
+
* @param {string} commandName - Name of the command
|
|
164
|
+
* @returns {ErrorHandler} New ErrorHandler instance
|
|
165
|
+
*/
|
|
166
|
+
function createErrorHandler(commandName) {
|
|
167
|
+
return new ErrorHandler(commandName);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
module.exports = {
|
|
171
|
+
ErrorHandler,
|
|
172
|
+
createErrorHandler,
|
|
173
|
+
};
|
package/tools/cli/lib/ui.js
CHANGED
|
@@ -9,6 +9,7 @@ const inquirer = require('inquirer');
|
|
|
9
9
|
const path = require('node:path');
|
|
10
10
|
const fs = require('node:fs');
|
|
11
11
|
const { IdeManager } = require('../installers/ide/manager');
|
|
12
|
+
const { BRAND_HEX } = require('../../../lib/colors');
|
|
12
13
|
|
|
13
14
|
// Load package.json for version
|
|
14
15
|
const packageJsonPath = path.join(__dirname, '..', '..', '..', 'package.json');
|
|
@@ -25,7 +26,7 @@ function displayLogo() {
|
|
|
25
26
|
██╔══██║██║ ██║██║██║ ██╔══╝ ██╔══╝ ██║ ██║ ██║██║███╗██║
|
|
26
27
|
██║ ██║╚██████╔╝██║███████╗███████╗██║ ███████╗╚██████╔╝╚███╔███╔╝
|
|
27
28
|
╚═╝ ╚═╝ ╚═════╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚══════╝ ╚═════╝ ╚══╝╚══╝ `;
|
|
28
|
-
console.log(chalk.hex(
|
|
29
|
+
console.log(chalk.hex(BRAND_HEX)(logo));
|
|
29
30
|
console.log(chalk.dim(` AgileFlow v${packageJson.version} - AI-Driven Agile Development\n`));
|
|
30
31
|
}
|
|
31
32
|
|
|
@@ -35,7 +36,7 @@ function displayLogo() {
|
|
|
35
36
|
* @param {string} subtitle - Optional subtitle
|
|
36
37
|
*/
|
|
37
38
|
function displaySection(title, subtitle = null) {
|
|
38
|
-
console.log(chalk.bold.hex(
|
|
39
|
+
console.log(chalk.bold.hex(BRAND_HEX)(`\n${title}`));
|
|
39
40
|
if (subtitle) {
|
|
40
41
|
console.log(chalk.dim(subtitle));
|
|
41
42
|
}
|