agileflow 2.94.1 → 2.95.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 (74) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +3 -3
  3. package/lib/colors.generated.js +117 -0
  4. package/lib/colors.js +59 -109
  5. package/lib/generator-factory.js +333 -0
  6. package/lib/path-utils.js +49 -0
  7. package/lib/session-registry.js +25 -15
  8. package/lib/smart-json-file.js +40 -32
  9. package/lib/state-machine.js +286 -0
  10. package/package.json +1 -1
  11. package/scripts/agileflow-configure.js +7 -6
  12. package/scripts/archive-completed-stories.sh +86 -11
  13. package/scripts/babysit-context-restore.js +89 -0
  14. package/scripts/claude-tmux.sh +111 -5
  15. package/scripts/damage-control/bash-tool-damage-control.js +11 -247
  16. package/scripts/damage-control/edit-tool-damage-control.js +9 -249
  17. package/scripts/damage-control/write-tool-damage-control.js +9 -244
  18. package/scripts/generate-colors.js +314 -0
  19. package/scripts/lib/colors.generated.sh +82 -0
  20. package/scripts/lib/colors.sh +10 -70
  21. package/scripts/lib/configure-features.js +401 -0
  22. package/scripts/lib/context-loader.js +181 -52
  23. package/scripts/precompact-context.sh +54 -17
  24. package/scripts/session-coordinator.sh +2 -2
  25. package/scripts/session-manager.js +653 -10
  26. package/src/core/commands/audit.md +93 -0
  27. package/src/core/commands/auto.md +73 -0
  28. package/src/core/commands/babysit.md +169 -13
  29. package/src/core/commands/baseline.md +73 -0
  30. package/src/core/commands/batch.md +64 -0
  31. package/src/core/commands/blockers.md +60 -0
  32. package/src/core/commands/board.md +66 -0
  33. package/src/core/commands/choose.md +77 -0
  34. package/src/core/commands/ci.md +77 -0
  35. package/src/core/commands/compress.md +27 -1
  36. package/src/core/commands/configure.md +126 -10
  37. package/src/core/commands/council.md +74 -0
  38. package/src/core/commands/debt.md +72 -0
  39. package/src/core/commands/deploy.md +73 -0
  40. package/src/core/commands/deps.md +68 -0
  41. package/src/core/commands/docs.md +60 -0
  42. package/src/core/commands/feedback.md +68 -0
  43. package/src/core/commands/ideate.md +74 -0
  44. package/src/core/commands/impact.md +74 -0
  45. package/src/core/commands/install.md +529 -0
  46. package/src/core/commands/maintain.md +558 -0
  47. package/src/core/commands/metrics.md +75 -0
  48. package/src/core/commands/multi-expert.md +74 -0
  49. package/src/core/commands/packages.md +69 -0
  50. package/src/core/commands/readme-sync.md +64 -0
  51. package/src/core/commands/research/analyze.md +285 -121
  52. package/src/core/commands/research/import.md +281 -109
  53. package/src/core/commands/retro.md +76 -0
  54. package/src/core/commands/review.md +72 -0
  55. package/src/core/commands/rlm.md +83 -0
  56. package/src/core/commands/rpi.md +90 -0
  57. package/src/core/commands/session/cleanup.md +214 -12
  58. package/src/core/commands/session/end.md +155 -17
  59. package/src/core/commands/sprint.md +72 -0
  60. package/src/core/commands/story-validate.md +68 -0
  61. package/src/core/commands/template.md +69 -0
  62. package/src/core/commands/tests.md +83 -0
  63. package/src/core/commands/update.md +59 -0
  64. package/src/core/commands/validate-expertise.md +76 -0
  65. package/src/core/commands/velocity.md +74 -0
  66. package/src/core/commands/verify.md +91 -0
  67. package/src/core/commands/whats-new.md +69 -0
  68. package/src/core/commands/workflow.md +88 -0
  69. package/src/core/templates/command-documentation.md +187 -0
  70. package/tools/cli/commands/session.js +1171 -0
  71. package/tools/cli/commands/setup.js +2 -81
  72. package/tools/cli/installers/core/installer.js +0 -5
  73. package/tools/cli/installers/ide/claude-code.js +6 -0
  74. package/tools/cli/lib/config-manager.js +42 -5
