agileflow 3.1.0 → 3.2.1

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.
Files changed (106) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +57 -85
  3. package/lib/dashboard-automations.js +130 -0
  4. package/lib/dashboard-git.js +254 -0
  5. package/lib/dashboard-inbox.js +64 -0
  6. package/lib/dashboard-protocol.js +1 -0
  7. package/lib/dashboard-server.js +114 -924
  8. package/lib/dashboard-session.js +136 -0
  9. package/lib/dashboard-status.js +72 -0
  10. package/lib/dashboard-terminal.js +354 -0
  11. package/lib/dashboard-websocket.js +88 -0
  12. package/lib/drivers/codex-driver.ts +4 -4
  13. package/lib/logger.js +106 -0
  14. package/package.json +4 -2
  15. package/scripts/agileflow-configure.js +2 -2
  16. package/scripts/agileflow-welcome.js +409 -434
  17. package/scripts/claude-tmux.sh +80 -2
  18. package/scripts/context-loader.js +4 -9
  19. package/scripts/lib/browser-qa-evidence.js +409 -0
  20. package/scripts/lib/browser-qa-status.js +192 -0
  21. package/scripts/lib/command-prereqs.js +280 -0
  22. package/scripts/lib/configure-detect.js +92 -2
  23. package/scripts/lib/configure-features.js +295 -1
  24. package/scripts/lib/context-formatter.js +468 -233
  25. package/scripts/lib/context-loader.js +27 -15
  26. package/scripts/lib/damage-control-utils.js +8 -1
  27. package/scripts/lib/feature-catalog.js +321 -0
  28. package/scripts/lib/portable-tasks-cli.js +274 -0
  29. package/scripts/lib/portable-tasks.js +479 -0
  30. package/scripts/lib/signal-detectors.js +1 -1
  31. package/scripts/lib/team-events.js +86 -1
  32. package/scripts/obtain-context.js +28 -4
  33. package/scripts/smart-detect.js +17 -0
  34. package/scripts/strip-ai-attribution.js +63 -0
  35. package/scripts/team-manager.js +7 -2
  36. package/scripts/welcome-deferred.js +437 -0
  37. package/src/core/agents/browser-qa.md +328 -0
  38. package/src/core/agents/perf-analyzer-assets.md +174 -0
  39. package/src/core/agents/perf-analyzer-bundle.md +165 -0
  40. package/src/core/agents/perf-analyzer-caching.md +160 -0
  41. package/src/core/agents/perf-analyzer-compute.md +165 -0
  42. package/src/core/agents/perf-analyzer-memory.md +182 -0
  43. package/src/core/agents/perf-analyzer-network.md +157 -0
  44. package/src/core/agents/perf-analyzer-queries.md +155 -0
  45. package/src/core/agents/perf-analyzer-rendering.md +156 -0
  46. package/src/core/agents/perf-consensus.md +280 -0
  47. package/src/core/agents/security-analyzer-api.md +199 -0
  48. package/src/core/agents/security-analyzer-auth.md +160 -0
  49. package/src/core/agents/security-analyzer-authz.md +168 -0
  50. package/src/core/agents/security-analyzer-deps.md +147 -0
  51. package/src/core/agents/security-analyzer-infra.md +176 -0
  52. package/src/core/agents/security-analyzer-injection.md +148 -0
  53. package/src/core/agents/security-analyzer-input.md +191 -0
  54. package/src/core/agents/security-analyzer-secrets.md +175 -0
  55. package/src/core/agents/security-consensus.md +276 -0
  56. package/src/core/agents/test-analyzer-assertions.md +181 -0
  57. package/src/core/agents/test-analyzer-coverage.md +183 -0
  58. package/src/core/agents/test-analyzer-fragility.md +185 -0
  59. package/src/core/agents/test-analyzer-integration.md +155 -0
  60. package/src/core/agents/test-analyzer-maintenance.md +173 -0
  61. package/src/core/agents/test-analyzer-mocking.md +178 -0
  62. package/src/core/agents/test-analyzer-patterns.md +189 -0
  63. package/src/core/agents/test-analyzer-structure.md +177 -0
  64. package/src/core/agents/test-consensus.md +294 -0
  65. package/src/core/commands/{legal/audit.md → audit/legal.md} +13 -13
  66. package/src/core/commands/{logic/audit.md → audit/logic.md} +12 -12
  67. package/src/core/commands/audit/performance.md +443 -0
  68. package/src/core/commands/audit/security.md +443 -0
  69. package/src/core/commands/audit/test.md +442 -0
  70. package/src/core/commands/babysit.md +505 -463
  71. package/src/core/commands/browser-qa.md +240 -0
  72. package/src/core/commands/configure.md +8 -8
  73. package/src/core/commands/research/ask.md +42 -9
  74. package/src/core/commands/research/import.md +14 -8
  75. package/src/core/commands/research/list.md +17 -16
  76. package/src/core/commands/research/synthesize.md +8 -8
  77. package/src/core/commands/research/view.md +28 -4
  78. package/src/core/commands/whats-new.md +2 -2
  79. package/src/core/experts/devops/expertise.yaml +13 -2
  80. package/src/core/experts/documentation/expertise.yaml +26 -4
  81. package/src/core/profiles/COMPARISON.md +170 -0
  82. package/src/core/profiles/README.md +178 -0
  83. package/src/core/profiles/claude-code.yaml +111 -0
  84. package/src/core/profiles/codex.yaml +103 -0
  85. package/src/core/profiles/cursor.yaml +134 -0
  86. package/src/core/profiles/examples.js +250 -0
  87. package/src/core/profiles/loader.js +235 -0
  88. package/src/core/profiles/windsurf.yaml +159 -0
  89. package/src/core/teams/logic-audit.json +6 -0
  90. package/src/core/teams/perf-audit.json +71 -0
  91. package/src/core/teams/security-audit.json +71 -0
  92. package/src/core/teams/test-audit.json +71 -0
  93. package/src/core/templates/browser-qa-spec.yaml +94 -0
  94. package/src/core/templates/command-prerequisites.yaml +169 -0
  95. package/src/core/templates/damage-control-patterns.yaml +9 -0
  96. package/tools/cli/installers/ide/_base-ide.js +33 -3
  97. package/tools/cli/installers/ide/claude-code.js +2 -69
  98. package/tools/cli/installers/ide/codex.js +9 -9
  99. package/tools/cli/installers/ide/cursor.js +165 -4
  100. package/tools/cli/installers/ide/windsurf.js +237 -6
  101. package/tools/cli/lib/content-transformer.js +234 -9
  102. package/tools/cli/lib/docs-setup.js +1 -1
  103. package/tools/cli/lib/ide-generator.js +357 -0
  104. package/tools/cli/lib/ide-registry.js +2 -2
  105. package/scripts/tmux-task-name.sh +0 -105
  106. package/scripts/tmux-task-watcher.sh +0 -344
