agileflow 2.30.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 +61 -0
- package/src/core/agents/accessibility.md +445 -0
- package/src/core/agents/adr-writer.md +215 -0
- package/src/core/agents/analytics.md +523 -0
- package/src/core/agents/api.md +484 -0
- package/src/core/agents/ci.md +452 -0
- package/src/core/agents/compliance.md +401 -0
- package/src/core/agents/context7.md +164 -0
- package/src/core/agents/database.md +377 -0
- package/src/core/agents/datamigration.md +565 -0
- package/src/core/agents/design.md +400 -0
- package/src/core/agents/devops.md +576 -0
- package/src/core/agents/documentation.md +229 -0
- package/src/core/agents/epic-planner.md +277 -0
- package/src/core/agents/integrations.md +459 -0
- package/src/core/agents/mentor.md +375 -0
- package/src/core/agents/mobile.md +391 -0
- package/src/core/agents/monitoring.md +430 -0
- package/src/core/agents/performance.md +390 -0
- package/src/core/agents/product.md +311 -0
- package/src/core/agents/qa.md +647 -0
- package/src/core/agents/readme-updater.md +325 -0
- package/src/core/agents/refactor.md +432 -0
- package/src/core/agents/research.md +250 -0
- package/src/core/agents/security.md +379 -0
- package/src/core/agents/testing.md +397 -0
- package/src/core/agents/ui.md +999 -0
- package/src/core/commands/adr.md +32 -0
- package/src/core/commands/agent.md +23 -0
- package/src/core/commands/assign.md +34 -0
- package/src/core/commands/auto.md +364 -0
- package/src/core/commands/babysit.md +1357 -0
- package/src/core/commands/baseline.md +520 -0
- package/src/core/commands/blockers.md +343 -0
- package/src/core/commands/board.md +241 -0
- package/src/core/commands/changelog.md +321 -0
- package/src/core/commands/ci.md +36 -0
- package/src/core/commands/compress.md +270 -0
- package/src/core/commands/context.md +222 -0
- package/src/core/commands/debt.md +268 -0
- package/src/core/commands/deploy.md +544 -0
- package/src/core/commands/deps.md +560 -0
- package/src/core/commands/diagnose.md +227 -0
- package/src/core/commands/docs.md +166 -0
- package/src/core/commands/epic.md +40 -0
- package/src/core/commands/feedback.md +307 -0
- package/src/core/commands/handoff.md +33 -0
- package/src/core/commands/help.md +90 -0
- package/src/core/commands/impact.md +204 -0
- package/src/core/commands/metrics.md +530 -0
- package/src/core/commands/packages.md +369 -0
- package/src/core/commands/pr.md +35 -0
- package/src/core/commands/readme-sync.md +168 -0
- package/src/core/commands/research.md +30 -0
- package/src/core/commands/resume.md +475 -0
- package/src/core/commands/retro.md +538 -0
- package/src/core/commands/review.md +364 -0
- package/src/core/commands/session-init.md +532 -0
- package/src/core/commands/setup.md +708 -0
- package/src/core/commands/sprint.md +490 -0
- package/src/core/commands/status.md +38 -0
- package/src/core/commands/story-validate.md +242 -0
- package/src/core/commands/story.md +38 -0
- package/src/core/commands/template.md +458 -0
- package/src/core/commands/tests.md +359 -0
- package/src/core/commands/update.md +407 -0
- package/src/core/commands/velocity.md +369 -0
- package/src/core/commands/verify.md +283 -0
- package/src/core/skills/acceptance-criteria-generator/SKILL.md +46 -0
- package/src/core/skills/adr-template/SKILL.md +62 -0
- package/src/core/skills/agileflow-acceptance-criteria/SKILL.md +156 -0
- package/src/core/skills/agileflow-adr/SKILL.md +147 -0
- package/src/core/skills/agileflow-adr/examples/database-choice-example.md +122 -0
- package/src/core/skills/agileflow-adr/templates/adr-template.md +69 -0
- package/src/core/skills/agileflow-commit-messages/SKILL.md +130 -0
- package/src/core/skills/agileflow-commit-messages/reference/bad-examples.md +168 -0
- package/src/core/skills/agileflow-commit-messages/reference/good-examples.md +120 -0
- package/src/core/skills/agileflow-commit-messages/scripts/check-attribution.sh +15 -0
- package/src/core/skills/agileflow-epic-planner/SKILL.md +184 -0
- package/src/core/skills/agileflow-retro-facilitator/SKILL.md +281 -0
- package/src/core/skills/agileflow-sprint-planner/SKILL.md +212 -0
- package/src/core/skills/agileflow-story-writer/SKILL.md +163 -0
- package/src/core/skills/agileflow-story-writer/examples/good-story-example.md +63 -0
- package/src/core/skills/agileflow-story-writer/templates/story-template.md +44 -0
- package/src/core/skills/agileflow-tech-debt/SKILL.md +215 -0
- package/src/core/skills/api-documentation-generator/SKILL.md +65 -0
- package/src/core/skills/changelog-entry/SKILL.md +55 -0
- package/src/core/skills/commit-message-formatter/SKILL.md +50 -0
- package/src/core/skills/deployment-guide-generator/SKILL.md +84 -0
- package/src/core/skills/diagram-generator/SKILL.md +65 -0
- package/src/core/skills/error-handler-template/SKILL.md +78 -0
- package/src/core/skills/migration-checklist/SKILL.md +82 -0
- package/src/core/skills/pr-description/SKILL.md +65 -0
- package/src/core/skills/sql-schema-generator/SKILL.md +69 -0
- package/src/core/skills/story-skeleton/SKILL.md +34 -0
- package/src/core/skills/test-case-generator/SKILL.md +63 -0
- package/src/core/skills/type-definitions/SKILL.md +65 -0
- package/src/core/skills/validation-schema-generator/SKILL.md +64 -0
- package/src/core/templates/README-template.md +16 -0
- package/src/core/templates/adr-template.md +28 -0
- package/src/core/templates/agent-profile-template.md +51 -0
- package/src/core/templates/agileflow-metadata.json +41 -0
- package/src/core/templates/ci-workflow.yml +74 -0
- package/src/core/templates/claude-settings.advanced.example.json +71 -0
- package/src/core/templates/claude-settings.example.json +26 -0
- package/src/core/templates/comms-note-template.md +24 -0
- package/src/core/templates/environment.json +18 -0
- package/src/core/templates/epic-template.md +27 -0
- package/src/core/templates/init.sh +76 -0
- package/src/core/templates/research-template.md +44 -0
- package/src/core/templates/resume-session.sh +121 -0
- package/src/core/templates/session-state.json +20 -0
- package/src/core/templates/skill-template.md +75 -0
- package/src/core/templates/story-template.md +88 -0
- package/src/core/templates/validate-tokens.sh +88 -0
- package/src/core/templates/worktree-create.sh +111 -0
- package/src/core/templates/worktrees-guide.md +235 -0
- package/tools/agileflow-npx.js +40 -0
- package/tools/cli/agileflow-cli.js +70 -0
- package/tools/cli/commands/doctor.js +243 -0
- package/tools/cli/commands/install.js +82 -0
- package/tools/cli/commands/status.js +121 -0
- package/tools/cli/commands/uninstall.js +110 -0
- package/tools/cli/commands/update.js +99 -0
- package/tools/cli/installers/core/installer.js +296 -0
- package/tools/cli/installers/ide/_base-ide.js +133 -0
- package/tools/cli/installers/ide/claude-code.js +174 -0
- package/tools/cli/installers/ide/cursor.js +189 -0
- package/tools/cli/installers/ide/manager.js +197 -0
- package/tools/cli/installers/ide/windsurf.js +192 -0
- package/tools/cli/lib/ui.js +203 -0
- package/tools/cli/lib/version-checker.js +95 -0
- package/tools/postinstall.js +141 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgileFlow CLI - Install Command
|
|
3
|
+
*
|
|
4
|
+
* Installs AgileFlow to a project directory.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
const { Installer } = require('../installers/core/installer');
|
|
10
|
+
const { IdeManager } = require('../installers/ide/manager');
|
|
11
|
+
const { promptInstall, success, error, info, displaySection } = require('../lib/ui');
|
|
12
|
+
|
|
13
|
+
const installer = new Installer();
|
|
14
|
+
const ideManager = new IdeManager();
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
name: 'install',
|
|
18
|
+
description: 'Install AgileFlow to a project',
|
|
19
|
+
options: [
|
|
20
|
+
['-d, --directory <path>', 'Installation directory (default: current directory)'],
|
|
21
|
+
['-y, --yes', 'Skip prompts and use defaults'],
|
|
22
|
+
],
|
|
23
|
+
action: async (options) => {
|
|
24
|
+
try {
|
|
25
|
+
let config;
|
|
26
|
+
|
|
27
|
+
if (options.yes) {
|
|
28
|
+
// Use defaults
|
|
29
|
+
config = {
|
|
30
|
+
directory: path.resolve(options.directory || '.'),
|
|
31
|
+
ides: ['claude-code'],
|
|
32
|
+
userName: 'Developer',
|
|
33
|
+
agileflowFolder: '.agileflow',
|
|
34
|
+
};
|
|
35
|
+
} else {
|
|
36
|
+
// Interactive prompts
|
|
37
|
+
config = await promptInstall();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
displaySection('Installing AgileFlow', `Target: ${config.directory}`);
|
|
41
|
+
|
|
42
|
+
// Run core installation
|
|
43
|
+
const coreResult = await installer.install(config);
|
|
44
|
+
|
|
45
|
+
if (!coreResult.success) {
|
|
46
|
+
error('Core installation failed');
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
success(`Installed ${coreResult.counts.agents} agents`);
|
|
51
|
+
success(`Installed ${coreResult.counts.commands} commands`);
|
|
52
|
+
success(`Installed ${coreResult.counts.skills} skills`);
|
|
53
|
+
|
|
54
|
+
// Setup IDE configurations
|
|
55
|
+
displaySection('Configuring IDEs');
|
|
56
|
+
|
|
57
|
+
ideManager.setAgileflowFolder(config.agileflowFolder);
|
|
58
|
+
|
|
59
|
+
for (const ide of config.ides) {
|
|
60
|
+
await ideManager.setup(ide, config.directory, coreResult.path);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Final summary
|
|
64
|
+
console.log(chalk.green('\n✨ Installation complete!\n'));
|
|
65
|
+
|
|
66
|
+
console.log(chalk.bold('Get started:'));
|
|
67
|
+
info('Open your IDE and use /agileflow:help');
|
|
68
|
+
info(`Run 'npx agileflow status' to check installation`);
|
|
69
|
+
info(`Run 'npx agileflow update' to get updates`);
|
|
70
|
+
|
|
71
|
+
console.log(chalk.dim(`\nInstalled to: ${coreResult.path}\n`));
|
|
72
|
+
|
|
73
|
+
process.exit(0);
|
|
74
|
+
} catch (err) {
|
|
75
|
+
console.error(chalk.red('\nInstallation failed:'), err.message);
|
|
76
|
+
if (process.env.DEBUG) {
|
|
77
|
+
console.error(err.stack);
|
|
78
|
+
}
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgileFlow CLI - Status Command
|
|
3
|
+
*
|
|
4
|
+
* Shows installation status for the current project.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
const fs = require('fs-extra');
|
|
10
|
+
const ora = require('ora');
|
|
11
|
+
const { Installer } = require('../installers/core/installer');
|
|
12
|
+
const { displayLogo, displaySection, success, warning, info } = require('../lib/ui');
|
|
13
|
+
const { checkForUpdate } = require('../lib/version-checker');
|
|
14
|
+
|
|
15
|
+
const installer = new Installer();
|
|
16
|
+
|
|
17
|
+
module.exports = {
|
|
18
|
+
name: 'status',
|
|
19
|
+
description: 'Show AgileFlow installation status',
|
|
20
|
+
options: [
|
|
21
|
+
['-d, --directory <path>', 'Project directory (default: current directory)'],
|
|
22
|
+
],
|
|
23
|
+
action: async (options) => {
|
|
24
|
+
try {
|
|
25
|
+
const directory = path.resolve(options.directory || '.');
|
|
26
|
+
|
|
27
|
+
displayLogo();
|
|
28
|
+
displaySection('Installation Status');
|
|
29
|
+
|
|
30
|
+
const status = await installer.getStatus(directory);
|
|
31
|
+
|
|
32
|
+
if (!status.installed) {
|
|
33
|
+
warning('No AgileFlow installation found in this directory');
|
|
34
|
+
console.log(chalk.dim(`\nRun 'npx agileflow install' to set up AgileFlow\n`));
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Show installation info
|
|
39
|
+
console.log(chalk.bold('Location: '), status.path);
|
|
40
|
+
console.log(chalk.bold('Version: '), status.version);
|
|
41
|
+
|
|
42
|
+
// Count installed items
|
|
43
|
+
const counts = await installer.countInstalledItems(status.path);
|
|
44
|
+
|
|
45
|
+
console.log(chalk.bold('\nCore: '), chalk.green('✓ Installed'));
|
|
46
|
+
info(`${counts.agents} agents`);
|
|
47
|
+
info(`${counts.commands} commands`);
|
|
48
|
+
info(`${counts.skills} skills`);
|
|
49
|
+
|
|
50
|
+
// Show configured IDEs
|
|
51
|
+
if (status.ides && status.ides.length > 0) {
|
|
52
|
+
console.log(chalk.bold('\nConfigured IDEs:'));
|
|
53
|
+
for (const ide of status.ides) {
|
|
54
|
+
// Check if IDE config exists
|
|
55
|
+
const ideConfigPath = getIdeConfigPath(directory, ide);
|
|
56
|
+
const exists = await fs.pathExists(ideConfigPath);
|
|
57
|
+
|
|
58
|
+
if (exists) {
|
|
59
|
+
success(formatIdeName(ide));
|
|
60
|
+
} else {
|
|
61
|
+
warning(`${formatIdeName(ide)} (config missing)`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Check for updates
|
|
67
|
+
const spinner = ora('Checking for updates...').start();
|
|
68
|
+
const updateInfo = await checkForUpdate();
|
|
69
|
+
spinner.stop();
|
|
70
|
+
|
|
71
|
+
if (updateInfo.updateAvailable) {
|
|
72
|
+
console.log(chalk.bold('\nUpdate Available:'));
|
|
73
|
+
console.log(chalk.yellow(` ${updateInfo.current} → ${updateInfo.latest}`));
|
|
74
|
+
console.log(chalk.dim(` Run 'npx agileflow update' to update\n`));
|
|
75
|
+
} else if (updateInfo.error) {
|
|
76
|
+
console.log(chalk.dim(`\n${updateInfo.error}\n`));
|
|
77
|
+
} else {
|
|
78
|
+
console.log(chalk.green('\n✓ You are on the latest version\n'));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
process.exit(0);
|
|
82
|
+
} catch (err) {
|
|
83
|
+
console.error(chalk.red('Error:'), err.message);
|
|
84
|
+
if (process.env.DEBUG) {
|
|
85
|
+
console.error(err.stack);
|
|
86
|
+
}
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get IDE config path
|
|
94
|
+
* @param {string} projectDir - Project directory
|
|
95
|
+
* @param {string} ide - IDE name
|
|
96
|
+
* @returns {string}
|
|
97
|
+
*/
|
|
98
|
+
function getIdeConfigPath(projectDir, ide) {
|
|
99
|
+
const paths = {
|
|
100
|
+
'claude-code': '.claude/commands/AgileFlow',
|
|
101
|
+
'cursor': '.cursor/rules/agileflow',
|
|
102
|
+
'windsurf': '.windsurf/workflows/agileflow',
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
return path.join(projectDir, paths[ide] || '');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Format IDE name for display
|
|
110
|
+
* @param {string} ide - IDE name
|
|
111
|
+
* @returns {string}
|
|
112
|
+
*/
|
|
113
|
+
function formatIdeName(ide) {
|
|
114
|
+
const names = {
|
|
115
|
+
'claude-code': 'Claude Code',
|
|
116
|
+
'cursor': 'Cursor',
|
|
117
|
+
'windsurf': 'Windsurf',
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
return names[ide] || ide;
|
|
121
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgileFlow CLI - Uninstall Command
|
|
3
|
+
*
|
|
4
|
+
* Removes AgileFlow from a project.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
const fs = require('fs-extra');
|
|
10
|
+
const { Installer } = require('../installers/core/installer');
|
|
11
|
+
const { IdeManager } = require('../installers/ide/manager');
|
|
12
|
+
const { displayLogo, displaySection, success, warning, error, confirm } = require('../lib/ui');
|
|
13
|
+
|
|
14
|
+
const installer = new Installer();
|
|
15
|
+
const ideManager = new IdeManager();
|
|
16
|
+
|
|
17
|
+
module.exports = {
|
|
18
|
+
name: 'uninstall',
|
|
19
|
+
description: 'Remove AgileFlow from a project',
|
|
20
|
+
options: [
|
|
21
|
+
['-d, --directory <path>', 'Project directory (default: current directory)'],
|
|
22
|
+
['--force', 'Skip confirmation prompt'],
|
|
23
|
+
],
|
|
24
|
+
action: async (options) => {
|
|
25
|
+
try {
|
|
26
|
+
const directory = path.resolve(options.directory || '.');
|
|
27
|
+
|
|
28
|
+
displayLogo();
|
|
29
|
+
|
|
30
|
+
// Check for existing installation
|
|
31
|
+
const status = await installer.getStatus(directory);
|
|
32
|
+
|
|
33
|
+
if (!status.installed) {
|
|
34
|
+
warning('No AgileFlow installation found');
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
displaySection('Uninstalling AgileFlow', `Location: ${status.path}`);
|
|
39
|
+
|
|
40
|
+
// Confirm uninstall
|
|
41
|
+
if (!options.force) {
|
|
42
|
+
const proceed = await confirm('Are you sure you want to uninstall AgileFlow?', false);
|
|
43
|
+
if (!proceed) {
|
|
44
|
+
console.log(chalk.dim('\nUninstall cancelled\n'));
|
|
45
|
+
process.exit(0);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
console.log();
|
|
50
|
+
|
|
51
|
+
// Remove IDE configurations
|
|
52
|
+
if (status.ides && status.ides.length > 0) {
|
|
53
|
+
for (const ide of status.ides) {
|
|
54
|
+
const configPath = getIdeConfigPath(directory, ide);
|
|
55
|
+
if (await fs.pathExists(configPath)) {
|
|
56
|
+
await fs.remove(configPath);
|
|
57
|
+
success(`Removed ${formatIdeName(ide)} configuration`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Remove AgileFlow directory
|
|
63
|
+
if (await fs.pathExists(status.path)) {
|
|
64
|
+
await fs.remove(status.path);
|
|
65
|
+
success(`Removed ${path.basename(status.path)}/`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
console.log(chalk.green('\nAgileFlow has been uninstalled.\n'));
|
|
69
|
+
|
|
70
|
+
process.exit(0);
|
|
71
|
+
} catch (err) {
|
|
72
|
+
console.error(chalk.red('Uninstall failed:'), err.message);
|
|
73
|
+
if (process.env.DEBUG) {
|
|
74
|
+
console.error(err.stack);
|
|
75
|
+
}
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get IDE config path
|
|
83
|
+
* @param {string} projectDir - Project directory
|
|
84
|
+
* @param {string} ide - IDE name
|
|
85
|
+
* @returns {string}
|
|
86
|
+
*/
|
|
87
|
+
function getIdeConfigPath(projectDir, ide) {
|
|
88
|
+
const paths = {
|
|
89
|
+
'claude-code': '.claude/commands/AgileFlow',
|
|
90
|
+
'cursor': '.cursor/rules/agileflow',
|
|
91
|
+
'windsurf': '.windsurf/workflows/agileflow',
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
return path.join(projectDir, paths[ide] || '');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Format IDE name for display
|
|
99
|
+
* @param {string} ide - IDE name
|
|
100
|
+
* @returns {string}
|
|
101
|
+
*/
|
|
102
|
+
function formatIdeName(ide) {
|
|
103
|
+
const names = {
|
|
104
|
+
'claude-code': 'Claude Code',
|
|
105
|
+
'cursor': 'Cursor',
|
|
106
|
+
'windsurf': 'Windsurf',
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
return names[ide] || ide;
|
|
110
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgileFlow CLI - Update Command
|
|
3
|
+
*
|
|
4
|
+
* Updates an existing AgileFlow installation.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
const { Installer } = require('../installers/core/installer');
|
|
10
|
+
const { IdeManager } = require('../installers/ide/manager');
|
|
11
|
+
const { displayLogo, displaySection, success, warning, error, info, confirm } = require('../lib/ui');
|
|
12
|
+
|
|
13
|
+
const installer = new Installer();
|
|
14
|
+
const ideManager = new IdeManager();
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
name: 'update',
|
|
18
|
+
description: 'Update existing AgileFlow installation',
|
|
19
|
+
options: [
|
|
20
|
+
['-d, --directory <path>', 'Project directory (default: current directory)'],
|
|
21
|
+
['--force', 'Force update, overwriting modified files'],
|
|
22
|
+
],
|
|
23
|
+
action: async (options) => {
|
|
24
|
+
try {
|
|
25
|
+
const directory = path.resolve(options.directory || '.');
|
|
26
|
+
|
|
27
|
+
displayLogo();
|
|
28
|
+
|
|
29
|
+
// Check for existing installation
|
|
30
|
+
const status = await installer.getStatus(directory);
|
|
31
|
+
|
|
32
|
+
if (!status.installed) {
|
|
33
|
+
warning('No AgileFlow installation found');
|
|
34
|
+
console.log(chalk.dim(`\nRun 'npx agileflow install' to set up AgileFlow\n`));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
displaySection('Updating AgileFlow', `Current version: ${status.version}`);
|
|
39
|
+
|
|
40
|
+
// Get package version
|
|
41
|
+
const packageJson = require(path.join(__dirname, '..', '..', '..', 'package.json'));
|
|
42
|
+
const newVersion = packageJson.version;
|
|
43
|
+
|
|
44
|
+
console.log(chalk.bold('Current: '), status.version);
|
|
45
|
+
console.log(chalk.bold('Latest: '), newVersion);
|
|
46
|
+
|
|
47
|
+
if (status.version === newVersion && !options.force) {
|
|
48
|
+
success('Already on the latest version');
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Confirm update
|
|
53
|
+
if (!options.force) {
|
|
54
|
+
const proceed = await confirm(`Update to v${newVersion}?`);
|
|
55
|
+
if (!proceed) {
|
|
56
|
+
console.log(chalk.dim('\nUpdate cancelled\n'));
|
|
57
|
+
process.exit(0);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log();
|
|
62
|
+
|
|
63
|
+
// Re-run installation with existing config
|
|
64
|
+
const config = {
|
|
65
|
+
directory,
|
|
66
|
+
ides: status.ides || ['claude-code'],
|
|
67
|
+
userName: 'Developer', // Could read from existing config
|
|
68
|
+
agileflowFolder: path.basename(status.path),
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Run core installation
|
|
72
|
+
const coreResult = await installer.install(config);
|
|
73
|
+
|
|
74
|
+
if (!coreResult.success) {
|
|
75
|
+
error('Update failed');
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
success('Updated core content');
|
|
80
|
+
|
|
81
|
+
// Re-setup IDEs
|
|
82
|
+
ideManager.setAgileflowFolder(config.agileflowFolder);
|
|
83
|
+
|
|
84
|
+
for (const ide of config.ides) {
|
|
85
|
+
await ideManager.setup(ide, directory, status.path);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
console.log(chalk.green(`\n✨ Update complete! (${status.version} → ${newVersion})\n`));
|
|
89
|
+
|
|
90
|
+
process.exit(0);
|
|
91
|
+
} catch (err) {
|
|
92
|
+
console.error(chalk.red('Update failed:'), err.message);
|
|
93
|
+
if (process.env.DEBUG) {
|
|
94
|
+
console.error(err.stack);
|
|
95
|
+
}
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
};
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgileFlow CLI - Core Installer
|
|
3
|
+
*
|
|
4
|
+
* Handles the main installation logic for AgileFlow.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const path = require('node:path');
|
|
8
|
+
const fs = require('fs-extra');
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const ora = require('ora');
|
|
11
|
+
const yaml = require('js-yaml');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Get the source path for AgileFlow content
|
|
15
|
+
* @returns {string} Path to src directory
|
|
16
|
+
*/
|
|
17
|
+
function getSourcePath() {
|
|
18
|
+
return path.join(__dirname, '..', '..', '..', '..', 'src');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get the package root path
|
|
23
|
+
* @returns {string} Path to package root
|
|
24
|
+
*/
|
|
25
|
+
function getPackageRoot() {
|
|
26
|
+
return path.join(__dirname, '..', '..', '..', '..');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Core Installer class
|
|
31
|
+
*/
|
|
32
|
+
class Installer {
|
|
33
|
+
constructor() {
|
|
34
|
+
this.sourcePath = getSourcePath();
|
|
35
|
+
this.packageRoot = getPackageRoot();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Install AgileFlow to a project
|
|
40
|
+
* @param {Object} config - Installation configuration
|
|
41
|
+
* @returns {Promise<Object>} Installation result
|
|
42
|
+
*/
|
|
43
|
+
async install(config) {
|
|
44
|
+
const { directory, ides, userName, agileflowFolder } = config;
|
|
45
|
+
|
|
46
|
+
const agileflowDir = path.join(directory, agileflowFolder);
|
|
47
|
+
const spinner = ora('Installing AgileFlow...').start();
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
// Create AgileFlow directory
|
|
51
|
+
await fs.ensureDir(agileflowDir);
|
|
52
|
+
spinner.text = 'Creating directory structure...';
|
|
53
|
+
|
|
54
|
+
// Create _cfg directory for manifest
|
|
55
|
+
const cfgDir = path.join(agileflowDir, '_cfg');
|
|
56
|
+
await fs.ensureDir(cfgDir);
|
|
57
|
+
|
|
58
|
+
// Copy core content
|
|
59
|
+
spinner.text = 'Installing core content...';
|
|
60
|
+
const coreSourcePath = path.join(this.sourcePath, 'core');
|
|
61
|
+
|
|
62
|
+
if (await fs.pathExists(coreSourcePath)) {
|
|
63
|
+
await this.copyContent(coreSourcePath, agileflowDir, agileflowFolder);
|
|
64
|
+
} else {
|
|
65
|
+
// Fallback: copy from old structure (commands, agents, skills at root)
|
|
66
|
+
await this.copyLegacyContent(directory, agileflowDir, agileflowFolder);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Create config.yaml
|
|
70
|
+
spinner.text = 'Creating configuration...';
|
|
71
|
+
await this.createConfig(agileflowDir, userName, agileflowFolder);
|
|
72
|
+
|
|
73
|
+
// Create manifest
|
|
74
|
+
spinner.text = 'Creating manifest...';
|
|
75
|
+
await this.createManifest(cfgDir, ides);
|
|
76
|
+
|
|
77
|
+
// Count installed items
|
|
78
|
+
const counts = await this.countInstalledItems(agileflowDir);
|
|
79
|
+
|
|
80
|
+
spinner.succeed('Core installation complete');
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
success: true,
|
|
84
|
+
path: agileflowDir,
|
|
85
|
+
projectDir: directory,
|
|
86
|
+
counts,
|
|
87
|
+
};
|
|
88
|
+
} catch (error) {
|
|
89
|
+
spinner.fail('Installation failed');
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Copy content from source to destination with placeholder replacement
|
|
96
|
+
* @param {string} source - Source directory
|
|
97
|
+
* @param {string} dest - Destination directory
|
|
98
|
+
* @param {string} agileflowFolder - AgileFlow folder name
|
|
99
|
+
*/
|
|
100
|
+
async copyContent(source, dest, agileflowFolder) {
|
|
101
|
+
const entries = await fs.readdir(source, { withFileTypes: true });
|
|
102
|
+
|
|
103
|
+
for (const entry of entries) {
|
|
104
|
+
const srcPath = path.join(source, entry.name);
|
|
105
|
+
const destPath = path.join(dest, entry.name);
|
|
106
|
+
|
|
107
|
+
if (entry.isDirectory()) {
|
|
108
|
+
await fs.ensureDir(destPath);
|
|
109
|
+
await this.copyContent(srcPath, destPath, agileflowFolder);
|
|
110
|
+
} else {
|
|
111
|
+
await this.copyFileWithReplacements(srcPath, destPath, agileflowFolder);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Copy legacy content structure (from root commands/agents/skills)
|
|
118
|
+
* @param {string} projectDir - Project directory
|
|
119
|
+
* @param {string} agileflowDir - AgileFlow installation directory
|
|
120
|
+
* @param {string} agileflowFolder - AgileFlow folder name
|
|
121
|
+
*/
|
|
122
|
+
async copyLegacyContent(projectDir, agileflowDir, agileflowFolder) {
|
|
123
|
+
const packageRoot = this.packageRoot;
|
|
124
|
+
|
|
125
|
+
// Copy commands
|
|
126
|
+
const commandsSource = path.join(packageRoot, 'commands');
|
|
127
|
+
const commandsDest = path.join(agileflowDir, 'commands');
|
|
128
|
+
if (await fs.pathExists(commandsSource)) {
|
|
129
|
+
await fs.ensureDir(commandsDest);
|
|
130
|
+
await this.copyContent(commandsSource, commandsDest, agileflowFolder);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Copy agents
|
|
134
|
+
const agentsSource = path.join(packageRoot, 'agents');
|
|
135
|
+
const agentsDest = path.join(agileflowDir, 'agents');
|
|
136
|
+
if (await fs.pathExists(agentsSource)) {
|
|
137
|
+
await fs.ensureDir(agentsDest);
|
|
138
|
+
await this.copyContent(agentsSource, agentsDest, agileflowFolder);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Copy skills
|
|
142
|
+
const skillsSource = path.join(packageRoot, 'skills');
|
|
143
|
+
const skillsDest = path.join(agileflowDir, 'skills');
|
|
144
|
+
if (await fs.pathExists(skillsSource)) {
|
|
145
|
+
await fs.ensureDir(skillsDest);
|
|
146
|
+
await this.copyContent(skillsSource, skillsDest, agileflowFolder);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Copy templates
|
|
150
|
+
const templatesSource = path.join(packageRoot, 'templates');
|
|
151
|
+
const templatesDest = path.join(agileflowDir, 'templates');
|
|
152
|
+
if (await fs.pathExists(templatesSource)) {
|
|
153
|
+
await fs.ensureDir(templatesDest);
|
|
154
|
+
await this.copyContent(templatesSource, templatesDest, agileflowFolder);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Copy a file with placeholder replacements
|
|
160
|
+
* @param {string} source - Source file path
|
|
161
|
+
* @param {string} dest - Destination file path
|
|
162
|
+
* @param {string} agileflowFolder - AgileFlow folder name
|
|
163
|
+
*/
|
|
164
|
+
async copyFileWithReplacements(source, dest, agileflowFolder) {
|
|
165
|
+
const textExtensions = ['.md', '.yaml', '.yml', '.txt', '.json'];
|
|
166
|
+
const ext = path.extname(source).toLowerCase();
|
|
167
|
+
|
|
168
|
+
if (textExtensions.includes(ext)) {
|
|
169
|
+
let content = await fs.readFile(source, 'utf8');
|
|
170
|
+
|
|
171
|
+
// Replace placeholders
|
|
172
|
+
content = content.replace(/\{agileflow_folder\}/g, agileflowFolder);
|
|
173
|
+
content = content.replace(/\{project-root\}/g, '{project-root}'); // Keep as-is for runtime
|
|
174
|
+
|
|
175
|
+
await fs.writeFile(dest, content, 'utf8');
|
|
176
|
+
} else {
|
|
177
|
+
await fs.copy(source, dest);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Create configuration file
|
|
183
|
+
* @param {string} agileflowDir - AgileFlow directory
|
|
184
|
+
* @param {string} userName - User name
|
|
185
|
+
* @param {string} agileflowFolder - AgileFlow folder name
|
|
186
|
+
*/
|
|
187
|
+
async createConfig(agileflowDir, userName, agileflowFolder) {
|
|
188
|
+
const config = {
|
|
189
|
+
version: require(path.join(this.packageRoot, 'package.json')).version,
|
|
190
|
+
user_name: userName,
|
|
191
|
+
agileflow_folder: agileflowFolder,
|
|
192
|
+
communication_language: 'English',
|
|
193
|
+
created_at: new Date().toISOString(),
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const configPath = path.join(agileflowDir, 'config.yaml');
|
|
197
|
+
await fs.writeFile(configPath, yaml.dump(config), 'utf8');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Create manifest file
|
|
202
|
+
* @param {string} cfgDir - Config directory
|
|
203
|
+
* @param {string[]} ides - Selected IDEs
|
|
204
|
+
*/
|
|
205
|
+
async createManifest(cfgDir, ides) {
|
|
206
|
+
const packageJson = require(path.join(this.packageRoot, 'package.json'));
|
|
207
|
+
|
|
208
|
+
const manifest = {
|
|
209
|
+
version: packageJson.version,
|
|
210
|
+
installed_at: new Date().toISOString(),
|
|
211
|
+
updated_at: new Date().toISOString(),
|
|
212
|
+
ides: ides,
|
|
213
|
+
modules: ['core'],
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const manifestPath = path.join(cfgDir, 'manifest.yaml');
|
|
217
|
+
await fs.writeFile(manifestPath, yaml.dump(manifest), 'utf8');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Count installed items
|
|
222
|
+
* @param {string} agileflowDir - AgileFlow directory
|
|
223
|
+
* @returns {Promise<Object>} Counts
|
|
224
|
+
*/
|
|
225
|
+
async countInstalledItems(agileflowDir) {
|
|
226
|
+
const counts = {
|
|
227
|
+
agents: 0,
|
|
228
|
+
commands: 0,
|
|
229
|
+
skills: 0,
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// Count agents
|
|
233
|
+
const agentsDir = path.join(agileflowDir, 'agents');
|
|
234
|
+
if (await fs.pathExists(agentsDir)) {
|
|
235
|
+
const files = await fs.readdir(agentsDir);
|
|
236
|
+
counts.agents = files.filter((f) => f.endsWith('.md')).length;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Count commands
|
|
240
|
+
const commandsDir = path.join(agileflowDir, 'commands');
|
|
241
|
+
if (await fs.pathExists(commandsDir)) {
|
|
242
|
+
const files = await fs.readdir(commandsDir);
|
|
243
|
+
counts.commands = files.filter((f) => f.endsWith('.md')).length;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Count skills
|
|
247
|
+
const skillsDir = path.join(agileflowDir, 'skills');
|
|
248
|
+
if (await fs.pathExists(skillsDir)) {
|
|
249
|
+
const entries = await fs.readdir(skillsDir, { withFileTypes: true });
|
|
250
|
+
counts.skills = entries.filter((e) => e.isDirectory()).length;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return counts;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Get installation status
|
|
258
|
+
* @param {string} directory - Project directory
|
|
259
|
+
* @returns {Promise<Object>} Installation status
|
|
260
|
+
*/
|
|
261
|
+
async getStatus(directory) {
|
|
262
|
+
const status = {
|
|
263
|
+
installed: false,
|
|
264
|
+
path: null,
|
|
265
|
+
version: null,
|
|
266
|
+
ides: [],
|
|
267
|
+
modules: [],
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
// Look for AgileFlow installation
|
|
271
|
+
const possibleFolders = ['.agileflow', 'agileflow', '.aflow'];
|
|
272
|
+
|
|
273
|
+
for (const folder of possibleFolders) {
|
|
274
|
+
const agileflowDir = path.join(directory, folder);
|
|
275
|
+
const manifestPath = path.join(agileflowDir, '_cfg', 'manifest.yaml');
|
|
276
|
+
|
|
277
|
+
if (await fs.pathExists(manifestPath)) {
|
|
278
|
+
status.installed = true;
|
|
279
|
+
status.path = agileflowDir;
|
|
280
|
+
|
|
281
|
+
const manifestContent = await fs.readFile(manifestPath, 'utf8');
|
|
282
|
+
const manifest = yaml.load(manifestContent);
|
|
283
|
+
|
|
284
|
+
status.version = manifest.version;
|
|
285
|
+
status.ides = manifest.ides || [];
|
|
286
|
+
status.modules = manifest.modules || [];
|
|
287
|
+
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return status;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
module.exports = { Installer, getSourcePath, getPackageRoot };
|