@@ -12,15 +12,7 @@ const { spawnSync } = require('node:child_process');
12
12
  const semver = require('semver');
13
13
  const { Installer } = require('../installers/core/installer');
14
14
  const { IdeManager } = require('../installers/ide/manager');
15
- const {
16
- promptInstall,
17
- success,
18
- error,
19
- info,
20
- displaySection,
21
- displayLogo,
22
- warning,
23
- } = require('../lib/ui');
15
+ const { promptInstall, success, error, info, displaySection, displayLogo } = require('../lib/ui');
24
16
  const { createDocsStructure } = require('../lib/docs-setup');
25
17
  const { getLatestVersion } = require('../lib/npm-utils');
26
18
  const { ErrorHandler } = require('../lib/error-handler');
@@ -91,7 +83,6 @@ module.exports = {
91
83
  agileflowFolder: '.agileflow',
92
84
  docsFolder: 'docs',
93
85
  updateGitignore: true,
94
- claudeMdReinforcement: true,
95
86
  };
96
87
  } else {
97
88
  // Interactive prompts
@@ -112,16 +103,6 @@ module.exports = {
112
103
  success(`Installed ${coreResult.counts.commands} commands`);
113
104
  success(`Installed ${coreResult.counts.skills} skills`);
114
105
 
115
- // Report shell alias setup
116
- if (coreResult.shellAliases) {
117
- if (coreResult.shellAliases.configured.length > 0) {
118
- success(`Added 'af' alias to: ${coreResult.shellAliases.configured.join(', ')}`);
119
- }
120
- if (coreResult.shellAliases.skipped.length > 0) {
121
- info(`Shell aliases skipped: ${coreResult.shellAliases.skipped.join(', ')}`);
122
- }
123
- }
124
-
125
106
  // Setup IDE configurations
126
107
  displaySection('Configuring IDEs');
127
108
 
@@ -145,44 +126,6 @@ module.exports = {
145
126
  }
146
127
  }
147
128
 
148
- // CLAUDE.md reinforcement for /babysit AskUserQuestion rules
149
- if (config.claudeMdReinforcement) {
150
- const claudeMdPath = path.join(config.directory, 'CLAUDE.md');
151
- const claudeMdMarker = '<!-- AGILEFLOW_BABYSIT_RULES -->';
152
- const claudeMdContent = `
153
-
154
- ${claudeMdMarker}
155
- ## AgileFlow /babysit Context Preservation Rules
156
-
157
- When \`/agileflow:babysit\` is active (check session-state.json), these rules are MANDATORY:
158
-
159
- 1. **ALWAYS end responses with the AskUserQuestion tool** - Not text like "What next?" but the ACTUAL TOOL CALL
160
- 2. **Use Plan Mode for non-trivial tasks** - Call \`EnterPlanMode\` before complex implementations
161
- 3. **Delegate complex work to domain experts** - Use \`Task\` tool with appropriate \`subagent_type\`
162
- 4. **Track progress with TodoWrite** - For any task with 3+ steps
163
-
164
- These rules persist across conversation compaction. Check \`docs/09-agents/session-state.json\` for active commands.
165
- ${claudeMdMarker}
166
- `;
167
-
168
- try {
169
- let existingContent = '';
170
- if (fs.existsSync(claudeMdPath)) {
171
- existingContent = fs.readFileSync(claudeMdPath, 'utf8');
172
- }
173
-
174
- // Only append if marker doesn't exist
175
- if (!existingContent.includes(claudeMdMarker)) {
176
- fs.appendFileSync(claudeMdPath, claudeMdContent);
177
- success('Added /babysit rules to CLAUDE.md');
178
- } else {
179
- info('CLAUDE.md already has /babysit rules');
180
- }
181
- } catch (err) {
182
- warning(`Could not update CLAUDE.md: ${err.message}`);
183
- }
184
- }
185
-
186
129
  // Update metadata with config tracking
187
130
  try {
188
131
  const metadataPath = path.join(
@@ -199,18 +142,6 @@ ${claudeMdMarker}
199
142
  metadata.config_schema_version = packageJson.version;
200
143
  metadata.active_profile = options.yes ? 'default' : null; // null = custom
201
144
 
202
- // Track config options that were configured
203
- if (!metadata.agileflow) metadata.agileflow = {};
204
- if (!metadata.agileflow.config_options) metadata.agileflow.config_options = {};
205
-
206
- metadata.agileflow.config_options.claudeMdReinforcement = {
207
- available_since: '2.92.0',
208
- configured: true,
209
- enabled: config.claudeMdReinforcement,
210
- configured_at: new Date().toISOString(),
211
- description: 'Add /babysit AskUserQuestion rules to CLAUDE.md',
212
- };
213
-
214
145
  fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2) + '\n');
215
146
  }