@@ -71,7 +71,8 @@ class BaseIdeSetup {
71
71
  });
72
72
 
73
73
  // Replace standalone "docs" word (not followed by .)
74
- result = result.replace(/\bdocs\b(?!\.)/g, this.docsFolder);
74
+ // Use replacement function to avoid $ in docsFolder being interpreted as regex backreference
75
+ result = result.replace(/\bdocs\b(?!\.)/g, () => this.docsFolder);
75
76
 
76
77
  return result;
77
78
  }
@@ -371,15 +372,38 @@ class BaseIdeSetup {
371
372
  /**
372
373
  * Recursively install markdown files from source to target directory
373
374
  * Handles content injection and docs reference replacement.
375
+ * Optionally applies IDE-specific transformations via ideTransform callback.
376
+ *
374
377
  * @param {string} sourceDir - Source directory path
375
378
  * @param {string} targetDir - Target directory path
376
379
  * @param {string} agileflowDir - AgileFlow installation directory (for dynamic content)
377
380
  * @param {boolean} injectDynamic - Whether to inject dynamic content (only for top-level commands)
381
+ * @param {Function} [ideTransform] - Optional IDE transformation function: (content, filename) => string
378
382
  * @returns {Promise<{commands: number, subdirs: number}>} Count of installed items
379
383
  * @throws {CommandInstallationError} If command installation fails
380
384
  * @throws {FilePermissionError} If permission denied
385
+ *
386
+ * @example
387
+ * // Without transformation (backward compatible)
388
+ * await installer.installCommandsRecursive(src, target, agileflow, true);
389
+ *
390
+ * @example
391
+ * // With IDE transformation
392
+ * await installer.installCommandsRecursive(
393
+ * src,
394
+ * target,
395
+ * agileflow,
396
+ * true,
397
+ * (content, filename) => ideGenerator.generateForIde(content, 'cursor')
398
+ * );
381
399
  */
382
- async installCommandsRecursive(sourceDir, targetDir, agileflowDir, injectDynamic = false) {
400
+ async installCommandsRecursive(
401
+ sourceDir,
402
+ targetDir,
403
+ agileflowDir,
404
+ injectDynamic = false,
405
+ ideTransform = null
406
+ ) {
383
407
  let commandCount = 0;
384
408
  let subdirCount = 0;
385
409
 
@@ -419,6 +443,11 @@ class BaseIdeSetup {
419
443
  // Replace docs/ references with custom folder name
420
444
  content = this.replaceDocsReferences(content);
421
445
 
446
+ // Apply IDE-specific transformation if provided
447
+ if (ideTransform && typeof ideTransform === 'function') {
448
+ content = ideTransform(content, entry.name);
449
+ }
450
+
422
451
  await this.writeFile(targetPath, content);
423
452
  commandCount++;
424
453
  } catch (error) {
@@ -437,7 +466,8 @@ class BaseIdeSetup {
437
466
  sourcePath,
438
467
  targetPath,
439
468
  agileflowDir,
440
- false // Don't inject dynamic content in subdirectories
469
+ false, // Don't inject dynamic content in subdirectories
470
+ ideTransform // Pass ideTransform to recursive calls
441
471
  );
442
472
  commandCount += subResult.commands;
443
473
  subdirCount += 1 + subResult.subdirs;
@@ -61,12 +61,9 @@ class ClaudeCodeSetup extends BaseIdeSetup {
61
61
  // Claude Code specific: Setup damage control hooks
62
62
  await this.setupDamageControl(projectDir, agileflowDir, ideDir, options);
63
63
 
64
- // Claude Code specific: Setup SessionStart hooks (welcome, archive, context-loader, tmux-task-watcher)
64
+ // Claude Code specific: Setup SessionStart hooks (welcome, archive, context-loader)
65
65
  await this.setupSessionStartHooks(projectDir, agileflowDir, ideDir, options);
66
66
 
67
- // Claude Code specific: Setup Stop hooks (tmux-task-watcher cleanup)
68
- await this.setupStopHooks(projectDir, agileflowDir, ideDir, options);
69
-
70
67
  return result;
71
68
  }
72
69
 
@@ -259,12 +256,6 @@ class ClaudeCodeSetup extends BaseIdeSetup {
259
256
  'node $CLAUDE_PROJECT_DIR/.agileflow/scripts/context-loader.js 2>/dev/null || true',
260
257
  timeout: 5000,
261
258
  },
262
- {
263
- type: 'command',
264
- command:
265
- 'bash $CLAUDE_PROJECT_DIR/.agileflow/scripts/tmux-task-watcher.sh 2>/dev/null || true',
266
- timeout: 5000,
267
- },
268
259
  ];
269
260
 
270
261
  // Check if SessionStart hooks already exist
@@ -294,65 +285,7 @@ class ClaudeCodeSetup extends BaseIdeSetup {
294
285
 
295
286
  // Write settings
296
287
  await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2));
297
- console.log(
298
- chalk.dim(` - SessionStart hooks: welcome, archive, context-loader, tmux-task-watcher`)
299
- );
300
- }
301
-
302
- /**
303
- * Setup Stop hooks (tmux-task-watcher cleanup)
304
- * @param {string} projectDir - Project directory
305
- * @param {string} agileflowDir - AgileFlow installation directory
306
- * @param {string} claudeDir - .claude directory path
307
- * @param {Object} options - Setup options
308
- */
309
- async setupStopHooks(projectDir, agileflowDir, claudeDir, options = {}) {
310
- const settingsPath = path.join(claudeDir, 'settings.json');
311
- let settings = {};
312
-
313
- if (fs.existsSync(settingsPath)) {
314
- try {
315
- settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
316
- } catch (e) {
317
- settings = {};
318
- }
319
- }
320
-
321
- if (!settings.hooks) settings.hooks = {};
322
- if (!settings.hooks.Stop) settings.hooks.Stop = [];
323
-
324
- const stopHooks = [
325
- {
326
- type: 'command',
327
- command:
328
- 'bash $CLAUDE_PROJECT_DIR/.agileflow/scripts/tmux-task-watcher.sh stop 2>/dev/null || true',
329
- timeout: 3000,
330
- },
331
- ];
332
-
333
- const existingEntry = settings.hooks.Stop.find(
334
- h => h.matcher === '' || h.matcher === undefined
335
- );
336
-
337
- if (existingEntry) {
338
- if (!existingEntry.hooks) existingEntry.hooks = [];
339
- for (const newHook of stopHooks) {
340
- const alreadyExists = existingEntry.hooks.some(
341
- h => h.command && h.command.includes('tmux-task-watcher')
342
- );
343
- if (!alreadyExists) {
344
- existingEntry.hooks.push(newHook);
345
- }
346
- }
347
- } else {
348
- settings.hooks.Stop.push({
349
- matcher: '',
350
- hooks: stopHooks,
351
- });
352
- }
353
-
354
- await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2));
355
- console.log(chalk.dim(` - Stop hooks: tmux-task-watcher cleanup`));
288
+ console.log(chalk.dim(` - SessionStart hooks: welcome, archive, context-loader`));
356
289
  }
