agileflow 3.0.1 → 3.1.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.
Files changed (69) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +8 -8
  3. package/lib/api-server.js +3 -2
  4. package/lib/feedback.js +9 -2
  5. package/lib/flag-detection.js +4 -2
  6. package/lib/git-operations.js +4 -2
  7. package/lib/lazy-require.js +59 -0
  8. package/lib/process-executor.js +24 -9
  9. package/lib/skill-loader.js +11 -3
  10. package/package.json +1 -1
  11. package/scripts/agileflow-configure.js +12 -0
  12. package/scripts/agileflow-welcome.js +146 -90
  13. package/scripts/claude-tmux.sh +42 -6
  14. package/scripts/damage-control-multi-agent.js +14 -10
  15. package/scripts/lib/bus-utils.js +3 -1
  16. package/scripts/lib/configure-detect.js +12 -9
  17. package/scripts/lib/configure-features.js +128 -7
  18. package/scripts/lib/configure-repair.js +6 -5
  19. package/scripts/lib/context-formatter.js +13 -3
  20. package/scripts/lib/damage-control-utils.js +5 -1
  21. package/scripts/lib/lifecycle-detector.js +5 -3
  22. package/scripts/lib/process-cleanup.js +8 -4
  23. package/scripts/lib/scale-detector.js +47 -8
  24. package/scripts/lib/signal-detectors.js +117 -59
  25. package/scripts/lib/task-registry.js +5 -1
  26. package/scripts/lib/team-events.js +4 -4
  27. package/scripts/messaging-bridge.js +7 -1
  28. package/scripts/ralph-loop.js +10 -8
  29. package/scripts/smart-detect.js +32 -11
  30. package/scripts/team-manager.js +86 -1
  31. package/scripts/tmux-task-name.sh +105 -0
  32. package/scripts/tmux-task-watcher.sh +344 -0
  33. package/src/core/agents/legal-analyzer-a11y.md +110 -0
  34. package/src/core/agents/legal-analyzer-ai.md +117 -0
  35. package/src/core/agents/legal-analyzer-consumer.md +108 -0
  36. package/src/core/agents/legal-analyzer-content.md +113 -0
  37. package/src/core/agents/legal-analyzer-international.md +115 -0
  38. package/src/core/agents/legal-analyzer-licensing.md +115 -0
  39. package/src/core/agents/legal-analyzer-privacy.md +108 -0
  40. package/src/core/agents/legal-analyzer-security.md +112 -0
  41. package/src/core/agents/legal-analyzer-terms.md +111 -0
  42. package/src/core/agents/legal-consensus.md +242 -0
  43. package/src/core/agents/team-lead.md +50 -13
  44. package/src/core/commands/babysit.md +75 -42
  45. package/src/core/commands/blockers.md +7 -7
  46. package/src/core/commands/configure.md +15 -61
  47. package/src/core/commands/discovery/brief.md +363 -0
  48. package/src/core/commands/discovery/new.md +395 -0
  49. package/src/core/commands/ideate/new.md +5 -5
  50. package/src/core/commands/legal/audit.md +446 -0
  51. package/src/core/commands/logic/audit.md +5 -5
  52. package/src/core/commands/review.md +7 -1
  53. package/src/core/commands/rpi.md +61 -26
  54. package/src/core/commands/sprint.md +7 -6
  55. package/src/core/commands/team/start.md +36 -7
  56. package/src/core/commands/team/stop.md +5 -2
  57. package/src/core/templates/product-brief.md +136 -0
  58. package/tools/cli/installers/ide/claude-code.js +69 -2
  59. package/src/core/agents/configuration/archival.md +0 -350
  60. package/src/core/agents/configuration/attribution.md +0 -343
  61. package/src/core/agents/configuration/ci.md +0 -1103
  62. package/src/core/agents/configuration/damage-control.md +0 -375
  63. package/src/core/agents/configuration/git-config.md +0 -537
  64. package/src/core/agents/configuration/hooks.md +0 -623
  65. package/src/core/agents/configuration/precompact.md +0 -302
  66. package/src/core/agents/configuration/status-line.md +0 -557
  67. package/src/core/agents/configuration/verify.md +0 -618
  68. package/src/core/agents/configuration-damage-control.md +0 -259
  69. package/src/core/agents/configuration-visual-e2e.md +0 -339
