agileflow 3.0.0 → 3.0.2

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 (57) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +6 -6
  3. package/lib/api-server.js +3 -2
  4. package/lib/dashboard-server.js +131 -50
  5. package/lib/flag-detection.js +4 -2
  6. package/lib/git-operations.js +4 -2
  7. package/lib/process-executor.js +24 -9
  8. package/lib/skill-loader.js +11 -3
  9. package/package.json +1 -1
  10. package/scripts/agileflow-welcome.js +65 -25
  11. package/scripts/archive-completed-stories.sh +3 -0
  12. package/scripts/ci-summary.js +294 -0
  13. package/scripts/claude-smart.sh +18 -0
  14. package/scripts/claude-tmux.sh +50 -20
  15. package/scripts/damage-control-multi-agent.js +14 -10
  16. package/scripts/lib/bus-utils.js +3 -1
  17. package/scripts/lib/configure-detect.js +89 -8
  18. package/scripts/lib/configure-features.js +77 -10
  19. package/scripts/lib/configure-repair.js +6 -5
  20. package/scripts/lib/context-formatter.js +13 -3
  21. package/scripts/lib/damage-control-utils.js +5 -1
  22. package/scripts/lib/lifecycle-detector.js +5 -3
  23. package/scripts/lib/process-cleanup.js +8 -4
  24. package/scripts/lib/scale-detector.js +47 -8
  25. package/scripts/lib/signal-detectors.js +117 -59
  26. package/scripts/lib/task-registry.js +5 -1
  27. package/scripts/lib/team-events.js +4 -4
  28. package/scripts/messaging-bridge.js +7 -1
  29. package/scripts/precompact-context.sh +3 -0
  30. package/scripts/ralph-loop.js +10 -8
  31. package/scripts/smart-detect.js +32 -11
  32. package/scripts/team-manager.js +1 -1
  33. package/scripts/tmux-task-name.sh +75 -0
  34. package/scripts/tmux-task-watcher.sh +177 -0
  35. package/src/core/commands/babysit.md +75 -42
  36. package/src/core/commands/blockers.md +7 -7
  37. package/src/core/commands/configure.md +49 -63
  38. package/src/core/commands/discovery/brief.md +363 -0
  39. package/src/core/commands/discovery/new.md +395 -0
  40. package/src/core/commands/ideate/new.md +5 -5
  41. package/src/core/commands/logic/audit.md +5 -5
  42. package/src/core/commands/review.md +7 -1
  43. package/src/core/commands/rpi.md +61 -26
  44. package/src/core/commands/sprint.md +7 -6
  45. package/src/core/templates/product-brief.md +136 -0
  46. package/tools/cli/installers/ide/claude-code.js +67 -2
  47. package/src/core/agents/configuration/archival.md +0 -350
  48. package/src/core/agents/configuration/attribution.md +0 -343
  49. package/src/core/agents/configuration/ci.md +0 -1103
  50. package/src/core/agents/configuration/damage-control.md +0 -375
  51. package/src/core/agents/configuration/git-config.md +0 -537
  52. package/src/core/agents/configuration/hooks.md +0 -623
  53. package/src/core/agents/configuration/precompact.md +0 -302
  54. package/src/core/agents/configuration/status-line.md +0 -557
  55. package/src/core/agents/configuration/verify.md +0 -618
  56. package/src/core/agents/configuration-damage-control.md +0 -259
  57. 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.0.2] - 2026-02-14
11
+
12
+ ### Added
13
+ - Automatic tmux window naming and configuration agent consolidation
14
+
15
+ ## [3.0.1] - 2026-02-13
16
+
17
+ ### Fixed
18
+ - Configure writes directly to Claude Code settings.json for Agent Teams and permissions
19
+
10
20
  ## [3.0.0] - 2026-02-13
11
21
 
