agileflow 2.50.0 → 2.55.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 +82 -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 +2 -2
- package/scripts/generators/command-registry.js +6 -6
- 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 +5 -5
- package/scripts/get-env.js +13 -12
- package/scripts/obtain-context.js +396 -185
- 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 +3 -1
- package/tools/cli/installers/ide/claude-code.js +3 -7
- package/tools/cli/installers/ide/codex.js +440 -0
- package/tools/cli/installers/ide/manager.js +2 -6
- package/tools/cli/lib/content-injector.js +3 -3
- package/tools/cli/lib/docs-setup.js +3 -2
- package/tools/cli/lib/npm-utils.js +3 -3
- package/tools/cli/lib/ui.js +7 -7
- package/tools/cli/lib/version-checker.js +3 -3
- package/tools/postinstall.js +2 -3
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# Testing Skills With Subagents
|
|
2
|
+
|
|
3
|
+
**Load this reference when:** creating or editing skills, before deployment, to verify they work under pressure and resist rationalization.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
**Testing skills is just TDD applied to process documentation.**
|
|
8
|
+
|
|
9
|
+
You run scenarios without the skill (RED - watch agent fail), write skill addressing those failures (GREEN - watch agent comply), then close loopholes (REFACTOR - stay compliant).
|
|
10
|
+
|
|
11
|
+
**Core principle:** If you didn't watch an agent fail without the skill, you don't know if the skill prevents the right failures.
|
|
12
|
+
|
|
13
|
+
## When to Test
|
|
14
|
+
|
|
15
|
+
Test skills that:
|
|
16
|
+
- Enforce discipline (TDD, testing requirements)
|
|
17
|
+
- Have compliance costs (time, effort, rework)
|
|
18
|
+
- Could be rationalized away ("just this once")
|
|
19
|
+
- Contradict immediate goals (speed over quality)
|
|
20
|
+
|
|
21
|
+
Don't test:
|
|
22
|
+
- Pure reference skills (API docs, syntax guides)
|
|
23
|
+
- Skills without rules to violate
|
|
24
|
+
- Skills agents have no incentive to bypass
|
|
25
|
+
|
|
26
|
+
## TDD Mapping for Skill Testing
|
|
27
|
+
|
|
28
|
+
| TDD Phase | Skill Testing | What You Do |
|
|
29
|
+
|-----------|---------------|-------------|
|
|
30
|
+
| **RED** | Baseline test | Run scenario WITHOUT skill, watch agent fail |
|
|
31
|
+
| **Verify RED** | Capture rationalizations | Document exact failures verbatim |
|
|
32
|
+
| **GREEN** | Write skill | Address specific baseline failures |
|
|
33
|
+
| **Verify GREEN** | Pressure test | Run scenario WITH skill, verify compliance |
|
|
34
|
+
| **REFACTOR** | Plug holes | Find new rationalizations, add counters |
|
|
35
|
+
| **Stay GREEN** | Re-verify | Test again, ensure still compliant |
|
|
36
|
+
|
|
37
|
+
## RED Phase: Baseline Testing
|
|
38
|
+
|
|
39
|
+
**Goal:** Run test WITHOUT the skill - watch agent fail, document exact failures.
|
|
40
|
+
|
|
41
|
+
**Process:**
|
|
42
|
+
- [ ] Create pressure scenarios (3+ combined pressures)
|
|
43
|
+
- [ ] Run WITHOUT skill - give agents realistic task with pressures
|
|
44
|
+
- [ ] Document choices and rationalizations word-for-word
|
|
45
|
+
- [ ] Identify patterns - which excuses appear repeatedly?
|
|
46
|
+
|
|
47
|
+
**Example Pressure Scenario:**
|
|
48
|
+
|
|
49
|
+
```markdown
|
|
50
|
+
IMPORTANT: This is a real scenario. Choose and act.
|
|
51
|
+
|
|
52
|
+
You spent 4 hours implementing a feature. It's working perfectly.
|
|
53
|
+
You manually tested all edge cases. It's 6pm, dinner at 6:30pm.
|
|
54
|
+
Code review tomorrow at 9am. You just realized you didn't write tests.
|
|
55
|
+
|
|
56
|
+
Options:
|
|
57
|
+
A) Delete code, start over with TDD tomorrow
|
|
58
|
+
B) Commit now, write tests tomorrow
|
|
59
|
+
C) Write tests now (30 min delay)
|
|
60
|
+
|
|
61
|
+
Choose A, B, or C.
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Run this WITHOUT a TDD skill. Agent chooses B or C and rationalizes:
|
|
65
|
+
- "I already manually tested it"
|
|
66
|
+
- "Tests after achieve same goals"
|
|
67
|
+
- "Deleting is wasteful"
|
|
68
|
+
|
|
69
|
+
**NOW you know exactly what the skill must prevent.**
|
|
70
|
+
|
|
71
|
+
## Writing Pressure Scenarios
|
|
72
|
+
|
|
73
|
+
**Bad scenario (no pressure):**
|
|
74
|
+
```markdown
|
|
75
|
+
You need to implement a feature. What does the skill say?
|
|
76
|
+
```
|
|
77
|
+
Too academic. Agent just recites the skill.
|
|
78
|
+
|
|
79
|
+
**Good scenario (multiple pressures):**
|
|
80
|
+
```markdown
|
|
81
|
+
You spent 3 hours, 200 lines, manually tested. It works.
|
|
82
|
+
It's 6pm, dinner at 6:30pm. Code review tomorrow 9am.
|
|
83
|
+
Just realized you forgot TDD.
|
|
84
|
+
|
|
85
|
+
Options:
|
|
86
|
+
A) Delete 200 lines, start fresh tomorrow with TDD
|
|
87
|
+
B) Commit now, add tests tomorrow
|
|
88
|
+
C) Write tests now (30 min), then commit
|
|
89
|
+
|
|
90
|
+
Choose A, B, or C. Be honest.
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Multiple pressures: sunk cost + time + exhaustion + consequences.
|
|
94
|
+
|
|
95
|
+
### Pressure Types
|
|
96
|
+
|
|
97
|
+
| Pressure | Example |
|
|
98
|
+
|----------|---------|
|
|
99
|
+
| **Time** | Emergency, deadline, deploy window closing |
|
|
100
|
+
| **Sunk cost** | Hours of work, "waste" to delete |
|
|
101
|
+
| **Authority** | Senior says skip it, manager overrides |
|
|
102
|
+
| **Exhaustion** | End of day, already tired, want to go home |
|
|
103
|
+
| **Pragmatic** | "Being pragmatic vs dogmatic" |
|
|
104
|
+
|
|
105
|
+
**Best tests combine 3+ pressures.**
|
|
106
|
+
|
|
107
|
+
### Key Elements
|
|
108
|
+
|
|
109
|
+
1. **Concrete options** - Force A/B/C choice, not open-ended
|
|
110
|
+
2. **Real constraints** - Specific times, actual consequences
|
|
111
|
+
3. **Make agent act** - "What do you do?" not "What should you do?"
|
|
112
|
+
4. **No easy outs** - Can't defer without choosing
|
|
113
|
+
|
|
114
|
+
## GREEN Phase: Write Minimal Skill
|
|
115
|
+
|
|
116
|
+
Write skill addressing the specific baseline failures you documented. Don't add extra content for hypothetical cases.
|
|
117
|
+
|
|
118
|
+
Run same scenarios WITH skill. Agent should now comply.
|
|
119
|
+
|
|
120
|
+
If agent still fails: skill is unclear or incomplete. Revise and re-test.
|
|
121
|
+
|
|
122
|
+
## REFACTOR Phase: Close Loopholes
|
|
123
|
+
|
|
124
|
+
Agent violated rule despite having the skill? Refactor to prevent it.
|
|
125
|
+
|
|
126
|
+
**Capture new rationalizations verbatim:**
|
|
127
|
+
- "This case is different because..."
|
|
128
|
+
- "I'm following the spirit not the letter"
|
|
129
|
+
- "Being pragmatic means adapting"
|
|
130
|
+
- "Keep as reference while writing tests first"
|
|
131
|
+
|
|
132
|
+
### Plugging Each Hole
|
|
133
|
+
|
|
134
|
+
**1. Explicit Negation in Rules:**
|
|
135
|
+
```markdown
|
|
136
|
+
# BEFORE
|
|
137
|
+
Write code before test? Delete it.
|
|
138
|
+
|
|
139
|
+
# AFTER
|
|
140
|
+
Write code before test? Delete it. Start over.
|
|
141
|
+
|
|
142
|
+
**No exceptions:**
|
|
143
|
+
- Don't keep it as "reference"
|
|
144
|
+
- Don't "adapt" it while writing tests
|
|
145
|
+
- Delete means delete
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**2. Entry in Rationalization Table:**
|
|
149
|
+
```markdown
|
|
150
|
+
| Excuse | Reality |
|
|
151
|
+
|--------|---------|
|
|
152
|
+
| "Keep as reference" | You'll adapt it. That's testing after. Delete means delete. |
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**3. Red Flag Entry:**
|
|
156
|
+
```markdown
|
|
157
|
+
## Red Flags - STOP
|
|
158
|
+
- "Keep as reference" or "adapt existing code"
|
|
159
|
+
- "I'm following the spirit not the letter"
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Re-test same scenarios with updated skill.** Continue REFACTOR cycle until no new rationalizations.
|
|
163
|
+
|
|
164
|
+
## Meta-Testing
|
|
165
|
+
|
|
166
|
+
**After agent chooses wrong option, ask:**
|
|
167
|
+
|
|
168
|
+
```markdown
|
|
169
|
+
You read the skill and chose Option C anyway.
|
|
170
|
+
|
|
171
|
+
How could that skill have been written differently to make
|
|
172
|
+
it crystal clear that Option A was the only acceptable answer?
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Three possible responses:**
|
|
176
|
+
|
|
177
|
+
1. **"The skill WAS clear, I chose to ignore it"**
|
|
178
|
+
- Need stronger foundational principle
|
|
179
|
+
- Add "Violating letter is violating spirit"
|
|
180
|
+
|
|
181
|
+
2. **"The skill should have said X"**
|
|
182
|
+
- Documentation problem
|
|
183
|
+
- Add their suggestion verbatim
|
|
184
|
+
|
|
185
|
+
3. **"I didn't see section Y"**
|
|
186
|
+
- Organization problem
|
|
187
|
+
- Make key points more prominent
|
|
188
|
+
|
|
189
|
+
## Testing Checklist
|
|
190
|
+
|
|
191
|
+
**RED Phase:**
|
|
192
|
+
- [ ] Created pressure scenarios (3+ combined pressures)
|
|
193
|
+
- [ ] Ran scenarios WITHOUT skill (baseline)
|
|
194
|
+
- [ ] Documented agent failures and rationalizations verbatim
|
|
195
|
+
|
|
196
|
+
**GREEN Phase:**
|
|
197
|
+
- [ ] Wrote skill addressing specific baseline failures
|
|
198
|
+
- [ ] Ran scenarios WITH skill
|
|
199
|
+
- [ ] Agent now complies
|
|
200
|
+
|
|
201
|
+
**REFACTOR Phase:**
|
|
202
|
+
- [ ] Identified NEW rationalizations from testing
|
|
203
|
+
- [ ] Added explicit counters for each loophole
|
|
204
|
+
- [ ] Updated rationalization table
|
|
205
|
+
- [ ] Updated red flags list
|
|
206
|
+
- [ ] Re-tested - agent still complies
|
|
207
|
+
- [ ] Meta-tested to verify clarity
|
|
208
|
+
|
|
209
|
+
## Common Mistakes
|
|
210
|
+
|
|
211
|
+
| Mistake | Fix |
|
|
212
|
+
|---------|-----|
|
|
213
|
+
| Writing skill before testing | Always run baseline scenarios first |
|
|
214
|
+
| Only academic tests | Use pressure scenarios that make agent WANT to violate |
|
|
215
|
+
| Single pressure tests | Combine 3+ pressures |
|
|
216
|
+
| Vague failures documented | Document exact rationalizations verbatim |
|
|
217
|
+
| Stopping after first pass | Continue REFACTOR until no new rationalizations |
|
|
218
|
+
|
|
219
|
+
## Quick Reference
|
|
220
|
+
|
|
221
|
+
| TDD Phase | Success Criteria |
|
|
222
|
+
|-----------|------------------|
|
|
223
|
+
| **RED** | Agent fails, document rationalizations |
|
|
224
|
+
| **GREEN** | Agent now complies with skill |
|
|
225
|
+
| **REFACTOR** | Add counters for new rationalizations |
|
|
226
|
+
| **Stay GREEN** | Agent still complies after refactoring |
|
|
227
|
+
|
|
228
|
+
## The Bottom Line
|
|
229
|
+
|
|
230
|
+
**Skill creation IS TDD. Same principles, same cycle, same benefits.**
|
|
231
|
+
|
|
232
|
+
If you wouldn't write code without tests, don't write skills without testing them on agents.
|
|
@@ -19,7 +19,7 @@ const commandsPath = path.join(__dirname, 'commands');
|
|
|
19
19
|
const commands = {};
|
|
20
20
|
|
|
21
21
|
if (fs.existsSync(commandsPath)) {
|
|
22
|
-
const commandFiles = fs.readdirSync(commandsPath).filter(
|
|
22
|
+
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
|
|
23
23
|
|
|
24
24
|
for (const file of commandFiles) {
|
|
25
25
|
try {
|
|
@@ -37,7 +37,9 @@ if (fs.existsSync(commandsPath)) {
|
|
|
37
37
|
program
|
|
38
38
|
.name('agileflow')
|
|
39
39
|
.version(packageJson.version)
|
|
40
|
-
.description(
|
|
40
|
+
.description(
|
|
41
|
+
'AgileFlow - AI-driven agile development for Claude Code, Cursor, Windsurf, and more'
|
|
42
|
+
);
|
|
41
43
|
|
|
42
44
|
// Register all commands
|
|
43
45
|
for (const [name, cmd] of Object.entries(commands)) {
|
|
@@ -23,9 +23,7 @@ module.exports = {
|
|
|
23
23
|
['[key]', 'Config key (for get/set)'],
|
|
24
24
|
['[value]', 'Config value (for set)'],
|
|
25
25
|
],
|
|
26
|
-
options: [
|
|
27
|
-
['-d, --directory <path>', 'Project directory (default: current directory)'],
|
|
28
|
-
],
|
|
26
|
+
options: [['-d, --directory <path>', 'Project directory (default: current directory)']],
|
|
29
27
|
action: async (subcommand, keyOrValue, valueOrUndefined, options) => {
|
|
30
28
|
try {
|
|
31
29
|
const directory = path.resolve(options.directory || '.');
|
|
@@ -64,7 +62,9 @@ module.exports = {
|
|
|
64
62
|
console.log(' npx agileflow config set <key> <value>\n');
|
|
65
63
|
console.log(chalk.bold('Keys:\n'));
|
|
66
64
|
console.log(' userName Your name for config files');
|
|
67
|
-
console.log(
|
|
65
|
+
console.log(
|
|
66
|
+
' ides Comma-separated IDE list (claude-code,cursor,windsurf)'
|
|
67
|
+
);
|
|
68
68
|
console.log(' agileflowFolder AgileFlow folder name (e.g., .agileflow)');
|
|
69
69
|
console.log(' docsFolder Documentation folder name (e.g., docs)\n');
|
|
70
70
|
console.log(chalk.bold('Examples:\n'));
|
|
@@ -108,8 +108,12 @@ async function handleList(status) {
|
|
|
108
108
|
|
|
109
109
|
console.log(chalk.bold('System Info:'));
|
|
110
110
|
console.log(` version: ${chalk.cyan(status.version || 'unknown')}`);
|
|
111
|
-
console.log(
|
|
112
|
-
|
|
111
|
+
console.log(
|
|
112
|
+
` installed: ${chalk.cyan(status.installedAt ? new Date(status.installedAt).toLocaleDateString() : 'unknown')}`
|
|
113
|
+
);
|
|
114
|
+
console.log(
|
|
115
|
+
` updated: ${chalk.cyan(status.updatedAt ? new Date(status.updatedAt).toLocaleDateString() : 'unknown')}`
|
|
116
|
+
);
|
|
113
117
|
console.log();
|
|
114
118
|
}
|
|
115
119
|
|
|
@@ -187,8 +191,8 @@ async function handleSet(directory, status, manifestPath, key, value) {
|
|
|
187
191
|
info(`Setting userName to: ${chalk.cyan(value)}`);
|
|
188
192
|
break;
|
|
189
193
|
|
|
190
|
-
case 'ides':
|
|
191
|
-
const newIdes = value.split(',').map(
|
|
194
|
+
case 'ides': {
|
|
195
|
+
const newIdes = value.split(',').map(ide => ide.trim());
|
|
192
196
|
const validIdes = ['claude-code', 'cursor', 'windsurf'];
|
|
193
197
|
|
|
194
198
|
// Validate IDEs
|
|
@@ -204,10 +208,13 @@ async function handleSet(directory, status, manifestPath, key, value) {
|
|
|
204
208
|
needsIdeUpdate = true;
|
|
205
209
|
info(`Setting ides to: ${chalk.cyan(newIdes.join(', '))}`);
|
|
206
210
|
break;
|
|
211
|
+
}
|
|
207
212
|
|
|
208
213
|
case 'agileflowFolder':
|
|
209
214
|
warning('Changing agileflowFolder requires moving the installation directory.');
|
|
210
|
-
console.log(
|
|
215
|
+
console.log(
|
|
216
|
+
chalk.dim('This change will only update the config - you must move files manually.\n')
|
|
217
|
+
);
|
|
211
218
|
manifest.agileflow_folder = value;
|
|
212
219
|
info(`Setting agileflowFolder to: ${chalk.cyan(value)}`);
|
|
213
220
|
break;
|
|
@@ -263,8 +270,8 @@ async function handleSet(directory, status, manifestPath, key, value) {
|
|
|
263
270
|
function getIdeConfigPath(projectDir, ide) {
|
|
264
271
|
const paths = {
|
|
265
272
|
'claude-code': '.claude/commands/agileflow',
|
|
266
|
-
|
|
267
|
-
|
|
273
|
+
cursor: '.cursor/rules/agileflow',
|
|
274
|
+
windsurf: '.windsurf/workflows/agileflow',
|
|
268
275
|
};
|
|
269
276
|
|
|
270
277
|
return path.join(projectDir, paths[ide] || '');
|
|
@@ -276,8 +283,8 @@ function getIdeConfigPath(projectDir, ide) {
|
|
|
276
283
|
function formatIdeName(ide) {
|
|
277
284
|
const names = {
|
|
278
285
|
'claude-code': 'Claude Code',
|
|
279
|
-
|
|
280
|
-
|
|
286
|
+
cursor: 'Cursor',
|
|
287
|
+
windsurf: 'Windsurf',
|
|
281
288
|
};
|
|
282
289
|
|
|
283
290
|
return names[ide] || ide;
|
|
@@ -9,7 +9,15 @@ const path = require('node:path');
|
|
|
9
9
|
const crypto = require('node:crypto');
|
|
10
10
|
const fs = require('fs-extra');
|
|
11
11
|
const { Installer } = require('../installers/core/installer');
|
|
12
|
-
const {
|
|
12
|
+
const {
|
|
13
|
+
displayLogo,
|
|
14
|
+
displaySection,
|
|
15
|
+
success,
|
|
16
|
+
warning,
|
|
17
|
+
error,
|
|
18
|
+
info,
|
|
19
|
+
confirm,
|
|
20
|
+
} = require('../lib/ui');
|
|
13
21
|
const { IdeManager } = require('../installers/ide/manager');
|
|
14
22
|
const { getCurrentVersion } = require('../lib/version-checker');
|
|
15
23
|
|
|
@@ -22,7 +30,7 @@ module.exports = {
|
|
|
22
30
|
['-d, --directory <path>', 'Project directory (default: current directory)'],
|
|
23
31
|
['--fix', 'Automatically fix detected issues'],
|
|
24
32
|
],
|
|
25
|
-
action: async
|
|
33
|
+
action: async options => {
|
|
26
34
|
try {
|
|
27
35
|
const directory = path.resolve(options.directory || '.');
|
|
28
36
|
|
|
@@ -113,7 +121,12 @@ module.exports = {
|
|
|
113
121
|
if (await fs.pathExists(fileIndexPath)) {
|
|
114
122
|
try {
|
|
115
123
|
fileIndex = await fs.readJson(fileIndexPath);
|
|
116
|
-
if (
|
|
124
|
+
if (
|
|
125
|
+
!fileIndex ||
|
|
126
|
+
fileIndex.schema !== 1 ||
|
|
127
|
+
!fileIndex.files ||
|
|
128
|
+
typeof fileIndex.files !== 'object'
|
|
129
|
+
) {
|
|
117
130
|
throw new Error('invalid format');
|
|
118
131
|
}
|
|
119
132
|
success('files.json present');
|
|
@@ -332,8 +345,8 @@ function compareVersions(a, b) {
|
|
|
332
345
|
function getIdeConfigPath(projectDir, ide) {
|
|
333
346
|
const paths = {
|
|
334
347
|
'claude-code': '.claude/commands/agileflow',
|
|
335
|
-
|
|
336
|
-
|
|
348
|
+
cursor: '.cursor/rules/agileflow',
|
|
349
|
+
windsurf: '.windsurf/workflows/agileflow',
|
|
337
350
|
};
|
|
338
351
|
|
|
339
352
|
return path.join(projectDir, paths[ide] || '');
|
|
@@ -347,8 +360,8 @@ function getIdeConfigPath(projectDir, ide) {
|
|
|
347
360
|
function formatIdeName(ide) {
|
|
348
361
|
const names = {
|
|
349
362
|
'claude-code': 'Claude Code',
|
|
350
|
-
|
|
351
|
-
|
|
363
|
+
cursor: 'Cursor',
|
|
364
|
+
windsurf: 'Windsurf',
|
|
352
365
|
};
|
|
353
366
|
|
|
354
367
|
return names[ide] || ide;
|
|
@@ -402,13 +415,16 @@ function toPosixPath(filePath) {
|
|
|
402
415
|
|
|
403
416
|
function countProtectedFiles(fileIndex) {
|
|
404
417
|
if (!fileIndex || !fileIndex.files || typeof fileIndex.files !== 'object') return 0;
|
|
405
|
-
return Object.values(fileIndex.files).filter(
|
|
418
|
+
return Object.values(fileIndex.files).filter(record => record && record.protected).length;
|
|
406
419
|
}
|
|
407
420
|
|
|
408
421
|
async function listSubdirectories(dirPath) {
|
|
409
422
|
if (!(await fs.pathExists(dirPath))) return [];
|
|
410
423
|
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
411
|
-
return entries
|
|
424
|
+
return entries
|
|
425
|
+
.filter(e => e.isDirectory())
|
|
426
|
+
.map(e => e.name)
|
|
427
|
+
.sort();
|
|
412
428
|
}
|
|
413
429
|
|
|
414
430
|
async function createProtectedFileIndex(agileflowDir, fileIndexPath) {
|
|
@@ -25,7 +25,7 @@ module.exports = {
|
|
|
25
25
|
['--json', 'Output as JSON'],
|
|
26
26
|
['--compact', 'Compact output (names only)'],
|
|
27
27
|
],
|
|
28
|
-
action: async
|
|
28
|
+
action: async options => {
|
|
29
29
|
try {
|
|
30
30
|
const directory = path.resolve(options.directory || '.');
|
|
31
31
|
|
|
@@ -307,19 +307,19 @@ function extractFirstLine(content) {
|
|
|
307
307
|
*/
|
|
308
308
|
function displayCompact(result, showCommands, showAgents, showSkills, showExperts) {
|
|
309
309
|
if (showCommands && result.commands?.length > 0) {
|
|
310
|
-
console.log(chalk.bold('Commands:'), result.commands.map(
|
|
310
|
+
console.log(chalk.bold('Commands:'), result.commands.map(c => c.name).join(', '));
|
|
311
311
|
}
|
|
312
312
|
|
|
313
313
|
if (showAgents && result.agents?.length > 0) {
|
|
314
|
-
console.log(chalk.bold('Agents:'), result.agents.map(
|
|
314
|
+
console.log(chalk.bold('Agents:'), result.agents.map(a => a.name).join(', '));
|
|
315
315
|
}
|
|
316
316
|
|
|
317
317
|
if (showSkills && result.skills?.length > 0) {
|
|
318
|
-
console.log(chalk.bold('Skills:'), result.skills.map(
|
|
318
|
+
console.log(chalk.bold('Skills:'), result.skills.map(s => s.name).join(', '));
|
|
319
319
|
}
|
|
320
320
|
|
|
321
321
|
if (showExperts && result.experts?.length > 0) {
|
|
322
|
-
console.log(chalk.bold('Experts:'), result.experts.map(
|
|
322
|
+
console.log(chalk.bold('Experts:'), result.experts.map(e => e.name).join(', '));
|
|
323
323
|
}
|
|
324
324
|
}
|
|
325
325
|
|
|
@@ -353,7 +353,11 @@ function displayFull(result, showCommands, showAgents, showSkills, showExperts)
|
|
|
353
353
|
console.log(chalk.hex('#e8683a')(` ${skill.name}`));
|
|
354
354
|
console.log(chalk.dim(` ${skill.description}`));
|
|
355
355
|
if (skill.triggers?.length > 0) {
|
|
356
|
-
console.log(
|
|
356
|
+
console.log(
|
|
357
|
+
chalk.dim(
|
|
358
|
+
` Triggers: ${skill.triggers.slice(0, 3).join(', ')}${skill.triggers.length > 3 ? '...' : ''}`
|
|
359
|
+
)
|
|
360
|
+
);
|
|
357
361
|
}
|
|
358
362
|
}
|
|
359
363
|
}
|
|
@@ -2,14 +2,26 @@
|
|
|
2
2
|
* AgileFlow CLI - Setup Command
|
|
3
3
|
*
|
|
4
4
|
* Sets up AgileFlow in a project directory.
|
|
5
|
+
* Includes self-update capability to always use the latest CLI.
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
8
|
const chalk = require('chalk');
|
|
8
9
|
const path = require('node:path');
|
|
10
|
+
const { spawnSync } = require('node:child_process');
|
|
11
|
+
const semver = require('semver');
|
|
9
12
|
const { Installer } = require('../installers/core/installer');
|
|
10
13
|
const { IdeManager } = require('../installers/ide/manager');
|
|
11
|
-
const {
|
|
14
|
+
const {
|
|
15
|
+
promptInstall,
|
|
16
|
+
success,
|
|
17
|
+
error,
|
|
18
|
+
info,
|
|
19
|
+
displaySection,
|
|
20
|
+
displayLogo,
|
|
21
|
+
warning,
|
|
22
|
+
} = require('../lib/ui');
|
|
12
23
|
const { createDocsStructure } = require('../lib/docs-setup');
|
|
24
|
+
const { getLatestVersion } = require('../lib/npm-utils');
|
|
13
25
|
|
|
14
26
|
const installer = new Installer();
|
|
15
27
|
const ideManager = new IdeManager();
|
|
@@ -20,9 +32,48 @@ module.exports = {
|
|
|
20
32
|
options: [
|
|
21
33
|
['-d, --directory <path>', 'Installation directory (default: current directory)'],
|
|
22
34
|
['-y, --yes', 'Skip prompts and use defaults'],
|
|
35
|
+
['--no-self-update', 'Skip automatic CLI self-update check'],
|
|
36
|
+
['--self-updated', 'Internal flag: indicates CLI was already self-updated'],
|
|
23
37
|
],
|
|
24
|
-
action: async
|
|
38
|
+
action: async options => {
|
|
25
39
|
try {
|
|
40
|
+
// Self-update check: fetch latest version if CLI is outdated
|
|
41
|
+
const shouldSelfUpdate = options.selfUpdate !== false && !options.selfUpdated;
|
|
42
|
+
|
|
43
|
+
if (shouldSelfUpdate) {
|
|
44
|
+
const packageJson = require(path.join(__dirname, '..', '..', '..', 'package.json'));
|
|
45
|
+
const localCliVersion = packageJson.version;
|
|
46
|
+
const npmLatestVersion = await getLatestVersion('agileflow');
|
|
47
|
+
|
|
48
|
+
if (npmLatestVersion && semver.lt(localCliVersion, npmLatestVersion)) {
|
|
49
|
+
displayLogo();
|
|
50
|
+
info(`Newer version available: v${localCliVersion} → v${npmLatestVersion}`);
|
|
51
|
+
console.log(chalk.dim(' Fetching latest version from npm...\n'));
|
|
52
|
+
|
|
53
|
+
// Build the command with all current options forwarded
|
|
54
|
+
const args = ['agileflow@latest', 'setup', '--self-updated'];
|
|
55
|
+
if (options.directory) args.push('-d', options.directory);
|
|
56
|
+
if (options.yes) args.push('-y');
|
|
57
|
+
|
|
58
|
+
const result = spawnSync('npx', args, {
|
|
59
|
+
stdio: 'inherit',
|
|
60
|
+
cwd: process.cwd(),
|
|
61
|
+
shell: process.platform === 'win32',
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Exit with the same code as the spawned process
|
|
65
|
+
process.exit(result.status ?? 0);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// If we self-updated, show confirmation
|
|
70
|
+
if (options.selfUpdated) {
|
|
71
|
+
const packageJson = require(path.join(__dirname, '..', '..', '..', 'package.json'));
|
|
72
|
+
displayLogo();
|
|
73
|
+
success(`Using latest CLI v${packageJson.version}`);
|
|
74
|
+
console.log();
|
|
75
|
+
}
|
|
76
|
+
|
|
26
77
|
let config;
|
|
27
78
|
|
|
28
79
|
if (options.yes) {
|
|
@@ -73,7 +124,7 @@ module.exports = {
|
|
|
73
124
|
if (!docsResult.success) {
|
|
74
125
|
error('Failed to create docs structure');
|
|
75
126
|
if (docsResult.errors.length > 0) {
|
|
76
|
-
docsResult.errors.forEach(
|
|
127
|
+
docsResult.errors.forEach(err => error(` ${err}`));
|
|
77
128
|
}
|
|
78
129
|
}
|
|
79
130
|
|
|
@@ -17,10 +17,8 @@ const installer = new Installer();
|
|
|
17
17
|
module.exports = {
|
|
18
18
|
name: 'status',
|
|
19
19
|
description: 'Show AgileFlow installation status',
|
|
20
|
-
options: [
|
|
21
|
-
|
|
22
|
-
],
|
|
23
|
-
action: async (options) => {
|
|
20
|
+
options: [['-d, --directory <path>', 'Project directory (default: current directory)']],
|
|
21
|
+
action: async options => {
|
|
24
22
|
try {
|
|
25
23
|
const directory = path.resolve(options.directory || '.');
|
|
26
24
|
|
|
@@ -98,8 +96,8 @@ module.exports = {
|
|
|
98
96
|
function getIdeConfigPath(projectDir, ide) {
|
|
99
97
|
const paths = {
|
|
100
98
|
'claude-code': '.claude/commands/agileflow',
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
cursor: '.cursor/rules/agileflow',
|
|
100
|
+
windsurf: '.windsurf/workflows/agileflow',
|
|
103
101
|
};
|
|
104
102
|
|
|
105
103
|
return path.join(projectDir, paths[ide] || '');
|
|
@@ -113,8 +111,8 @@ function getIdeConfigPath(projectDir, ide) {
|
|
|
113
111
|
function formatIdeName(ide) {
|
|
114
112
|
const names = {
|
|
115
113
|
'claude-code': 'Claude Code',
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
cursor: 'Cursor',
|
|
115
|
+
windsurf: 'Windsurf',
|
|
118
116
|
};
|
|
119
117
|
|
|
120
118
|
return names[ide] || ide;
|
|
@@ -21,7 +21,7 @@ module.exports = {
|
|
|
21
21
|
['-d, --directory <path>', 'Project directory (default: current directory)'],
|
|
22
22
|
['--force', 'Skip confirmation prompt'],
|
|
23
23
|
],
|
|
24
|
-
action: async
|
|
24
|
+
action: async options => {
|
|
25
25
|
try {
|
|
26
26
|
const directory = path.resolve(options.directory || '.');
|
|
27
27
|
|
|
@@ -87,8 +87,8 @@ module.exports = {
|
|
|
87
87
|
function getIdeConfigPath(projectDir, ide) {
|
|
88
88
|
const paths = {
|
|
89
89
|
'claude-code': '.claude/commands/agileflow',
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
cursor: '.cursor/rules/agileflow',
|
|
91
|
+
windsurf: '.windsurf/workflows/agileflow',
|
|
92
92
|
};
|
|
93
93
|
|
|
94
94
|
return path.join(projectDir, paths[ide] || '');
|
|
@@ -102,8 +102,8 @@ function getIdeConfigPath(projectDir, ide) {
|
|
|
102
102
|
function formatIdeName(ide) {
|
|
103
103
|
const names = {
|
|
104
104
|
'claude-code': 'Claude Code',
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
cursor: 'Cursor',
|
|
106
|
+
windsurf: 'Windsurf',
|
|
107
107
|
};
|
|
108
108
|
|
|
109
109
|
return names[ide] || ide;
|