357
290
 
358
291
  /**
@@ -1,13 +1,13 @@
1
1
  /**
2
- * AgileFlow CLI - OpenAI Codex CLI Installer
2
+ * AgileFlow CLI - OpenAI Codex Installer
3
3
  *
4
- * Installs AgileFlow for OpenAI Codex CLI:
4
+ * Installs AgileFlow for OpenAI Codex:
5
5
  * - Agents become Codex Skills (.codex/skills/agileflow-NAME/)
6
6
  * - Commands become Codex Prompts (~/.codex/prompts/agileflow-NAME.md)
7
7
  * - AGENTS.md provides project instructions at repo root
8
8
  *
9
9
  * @see https://developers.openai.com/codex/
10
- * @see ADR-0002: Codex CLI Integration Strategy
10
+ * @see ADR-0002: OpenAI Codex Integration Strategy
11
11
  */
12
12
 
13
13
  const path = require('node:path');
@@ -24,11 +24,11 @@ const {
24
24
  } = require('../../lib/content-transformer');
25
25
 
26
26
  /**
27
- * OpenAI Codex CLI setup handler
27
+ * OpenAI Codex setup handler
28
28
  */
29
29
  class CodexSetup extends BaseIdeSetup {
30
30
  constructor() {
31
- super('codex', 'OpenAI Codex CLI', false);
31
+ super('codex', 'OpenAI Codex', false);
32
32
  // Per-repo config directory
33
33
  this.configDir = '.codex';
34
34
  // User-level Codex home (can be overridden by $CODEX_HOME)
@@ -44,12 +44,12 @@ class CodexSetup extends BaseIdeSetup {
44
44
  }
45
45
 
46
46
  /**
47
- * Detect if Codex CLI is installed/configured
47
+ * Detect if OpenAI Codex is installed/configured
48
48
  * @param {string} projectDir - Project directory
49
49
  * @returns {Promise<boolean>}
50
50
  */
51
51
  async detect(projectDir) {
52
- // Check if Codex home exists (user has Codex CLI)
52
+ // Check if Codex home exists (user has OpenAI Codex)
53
53
  const codexHomeExists = await this.exists(this.codexHome);
54
54
  // Check if project has .codex/ or AGENTS.md
55
55
  const projectCodexExists = await this.exists(path.join(projectDir, this.configDir));
@@ -229,7 +229,7 @@ ${codexHeader}${bodyContent}`;
229
229
 
230
230
  const content = `# AGENTS.md
231
231
 
232
- > Project instructions for Codex CLI with AgileFlow integration
232
+ > Project instructions for OpenAI Codex with AgileFlow integration
233
233
 
234
234
  ## Project Commands
235
235
 
@@ -334,7 +334,7 @@ This directory contains: [describe purpose]
334
334
  }
335
335
 
336
336
  /**
337
- * Setup Codex CLI configuration
337
+ * Setup OpenAI Codex configuration
338
338
  * @param {string} projectDir - Project directory
339
339
  * @param {string} agileflowDir - AgileFlow installation directory
340
340
  * @param {Object} options - Setup options
@@ -1,8 +1,11 @@
1
1
  /**
2
2
  * AgileFlow CLI - Cursor IDE Installer
3
3
  *
4
- * Installs AgileFlow commands for Cursor IDE.
5
- * Cursor uses plain Markdown files in .cursor/commands/
4
+ * Installs AgileFlow commands, agents, and hooks for Cursor IDE.
5
+ * Cursor uses:
6
+ * - Plain Markdown files in .cursor/commands/ for slash commands
7
+ * - Markdown files in .cursor/agents/ for subagents (with YAML frontmatter)
8
+ * - .cursor/hooks.json for lifecycle hooks
6
9
  */
7
10
 
8
11
  const path = require('node:path');
@@ -27,10 +30,162 @@ class CursorSetup extends BaseIdeSetup {
27
30
  * @param {Object} options - Setup options
28
31
  */
29
32
  async setup(projectDir, agileflowDir, options = {}) {
30
- return this.setupStandard(projectDir, agileflowDir, {
33
+ // Use standard setup for commands and agents
34
+ const result = await this.setupStandard(projectDir, agileflowDir, {
31
35
  targetSubdir: this.commandsDir,
32
36
  agileflowFolder: 'AgileFlow',
33
37
  });
38
+
39
+ const { ideDir, agileflowTargetDir } = result;
40
+ const agentsSource = path.join(agileflowDir, 'agents');
41
+
42
+ // Cursor specific: Install agents as spawnable subagents (.cursor/agents/AgileFlow/)
43
+ // This allows Cursor's async subagent spawning feature
44
+ const spawnableAgentsDir = path.join(ideDir, 'agents', 'AgileFlow');
45
+
46
+ // Clean existing spawnable agents directory to prevent duplicates during update
47
+ if (await fs.pathExists(spawnableAgentsDir)) {
48
+ await fs.remove(spawnableAgentsDir);
49
+ }
50
+
51
+ const agentInstallResult = await this.installCommandsRecursive(
52
+ agentsSource,
53
+ spawnableAgentsDir,
54
+ agileflowDir,
55
+ false
56
+ );
57
+ console.log(chalk.dim(` - Spawnable agents: .cursor/agents/AgileFlow/`));
58
+
59
+ // Cursor specific: Setup damage control hooks
60
+ await this.setupDamageControlHooks(projectDir, agileflowDir, ideDir, options);
61
+
62
+ return {
63
+ ...result,
64
+ agents: agentInstallResult.commands,
65
+ };
66
+ }
67
+
68
+ /**
69
+ * Setup damage control hooks for Cursor
70
+ * Maps Claude Code's PreToolUse hooks to Cursor's lifecycle events:
71
+ * - beforeShellExecution (for bash commands)
72
+ * - afterFileEdit (for file edits)
73
+ *
74
+ * @param {string} projectDir - Project directory
75
+ * @param {string} agileflowDir - AgileFlow installation directory
76
+ * @param {string} cursorDir - .cursor directory path
77
+ * @param {Object} options - Setup options
78
+ */
79
+ async setupDamageControlHooks(projectDir, agileflowDir, cursorDir, options = {}) {
80
+ if (options.skipDamageControl) {
81
+ return;
82
+ }
83
+
84
+ const hooksPath = path.join(cursorDir, 'hooks.json');
85
+ let hooks = [];
86
+
87
+ // Load existing hooks if they exist
88
+ if (fs.existsSync(hooksPath)) {
89
+ try {
90
+ const content = await fs.readFile(hooksPath, 'utf8');
91
+ hooks = JSON.parse(content);
92
+ if (!Array.isArray(hooks)) {
93
+ hooks = [];
94
+ }
95
+ } catch (e) {
96
+ hooks = [];
97
+ }
98
+ }
99
+
100
+ // Define damage control hooks for Cursor
101
+ // Cursor's hooks.json format: Array of {event, command, args, order}
102
+ const damageControlHooks = [
103
+ {
104
+ event: 'beforeShellExecution',
105
+ command: 'node',
106
+ args: ['$CURSOR_PROJECT_DIR/.cursor/hooks/damage-control/bash-tool-damage-control.js'],
107
+ order: 1,
108
+ },
109
+ {
110
+ event: 'afterFileEdit',
111
+ command: 'node',
112
+ args: ['$CURSOR_PROJECT_DIR/.cursor/hooks/damage-control/edit-tool-damage-control.js'],
113
+ order: 1,
114
+ },
115
+ ];
116
+
117
+ // Check if damage control hooks already exist and merge
118
+ let hasUpdates = false;
119
+ for (const newHook of damageControlHooks) {
120
+ const existingIdx = hooks.findIndex(
121
+ h =>
122
+ h.event === newHook.event &&
123
+ h.command === newHook.command &&
124
+ (h.args?.join(' ') === newHook.args?.join(' ') ||
125
+ (h.args && h.args.some(arg => arg.includes('damage-control'))))
126
+ );
127
+
128
+ if (existingIdx === -1) {
129
+ hooks.push(newHook);
130
+ hasUpdates = true;
131
+ }
132
+ }
133
+
134
+ // Only write if we have updates or if file didn't exist
135
+ if (hasUpdates || !fs.existsSync(hooksPath)) {
136
+ await fs.ensureDir(path.dirname(hooksPath));
137
+ await fs.writeFile(hooksPath, JSON.stringify(hooks, null, 2));
138
+ console.log(chalk.dim(` - Damage control: hooks enabled`));
139
+ }
140
+
141
+ // Copy damage control scripts
142
+ await this.setupDamageControlScripts(agileflowDir, cursorDir);
143
+ }
144
+
145
+ /**
146
+ * Copy damage control scripts to .cursor/hooks/damage-control/
147
+ * @param {string} agileflowDir - AgileFlow installation directory
148
+ * @param {string} cursorDir - .cursor directory path
149
+ */
150
+ async setupDamageControlScripts(agileflowDir, cursorDir) {
151
+ const damageControlSource = path.join(agileflowDir, 'scripts', 'damage-control');
152
+ const damageControlTarget = path.join(cursorDir, 'hooks', 'damage-control');
153
+
154
+ if (!fs.existsSync(damageControlSource)) {
155
+ return;
156
+ }
157
+
158
+ await this.ensureDir(damageControlTarget);
159
+
160
+ // Copy hook scripts
161
+ const scripts = [
162
+ 'bash-tool-damage-control.js',
163
+ 'edit-tool-damage-control.js',
164
+ 'write-tool-damage-control.js',
165
+ ];
166
+
167
+ for (const script of scripts) {
168
+ const src = path.join(damageControlSource, script);
169
+ const dest = path.join(damageControlTarget, script);
170
+ if (fs.existsSync(src)) {
171
+ await fs.copy(src, dest);
172
+ }
173
+ }
174
+
175
+ // Copy lib/damage-control-utils.js (required by hook scripts)
176
+ const libSource = path.join(agileflowDir, 'scripts', 'lib', 'damage-control-utils.js');
177
+ const libTarget = path.join(cursorDir, 'hooks', 'lib', 'damage-control-utils.js');
178
+ if (fs.existsSync(libSource)) {
179
+ await this.ensureDir(path.dirname(libTarget));
180
+ await fs.copy(libSource, libTarget);
181
+ }
182
+
183
+ // Copy patterns.yaml (preserve existing)
184
+ const patternsSource = path.join(damageControlSource, 'patterns.yaml');
185
+ const patternsTarget = path.join(damageControlTarget, 'patterns.yaml');
186
+ if (fs.existsSync(patternsSource) && !fs.existsSync(patternsTarget)) {
187
+ await fs.copy(patternsSource, patternsTarget);
188
+ }
34
189
  }
35
190
 
36
191
  /**
@@ -45,11 +200,17 @@ class CursorSetup extends BaseIdeSetup {
45
200
  console.log(chalk.dim(` Removed old AgileFlow rules from ${this.displayName}`));
46
201
  }
47
202
 
48
- // Remove .cursor/commands/agileflow (for re-installation)
203
+ // Remove .cursor/commands/AgileFlow (for re-installation)
49
204
  const commandsPath = path.join(projectDir, this.configDir, this.commandsDir, 'AgileFlow');
50
205
  if (await this.exists(commandsPath)) {
51
206
  await fs.remove(commandsPath);
52
207
  }
208
+
209
+ // Remove .cursor/agents/AgileFlow (for re-installation)
210
+ const agentsPath = path.join(projectDir, this.configDir, 'agents', 'AgileFlow');
211
+ if (await this.exists(agentsPath)) {
212
+ await fs.remove(agentsPath);
213
+ }
53
214
  }
54
215
  }
55
216