216
147
  } catch (err) {
@@ -224,17 +155,7 @@ ${claudeMdMarker}
224
155
  info('Open your IDE and use /agileflow:help');
225
156
  info(`Run 'npx agileflow status' to check setup`);
226
157
  info(`Run 'npx agileflow update' to get updates`);
227
-
228
- // Shell alias reload reminder
229
- if (coreResult.shellAliases?.configured?.length > 0) {
230
- console.log(chalk.bold('\nShell aliases:'));
231
- info(
232
- `Reload shell to use: ${chalk.cyan('source ~/.bashrc')} or ${chalk.cyan('source ~/.zshrc')}`
233
- );
234
- info(
235
- `Then run ${chalk.cyan('af')} to start Claude in tmux (or ${chalk.cyan('claude')} for normal)`
236
- );
237
- }
158
+ info(`Run '/agileflow:configure' to enable optional features`);
238
159
 
239
160
  console.log(chalk.dim(`\nInstalled to: ${coreResult.path}\n`));
240
161
 
@@ -164,10 +164,6 @@ class Installer {
164
164
  spinner.text = 'Installing changelog...';
165
165
  await this.installChangelog(agileflowDir, { force: effectiveForce });
166
166
 
167
- // Set up shell aliases for claude command
168
- spinner.text = 'Setting up shell aliases...';
169
- const aliasResult = await this.setupShellAliases(directory, { force: effectiveForce });
170
-
171
167
  // Create config.yaml
172
168
  spinner.text = 'Creating configuration...';
173
169
  await this.createConfig(agileflowDir, userName, agileflowFolder, { force: effectiveForce });
@@ -195,7 +191,6 @@ class Installer {
195
191
  projectDir: directory,
196
192
  counts,
197
193
  fileOps,
198
- shellAliases: aliasResult,
199
194
  };
200
195
  } catch (error) {
201
196
  spinner.fail('Installation failed');
@@ -38,6 +38,12 @@ class ClaudeCodeSetup extends BaseIdeSetup {
38
38
  // Claude Code specific: Install agents as spawnable subagents (.claude/agents/agileflow/)
39
39
  // This allows Task tool to spawn them with subagent_type: "agileflow-ui"
40
40
  const spawnableAgentsDir = path.join(ideDir, 'agents', 'agileflow');
41
+
42
+ // Clean existing spawnable agents directory to prevent duplicates during update
43
+ if (await fs.pathExists(spawnableAgentsDir)) {
44
+ await fs.remove(spawnableAgentsDir);
45
+ }
46
+
41
47
  await this.installCommandsRecursive(agentsSource, spawnableAgentsDir, agileflowDir, false);
42
48
  console.log(chalk.dim(` - Spawnable agents: .claude/agents/agileflow/`));
43
49
 
@@ -13,7 +13,7 @@
13
13
  const path = require('path');
14
14
  const fs = require('fs-extra');
15
15
  const { safeLoad, safeDump } = require('../../../lib/yaml-utils');
16
- const { hasUnsafePathPatterns } = require('../../../lib/validate-paths');
16
+ const { hasUnsafePathPatterns, validatePath } = require('../../../lib/validate-paths');
17
17
 
18
18
  /**
19
19
  * Configuration schema definition
@@ -95,6 +95,11 @@ const VALID_CONFIG_KEYS = Object.keys(CONFIG_SCHEMA);
95
95
  */
96
96
  const EDITABLE_CONFIG_KEYS = ['userName', 'ides', 'agileflowFolder', 'docsFolder'];
97
97
 
98
+ /**
99
+ * Path fields that require validatePath() boundary checking
100
+ */
101
+ const PATH_CONFIG_FIELDS = ['agileflowFolder', 'docsFolder'];
102
+
98
103
  /**
99
104
  * Configuration Manager class
100
105
  */
@@ -103,10 +108,12 @@ class ConfigManager {
103
108
  * Create a new ConfigManager instance
104
109
  * @param {Object} data - Configuration data
105
110
  * @param {string} manifestPath - Path to manifest file
111
+ * @param {string} projectDir - Project root directory for path validation
106
112
  */
107
- constructor(data = {}, manifestPath = null) {
113
+ constructor(data = {}, manifestPath = null, projectDir = null) {
108
114
  this._data = { ...data };
109
115
  this._manifestPath = manifestPath;
116
+ this._projectDir = projectDir;
110
117
  this._dirty = false;
111
118
  }
112
119
 
@@ -142,7 +149,7 @@ class ConfigManager {
142
149
  }
143
150
  }
144
151
 
145
- return new ConfigManager(data, manifestPath);
152
+ return new ConfigManager(data, manifestPath, projectDir);
146
153
  }
147
154
 
148
155
  /**
@@ -225,11 +232,22 @@ class ConfigManager {
225
232
  return { ok: false, error: typeError };
226
233
  }
227
234
 
228
- // Custom validation
235
+ // Custom validation (basic schema-level checks)
229
236
  if (schema.validate && !schema.validate(value)) {
230
237
  return { ok: false, error: `Invalid value for '${key}'` };
231
238
  }
232
239
 
240
+ // Security: Path fields require additional boundary validation (US-0189)
241
+ if (PATH_CONFIG_FIELDS.includes(key) && this._projectDir) {
242
+ const pathResult = validatePath(value, this._projectDir, { allowSymlinks: false });
243
+ if (!pathResult.ok) {
244
+ return {
245
+ ok: false,
246
+ error: `Path validation failed for '${key}': ${pathResult.error?.message || 'Invalid path'}`,
247
+ };
248
+ }
249
+ }
250
+
233
251
  this._data[key] = value;
234
252
  this._dirty = true;
235
253
  return { ok: true };
@@ -296,9 +314,20 @@ class ConfigManager {
296
314
  continue;
297
315
  }
298
316
 
299
- // Custom validation
317
+ // Custom validation (basic schema-level checks)
300
318
  if (schema.validate && !schema.validate(value)) {
301
319
  errors.push(`Invalid value for '${key}'`);
320
+ continue;
321
+ }
322
+
323
+ // Security: Path fields require additional boundary validation (US-0189)
324
+ if (PATH_CONFIG_FIELDS.includes(key) && this._projectDir) {
325
+ const pathResult = validatePath(value, this._projectDir, { allowSymlinks: false });
326
+ if (!pathResult.ok) {
327
+ errors.push(
328
+ `Path validation failed for '${key}': ${pathResult.error?.message || 'Invalid path'}`
329
+ );
330
+ }
302
331
  }
303
332
  }
304
333
 
@@ -362,6 +391,14 @@ class ConfigManager {
362
391
  return this._manifestPath;
363
392
  }
364
393
 
394
+ /**
395
+ * Get the project directory (used for path validation)
396
+ * @returns {string|null}
397
+ */
398
+ getProjectDir() {
399
+ return this._projectDir;
400
+ }
401
+
365
402
  /**
366
403
  * Migrate configuration from an older format
367
404
  * @param {Object} oldData - Old configuration data