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.
- package/CHANGELOG.md +20 -0
- package/README.md +3 -3
- package/lib/colors.generated.js +117 -0
- package/lib/colors.js +59 -109
- package/lib/generator-factory.js +333 -0
- package/lib/path-utils.js +49 -0
- package/lib/session-registry.js +25 -15
- package/lib/smart-json-file.js +40 -32
- package/lib/state-machine.js +286 -0
- package/package.json +1 -1
- package/scripts/agileflow-configure.js +7 -6
- package/scripts/archive-completed-stories.sh +86 -11
- package/scripts/babysit-context-restore.js +89 -0
- package/scripts/claude-tmux.sh +111 -5
- package/scripts/damage-control/bash-tool-damage-control.js +11 -247
- package/scripts/damage-control/edit-tool-damage-control.js +9 -249
- package/scripts/damage-control/write-tool-damage-control.js +9 -244
- package/scripts/generate-colors.js +314 -0
- package/scripts/lib/colors.generated.sh +82 -0
- package/scripts/lib/colors.sh +10 -70
- package/scripts/lib/configure-features.js +401 -0
- package/scripts/lib/context-loader.js +181 -52
- package/scripts/precompact-context.sh +54 -17
- package/scripts/session-coordinator.sh +2 -2
- package/scripts/session-manager.js +653 -10
- package/src/core/commands/audit.md +93 -0
- package/src/core/commands/auto.md +73 -0
- package/src/core/commands/babysit.md +169 -13
- package/src/core/commands/baseline.md +73 -0
- package/src/core/commands/batch.md +64 -0
- package/src/core/commands/blockers.md +60 -0
- package/src/core/commands/board.md +66 -0
- package/src/core/commands/choose.md +77 -0
- package/src/core/commands/ci.md +77 -0
- package/src/core/commands/compress.md +27 -1
- package/src/core/commands/configure.md +126 -10
- package/src/core/commands/council.md +74 -0
- package/src/core/commands/debt.md +72 -0
- package/src/core/commands/deploy.md +73 -0
- package/src/core/commands/deps.md +68 -0
- package/src/core/commands/docs.md +60 -0
- package/src/core/commands/feedback.md +68 -0
- package/src/core/commands/ideate.md +74 -0
- package/src/core/commands/impact.md +74 -0
- package/src/core/commands/install.md +529 -0
- package/src/core/commands/maintain.md +558 -0
- package/src/core/commands/metrics.md +75 -0
- package/src/core/commands/multi-expert.md +74 -0
- package/src/core/commands/packages.md +69 -0
- package/src/core/commands/readme-sync.md +64 -0
- package/src/core/commands/research/analyze.md +285 -121
- package/src/core/commands/research/import.md +281 -109
- package/src/core/commands/retro.md +76 -0
- package/src/core/commands/review.md +72 -0
- package/src/core/commands/rlm.md +83 -0
- package/src/core/commands/rpi.md +90 -0
- package/src/core/commands/session/cleanup.md +214 -12
- package/src/core/commands/session/end.md +155 -17
- package/src/core/commands/sprint.md +72 -0
- package/src/core/commands/story-validate.md +68 -0
- package/src/core/commands/template.md +69 -0
- package/src/core/commands/tests.md +83 -0
- package/src/core/commands/update.md +59 -0
- package/src/core/commands/validate-expertise.md +76 -0
- package/src/core/commands/velocity.md +74 -0
- package/src/core/commands/verify.md +91 -0
- package/src/core/commands/whats-new.md +69 -0
- package/src/core/commands/workflow.md +88 -0
- package/src/core/templates/command-documentation.md +187 -0
- package/tools/cli/commands/session.js +1171 -0
- package/tools/cli/commands/setup.js +2 -81
- package/tools/cli/installers/core/installer.js +0 -5
- package/tools/cli/installers/ide/claude-code.js +6 -0
- 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
|