12
22
  ### Added
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-91-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-93-blue)](docs/04-architecture/commands.md)
7
+ [![Agents/Experts](https://img.shields.io/badge/agents%2Fexperts-45-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.
@@ -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) | 91 | 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) | 93 | Slash commands for agile workflows |
69
+ | [Agents/Experts](docs/04-architecture/subagents.md) | 45 | 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 91 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 93 slash commands
80
+ - [Agents/Experts](docs/04-architecture/subagents.md) - 45 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({
@@ -26,12 +26,30 @@ const { EventEmitter } = require('events');
26
26
  // Lazy-loaded dependencies - deferred until first use
27
27
  let _http, _crypto, _protocol, _paths, _validatePaths, _childProcess;
28
28
 
29
- function getHttp() { if (!_http) _http = require('http'); return _http; }
30
- function getCrypto() { if (!_crypto) _crypto = require('crypto'); return _crypto; }
31
- function getProtocol() { if (!_protocol) _protocol = require('./dashboard-protocol'); return _protocol; }
32
- function getPaths() { if (!_paths) _paths = require('./paths'); return _paths; }
33
- function getValidatePaths() { if (!_validatePaths) _validatePaths = require('./validate-paths'); return _validatePaths; }
34
- function getChildProcess() { if (!_childProcess) _childProcess = require('child_process'); return _childProcess; }
29
+ function getHttp() {
30
+ if (!_http) _http = require('http');
31
+ return _http;
32
+ }
33
+ function getCrypto() {
34
+ if (!_crypto) _crypto = require('crypto');
35
+ return _crypto;
36
+ }
37
+ function getProtocol() {
38
+ if (!_protocol) _protocol = require('./dashboard-protocol');
39
+ return _protocol;
40
+ }
41
+ function getPaths() {
42
+ if (!_paths) _paths = require('./paths');
43
+ return _paths;
44
+ }
45
+ function getValidatePaths() {
46
+ if (!_validatePaths) _validatePaths = require('./validate-paths');
47
+ return _validatePaths;
48
+ }
49
+ function getChildProcess() {
50
+ if (!_childProcess) _childProcess = require('child_process');
51
+ return _childProcess;
52
+ }
35
53
 
36
54
  // Lazy-load automation modules to avoid circular dependencies
37
55
  let AutomationRegistry = null;
@@ -294,7 +312,9 @@ class TerminalInstance {
294
312
  this.pty.on('error', error => {
295
313
  console.error('[Terminal] Shell error:', error.message);
296
314
  if (!this.closed) {
297
- this.session.send(getProtocol().createTerminalOutput(this.id, `\r\nError: ${error.message}\r\n`));
315
+ this.session.send(
316
+ getProtocol().createTerminalOutput(this.id, `\r\nError: ${error.message}\r\n`)
317
+ );
298
318
  }
299
319
  });
300
320
 
@@ -558,7 +578,9 @@ class DashboardServer extends EventEmitter {
558
578
 
559
579
  this._automationRunner.on('failed', ({ automationId, result }) => {
560
580
  this._runningAutomations.delete(automationId);
561
- this.broadcast(getProtocol().createAutomationStatus(automationId, 'error', { error: result.error }));
581
+ this.broadcast(
582
+ getProtocol().createAutomationStatus(automationId, 'error', { error: result.error })
583
+ );
562
584
 
563
585
  // Add failure to inbox
564
586
  this._addToInbox(automationId, result);
@@ -732,7 +754,7 @@ class DashboardServer extends EventEmitter {
732
754
 
733
755
  // Complete WebSocket handshake
734
756
  const key = req.headers['sec-websocket-key'];
735
- const acceptKey = crypto
757
+ const acceptKey = getCrypto()
736
758
  .createHash('sha1')
737
759
  .update(key + WS_GUID)
738
760
  .digest('base64');
@@ -865,7 +887,9 @@ class DashboardServer extends EventEmitter {
865
887
  handleMessage(session, data) {
866
888
  // Rate limit incoming messages
867
889
  if (!session.checkRateLimit()) {
868
- session.send(getProtocol().createError('RATE_LIMITED', 'Too many messages, please slow down'));
890
+ session.send(
891
+ getProtocol().createError('RATE_LIMITED', 'Too many messages, please slow down')
892
+ );
869
893
  return;
870
894
  }
871
895
 
@@ -1059,7 +1083,9 @@ class DashboardServer extends EventEmitter {
1059
1083
  switch (type) {
1060
1084
  case getProtocol().InboundMessageType.GIT_STAGE:
1061
1085
  if (fileArgs) {
1062
- getChildProcess().execFileSync('git', ['add', '--', ...fileArgs], { cwd: this.projectRoot });
1086
+ getChildProcess().execFileSync('git', ['add', '--', ...fileArgs], {
1087
+ cwd: this.projectRoot,
1088
+ });
1063
1089
  } else {
1064
1090
  getChildProcess().execFileSync('git', ['add', '-A'], { cwd: this.projectRoot });
1065
1091
  }
@@ -1070,24 +1096,32 @@ class DashboardServer extends EventEmitter {
1070
1096
  cwd: this.projectRoot,
1071
1097
  });
1072
1098
  } else {
1073
- getChildProcess().execFileSync('git', ['restore', '--staged', '.'], { cwd: this.projectRoot });
1099
+ getChildProcess().execFileSync('git', ['restore', '--staged', '.'], {
1100
+ cwd: this.projectRoot,
1101
+ });
1074
1102
  }
1075
1103
  break;
1076
1104
  case getProtocol().InboundMessageType.GIT_REVERT:
1077
1105
  if (fileArgs) {
1078
- getChildProcess().execFileSync('git', ['checkout', '--', ...fileArgs], { cwd: this.projectRoot });
1106
+ getChildProcess().execFileSync('git', ['checkout', '--', ...fileArgs], {
1107
+ cwd: this.projectRoot,
1108
+ });
1079
1109
  }
1080
1110
  break;
1081
1111
  case getProtocol().InboundMessageType.GIT_COMMIT:
1082
1112
  if (commitMessage) {
1083
- getChildProcess().execFileSync('git', ['commit', '-m', commitMessage], { cwd: this.projectRoot });
1113
+ getChildProcess().execFileSync('git', ['commit', '-m', commitMessage], {
1114
+ cwd: this.projectRoot,
1115
+ });
1084
1116
  }
1085
1117
  break;
1086
1118
  }
1087
1119
 
1088
1120
  // Send updated git status
1089
1121
  this.sendGitStatus(session);
1090
- session.send(getProtocol().createNotification('success', 'Git', `${type.replace('git_', '')} completed`));
1122
+ session.send(
1123
+ getProtocol().createNotification('success', 'Git', `${type.replace('git_', '')} completed`)
1124
+ );
1091
1125
  } catch (error) {
1092
1126
  console.error('[Git Error]', error.message);
1093
1127
  session.send(getProtocol().createError('GIT_ERROR', 'Git operation failed'));
@@ -1115,11 +1149,13 @@ class DashboardServer extends EventEmitter {
1115
1149
  */
1116
1150
  getGitStatus() {
1117
1151
  try {
1118
- const branch = getChildProcess().execFileSync('git', ['branch', '--show-current'], {
1119
- cwd: this.projectRoot,
1120
- encoding: 'utf8',
1121
- stdio: ['pipe', 'pipe', 'pipe'],
1122
- }).trim();
1152
+ const branch = getChildProcess()
1153
+ .execFileSync('git', ['branch', '--show-current'], {
1154
+ cwd: this.projectRoot,
1155
+ encoding: 'utf8',
1156
+ stdio: ['pipe', 'pipe', 'pipe'],
1157
+ })
1158
+ .trim();
1123
1159
 
1124
1160
  const statusOutput = getChildProcess().execFileSync('git', ['status', '--porcelain'], {
1125
1161
  cwd: this.projectRoot,
@@ -1209,7 +1245,9 @@ class DashboardServer extends EventEmitter {
1209
1245
  */
1210
1246
  getFileDiff(filePath, staged = false) {
1211
1247
  // Validate filePath stays within project root
1212
- const pathResult = getValidatePaths().validatePath(filePath, this.projectRoot, { allowSymlinks: true });
1248
+ const pathResult = getValidatePaths().validatePath(filePath, this.projectRoot, {
1249
+ allowSymlinks: true,
1250
+ });
1213
1251
  if (!pathResult.ok) {
1214
1252
  return '';
1215
1253
  }
@@ -1224,10 +1262,12 @@ class DashboardServer extends EventEmitter {
1224
1262
 
1225
1263
  // If no diff, file might be untracked - show entire file content as addition
1226
1264
  if (!diff && !staged) {
1227
- const statusOutput = getChildProcess().execFileSync('git', ['status', '--porcelain', '--', filePath], {
1228
- cwd: this.projectRoot,
1229
- encoding: 'utf8',
1230
- }).trim();
1265
+ const statusOutput = getChildProcess()
1266
+ .execFileSync('git', ['status', '--porcelain', '--', filePath], {
1267
+ cwd: this.projectRoot,
1268
+ encoding: 'utf8',
1269
+ })
1270
+ .trim();
1231
1271
 
1232
1272
  // Check if file is untracked
1233
1273
  if (statusOutput.startsWith('??')) {
@@ -1398,23 +1438,23 @@ class DashboardServer extends EventEmitter {
1398
1438
  // Get branch and sync status via git
1399
1439
  try {
1400
1440
  const cwd = s.metadata.worktreePath || this.projectRoot;
1401
- entry.branch = getChildProcess().execFileSync('git', ['branch', '--show-current'], {
1402
- cwd,
1403
- encoding: 'utf8',
1404
- stdio: ['pipe', 'pipe', 'pipe'],
1405
- }).trim();
1441
+ entry.branch = getChildProcess()
1442
+ .execFileSync('git', ['branch', '--show-current'], {
1443
+ cwd,
1444
+ encoding: 'utf8',
1445
+ stdio: ['pipe', 'pipe', 'pipe'],
1446
+ })
1447
+ .trim();
1406
1448
 
1407
1449
  // Get ahead/behind counts relative to upstream
1408
1450
  try {
1409
- const counts = getChildProcess().execFileSync(
1410
- 'git',
1411
- ['rev-list', '--left-right', '--count', 'HEAD...@{u}'],
1412
- {
1451
+ const counts = getChildProcess()
1452
+ .execFileSync('git', ['rev-list', '--left-right', '--count', 'HEAD...@{u}'], {
1413
1453
  cwd,
1414
1454
  encoding: 'utf8',
1415
1455
  stdio: ['pipe', 'pipe', 'pipe'],
1416
- }
1417
- ).trim();
1456
+ })
1457
+ .trim();
1418
1458
  const [ahead, behind] = counts.split(/\s+/).map(Number);
1419
1459
  entry.ahead = ahead || 0;
1420
1460
  entry.behind = behind || 0;
@@ -1454,7 +1494,9 @@ class DashboardServer extends EventEmitter {
1454
1494
  }
1455
1495
 
1456
1496
  // Validate the path stays within project root
1457
- const pathResult = getValidatePaths().validatePath(filePath, this.projectRoot, { allowSymlinks: true });
1497
+ const pathResult = getValidatePaths().validatePath(filePath, this.projectRoot, {
1498
+ allowSymlinks: true,
1499
+ });
1458
1500
  if (!pathResult.ok) {
1459
1501
  session.send(getProtocol().createError('OPEN_FILE_ERROR', 'File path outside project'));
1460
1502
  return;
@@ -1474,7 +1516,9 @@ class DashboardServer extends EventEmitter {
1474
1516
  case 'cursor':
1475
1517
  case 'windsurf': {
1476
1518
  const gotoArg = lineNum ? `${fullPath}:${lineNum}` : fullPath;
1477
- getChildProcess().spawn(editor, ['--goto', gotoArg], { detached: true, stdio: 'ignore' }).unref();
1519
+ getChildProcess()
1520
+ .spawn(editor, ['--goto', gotoArg], { detached: true, stdio: 'ignore' })
1521
+ .unref();
1478
1522
  break;
1479
1523
  }
1480
1524
  case 'subl':
@@ -1491,11 +1535,17 @@ class DashboardServer extends EventEmitter {
1491
1535
  }
1492
1536
 
1493
1537
  session.send(
1494
- getProtocol().createNotification('info', 'Editor', `Opened ${require('path').basename(fullPath)}`)
1538
+ getProtocol().createNotification(
1539
+ 'info',
1540
+ 'Editor',
1541
+ `Opened ${require('path').basename(fullPath)}`
1542
+ )
1495
1543
  );
1496
1544
  } catch (error) {
1497
1545
  console.error('[Open File Error]', error.message);
1498
- session.send(getProtocol().createError('OPEN_FILE_ERROR', `Failed to open file: ${error.message}`));
1546
+ session.send(
1547
+ getProtocol().createError('OPEN_FILE_ERROR', `Failed to open file: ${error.message}`)
1548
+ );
1499
1549
  }
1500
1550
  }
1501
1551
 
@@ -1508,10 +1558,15 @@ class DashboardServer extends EventEmitter {
1508
1558
  // Validate cwd stays within project root
1509
1559
  let safeCwd = this.projectRoot;
1510
1560
  if (cwd) {
1511
- const cwdResult = getValidatePaths().validatePath(cwd, this.projectRoot, { allowSymlinks: true });
1561
+ const cwdResult = getValidatePaths().validatePath(cwd, this.projectRoot, {
1562
+ allowSymlinks: true,
1563
+ });
1512
1564
  if (!cwdResult.ok) {
1513
1565
  session.send(
1514
- getProtocol().createError('TERMINAL_ERROR', 'Working directory must be within project root')
1566
+ getProtocol().createError(
1567
+ 'TERMINAL_ERROR',
1568
+ 'Working directory must be within project root'
1569
+ )
1515
1570
  );
1516
1571
  return;
1517
1572
  }
@@ -1684,7 +1739,9 @@ class DashboardServer extends EventEmitter {
1684
1739
  }
1685
1740
 
1686
1741
  if (!this._automationRunner) {
1687
- session.send(getProtocol().createError('AUTOMATION_ERROR', 'Automation runner not initialized'));
1742
+ session.send(
1743
+ getProtocol().createError('AUTOMATION_ERROR', 'Automation runner not initialized')
1744
+ );
1688
1745
  return;
1689
1746
  }
1690
1747
 
@@ -1692,12 +1749,18 @@ class DashboardServer extends EventEmitter {
1692
1749
  // Check if already running
1693
1750
  if (this._runningAutomations.has(automationId)) {
1694
1751
  session.send(
1695
- getProtocol().createNotification('warning', 'Automation', `${automationId} is already running`)
1752
+ getProtocol().createNotification(
1753
+ 'warning',
1754
+ 'Automation',
1755
+ `${automationId} is already running`
1756
+ )
1696
1757
  );
1697
1758
  return;
1698
1759
  }
1699
1760
 
1700
- session.send(getProtocol().createNotification('info', 'Automation', `Starting ${automationId}...`));
1761
+ session.send(
1762
+ getProtocol().createNotification('info', 'Automation', `Starting ${automationId}...`)
1763
+ );
1701
1764
 
1702
1765
  // Run the automation (async)
1703
1766
  const result = await this._automationRunner.run(automationId);
@@ -1705,23 +1768,39 @@ class DashboardServer extends EventEmitter {
1705
1768
  // Send result notification
1706
1769
  if (result.success) {
1707
1770
  session.send(
1708
- getProtocol().createNotification('success', 'Automation', `${automationId} completed successfully`)
1771
+ getProtocol().createNotification(
1772
+ 'success',
1773
+ 'Automation',
1774
+ `${automationId} completed successfully`
1775
+ )
1709
1776
  );
1710
1777
  } else {
1711
1778
  session.send(
1712
- getProtocol().createNotification('error', 'Automation', `${automationId} failed: ${result.error}`)
1779
+ getProtocol().createNotification(
1780
+ 'error',
1781
+ 'Automation',
1782
+ `${automationId} failed: ${result.error}`
1783
+ )
1713
1784
  );
1714
1785
  }
1715
1786
 
1716
1787
  // Send final status
1717
- session.send(getProtocol().createAutomationStatus(automationId, result.success ? 'idle' : 'error', result));
1788
+ session.send(
1789
+ getProtocol().createAutomationStatus(
1790
+ automationId,
1791
+ result.success ? 'idle' : 'error',
1792
+ result
1793
+ )
1794
+ );
1718
1795
 
1719
1796
  // Refresh the list
1720
1797
  this.sendAutomationList(session);
1721
1798
  } catch (error) {
1722
1799
  console.error('[Automation Error]', error.message);
1723
1800
  session.send(getProtocol().createError('AUTOMATION_ERROR', 'Automation execution failed'));
1724
- session.send(getProtocol().createAutomationStatus(automationId, 'error', { error: 'Execution failed' }));
1801
+ session.send(
1802
+ getProtocol().createAutomationStatus(automationId, 'error', { error: 'Execution failed' })
1803
+ );
1725
1804
  }
1726
1805
  }
1727
1806
 
@@ -1782,7 +1861,9 @@ class DashboardServer extends EventEmitter {
1782
1861
  case 'accept':
1783
1862
  // Mark as accepted and remove
1784
1863
  item.status = 'accepted';
1785
- session.send(getProtocol().createNotification('success', 'Inbox', `Accepted: ${item.title}`));
1864
+ session.send(
1865
+ getProtocol().createNotification('success', 'Inbox', `Accepted: ${item.title}`)
1866
+ );
1786
1867
  this._inbox.delete(itemId);
1787
1868
  break;
1788
1869
 
@@ -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
 
@@ -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.0",
3
+ "version": "3.0.2",
4
4
  "description": "AI-driven agile development system for Claude Code, Cursor, Windsurf, and more",
5
5
  "keywords": [
6
6
  "agile",