package/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [3.1.0] - 2026-02-14
11
+
12
+ ### Added
13
+ - Legal audit system, native Agent Teams integration, and startup performance improvements
14
+
15
+ ## [3.0.2] - 2026-02-14
16
+
17
+ ### Added
18
+ - Automatic tmux window naming and configuration agent consolidation
19
+
10
20
  ## [3.0.1] - 2026-02-13
11
21
 
12
22
  ### Fixed
package/README.md CHANGED
@@ -3,8 +3,8 @@
3
3
  </p>
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/agileflow?color=brightgreen)](https://www.npmjs.com/package/agileflow)
6
- [![Commands](https://img.shields.io/badge/commands-93-blue)](docs/04-architecture/commands.md)
7
- [![Agents/Experts](https://img.shields.io/badge/agents%2Fexperts-47-orange)](docs/04-architecture/subagents.md)
6
+ [![Commands](https://img.shields.io/badge/commands-94-blue)](docs/04-architecture/commands.md)
7
+ [![Agents/Experts](https://img.shields.io/badge/agents%2Fexperts-55-orange)](docs/04-architecture/subagents.md)
8
8
  [![Skills](https://img.shields.io/badge/skills-dynamic-purple)](docs/04-architecture/skills.md)
9
9
 
10
10
  **AI-driven agile development for Claude Code, Cursor, Windsurf, OpenAI Codex CLI, and more.** Combining Scrum, Kanban, ADRs, and docs-as-code principles into one framework-agnostic system.
@@ -39,9 +39,9 @@ npx agileflow@latest update
39
39
  | IDE | Status | Config Location |
40
40
  |-----|--------|-----------------|
41
41
  | Claude Code | Supported | `.claude/commands/agileflow/` |
42
- | Cursor | Supported | `.cursor/rules/agileflow/` |
42
+ | Cursor | Supported | `.cursor/commands/agileflow/` |
43
43
  | Windsurf | Supported | `.windsurf/workflows/agileflow/` |
44
- | OpenAI Codex CLI | Supported | `.codex/skills/` |
44
+ | OpenAI Codex CLI | Supported | `.codex/skills/` and `~/.codex/prompts/` |
45
45
 
46
46
  ---
47
47
 
@@ -65,8 +65,8 @@ AgileFlow combines three proven methodologies:
65
65
 
66
66
  | Component | Count | Description |
67
67
  |-----------|-------|-------------|
68
- | [Commands](docs/04-architecture/commands.md) | 93 | Slash commands for agile workflows |
69
- | [Agents/Experts](docs/04-architecture/subagents.md) | 47 | Specialized agents with self-improving knowledge bases |
68
+ | [Commands](docs/04-architecture/commands.md) | 94 | Slash commands for agile workflows |
69
+ | [Agents/Experts](docs/04-architecture/subagents.md) | 55 | Specialized agents with self-improving knowledge bases |
70
70
  | [Skills](docs/04-architecture/skills.md) | Dynamic | Generated on-demand with `/agileflow:skill:create` |
71
71
 
72
72
  ---
@@ -76,8 +76,8 @@ AgileFlow combines three proven methodologies:
76
76
  Full documentation lives in [`docs/04-architecture/`](docs/04-architecture/):
77
77
 
78
78
  ### Reference
79
- - [Commands](docs/04-architecture/commands.md) - All 93 slash commands
80
- - [Agents/Experts](docs/04-architecture/subagents.md) - 47 specialized agents with self-improving knowledge
79
+ - [Commands](docs/04-architecture/commands.md) - All 94 slash commands
80
+ - [Agents/Experts](docs/04-architecture/subagents.md) - 55 specialized agents with self-improving knowledge
81
81
  - [Skills](docs/04-architecture/skills.md) - Dynamic skill generator with MCP integration
82
82
 
83
83
  ### Architecture
package/lib/api-server.js CHANGED
@@ -71,7 +71,7 @@ class ApiCache {
71
71
  * @returns {{ server: http.Server, options: Object, cache: ApiCache }}
72
72
  */
73
73
  function createApiServer(options = {}) {
74
- const port = options.port || DEFAULT_PORT;
74
+ const port = options.port != null ? options.port : DEFAULT_PORT;
75
75
  const host = options.host || DEFAULT_HOST;
76
76
  const rootDir = options.rootDir || getProjectRoot();
77
77
  const cacheTTL = options.cacheTTL || 2000;
@@ -238,7 +238,8 @@ function startApiServer(serverInstance) {
238
238
  });
239
239
 
240
240
  server.listen(port, host, () => {
241
- const url = `http://${host}:${port}`;
241
+ const actualPort = server.address().port;
242
+ const url = `http://${host}:${actualPort}`;
242
243
  console.log(`[AgileFlow API] Server running at ${url}`);
243
244
  console.log(`[AgileFlow API] Project root: ${options.rootDir}`);
244
245
  resolve({
package/lib/feedback.js CHANGED
@@ -34,7 +34,14 @@
34
34
  */
35
35
 
36
36
  const { c, BRAND_HEX } = require('./colors');
37
- const chalk = require('chalk');
37
+ const { lazyRequire } = require('./lazy-require');
38
+
39
+ // Lazy-load chalk: feedback.js is imported by scripts that run as hooks in
40
+ // user projects (.agileflow/scripts/). If chalk isn't resolvable from the
41
+ // user's node_modules the eager require() would crash every hook that
42
+ // imports feedback. Deferring the require() to the single call-site that
43
+ // actually needs chalk (brand()) avoids the crash entirely.
44
+ const getChalk = lazyRequire('chalk');
38
45
 
39
46
  // Symbols for consistent output
40
47
  const SYMBOLS = {
@@ -182,7 +189,7 @@ class Feedback {
182
189
  brand(message) {
183
190
  if (this.quiet) return this;
184
191
  const prefix = this._indent();
185
- console.log(`${prefix}${chalk.hex(BRAND_HEX)(message)}`);
192
+ console.log(`${prefix}${getChalk().hex(BRAND_HEX)(message)}`);
186
193
  return this;
187
194
  }
188
195
 
@@ -219,7 +219,8 @@ function detectFromPs() {
219
219
  // Get command line for this PID
220
220
  let cmdline;
221
221
  const cmdResult = executeCommandSync('ps', ['-p', String(pid), '-o', 'args='], {
222
- timeout: 1000, fallback: null,
222
+ timeout: 1000,
223
+ fallback: null,
223
224
  });
224
225
  if (!cmdResult.ok || cmdResult.data === null) break;
225
226
  cmdline = cmdResult.data;
@@ -239,7 +240,8 @@ function detectFromPs() {
239
240
 
240
241
  // Get parent PID
241
242
  const ppidResult = executeCommandSync('ps', ['-p', String(pid), '-o', 'ppid='], {
242
- timeout: 1000, fallback: null,
243
+ timeout: 1000,
244
+ fallback: null,
243
245
  });
244
246
  if (!ppidResult.ok || ppidResult.data === null) break;
245
247
  pid = parseInt(ppidResult.data, 10);
@@ -176,12 +176,14 @@ function getSessionPhase(session) {
176
176
  try {
177
177
  const mainBranch = getMainBranch(sessionPath);
178
178
  const commitResult = git(['rev-list', '--count', `${mainBranch}..HEAD`], {
179
- cwd: sessionPath, fallback: '0',
179
+ cwd: sessionPath,
180
+ fallback: '0',
180
181
  });
181
182
  const commits = parseInt(commitResult.data, 10);
182
183
 
183
184
  const statusResult = git(['status', '--porcelain'], {
184
- cwd: sessionPath, fallback: '',
185
+ cwd: sessionPath,
186
+ fallback: '',
185
187
  });
186
188
  const status = statusResult.data;
187
189
 
@@ -0,0 +1,59 @@
1
+ /**
2
+ * lazy-require.js - Reusable Lazy-Loading Utility
3
+ *
4
+ * AgileFlow scripts are copied to user projects (.agileflow/scripts/) and run
5
+ * as hooks. When these scripts eagerly require() npm dependencies at module
6
+ * load time, they crash if the dependency isn't resolvable from the user's
7
+ * project directory. This utility standardizes the lazy-loading pattern used
8
+ * ad-hoc in yaml-utils.js and dashboard-server.js.
9
+ *
10
+ * Usage:
11
+ * const { lazyRequire } = require('./lazy-require');
12
+ *
13
+ * // Returns a getter function; require() is deferred until first call
14
+ * const getChalk = lazyRequire('chalk');
15
+ *
16
+ * // With fallback resolution paths
17
+ * const getYaml = lazyRequire('js-yaml',
18
+ * path.join(__dirname, '..', 'node_modules', 'js-yaml')
19
+ * );
20
+ *
21
+ * // Later, when actually needed:
22
+ * const chalk = getChalk();
23
+ */
24
+
25
+ 'use strict';
26
+
27
+ /**
28
+ * Create a lazy-loading getter for an npm module.
29
+ *
30
+ * The returned function defers require() until first invocation, then caches
31
+ * the result. Multiple resolution paths are tried in order, so the module can
32
+ * be found from the user's node_modules, AgileFlow's own node_modules, or any
33
+ * other location.
34
+ *
35
+ * @param {string} name - Primary module name (passed to require())
36
+ * @param {...string} fallbackPaths - Additional paths to try if primary fails
37
+ * @returns {function(): any} Getter that returns the loaded module
38
+ */
39
+ function lazyRequire(name, ...fallbackPaths) {
40
+ let cached = null;
41
+ return () => {
42
+ if (cached) return cached;
43
+ const paths = [name, ...fallbackPaths];
44
+ for (const p of paths) {
45
+ try {
46
+ cached = require(p);
47
+ return cached;
48
+ } catch (_e) {
49
+ // Continue to next path
50
+ }
51
+ }
52
+ throw new Error(
53
+ `${name} not found. Run: npm install ${name}\n` +
54
+ 'Or reinstall AgileFlow: npx agileflow setup --force'
55
+ );
56
+ };
57
+ }
58
+
59
+ module.exports = { lazyRequire };
@@ -91,13 +91,20 @@ function executeCommand(cmd, args = [], opts = {}) {
91
91
  let stderr = '';
92
92
  let timedOut = false;
93
93
 
94
- const timer = timeout > 0 ? setTimeout(() => {
95
- timedOut = true;
96
- proc.kill('SIGTERM');
97
- }, timeout) : null;
98
-
99
- proc.stdout.on('data', chunk => { stdout += chunk; });
100
- proc.stderr.on('data', chunk => { stderr += chunk; });
94
+ const timer =
95
+ timeout > 0
96
+ ? setTimeout(() => {
97
+ timedOut = true;
98
+ proc.kill('SIGTERM');
99
+ }, timeout)
100
+ : null;
101
+
102
+ proc.stdout.on('data', chunk => {
103
+ stdout += chunk;
104
+ });
105
+ proc.stderr.on('data', chunk => {
106
+ stderr += chunk;
107
+ });
101
108
 
102
109
  proc.on('error', err => {
103
110
  if (timer) clearTimeout(timer);
@@ -115,7 +122,11 @@ function executeCommand(cmd, args = [], opts = {}) {
115
122
  if (fallback !== undefined) {
116
123
  resolve({ ok: true, data: fallback });
117
124
  } else {
118
- resolve({ ok: false, error: `Command timed out after ${timeout}ms: ${cmd}`, exitCode: null });
125
+ resolve({
126
+ ok: false,
127
+ error: `Command timed out after ${timeout}ms: ${cmd}`,
128
+ exitCode: null,
129
+ });
119
130
  }
120
131
  return;
121
132
  }
@@ -124,7 +135,11 @@ function executeCommand(cmd, args = [], opts = {}) {
124
135
  if (fallback !== undefined) {
125
136
  resolve({ ok: true, data: fallback });
126
137
  } else {
127
- const result = { ok: false, error: `Command failed: ${cmd} ${args.join(' ')} (exit ${code})`, exitCode: code };
138
+ const result = {
139
+ ok: false,
140
+ error: `Command failed: ${cmd} ${args.join(' ')} (exit ${code})`,
141
+ exitCode: code,
142
+ };
128
143
  if (captureStderr) {
129
144
  result.stderr = trim ? stderr.trim() : stderr;
130
145
  }
@@ -57,13 +57,21 @@ function parseSkillFrontmatter(content) {
57
57
  let value = trimmed.substring(colonIndex + 1).trim();
58
58
 
59
59
  // Remove surrounding quotes
60
- if ((value.startsWith('"') && value.endsWith('"')) ||
61
- (value.startsWith("'") && value.endsWith("'"))) {
60
+ if (
61
+ (value.startsWith('"') && value.endsWith('"')) ||
62
+ (value.startsWith("'") && value.endsWith("'"))
63
+ ) {
62
64
  value = value.slice(1, -1);
63
65
  }
64
66
 
65
67
  // Type coercion for known fields
66
- if (key === 'version' || key === 'model' || key === 'category' || key === 'name' || key === 'type') {
68
+ if (
69
+ key === 'version' ||
70
+ key === 'model' ||
71
+ key === 'category' ||
72
+ key === 'name' ||
73
+ key === 'type'
74
+ ) {
67
75
  result.metadata[key] = value;
68
76
  } else if (value === 'true') {
69
77
  result.metadata[key] = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agileflow",
3
- "version": "3.0.1",
3
+ "version": "3.1.0",
4
4
  "description": "AI-driven agile development system for Claude Code, Cursor, Windsurf, and more",
5
5
  "keywords": [
6
6
  "agile",
@@ -18,6 +18,7 @@
18
18
  * --enable=<features> Enable specific features
19
19
  * --disable=<features> Disable specific features
20
20
  * --archival-days=<N> Set archival threshold
21
+ * --startup-mode=<MODE> Set default startup mode (atomic)
21
22
  * --migrate Fix old formats without changing features
22
23
  * --validate Check for issues
23
24
  * --detect Show current status
@@ -42,6 +43,7 @@ const {
42
43
  listStatuslineComponents,
43
44
  migrateSettings,
44
45
  upgradeFeatures,
46
+ enableStartupMode,
45
47
  } = require('./lib/configure-features');
46
48
  const { listScripts, showVersionInfo, repairScripts } = require('./lib/configure-repair');
47
49
  const { feedback } = require('../lib/feedback');
@@ -144,6 +146,7 @@ ${c.cyan}Statusline Components:${c.reset}
144
146
 
145
147
  ${c.cyan}Settings:${c.reset}
146
148
  --archival-days=N Set archival threshold (default: 30)
149
+ --startup-mode=MODE Set default startup mode (skip-permissions, accept-edits, normal, no-claude)
147
150
 
148
151
  ${c.cyan}Maintenance:${c.reset}
149
152
  --migrate Fix old/invalid formats
@@ -201,6 +204,7 @@ function main() {
201
204
  let repairFeature = null;
202
205
  let showVersion = false;
203
206
  let listScriptsMode = false;
207
+ let startupMode = null;
204
208
 
205
209
  args.forEach(arg => {
206
210
  if (arg.startsWith('--profile=')) profile = arg.split('=')[1];
@@ -237,6 +241,8 @@ function main() {
237
241
  repairFeature = arg.split('=')[1].trim().toLowerCase();
238
242
  } else if (arg === '--version' || arg === '-v') showVersion = true;
239
243
  else if (arg === '--list-scripts' || arg === '--scripts') listScriptsMode = true;
244
+ else if (arg.startsWith('--startup-mode='))
245
+ startupMode = arg.split('=')[1].trim().toLowerCase();
240
246
  });
241
247
 
242
248
  // Help mode
@@ -289,6 +295,12 @@ function main() {
289
295
  spinner.succeed('Configuration detected');
290
296
  const { hasIssues, hasOutdated } = printStatus(status);
291
297
 
298
+ // Startup mode (atomic - sets BOTH metadata AND settings.json)
299
+ if (startupMode) {
300
+ enableStartupMode(startupMode, VERSION);
301
+ return;
302
+ }
303
+
292
304
  // Detect only mode
293
305
  if (detect && !migrate && !upgrade && !profile && enable.length === 0 && disable.length === 0) {
294
306
  return;