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,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgileFlow CLI - Windsurf IDE Installer
|
|
3
|
+
*
|
|
4
|
+
* Installs AgileFlow workflows for Windsurf IDE.
|
|
5
|
+
* Windsurf uses markdown files in .windsurf/workflows/
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
const fs = require('fs-extra');
|
|
10
|
+
const chalk = require('chalk');
|
|
11
|
+
const { BaseIdeSetup } = require('./_base-ide');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Windsurf IDE setup handler
|
|
15
|
+
*/
|
|
16
|
+
class WindsurfSetup extends BaseIdeSetup {
|
|
17
|
+
constructor() {
|
|
18
|
+
super('windsurf', 'Windsurf', true);
|
|
19
|
+
this.configDir = '.windsurf';
|
|
20
|
+
this.workflowsDir = 'workflows';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Setup Windsurf IDE configuration
|
|
25
|
+
* @param {string} projectDir - Project directory
|
|
26
|
+
* @param {string} agileflowDir - AgileFlow installation directory
|
|
27
|
+
* @param {Object} options - Setup options
|
|
28
|
+
*/
|
|
29
|
+
async setup(projectDir, agileflowDir, options = {}) {
|
|
30
|
+
console.log(chalk.cyan(` Setting up ${this.displayName}...`));
|
|
31
|
+
|
|
32
|
+
// Clean up old installation first
|
|
33
|
+
await this.cleanup(projectDir);
|
|
34
|
+
|
|
35
|
+
// Create .windsurf/workflows/agileflow directory
|
|
36
|
+
const windsurfDir = path.join(projectDir, this.configDir);
|
|
37
|
+
const workflowsDir = path.join(windsurfDir, this.workflowsDir);
|
|
38
|
+
const agileflowWorkflowsDir = path.join(workflowsDir, 'agileflow');
|
|
39
|
+
|
|
40
|
+
await this.ensureDir(agileflowWorkflowsDir);
|
|
41
|
+
|
|
42
|
+
// Get commands from AgileFlow installation
|
|
43
|
+
const commandsSource = path.join(agileflowDir, 'commands');
|
|
44
|
+
let commandCount = 0;
|
|
45
|
+
|
|
46
|
+
if (await this.exists(commandsSource)) {
|
|
47
|
+
const commands = await this.scanDirectory(commandsSource, '.md');
|
|
48
|
+
|
|
49
|
+
for (const command of commands) {
|
|
50
|
+
// Create workflow file
|
|
51
|
+
const workflowContent = await this.createCommandWorkflow(command, agileflowDir, projectDir);
|
|
52
|
+
const targetPath = path.join(agileflowWorkflowsDir, `${command.name}.md`);
|
|
53
|
+
|
|
54
|
+
await this.writeFile(targetPath, workflowContent);
|
|
55
|
+
commandCount++;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Create agents subdirectory
|
|
60
|
+
const agileflowAgentsDir = path.join(agileflowWorkflowsDir, 'agents');
|
|
61
|
+
await this.ensureDir(agileflowAgentsDir);
|
|
62
|
+
|
|
63
|
+
// Get agents from AgileFlow installation
|
|
64
|
+
const agentsSource = path.join(agileflowDir, 'agents');
|
|
65
|
+
let agentCount = 0;
|
|
66
|
+
|
|
67
|
+
if (await this.exists(agentsSource)) {
|
|
68
|
+
const agents = await this.scanDirectory(agentsSource, '.md');
|
|
69
|
+
|
|
70
|
+
for (const agent of agents) {
|
|
71
|
+
// Create workflow file
|
|
72
|
+
const workflowContent = await this.createAgentWorkflow(agent, agileflowDir, projectDir);
|
|
73
|
+
const targetPath = path.join(agileflowAgentsDir, `${agent.name}.md`);
|
|
74
|
+
|
|
75
|
+
await this.writeFile(targetPath, workflowContent);
|
|
76
|
+
agentCount++;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
console.log(chalk.green(` ✓ ${this.displayName} configured:`));
|
|
81
|
+
console.log(chalk.dim(` - ${commandCount} workflows installed`));
|
|
82
|
+
console.log(chalk.dim(` - ${agentCount} agent workflows installed`));
|
|
83
|
+
console.log(chalk.dim(` - Path: ${path.relative(projectDir, agileflowWorkflowsDir)}`));
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
success: true,
|
|
87
|
+
commands: commandCount,
|
|
88
|
+
agents: agentCount,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Cleanup old AgileFlow installation
|
|
94
|
+
* @param {string} projectDir - Project directory
|
|
95
|
+
*/
|
|
96
|
+
async cleanup(projectDir) {
|
|
97
|
+
const agileflowPath = path.join(projectDir, this.configDir, this.workflowsDir, 'agileflow');
|
|
98
|
+
if (await this.exists(agileflowPath)) {
|
|
99
|
+
await fs.remove(agileflowPath);
|
|
100
|
+
console.log(chalk.dim(` Removed old AgileFlow workflows from ${this.displayName}`));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Create a workflow file for a command
|
|
106
|
+
* @param {Object} command - Command info
|
|
107
|
+
* @param {string} agileflowDir - AgileFlow directory
|
|
108
|
+
* @param {string} projectDir - Project directory
|
|
109
|
+
* @returns {Promise<string>} Workflow content
|
|
110
|
+
*/
|
|
111
|
+
async createCommandWorkflow(command, agileflowDir, projectDir) {
|
|
112
|
+
// Read the original command file
|
|
113
|
+
const content = await this.readFile(command.path);
|
|
114
|
+
|
|
115
|
+
// Extract description from frontmatter if present
|
|
116
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
117
|
+
let description = command.name;
|
|
118
|
+
|
|
119
|
+
if (frontmatterMatch) {
|
|
120
|
+
const descMatch = frontmatterMatch[1].match(/description:\s*["']?([^"'\n]+)["']?/);
|
|
121
|
+
if (descMatch) {
|
|
122
|
+
description = descMatch[1];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Create Windsurf workflow format
|
|
127
|
+
const relativePath = path.relative(projectDir, command.path);
|
|
128
|
+
|
|
129
|
+
return `---
|
|
130
|
+
description: ${description}
|
|
131
|
+
auto_execution_mode: 2
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
# AgileFlow: ${command.name}
|
|
135
|
+
|
|
136
|
+
Load and execute the AgileFlow command.
|
|
137
|
+
|
|
138
|
+
## Instructions
|
|
139
|
+
|
|
140
|
+
Read and follow the full command from: \`${relativePath}\`
|
|
141
|
+
|
|
142
|
+
Execute the command according to its specifications.
|
|
143
|
+
`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Create a workflow file for an agent
|
|
148
|
+
* @param {Object} agent - Agent info
|
|
149
|
+
* @param {string} agileflowDir - AgileFlow directory
|
|
150
|
+
* @param {string} projectDir - Project directory
|
|
151
|
+
* @returns {Promise<string>} Workflow content
|
|
152
|
+
*/
|
|
153
|
+
async createAgentWorkflow(agent, agileflowDir, projectDir) {
|
|
154
|
+
// Read the original agent file
|
|
155
|
+
const content = await this.readFile(agent.path);
|
|
156
|
+
|
|
157
|
+
// Extract metadata from frontmatter
|
|
158
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
159
|
+
let description = agent.name;
|
|
160
|
+
let name = agent.name;
|
|
161
|
+
|
|
162
|
+
if (frontmatterMatch) {
|
|
163
|
+
const descMatch = frontmatterMatch[1].match(/description:\s*["']?([^"'\n]+)["']?/);
|
|
164
|
+
const nameMatch = frontmatterMatch[1].match(/name:\s*["']?([^"'\n]+)["']?/);
|
|
165
|
+
|
|
166
|
+
if (descMatch) description = descMatch[1];
|
|
167
|
+
if (nameMatch) name = nameMatch[1];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Create Windsurf workflow format
|
|
171
|
+
const relativePath = path.relative(projectDir, agent.path);
|
|
172
|
+
|
|
173
|
+
return `---
|
|
174
|
+
description: ${description}
|
|
175
|
+
auto_execution_mode: 3
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
# AgileFlow Agent: ${name}
|
|
179
|
+
|
|
180
|
+
Activate the AgileFlow agent.
|
|
181
|
+
|
|
182
|
+
## Instructions
|
|
183
|
+
|
|
184
|
+
1. Read the full agent definition from: \`${relativePath}\`
|
|
185
|
+
2. Adopt the agent's persona and communication style
|
|
186
|
+
3. Follow all instructions and use the specified tools
|
|
187
|
+
4. Maintain the agent's character throughout the session
|
|
188
|
+
`;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
module.exports = { WindsurfSetup };
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgileFlow CLI - UI Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides interactive prompts and display utilities for the CLI.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const inquirer = require('inquirer');
|
|
9
|
+
const path = require('node:path');
|
|
10
|
+
const fs = require('node:fs');
|
|
11
|
+
|
|
12
|
+
// Load package.json for version
|
|
13
|
+
const packageJsonPath = path.join(__dirname, '..', '..', '..', 'package.json');
|
|
14
|
+
const packageJson = require(packageJsonPath);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Display the AgileFlow ASCII logo
|
|
18
|
+
*/
|
|
19
|
+
function displayLogo() {
|
|
20
|
+
const logo = `
|
|
21
|
+
_____ _ __ ________
|
|
22
|
+
/ _ \\ ____/ | \\_/ ____/
|
|
23
|
+
/ /_\\ \\ / ___\\ | |\\____ \\ ____ _ __
|
|
24
|
+
/ | \\ \\___|__|__/ \\/ __ \\/ \\/ /
|
|
25
|
+
\\____|____/\\____/____ /_______/\\____/ \\__/
|
|
26
|
+
`;
|
|
27
|
+
console.log(chalk.cyan(logo));
|
|
28
|
+
console.log(chalk.dim(` AgileFlow v${packageJson.version} - AI-Driven Agile Development\n`));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Display a section header
|
|
33
|
+
* @param {string} title - Section title
|
|
34
|
+
* @param {string} subtitle - Optional subtitle
|
|
35
|
+
*/
|
|
36
|
+
function displaySection(title, subtitle = null) {
|
|
37
|
+
console.log(chalk.bold.cyan(`\n${title}`));
|
|
38
|
+
if (subtitle) {
|
|
39
|
+
console.log(chalk.dim(subtitle));
|
|
40
|
+
}
|
|
41
|
+
console.log();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Display a success message
|
|
46
|
+
* @param {string} message - Success message
|
|
47
|
+
*/
|
|
48
|
+
function success(message) {
|
|
49
|
+
console.log(chalk.green(`✓ ${message}`));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Display a warning message
|
|
54
|
+
* @param {string} message - Warning message
|
|
55
|
+
*/
|
|
56
|
+
function warning(message) {
|
|
57
|
+
console.log(chalk.yellow(`⚠ ${message}`));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Display an error message
|
|
62
|
+
* @param {string} message - Error message
|
|
63
|
+
*/
|
|
64
|
+
function error(message) {
|
|
65
|
+
console.log(chalk.red(`✗ ${message}`));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Display an info message
|
|
70
|
+
* @param {string} message - Info message
|
|
71
|
+
*/
|
|
72
|
+
function info(message) {
|
|
73
|
+
console.log(chalk.dim(` ${message}`));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Available IDE configurations
|
|
78
|
+
*/
|
|
79
|
+
const IDE_CHOICES = [
|
|
80
|
+
{
|
|
81
|
+
name: 'Claude Code',
|
|
82
|
+
value: 'claude-code',
|
|
83
|
+
checked: true,
|
|
84
|
+
configDir: '.claude/commands',
|
|
85
|
+
description: 'Anthropic\'s Claude Code IDE',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'Cursor',
|
|
89
|
+
value: 'cursor',
|
|
90
|
+
checked: false,
|
|
91
|
+
configDir: '.cursor/rules',
|
|
92
|
+
description: 'AI-powered code editor',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'Windsurf',
|
|
96
|
+
value: 'windsurf',
|
|
97
|
+
checked: false,
|
|
98
|
+
configDir: '.windsurf/workflows',
|
|
99
|
+
description: 'Codeium\'s AI IDE',
|
|
100
|
+
},
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Prompt for installation configuration
|
|
105
|
+
* @returns {Promise<Object>} Installation configuration
|
|
106
|
+
*/
|
|
107
|
+
async function promptInstall() {
|
|
108
|
+
displayLogo();
|
|
109
|
+
|
|
110
|
+
const answers = await inquirer.prompt([
|
|
111
|
+
{
|
|
112
|
+
type: 'input',
|
|
113
|
+
name: 'directory',
|
|
114
|
+
message: 'Where would you like to install AgileFlow?',
|
|
115
|
+
default: '.',
|
|
116
|
+
validate: (input) => {
|
|
117
|
+
const resolved = path.resolve(input);
|
|
118
|
+
const parent = path.dirname(resolved);
|
|
119
|
+
if (!fs.existsSync(parent)) {
|
|
120
|
+
return `Parent directory does not exist: ${parent}`;
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
type: 'checkbox',
|
|
127
|
+
name: 'ides',
|
|
128
|
+
message: 'Select your IDE(s):',
|
|
129
|
+
choices: IDE_CHOICES,
|
|
130
|
+
validate: (input) => {
|
|
131
|
+
if (input.length === 0) {
|
|
132
|
+
return 'Please select at least one IDE';
|
|
133
|
+
}
|
|
134
|
+
return true;
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
type: 'input',
|
|
139
|
+
name: 'userName',
|
|
140
|
+
message: 'What should agents call you?',
|
|
141
|
+
default: 'Developer',
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
type: 'input',
|
|
145
|
+
name: 'agileflowFolder',
|
|
146
|
+
message: 'AgileFlow installation folder name:',
|
|
147
|
+
default: '.agileflow',
|
|
148
|
+
validate: (input) => {
|
|
149
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(input)) {
|
|
150
|
+
return 'Folder name can only contain letters, numbers, dots, underscores, and hyphens';
|
|
151
|
+
}
|
|
152
|
+
return true;
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
]);
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
directory: path.resolve(answers.directory),
|
|
159
|
+
ides: answers.ides,
|
|
160
|
+
userName: answers.userName,
|
|
161
|
+
agileflowFolder: answers.agileflowFolder,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Prompt for confirmation
|
|
167
|
+
* @param {string} message - Confirmation message
|
|
168
|
+
* @param {boolean} defaultValue - Default value
|
|
169
|
+
* @returns {Promise<boolean>}
|
|
170
|
+
*/
|
|
171
|
+
async function confirm(message, defaultValue = true) {
|
|
172
|
+
const { confirmed } = await inquirer.prompt([
|
|
173
|
+
{
|
|
174
|
+
type: 'confirm',
|
|
175
|
+
name: 'confirmed',
|
|
176
|
+
message,
|
|
177
|
+
default: defaultValue,
|
|
178
|
+
},
|
|
179
|
+
]);
|
|
180
|
+
return confirmed;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Get IDE configuration by name
|
|
185
|
+
* @param {string} ideName - IDE name
|
|
186
|
+
* @returns {Object|null}
|
|
187
|
+
*/
|
|
188
|
+
function getIdeConfig(ideName) {
|
|
189
|
+
return IDE_CHOICES.find((ide) => ide.value === ideName) || null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
module.exports = {
|
|
193
|
+
displayLogo,
|
|
194
|
+
displaySection,
|
|
195
|
+
success,
|
|
196
|
+
warning,
|
|
197
|
+
error,
|
|
198
|
+
info,
|
|
199
|
+
promptInstall,
|
|
200
|
+
confirm,
|
|
201
|
+
getIdeConfig,
|
|
202
|
+
IDE_CHOICES,
|
|
203
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgileFlow CLI - Version Checker
|
|
3
|
+
*
|
|
4
|
+
* Checks for updates from npm registry.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const https = require('node:https');
|
|
8
|
+
const semver = require('semver');
|
|
9
|
+
const path = require('node:path');
|
|
10
|
+
|
|
11
|
+
// Load package.json for current version
|
|
12
|
+
const packageJsonPath = path.join(__dirname, '..', '..', '..', 'package.json');
|
|
13
|
+
const packageJson = require(packageJsonPath);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Get the latest version from npm registry
|
|
17
|
+
* @param {string} packageName - Package name
|
|
18
|
+
* @returns {Promise<string|null>} Latest version or null
|
|
19
|
+
*/
|
|
20
|
+
async function getLatestVersion(packageName = 'agileflow') {
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
const url = `https://registry.npmjs.org/${packageName}/latest`;
|
|
23
|
+
|
|
24
|
+
const req = https.get(url, { timeout: 5000 }, (res) => {
|
|
25
|
+
if (res.statusCode !== 200) {
|
|
26
|
+
resolve(null);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let data = '';
|
|
31
|
+
res.on('data', (chunk) => {
|
|
32
|
+
data += chunk;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
res.on('end', () => {
|
|
36
|
+
try {
|
|
37
|
+
const json = JSON.parse(data);
|
|
38
|
+
resolve(json.version || null);
|
|
39
|
+
} catch {
|
|
40
|
+
resolve(null);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
req.on('error', () => {
|
|
46
|
+
resolve(null);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
req.on('timeout', () => {
|
|
50
|
+
req.destroy();
|
|
51
|
+
resolve(null);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Check if an update is available
|
|
58
|
+
* @returns {Promise<Object>} Update info
|
|
59
|
+
*/
|
|
60
|
+
async function checkForUpdate() {
|
|
61
|
+
const currentVersion = packageJson.version;
|
|
62
|
+
const latestVersion = await getLatestVersion();
|
|
63
|
+
|
|
64
|
+
if (!latestVersion) {
|
|
65
|
+
return {
|
|
66
|
+
current: currentVersion,
|
|
67
|
+
latest: null,
|
|
68
|
+
updateAvailable: false,
|
|
69
|
+
error: 'Could not check for updates',
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const updateAvailable = semver.gt(latestVersion, currentVersion);
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
current: currentVersion,
|
|
77
|
+
latest: latestVersion,
|
|
78
|
+
updateAvailable,
|
|
79
|
+
error: null,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Get current version
|
|
85
|
+
* @returns {string}
|
|
86
|
+
*/
|
|
87
|
+
function getCurrentVersion() {
|
|
88
|
+
return packageJson.version;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = {
|
|
92
|
+
getLatestVersion,
|
|
93
|
+
checkForUpdate,
|
|
94
|
+
getCurrentVersion,
|
|
95
|
+
};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AgileFlow Postinstall Script
|
|
5
|
+
*
|
|
6
|
+
* Automatically runs AgileFlow installation after npm install.
|
|
7
|
+
* Includes smart detection to avoid running in inappropriate contexts.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { execSync } = require('node:child_process');
|
|
11
|
+
const path = require('node:path');
|
|
12
|
+
const fs = require('node:fs');
|
|
13
|
+
|
|
14
|
+
// ANSI color codes for terminal output
|
|
15
|
+
const colors = {
|
|
16
|
+
green: '\x1b[32m',
|
|
17
|
+
yellow: '\x1b[33m',
|
|
18
|
+
blue: '\x1b[36m',
|
|
19
|
+
dim: '\x1b[2m',
|
|
20
|
+
reset: '\x1b[0m',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function log(message, color = 'reset') {
|
|
24
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function shouldSkipInstall() {
|
|
28
|
+
// Skip if environment variable is set
|
|
29
|
+
if (process.env.AGILEFLOW_SKIP_INSTALL === 'true') {
|
|
30
|
+
log('ℹ️ Skipping auto-install (AGILEFLOW_SKIP_INSTALL=true)', 'dim');
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Skip if running in npm cache or npx temp directory
|
|
35
|
+
if (__dirname.includes('_npx') || __dirname.includes('.npm')) {
|
|
36
|
+
log('ℹ️ Skipping auto-install (npm cache or npx temp directory)', 'dim');
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Skip if we're in the AgileFlow monorepo itself (development mode)
|
|
41
|
+
// Check for monorepo structure: packages/cli/tools/postinstall.js
|
|
42
|
+
// __dirname is tools/ so ../ goes to packages/cli/
|
|
43
|
+
const packageJsonPath = path.join(__dirname, '..', 'package.json');
|
|
44
|
+
|
|
45
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
46
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
47
|
+
|
|
48
|
+
if (packageJson.name === 'agileflow') {
|
|
49
|
+
// Check multiple indicators of monorepo development:
|
|
50
|
+
// 1. Parent directory structure (packages/cli pattern)
|
|
51
|
+
const isInPackagesDir = __dirname.includes('/packages/cli/');
|
|
52
|
+
|
|
53
|
+
// 2. Workspace root package.json exists
|
|
54
|
+
// Path from tools/ -> packages/cli -> packages -> AgileFlow
|
|
55
|
+
const rootPackageJson = path.join(__dirname, '..', '..', '..', 'package.json');
|
|
56
|
+
let isWorkspaceRoot = false;
|
|
57
|
+
if (fs.existsSync(rootPackageJson)) {
|
|
58
|
+
try {
|
|
59
|
+
const rootPkg = JSON.parse(fs.readFileSync(rootPackageJson, 'utf-8'));
|
|
60
|
+
isWorkspaceRoot = rootPkg.name === 'agileflow-monorepo' || Boolean(rootPkg.workspaces);
|
|
61
|
+
} catch (e) {
|
|
62
|
+
// Ignore parse errors
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 3. Git repository check (look for .git in monorepo root)
|
|
67
|
+
// Path from tools/ -> packages/cli -> packages -> AgileFlow -> .git
|
|
68
|
+
const gitDir = path.join(__dirname, '..', '..', '..', '.git');
|
|
69
|
+
const isGitRepo = fs.existsSync(gitDir);
|
|
70
|
+
|
|
71
|
+
if (isInPackagesDir || isWorkspaceRoot || isGitRepo) {
|
|
72
|
+
log('ℹ️ Skipping auto-install (running in development/monorepo)', 'dim');
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Get the installation directory (user's project root)
|
|
79
|
+
const installDir = process.cwd();
|
|
80
|
+
|
|
81
|
+
// Skip if .agileflow or .claude/commands/AgileFlow folder already exists
|
|
82
|
+
const agileflowPath = path.join(installDir, '.agileflow');
|
|
83
|
+
const claudeAgileflowPath = path.join(installDir, '.claude', 'commands', 'AgileFlow');
|
|
84
|
+
|
|
85
|
+
if (fs.existsSync(agileflowPath) || fs.existsSync(claudeAgileflowPath)) {
|
|
86
|
+
log('ℹ️ AgileFlow already installed in this project', 'dim');
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function runAutoInstall() {
|
|
94
|
+
try {
|
|
95
|
+
console.log(''); // Blank line for spacing
|
|
96
|
+
log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'blue');
|
|
97
|
+
log(' AgileFlow Auto-Setup', 'blue');
|
|
98
|
+
log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'blue');
|
|
99
|
+
console.log('');
|
|
100
|
+
|
|
101
|
+
log('🚀 Setting up AgileFlow in your project...', 'green');
|
|
102
|
+
console.log('');
|
|
103
|
+
|
|
104
|
+
// Path to the CLI
|
|
105
|
+
const cliPath = path.join(__dirname, 'cli', 'agileflow-cli.js');
|
|
106
|
+
|
|
107
|
+
if (!fs.existsSync(cliPath)) {
|
|
108
|
+
log('⚠️ Could not find AgileFlow CLI. Run "npx agileflow install" manually.', 'yellow');
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Run install command with --yes flag (non-interactive)
|
|
113
|
+
execSync(`node "${cliPath}" install --yes`, {
|
|
114
|
+
stdio: 'inherit',
|
|
115
|
+
cwd: process.cwd(),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
console.log('');
|
|
119
|
+
log('✨ AgileFlow is ready to use!', 'green');
|
|
120
|
+
console.log('');
|
|
121
|
+
log('To skip auto-install in the future, set: AGILEFLOW_SKIP_INSTALL=true', 'dim');
|
|
122
|
+
console.log('');
|
|
123
|
+
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.log('');
|
|
126
|
+
log('⚠️ Auto-installation encountered an issue.', 'yellow');
|
|
127
|
+
log(' You can run "npx agileflow install" manually to complete setup.', 'yellow');
|
|
128
|
+
console.log('');
|
|
129
|
+
|
|
130
|
+
if (process.env.DEBUG) {
|
|
131
|
+
console.error(error);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Main execution
|
|
137
|
+
if (shouldSkipInstall()) {
|
|
138
|
+
process.exit(0);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
runAutoInstall();
|