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.
- package/CHANGELOG.md +10 -0
- package/README.md +8 -8
- package/lib/api-server.js +3 -2
- package/lib/feedback.js +9 -2
- package/lib/flag-detection.js +4 -2
- package/lib/git-operations.js +4 -2
- package/lib/lazy-require.js +59 -0
- package/lib/process-executor.js +24 -9
- package/lib/skill-loader.js +11 -3
- package/package.json +1 -1
- package/scripts/agileflow-configure.js +12 -0
- package/scripts/agileflow-welcome.js +146 -90
- package/scripts/claude-tmux.sh +42 -6
- package/scripts/damage-control-multi-agent.js +14 -10
- package/scripts/lib/bus-utils.js +3 -1
- package/scripts/lib/configure-detect.js +12 -9
- package/scripts/lib/configure-features.js +128 -7
- package/scripts/lib/configure-repair.js +6 -5
- package/scripts/lib/context-formatter.js +13 -3
- package/scripts/lib/damage-control-utils.js +5 -1
- package/scripts/lib/lifecycle-detector.js +5 -3
- package/scripts/lib/process-cleanup.js +8 -4
- package/scripts/lib/scale-detector.js +47 -8
- package/scripts/lib/signal-detectors.js +117 -59
- package/scripts/lib/task-registry.js +5 -1
- package/scripts/lib/team-events.js +4 -4
- package/scripts/messaging-bridge.js +7 -1
- package/scripts/ralph-loop.js +10 -8
- package/scripts/smart-detect.js +32 -11
- package/scripts/team-manager.js +86 -1
- package/scripts/tmux-task-name.sh +105 -0
- package/scripts/tmux-task-watcher.sh +344 -0
- package/src/core/agents/legal-analyzer-a11y.md +110 -0
- package/src/core/agents/legal-analyzer-ai.md +117 -0
- package/src/core/agents/legal-analyzer-consumer.md +108 -0
- package/src/core/agents/legal-analyzer-content.md +113 -0
- package/src/core/agents/legal-analyzer-international.md +115 -0
- package/src/core/agents/legal-analyzer-licensing.md +115 -0
- package/src/core/agents/legal-analyzer-privacy.md +108 -0
- package/src/core/agents/legal-analyzer-security.md +112 -0
- package/src/core/agents/legal-analyzer-terms.md +111 -0
- package/src/core/agents/legal-consensus.md +242 -0
- package/src/core/agents/team-lead.md +50 -13
- package/src/core/commands/babysit.md +75 -42
- package/src/core/commands/blockers.md +7 -7
- package/src/core/commands/configure.md +15 -61
- package/src/core/commands/discovery/brief.md +363 -0
- package/src/core/commands/discovery/new.md +395 -0
- package/src/core/commands/ideate/new.md +5 -5
- package/src/core/commands/legal/audit.md +446 -0
- package/src/core/commands/logic/audit.md +5 -5
- package/src/core/commands/review.md +7 -1
- package/src/core/commands/rpi.md +61 -26
- package/src/core/commands/sprint.md +7 -6
- package/src/core/commands/team/start.md +36 -7
- package/src/core/commands/team/stop.md +5 -2
- package/src/core/templates/product-brief.md +136 -0
- package/tools/cli/installers/ide/claude-code.js +69 -2
- package/src/core/agents/configuration/archival.md +0 -350
- package/src/core/agents/configuration/attribution.md +0 -343
- package/src/core/agents/configuration/ci.md +0 -1103
- package/src/core/agents/configuration/damage-control.md +0 -375
- package/src/core/agents/configuration/git-config.md +0 -537
- package/src/core/agents/configuration/hooks.md +0 -623
- package/src/core/agents/configuration/precompact.md +0 -302
- package/src/core/agents/configuration/status-line.md +0 -557
- package/src/core/agents/configuration/verify.md +0 -618
- package/src/core/agents/configuration-damage-control.md +0 -259
- package/src/core/agents/configuration-visual-e2e.md +0 -339
|
@@ -55,7 +55,8 @@ const FEATURES = {
|
|
|
55
55
|
},
|
|
56
56
|
claudeflags: {
|
|
57
57
|
metadataOnly: false,
|
|
58
|
-
description:
|
|
58
|
+
description:
|
|
59
|
+
'Default flags for Claude CLI (sets permissions.defaultMode in .claude/settings.json)',
|
|
59
60
|
},
|
|
60
61
|
agentteams: {
|
|
61
62
|
metadataOnly: false,
|
|
@@ -459,12 +460,16 @@ function enableFeature(feature, options = {}, version) {
|
|
|
459
460
|
: null;
|
|
460
461
|
writeJSON('.claude/settings.json', settings);
|
|
461
462
|
updateMetadata(
|
|
462
|
-
{
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
463
|
+
{
|
|
464
|
+
features: {
|
|
465
|
+
[feature]: {
|
|
466
|
+
enabled: true,
|
|
467
|
+
version,
|
|
468
|
+
...(contentHash ? { contentHash } : {}),
|
|
469
|
+
at: new Date().toISOString(),
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
},
|
|
468
473
|
version
|
|
469
474
|
);
|
|
470
475
|
updateGitignore();
|
|
@@ -1210,6 +1215,119 @@ function upgradeFeatures(status, version) {
|
|
|
1210
1215
|
return upgraded > 0;
|
|
1211
1216
|
}
|
|
1212
1217
|
|
|
1218
|
+
// ============================================================================
|
|
1219
|
+
// STARTUP MODE (atomic command)
|
|
1220
|
+
// ============================================================================
|
|
1221
|
+
|
|
1222
|
+
/**
|
|
1223
|
+
* Valid startup modes and their mappings
|
|
1224
|
+
*/
|
|
1225
|
+
const STARTUP_MODES = {
|
|
1226
|
+
'skip-permissions': {
|
|
1227
|
+
flags: '--dangerously-skip-permissions',
|
|
1228
|
+
defaultMode: 'bypassPermissions',
|
|
1229
|
+
description: 'Skip all permission prompts (trusted mode)',
|
|
1230
|
+
},
|
|
1231
|
+
'accept-edits': {
|
|
1232
|
+
flags: '--permission-mode acceptEdits',
|
|
1233
|
+
defaultMode: 'acceptEdits',
|
|
1234
|
+
description: 'Auto-accept file edits, prompt for other actions',
|
|
1235
|
+
},
|
|
1236
|
+
normal: {
|
|
1237
|
+
flags: null,
|
|
1238
|
+
defaultMode: null,
|
|
1239
|
+
description: 'Standard Claude with permission prompts',
|
|
1240
|
+
},
|
|
1241
|
+
'no-claude': {
|
|
1242
|
+
flags: null,
|
|
1243
|
+
defaultMode: null,
|
|
1244
|
+
description: 'Create worktree only, start Claude manually',
|
|
1245
|
+
},
|
|
1246
|
+
};
|
|
1247
|
+
|
|
1248
|
+
/**
|
|
1249
|
+
* Set startup mode atomically - updates BOTH metadata AND .claude/settings.json
|
|
1250
|
+
* This replaces the fragile two-step process of updating metadata + running --enable=claudeflags
|
|
1251
|
+
*
|
|
1252
|
+
* @param {string} mode - One of: skip-permissions, accept-edits, normal, no-claude
|
|
1253
|
+
* @param {string} version - Current version string
|
|
1254
|
+
* @returns {boolean} Success
|
|
1255
|
+
*/
|
|
1256
|
+
function enableStartupMode(mode, version) {
|
|
1257
|
+
const modeConfig = STARTUP_MODES[mode];
|
|
1258
|
+
if (!modeConfig) {
|
|
1259
|
+
error(`Unknown startup mode: ${mode}`);
|
|
1260
|
+
log(` Valid modes: ${Object.keys(STARTUP_MODES).join(', ')}`, c.dim);
|
|
1261
|
+
return false;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
ensureDir('.claude');
|
|
1265
|
+
const settings = readJSON('.claude/settings.json') || {};
|
|
1266
|
+
settings.permissions = settings.permissions || { allow: [], deny: [], ask: [] };
|
|
1267
|
+
|
|
1268
|
+
if (mode === 'normal' || mode === 'no-claude') {
|
|
1269
|
+
// Remove defaultMode from settings
|
|
1270
|
+
if (settings.permissions.defaultMode) {
|
|
1271
|
+
delete settings.permissions.defaultMode;
|
|
1272
|
+
}
|
|
1273
|
+
writeJSON('.claude/settings.json', settings);
|
|
1274
|
+
|
|
1275
|
+
// Disable claudeflags + set defaultStartupMode in metadata (single write)
|
|
1276
|
+
updateMetadata(
|
|
1277
|
+
{
|
|
1278
|
+
features: {
|
|
1279
|
+
claudeFlags: {
|
|
1280
|
+
enabled: false,
|
|
1281
|
+
defaultFlags: '',
|
|
1282
|
+
version,
|
|
1283
|
+
at: new Date().toISOString(),
|
|
1284
|
+
},
|
|
1285
|
+
},
|
|
1286
|
+
},
|
|
1287
|
+
version
|
|
1288
|
+
);
|
|
1289
|
+
} else {
|
|
1290
|
+
// Set defaultMode in settings.json
|
|
1291
|
+
settings.permissions.defaultMode = modeConfig.defaultMode;
|
|
1292
|
+
writeJSON('.claude/settings.json', settings);
|
|
1293
|
+
|
|
1294
|
+
// Enable claudeflags + set defaultStartupMode in metadata (single write)
|
|
1295
|
+
updateMetadata(
|
|
1296
|
+
{
|
|
1297
|
+
features: {
|
|
1298
|
+
claudeFlags: {
|
|
1299
|
+
enabled: true,
|
|
1300
|
+
defaultFlags: modeConfig.flags,
|
|
1301
|
+
version,
|
|
1302
|
+
at: new Date().toISOString(),
|
|
1303
|
+
},
|
|
1304
|
+
},
|
|
1305
|
+
},
|
|
1306
|
+
version
|
|
1307
|
+
);
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
// Set defaultStartupMode in metadata (updateMetadata already created file if missing)
|
|
1311
|
+
const metaPath = 'docs/00-meta/agileflow-metadata.json';
|
|
1312
|
+
const meta = readJSON(metaPath) || {};
|
|
1313
|
+
meta.defaultStartupMode = mode;
|
|
1314
|
+
meta.updated = new Date().toISOString();
|
|
1315
|
+
writeJSON(metaPath, meta);
|
|
1316
|
+
|
|
1317
|
+
success(`Default startup mode set to: ${mode}`);
|
|
1318
|
+
if (modeConfig.defaultMode) {
|
|
1319
|
+
info(`Set permissions.defaultMode = "${modeConfig.defaultMode}" in .claude/settings.json`);
|
|
1320
|
+
} else {
|
|
1321
|
+
info('Removed permissions.defaultMode from .claude/settings.json');
|
|
1322
|
+
}
|
|
1323
|
+
info(`Metadata: defaultStartupMode = "${mode}"`);
|
|
1324
|
+
if (mode !== 'normal') {
|
|
1325
|
+
info('Restart Claude Code for the new mode to take effect');
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
return true;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1213
1331
|
// ============================================================================
|
|
1214
1332
|
// SHELL ALIASES
|
|
1215
1333
|
// ============================================================================
|
|
@@ -1468,6 +1586,9 @@ module.exports = {
|
|
|
1468
1586
|
// Helpers
|
|
1469
1587
|
scriptExists,
|
|
1470
1588
|
getScriptPath,
|
|
1589
|
+
// Startup mode
|
|
1590
|
+
enableStartupMode,
|
|
1591
|
+
STARTUP_MODES,
|
|
1471
1592
|
// Shell aliases
|
|
1472
1593
|
enableShellAliases,
|
|
1473
1594
|
disableShellAliases,
|
|
@@ -116,11 +116,12 @@ function listScripts() {
|
|
|
116
116
|
// Check if modified
|
|
117
117
|
let isModified = false;
|
|
118
118
|
if (exists && fileIndex?.files?.[`scripts/${script}`]) {
|
|
119
|
-
isModified =
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
119
|
+
isModified =
|
|
120
|
+
tryOptional(() => {
|
|
121
|
+
const currentHash = sha256(fs.readFileSync(scriptPath));
|
|
122
|
+
const indexHash = fileIndex.files[`scripts/${script}`].sha256;
|
|
123
|
+
return currentHash !== indexHash;
|
|
124
|
+
}, 'hash check') ?? false;
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
// Print status
|
|
@@ -323,7 +323,11 @@ function generateSummary(prefetched = null, options = {}) {
|
|
|
323
323
|
|
|
324
324
|
// Scale indicator (EP-0033)
|
|
325
325
|
let scaleDetectorSummary;
|
|
326
|
-
try {
|
|
326
|
+
try {
|
|
327
|
+
scaleDetectorSummary = require('./scale-detector');
|
|
328
|
+
} catch {
|
|
329
|
+
/* not available */
|
|
330
|
+
}
|
|
327
331
|
if (scaleDetectorSummary) {
|
|
328
332
|
try {
|
|
329
333
|
const scaleResult = scaleDetectorSummary.detectScale({
|
|
@@ -503,7 +507,11 @@ function generateFullContent(prefetched = null, options = {}) {
|
|
|
503
507
|
|
|
504
508
|
// SCALE DETECTION (EP-0033)
|
|
505
509
|
let scaleDetector;
|
|
506
|
-
try {
|
|
510
|
+
try {
|
|
511
|
+
scaleDetector = require('./scale-detector');
|
|
512
|
+
} catch {
|
|
513
|
+
/* not available */
|
|
514
|
+
}
|
|
507
515
|
if (scaleDetector) {
|
|
508
516
|
try {
|
|
509
517
|
const scaleResult = scaleDetector.detectScale({
|
|
@@ -886,7 +894,9 @@ function generateRemainingContent(prefetched, options = {}) {
|
|
|
886
894
|
|
|
887
895
|
// Show auto-enabled modes
|
|
888
896
|
const modes = auto_enabled || {};
|
|
889
|
-
const enabledModes = Object.entries(modes)
|
|
897
|
+
const enabledModes = Object.entries(modes)
|
|
898
|
+
.filter(([, v]) => v)
|
|
899
|
+
.map(([k]) => k.replace('_', ' '));
|
|
890
900
|
if (enabledModes.length > 0) {
|
|
891
901
|
content += `\n${C.mintGreen}Auto-enabled:${C.reset} ${enabledModes.join(', ')}\n`;
|
|
892
902
|
}
|
|
@@ -96,7 +96,11 @@ function loadPatterns(projectRoot, parseYAML, defaultConfig = {}) {
|
|
|
96
96
|
const stat = fs.statSync(fullPath);
|
|
97
97
|
const mtime = stat.mtimeMs;
|
|
98
98
|
|
|
99
|
-
if (
|
|
99
|
+
if (
|
|
100
|
+
_patternCache.filePath === fullPath &&
|
|
101
|
+
_patternCache.mtime === mtime &&
|
|
102
|
+
_patternCache.config
|
|
103
|
+
) {
|
|
100
104
|
return _patternCache.config;
|
|
101
105
|
}
|
|
102
106
|
|
|
@@ -92,7 +92,9 @@ function detectLifecyclePhase(signals = {}) {
|
|
|
92
92
|
return {
|
|
93
93
|
phase: 'pre-story',
|
|
94
94
|
confidence: story.id ? 0.6 : 0.9,
|
|
95
|
-
reason: story.id
|
|
95
|
+
reason: story.id
|
|
96
|
+
? `Story ${story.id} not yet started (status: ${story.status || 'unknown'})`
|
|
97
|
+
: 'No active story',
|
|
96
98
|
};
|
|
97
99
|
}
|
|
98
100
|
|
|
@@ -107,8 +109,8 @@ function getRelevantPhases(phase) {
|
|
|
107
109
|
// Each phase also includes adjacent phase features (for smooth transitions)
|
|
108
110
|
const phaseMap = {
|
|
109
111
|
'pre-story': ['pre-story'],
|
|
110
|
-
|
|
111
|
-
|
|
112
|
+
planning: ['pre-story', 'planning'],
|
|
113
|
+
implementation: ['planning', 'implementation'],
|
|
112
114
|
'post-impl': ['implementation', 'post-impl'],
|
|
113
115
|
'pre-pr': ['post-impl', 'pre-pr'],
|
|
114
116
|
};
|
|
@@ -104,7 +104,8 @@ function getProcessStartTime(pid) {
|
|
|
104
104
|
|
|
105
105
|
if (process.platform === 'darwin') {
|
|
106
106
|
const result = executeCommandSync('ps', ['-o', 'lstart=', '-p', String(pid)], {
|
|
107
|
-
timeout: 2000,
|
|
107
|
+
timeout: 2000,
|
|
108
|
+
fallback: null,
|
|
108
109
|
});
|
|
109
110
|
if (result.data === null) return null;
|
|
110
111
|
const ts = new Date(result.data).getTime();
|
|
@@ -142,7 +143,8 @@ function getParentPid(pid) {
|
|
|
142
143
|
|
|
143
144
|
if (process.platform === 'darwin') {
|
|
144
145
|
const result = executeCommandSync('ps', ['-o', 'ppid=', '-p', String(pid)], {
|
|
145
|
-
timeout: 2000,
|
|
146
|
+
timeout: 2000,
|
|
147
|
+
fallback: null,
|
|
146
148
|
});
|
|
147
149
|
if (result.data === null) return null;
|
|
148
150
|
const ppid = parseInt(result.data, 10);
|
|
@@ -172,7 +174,8 @@ function getArgsForPid(pid) {
|
|
|
172
174
|
|
|
173
175
|
if (process.platform === 'darwin') {
|
|
174
176
|
const result = executeCommandSync('ps', ['-o', 'command=', '-p', String(pid)], {
|
|
175
|
-
timeout: 2000,
|
|
177
|
+
timeout: 2000,
|
|
178
|
+
fallback: null,
|
|
176
179
|
});
|
|
177
180
|
if (result.data === null) return [];
|
|
178
181
|
return result.data ? [result.data] : [];
|
|
@@ -292,7 +295,8 @@ function findClaudeProcesses() {
|
|
|
292
295
|
// Get cwd via lsof (slower but works on macOS)
|
|
293
296
|
let cwd = null;
|
|
294
297
|
const lsofResult = executeCommandSync('lsof', ['-p', String(pid)], {
|
|
295
|
-
timeout: 1000,
|
|
298
|
+
timeout: 1000,
|
|
299
|
+
fallback: null,
|
|
296
300
|
});
|
|
297
301
|
if (lsofResult.data) {
|
|
298
302
|
const cwdLine = lsofResult.data.split('\n').find(l => l.includes('cwd'));
|
|
@@ -38,17 +38,54 @@ const SCALE_THRESHOLDS = {
|
|
|
38
38
|
|
|
39
39
|
// Directories to exclude from file counting
|
|
40
40
|
const EXCLUDE_DIRS = new Set([
|
|
41
|
-
'node_modules',
|
|
42
|
-
'
|
|
43
|
-
'
|
|
41
|
+
'node_modules',
|
|
42
|
+
'.git',
|
|
43
|
+
'dist',
|
|
44
|
+
'build',
|
|
45
|
+
'.next',
|
|
46
|
+
'.nuxt',
|
|
47
|
+
'coverage',
|
|
48
|
+
'.agileflow',
|
|
49
|
+
'.claude',
|
|
50
|
+
'__pycache__',
|
|
51
|
+
'.venv',
|
|
52
|
+
'vendor',
|
|
53
|
+
'target',
|
|
54
|
+
'out',
|
|
55
|
+
'.cache',
|
|
56
|
+
'.turbo',
|
|
57
|
+
'.vercel',
|
|
44
58
|
]);
|
|
45
59
|
|
|
46
60
|
// Source file extensions to count
|
|
47
61
|
const SOURCE_EXTENSIONS = new Set([
|
|
48
|
-
'.js',
|
|
49
|
-
'.
|
|
50
|
-
'.
|
|
51
|
-
'.
|
|
62
|
+
'.js',
|
|
63
|
+
'.jsx',
|
|
64
|
+
'.ts',
|
|
65
|
+
'.tsx',
|
|
66
|
+
'.py',
|
|
67
|
+
'.rb',
|
|
68
|
+
'.go',
|
|
69
|
+
'.rs',
|
|
70
|
+
'.java',
|
|
71
|
+
'.kt',
|
|
72
|
+
'.swift',
|
|
73
|
+
'.c',
|
|
74
|
+
'.cpp',
|
|
75
|
+
'.h',
|
|
76
|
+
'.cs',
|
|
77
|
+
'.vue',
|
|
78
|
+
'.svelte',
|
|
79
|
+
'.astro',
|
|
80
|
+
'.php',
|
|
81
|
+
'.sh',
|
|
82
|
+
'.bash',
|
|
83
|
+
'.css',
|
|
84
|
+
'.scss',
|
|
85
|
+
'.less',
|
|
86
|
+
'.html',
|
|
87
|
+
'.sql',
|
|
88
|
+
'.graphql',
|
|
52
89
|
]);
|
|
53
90
|
|
|
54
91
|
/**
|
|
@@ -123,7 +160,9 @@ function countStories(statusJson, rootDir) {
|
|
|
123
160
|
*/
|
|
124
161
|
function countGitCommits(rootDir) {
|
|
125
162
|
const result = git(['rev-list', '--count', '--since=6 months ago', 'HEAD'], {
|
|
126
|
-
cwd: rootDir,
|
|
163
|
+
cwd: rootDir,
|
|
164
|
+
timeout: 5000,
|
|
165
|
+
fallback: '0',
|
|
127
166
|
});
|
|
128
167
|
const count = parseInt(result.data, 10);
|
|
129
168
|
return isNaN(count) ? 0 : count;
|