agileflow 2.51.0 → 2.56.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/README.md +80 -460
- package/package.json +18 -3
- package/scripts/agileflow-configure.js +134 -63
- package/scripts/agileflow-welcome.js +161 -31
- package/scripts/generators/agent-registry.js +45 -57
- package/scripts/generators/command-registry.js +48 -32
- package/scripts/generators/index.js +2 -6
- package/scripts/generators/inject-babysit.js +9 -2
- package/scripts/generators/inject-help.js +3 -1
- package/scripts/generators/inject-readme.js +7 -3
- package/scripts/generators/skill-registry.js +60 -33
- package/scripts/get-env.js +13 -12
- package/scripts/lib/frontmatter-parser.js +82 -0
- package/scripts/obtain-context.js +79 -26
- package/scripts/session-coordinator.sh +232 -0
- package/scripts/session-manager.js +512 -0
- package/src/core/agents/orchestrator.md +275 -0
- package/src/core/commands/adr.md +38 -16
- package/src/core/commands/agent.md +39 -22
- package/src/core/commands/assign.md +17 -0
- package/src/core/commands/auto.md +60 -46
- package/src/core/commands/babysit.md +302 -637
- package/src/core/commands/baseline.md +20 -0
- package/src/core/commands/blockers.md +33 -48
- package/src/core/commands/board.md +19 -0
- package/src/core/commands/changelog.md +20 -0
- package/src/core/commands/ci.md +17 -0
- package/src/core/commands/context.md +43 -40
- package/src/core/commands/debt.md +76 -45
- package/src/core/commands/deploy.md +20 -0
- package/src/core/commands/deps.md +40 -46
- package/src/core/commands/diagnose.md +24 -18
- package/src/core/commands/docs.md +18 -0
- package/src/core/commands/epic.md +31 -0
- package/src/core/commands/feedback.md +33 -21
- package/src/core/commands/handoff.md +29 -0
- package/src/core/commands/help.md +16 -7
- package/src/core/commands/impact.md +31 -61
- package/src/core/commands/metrics.md +17 -35
- package/src/core/commands/packages.md +21 -0
- package/src/core/commands/pr.md +15 -0
- package/src/core/commands/readme-sync.md +42 -9
- package/src/core/commands/research.md +58 -11
- package/src/core/commands/retro.md +42 -50
- package/src/core/commands/review.md +22 -27
- package/src/core/commands/session/end.md +53 -297
- package/src/core/commands/session/history.md +38 -257
- package/src/core/commands/session/init.md +44 -446
- package/src/core/commands/session/new.md +152 -0
- package/src/core/commands/session/resume.md +51 -447
- package/src/core/commands/session/status.md +32 -244
- package/src/core/commands/sprint.md +33 -0
- package/src/core/commands/status.md +18 -0
- package/src/core/commands/story-validate.md +32 -0
- package/src/core/commands/story.md +21 -6
- package/src/core/commands/template.md +18 -0
- package/src/core/commands/tests.md +22 -0
- package/src/core/commands/update.md +72 -58
- package/src/core/commands/validate-expertise.md +25 -37
- package/src/core/commands/velocity.md +33 -74
- package/src/core/commands/verify.md +16 -0
- package/src/core/experts/documentation/expertise.yaml +16 -2
- package/src/core/skills/agileflow-retro-facilitator/SKILL.md +57 -219
- package/src/core/skills/agileflow-retro-facilitator/cookbook/4ls.md +86 -0
- package/src/core/skills/agileflow-retro-facilitator/cookbook/glad-sad-mad.md +79 -0
- package/src/core/skills/agileflow-retro-facilitator/cookbook/start-stop-continue.md +142 -0
- package/src/core/skills/agileflow-retro-facilitator/prompts/action-items.md +83 -0
- package/src/core/skills/writing-skills/SKILL.md +352 -0
- package/src/core/skills/writing-skills/testing-skills-with-subagents.md +232 -0
- package/tools/cli/agileflow-cli.js +4 -2
- package/tools/cli/commands/config.js +20 -13
- package/tools/cli/commands/doctor.js +25 -9
- package/tools/cli/commands/list.js +10 -6
- package/tools/cli/commands/setup.js +54 -3
- package/tools/cli/commands/status.js +6 -8
- package/tools/cli/commands/uninstall.js +5 -5
- package/tools/cli/commands/update.js +51 -7
- package/tools/cli/installers/core/installer.js +8 -4
- package/tools/cli/installers/ide/_base-ide.js +58 -1
- package/tools/cli/installers/ide/claude-code.js +3 -61
- package/tools/cli/installers/ide/codex.js +440 -0
- package/tools/cli/installers/ide/cursor.js +21 -51
- package/tools/cli/installers/ide/manager.js +2 -6
- package/tools/cli/installers/ide/windsurf.js +20 -50
- package/tools/cli/lib/content-injector.js +26 -49
- package/tools/cli/lib/docs-setup.js +3 -2
- package/tools/cli/lib/npm-utils.js +39 -12
- package/tools/cli/lib/ui.js +31 -10
- package/tools/cli/lib/version-checker.js +3 -3
- package/tools/postinstall.js +2 -3
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
const fs = require('fs');
|
|
9
9
|
const path = require('path');
|
|
10
|
-
const
|
|
10
|
+
const { parseFrontmatter, normalizeTools } = require('../../../scripts/lib/frontmatter-parser');
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Scan agents directory and generate formatted agent list
|
|
@@ -22,34 +22,20 @@ function generateAgentList(agentsDir) {
|
|
|
22
22
|
const filePath = path.join(agentsDir, file);
|
|
23
23
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
24
24
|
|
|
25
|
-
//
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const frontmatter = yaml.load(match[1]);
|
|
31
|
-
|
|
32
|
-
// Skip if frontmatter is null or not an object
|
|
33
|
-
if (!frontmatter || typeof frontmatter !== 'object') {
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Handle tools field - can be array or string
|
|
38
|
-
let tools = frontmatter.tools || [];
|
|
39
|
-
if (typeof tools === 'string') {
|
|
40
|
-
tools = tools.split(',').map(t => t.trim());
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
agents.push({
|
|
44
|
-
name: frontmatter.name || path.basename(file, '.md'),
|
|
45
|
-
description: frontmatter.description || '',
|
|
46
|
-
tools: tools,
|
|
47
|
-
model: frontmatter.model || 'haiku'
|
|
48
|
-
});
|
|
49
|
-
} catch (err) {
|
|
50
|
-
// Silently skip files with parsing errors
|
|
25
|
+
// Parse frontmatter using shared parser
|
|
26
|
+
const frontmatter = parseFrontmatter(content);
|
|
27
|
+
|
|
28
|
+
// Skip if no frontmatter found
|
|
29
|
+
if (!frontmatter || Object.keys(frontmatter).length === 0) {
|
|
51
30
|
continue;
|
|
52
31
|
}
|
|
32
|
+
|
|
33
|
+
agents.push({
|
|
34
|
+
name: frontmatter.name || path.basename(file, '.md'),
|
|
35
|
+
description: frontmatter.description || '',
|
|
36
|
+
tools: normalizeTools(frontmatter.tools),
|
|
37
|
+
model: frontmatter.model || 'haiku',
|
|
38
|
+
});
|
|
53
39
|
}
|
|
54
40
|
|
|
55
41
|
// Sort alphabetically by name
|
|
@@ -82,29 +68,20 @@ function generateCommandList(commandsDir) {
|
|
|
82
68
|
const filePath = path.join(commandsDir, file);
|
|
83
69
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
84
70
|
|
|
85
|
-
//
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const cmdName = path.basename(file, '.md');
|
|
92
|
-
|
|
93
|
-
// Skip if frontmatter is null or not an object
|
|
94
|
-
if (!frontmatter || typeof frontmatter !== 'object') {
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
commands.push({
|
|
99
|
-
name: cmdName,
|
|
100
|
-
description: frontmatter.description || '',
|
|
101
|
-
argumentHint: frontmatter['argument-hint'] || ''
|
|
102
|
-
});
|
|
103
|
-
} catch (err) {
|
|
104
|
-
// Silently skip files with parsing errors - they might be generated files
|
|
105
|
-
// with content that looks like frontmatter but isn't
|
|
71
|
+
// Parse frontmatter using shared parser
|
|
72
|
+
const frontmatter = parseFrontmatter(content);
|
|
73
|
+
const cmdName = path.basename(file, '.md');
|
|
74
|
+
|
|
75
|
+
// Skip if no frontmatter found
|
|
76
|
+
if (!frontmatter || Object.keys(frontmatter).length === 0) {
|
|
106
77
|
continue;
|
|
107
78
|
}
|
|
79
|
+
|
|
80
|
+
commands.push({
|
|
81
|
+
name: cmdName,
|
|
82
|
+
description: frontmatter.description || '',
|
|
83
|
+
argumentHint: frontmatter['argument-hint'] || '',
|
|
84
|
+
});
|
|
108
85
|
}
|
|
109
86
|
|
|
110
87
|
// Sort alphabetically by name
|
|
@@ -149,5 +126,5 @@ function injectContent(templateContent, agentsDir, commandsDir) {
|
|
|
149
126
|
module.exports = {
|
|
150
127
|
generateAgentList,
|
|
151
128
|
generateCommandList,
|
|
152
|
-
injectContent
|
|
129
|
+
injectContent,
|
|
153
130
|
};
|
|
@@ -25,7 +25,8 @@ try {
|
|
|
25
25
|
);
|
|
26
26
|
} catch (e) {
|
|
27
27
|
// Fallback if README not found
|
|
28
|
-
packageReadme =
|
|
28
|
+
packageReadme =
|
|
29
|
+
'# AgileFlow\n\nSee https://github.com/projectquestorg/AgileFlow for documentation.';
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
/**
|
|
@@ -386,7 +387,7 @@ Document your CI/CD workflows and configuration here.
|
|
|
386
387
|
|
|
387
388
|
if (fs.existsSync(gitignorePath)) {
|
|
388
389
|
const existingGitignore = await fs.readFile(gitignorePath, 'utf8');
|
|
389
|
-
const newEntries = gitignoreEntries.filter(
|
|
390
|
+
const newEntries = gitignoreEntries.filter(entry => !existingGitignore.includes(entry));
|
|
390
391
|
if (newEntries.length > 0) {
|
|
391
392
|
await fs.appendFile(gitignorePath, '\n' + newEntries.join('\n') + '\n', 'utf8');
|
|
392
393
|
console.log(chalk.yellow(` ↻ Updated .gitignore with ${newEntries.length} entries`));
|
|
@@ -2,17 +2,36 @@
|
|
|
2
2
|
* AgileFlow CLI - npm Registry Utilities
|
|
3
3
|
*
|
|
4
4
|
* Utilities for interacting with the npm registry.
|
|
5
|
+
* Set DEBUG_NPM=1 environment variable for verbose error logging.
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
8
|
const https = require('https');
|
|
8
9
|
|
|
10
|
+
// Debug mode: set DEBUG_NPM=1 to see error details
|
|
11
|
+
const DEBUG = process.env.DEBUG_NPM === '1';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Log debug messages when DEBUG_NPM=1
|
|
15
|
+
* @param {string} message - Message to log
|
|
16
|
+
* @param {*} data - Optional data to include
|
|
17
|
+
*/
|
|
18
|
+
function debugLog(message, data = null) {
|
|
19
|
+
if (DEBUG) {
|
|
20
|
+
console.error(`[npm-utils] ${message}`, data ? JSON.stringify(data) : '');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
9
24
|
/**
|
|
10
25
|
* Get the latest version of a package from npm registry
|
|
11
|
-
*
|
|
12
|
-
*
|
|
26
|
+
*
|
|
27
|
+
* Returns null on any error (network, timeout, invalid response) since
|
|
28
|
+
* version checking should not block the CLI. Set DEBUG_NPM=1 to see errors.
|
|
29
|
+
*
|
|
30
|
+
* @param {string} packageName - Name of the package (e.g., 'agileflow' or '@scope/pkg')
|
|
31
|
+
* @returns {Promise<string|null>} Latest version string or null if unavailable
|
|
13
32
|
*/
|
|
14
33
|
async function getLatestVersion(packageName) {
|
|
15
|
-
return new Promise(
|
|
34
|
+
return new Promise(resolve => {
|
|
16
35
|
const options = {
|
|
17
36
|
hostname: 'registry.npmjs.org',
|
|
18
37
|
port: 443,
|
|
@@ -23,32 +42,40 @@ async function getLatestVersion(packageName) {
|
|
|
23
42
|
},
|
|
24
43
|
};
|
|
25
44
|
|
|
26
|
-
|
|
45
|
+
debugLog('Fetching version', { package: packageName, path: options.path });
|
|
46
|
+
|
|
47
|
+
const req = https.request(options, res => {
|
|
27
48
|
let data = '';
|
|
28
49
|
|
|
29
|
-
res.on('data',
|
|
50
|
+
res.on('data', chunk => {
|
|
30
51
|
data += chunk;
|
|
31
52
|
});
|
|
32
53
|
|
|
33
54
|
res.on('end', () => {
|
|
55
|
+
if (res.statusCode !== 200) {
|
|
56
|
+
debugLog('Non-200 status', { statusCode: res.statusCode });
|
|
57
|
+
return resolve(null);
|
|
58
|
+
}
|
|
59
|
+
|
|
34
60
|
try {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
resolve(null);
|
|
40
|
-
}
|
|
61
|
+
const json = JSON.parse(data);
|
|
62
|
+
const version = json.version || null;
|
|
63
|
+
debugLog('Version found', { version });
|
|
64
|
+
resolve(version);
|
|
41
65
|
} catch (err) {
|
|
66
|
+
debugLog('JSON parse error', { error: err.message });
|
|
42
67
|
resolve(null);
|
|
43
68
|
}
|
|
44
69
|
});
|
|
45
70
|
});
|
|
46
71
|
|
|
47
|
-
req.on('error',
|
|
72
|
+
req.on('error', err => {
|
|
73
|
+
debugLog('Network error', { error: err.message });
|
|
48
74
|
resolve(null);
|
|
49
75
|
});
|
|
50
76
|
|
|
51
77
|
req.setTimeout(5000, () => {
|
|
78
|
+
debugLog('Request timeout');
|
|
52
79
|
req.destroy();
|
|
53
80
|
resolve(null);
|
|
54
81
|
});
|
package/tools/cli/lib/ui.js
CHANGED
|
@@ -8,6 +8,7 @@ const chalk = require('chalk');
|
|
|
8
8
|
const inquirer = require('inquirer');
|
|
9
9
|
const path = require('node:path');
|
|
10
10
|
const fs = require('node:fs');
|
|
11
|
+
const { IdeManager } = require('../installers/ide/manager');
|
|
11
12
|
|
|
12
13
|
// Load package.json for version
|
|
13
14
|
const packageJsonPath = path.join(__dirname, '..', '..', '..', 'package.json');
|
|
@@ -73,8 +74,27 @@ function info(message) {
|
|
|
73
74
|
console.log(chalk.dim(` ${message}`));
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
// IDE Manager instance for dynamic IDE discovery
|
|
78
|
+
const ideManager = new IdeManager();
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get available IDE choices dynamically from installed handlers
|
|
82
|
+
* @returns {Array} IDE choices formatted for inquirer
|
|
83
|
+
*/
|
|
84
|
+
function getIdeChoices() {
|
|
85
|
+
const ides = ideManager.getAvailableIdes();
|
|
86
|
+
|
|
87
|
+
return ides.map((ide, index) => ({
|
|
88
|
+
name: ide.name,
|
|
89
|
+
value: ide.value,
|
|
90
|
+
// First IDE (preferred) is checked by default
|
|
91
|
+
checked: ide.preferred || index === 0,
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
|
|
76
95
|
/**
|
|
77
|
-
*
|
|
96
|
+
* @deprecated Use getIdeChoices() instead - dynamically loaded from IDE handlers
|
|
97
|
+
* Legacy hardcoded IDE choices kept for backward compatibility
|
|
78
98
|
*/
|
|
79
99
|
const IDE_CHOICES = [
|
|
80
100
|
{
|
|
@@ -82,7 +102,7 @@ const IDE_CHOICES = [
|
|
|
82
102
|
value: 'claude-code',
|
|
83
103
|
checked: true,
|
|
84
104
|
configDir: '.claude/commands',
|
|
85
|
-
description:
|
|
105
|
+
description: "Anthropic's Claude Code IDE",
|
|
86
106
|
},
|
|
87
107
|
{
|
|
88
108
|
name: 'Cursor',
|
|
@@ -96,7 +116,7 @@ const IDE_CHOICES = [
|
|
|
96
116
|
value: 'windsurf',
|
|
97
117
|
checked: false,
|
|
98
118
|
configDir: '.windsurf/workflows',
|
|
99
|
-
description:
|
|
119
|
+
description: "Codeium's AI IDE",
|
|
100
120
|
},
|
|
101
121
|
];
|
|
102
122
|
|
|
@@ -113,7 +133,7 @@ async function promptInstall() {
|
|
|
113
133
|
name: 'directory',
|
|
114
134
|
message: 'Where would you like to install AgileFlow?',
|
|
115
135
|
default: '.',
|
|
116
|
-
validate:
|
|
136
|
+
validate: input => {
|
|
117
137
|
const resolved = path.resolve(input);
|
|
118
138
|
const parent = path.dirname(resolved);
|
|
119
139
|
if (!fs.existsSync(parent)) {
|
|
@@ -126,8 +146,8 @@ async function promptInstall() {
|
|
|
126
146
|
type: 'checkbox',
|
|
127
147
|
name: 'ides',
|
|
128
148
|
message: 'Select your IDE(s):',
|
|
129
|
-
choices:
|
|
130
|
-
validate:
|
|
149
|
+
choices: getIdeChoices(),
|
|
150
|
+
validate: input => {
|
|
131
151
|
if (input.length === 0) {
|
|
132
152
|
return 'Please select at least one IDE';
|
|
133
153
|
}
|
|
@@ -145,7 +165,7 @@ async function promptInstall() {
|
|
|
145
165
|
name: 'agileflowFolder',
|
|
146
166
|
message: 'AgileFlow installation folder name:',
|
|
147
167
|
default: '.agileflow',
|
|
148
|
-
validate:
|
|
168
|
+
validate: input => {
|
|
149
169
|
if (!/^[a-zA-Z0-9._-]+$/.test(input)) {
|
|
150
170
|
return 'Folder name can only contain letters, numbers, dots, underscores, and hyphens';
|
|
151
171
|
}
|
|
@@ -157,7 +177,7 @@ async function promptInstall() {
|
|
|
157
177
|
name: 'docsFolder',
|
|
158
178
|
message: 'Documentation folder name:',
|
|
159
179
|
default: 'docs',
|
|
160
|
-
validate:
|
|
180
|
+
validate: input => {
|
|
161
181
|
if (!/^[a-zA-Z0-9._-]+$/.test(input)) {
|
|
162
182
|
return 'Folder name can only contain letters, numbers, dots, underscores, and hyphens';
|
|
163
183
|
}
|
|
@@ -206,7 +226,7 @@ async function confirm(message, defaultValue = true) {
|
|
|
206
226
|
* @returns {Object|null}
|
|
207
227
|
*/
|
|
208
228
|
function getIdeConfig(ideName) {
|
|
209
|
-
return IDE_CHOICES.find(
|
|
229
|
+
return IDE_CHOICES.find(ide => ide.value === ideName) || null;
|
|
210
230
|
}
|
|
211
231
|
|
|
212
232
|
module.exports = {
|
|
@@ -219,5 +239,6 @@ module.exports = {
|
|
|
219
239
|
promptInstall,
|
|
220
240
|
confirm,
|
|
221
241
|
getIdeConfig,
|
|
222
|
-
|
|
242
|
+
getIdeChoices,
|
|
243
|
+
IDE_CHOICES, // @deprecated - kept for backward compatibility
|
|
223
244
|
};
|
|
@@ -18,17 +18,17 @@ const packageJson = require(packageJsonPath);
|
|
|
18
18
|
* @returns {Promise<string|null>} Latest version or null
|
|
19
19
|
*/
|
|
20
20
|
async function getLatestVersion(packageName = 'agileflow') {
|
|
21
|
-
return new Promise(
|
|
21
|
+
return new Promise(resolve => {
|
|
22
22
|
const url = `https://registry.npmjs.org/${packageName}/latest`;
|
|
23
23
|
|
|
24
|
-
const req = https.get(url, { timeout: 5000 },
|
|
24
|
+
const req = https.get(url, { timeout: 5000 }, res => {
|
|
25
25
|
if (res.statusCode !== 200) {
|
|
26
26
|
resolve(null);
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
let data = '';
|
|
31
|
-
res.on('data',
|
|
31
|
+
res.on('data', chunk => {
|
|
32
32
|
data += chunk;
|
|
33
33
|
});
|
|
34
34
|
|
package/tools/postinstall.js
CHANGED
|
@@ -137,8 +137,8 @@ async function runAutoInstall() {
|
|
|
137
137
|
output: process.stdout,
|
|
138
138
|
});
|
|
139
139
|
|
|
140
|
-
const answer = await new Promise(
|
|
141
|
-
readline.question('Choose an option (1 or 2): ',
|
|
140
|
+
const answer = await new Promise(resolve => {
|
|
141
|
+
readline.question('Choose an option (1 or 2): ', ans => {
|
|
142
142
|
readline.close();
|
|
143
143
|
resolve(ans.trim());
|
|
144
144
|
});
|
|
@@ -176,7 +176,6 @@ async function runAutoInstall() {
|
|
|
176
176
|
console.log('');
|
|
177
177
|
log('To skip auto-setup in the future, set: AGILEFLOW_SKIP_INSTALL=true', 'dim');
|
|
178
178
|
console.log('');
|
|
179
|
-
|
|
180
179
|
} catch (error) {
|
|
181
180
|
console.log('');
|
|
182
181
|
log('⚠️ Auto-setup encountered an issue.', 'yellow');
|