agileflow 3.3.0 → 3.4.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 +5 -0
- package/README.md +6 -6
- package/lib/skill-loader.js +0 -1
- package/package.json +1 -1
- package/scripts/agileflow-statusline.sh +81 -0
- package/scripts/claude-tmux.sh +113 -22
- package/scripts/claude-watchdog.sh +225 -0
- package/scripts/generators/agent-registry.js +14 -1
- package/scripts/generators/inject-babysit.js +22 -9
- package/scripts/generators/inject-help.js +19 -9
- package/scripts/lib/audit-cleanup.js +250 -0
- package/scripts/lib/audit-registry.js +248 -0
- package/scripts/lib/feature-catalog.js +3 -3
- package/scripts/lib/gate-enforcer.js +295 -0
- package/scripts/lib/model-profiles.js +98 -0
- package/scripts/lib/signal-detectors.js +1 -1
- package/scripts/lib/skill-catalog.js +557 -0
- package/scripts/lib/skill-recommender.js +311 -0
- package/scripts/lib/tdd-phase-manager.js +455 -0
- package/scripts/lib/team-events.js +34 -3
- package/scripts/lib/tmux-group-colors.js +113 -0
- package/scripts/messaging-bridge.js +209 -1
- package/scripts/spawn-audit-sessions.js +549 -0
- package/scripts/team-manager.js +37 -16
- package/scripts/tmux-close-windows.sh +180 -0
- package/src/core/agents/ads-audit-budget.md +181 -0
- package/src/core/agents/ads-audit-compliance.md +169 -0
- package/src/core/agents/ads-audit-creative.md +164 -0
- package/src/core/agents/ads-audit-google.md +226 -0
- package/src/core/agents/ads-audit-meta.md +183 -0
- package/src/core/agents/ads-audit-tracking.md +197 -0
- package/src/core/agents/ads-consensus.md +322 -0
- package/src/core/agents/brainstorm-analyzer-features.md +169 -0
- package/src/core/agents/brainstorm-analyzer-growth.md +161 -0
- package/src/core/agents/brainstorm-analyzer-integration.md +172 -0
- package/src/core/agents/brainstorm-analyzer-market.md +147 -0
- package/src/core/agents/brainstorm-analyzer-ux.md +167 -0
- package/src/core/agents/brainstorm-consensus.md +237 -0
- package/src/core/agents/completeness-consensus.md +5 -5
- package/src/core/agents/perf-consensus.md +2 -2
- package/src/core/agents/security-consensus.md +2 -2
- package/src/core/agents/seo-analyzer-content.md +167 -0
- package/src/core/agents/seo-analyzer-images.md +187 -0
- package/src/core/agents/seo-analyzer-performance.md +206 -0
- package/src/core/agents/seo-analyzer-schema.md +176 -0
- package/src/core/agents/seo-analyzer-sitemap.md +172 -0
- package/src/core/agents/seo-analyzer-technical.md +144 -0
- package/src/core/agents/seo-consensus.md +289 -0
- package/src/core/agents/test-consensus.md +2 -2
- package/src/core/commands/ads/audit.md +375 -0
- package/src/core/commands/ads/budget.md +97 -0
- package/src/core/commands/ads/competitor.md +112 -0
- package/src/core/commands/ads/creative.md +85 -0
- package/src/core/commands/ads/google.md +112 -0
- package/src/core/commands/ads/landing.md +119 -0
- package/src/core/commands/ads/linkedin.md +112 -0
- package/src/core/commands/ads/meta.md +91 -0
- package/src/core/commands/ads/microsoft.md +115 -0
- package/src/core/commands/ads/plan.md +321 -0
- package/src/core/commands/ads/tiktok.md +129 -0
- package/src/core/commands/ads/youtube.md +124 -0
- package/src/core/commands/ads.md +128 -0
- package/src/core/commands/babysit.md +249 -1284
- package/src/core/commands/{audit → code}/completeness.md +35 -25
- package/src/core/commands/{audit → code}/legal.md +26 -16
- package/src/core/commands/{audit → code}/logic.md +27 -16
- package/src/core/commands/{audit → code}/performance.md +30 -20
- package/src/core/commands/{audit → code}/security.md +32 -19
- package/src/core/commands/{audit → code}/test.md +30 -20
- package/src/core/commands/{discovery → ideate}/brief.md +12 -12
- package/src/core/commands/{discovery/new.md → ideate/discover.md} +13 -13
- package/src/core/commands/ideate/features.md +435 -0
- package/src/core/commands/seo/audit.md +373 -0
- package/src/core/commands/seo/competitor.md +174 -0
- package/src/core/commands/seo/content.md +107 -0
- package/src/core/commands/seo/geo.md +229 -0
- package/src/core/commands/seo/hreflang.md +140 -0
- package/src/core/commands/seo/images.md +96 -0
- package/src/core/commands/seo/page.md +198 -0
- package/src/core/commands/seo/plan.md +163 -0
- package/src/core/commands/seo/programmatic.md +131 -0
- package/src/core/commands/seo/references/cwv-thresholds.md +64 -0
- package/src/core/commands/seo/references/eeat-framework.md +110 -0
- package/src/core/commands/seo/references/quality-gates.md +91 -0
- package/src/core/commands/seo/references/schema-types.md +102 -0
- package/src/core/commands/seo/schema.md +183 -0
- package/src/core/commands/seo/sitemap.md +97 -0
- package/src/core/commands/seo/technical.md +100 -0
- package/src/core/commands/seo.md +107 -0
- package/src/core/commands/skill/list.md +68 -212
- package/src/core/commands/skill/recommend.md +216 -0
- package/src/core/commands/tdd-next.md +238 -0
- package/src/core/commands/tdd.md +210 -0
- package/src/core/experts/_core-expertise.yaml +105 -0
- package/src/core/experts/analytics/expertise.yaml +5 -99
- package/src/core/experts/codebase-query/expertise.yaml +3 -72
- package/src/core/experts/compliance/expertise.yaml +6 -72
- package/src/core/experts/database/expertise.yaml +9 -52
- package/src/core/experts/documentation/expertise.yaml +7 -140
- package/src/core/experts/integrations/expertise.yaml +7 -127
- package/src/core/experts/mentor/expertise.yaml +8 -35
- package/src/core/experts/monitoring/expertise.yaml +7 -49
- package/src/core/experts/performance/expertise.yaml +1 -26
- package/src/core/experts/security/expertise.yaml +9 -34
- package/src/core/experts/ui/expertise.yaml +6 -36
- package/src/core/knowledge/ads/ad-audit-checklist-scoring.md +424 -0
- package/src/core/knowledge/ads/ad-optimization-logic.md +590 -0
- package/src/core/knowledge/ads/ad-technical-specifications.md +385 -0
- package/src/core/knowledge/ads/definitive-advertising-reference-2026.md +506 -0
- package/src/core/knowledge/ads/paid-advertising-research-2026.md +445 -0
- package/src/core/templates/agileflow-metadata.json +15 -1
- package/tools/cli/installers/ide/_base-ide.js +42 -5
- package/tools/cli/installers/ide/claude-code.js +3 -3
- package/tools/cli/lib/content-injector.js +160 -12
- package/tools/cli/lib/docs-setup.js +1 -1
- package/src/core/commands/skill/create.md +0 -698
- package/src/core/commands/skill/delete.md +0 -316
- package/src/core/commands/skill/edit.md +0 -359
- package/src/core/commands/skill/test.md +0 -394
- package/src/core/commands/skill/upgrade.md +0 -552
- package/src/core/templates/skill-template.md +0 -117
|
@@ -14,9 +14,11 @@ const { scanAgents } = require('./agent-registry');
|
|
|
14
14
|
const { scanCommands } = require('./command-registry');
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Generate agent list content with
|
|
17
|
+
* Generate agent list content as category summary with counts.
|
|
18
|
+
* Uses compact format with discovery pointer instead of listing every agent name.
|
|
19
|
+
* Research (arXiv:2602.11988): Full lists increase context cost without improving performance.
|
|
18
20
|
* @param {Array} agents - Array of agent metadata
|
|
19
|
-
* @returns {string} Formatted agent
|
|
21
|
+
* @returns {string} Formatted agent category summary
|
|
20
22
|
*/
|
|
21
23
|
function generateAgentList(agents) {
|
|
22
24
|
const lines = [];
|
|
@@ -24,16 +26,27 @@ function generateAgentList(agents) {
|
|
|
24
26
|
lines.push(`**AVAILABLE AGENTS** (${agents.length} total):`);
|
|
25
27
|
lines.push('');
|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
// Group agents by category for compact output (counts only, not full names)
|
|
30
|
+
const categories = {};
|
|
28
31
|
for (const agent of agents) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
const cat = agent.category || 'Other';
|
|
33
|
+
if (!categories[cat]) categories[cat] = { count: 0, examples: [] };
|
|
34
|
+
categories[cat].count++;
|
|
35
|
+
// Keep first 3 names as examples
|
|
36
|
+
if (categories[cat].examples.length < 3) {
|
|
37
|
+
categories[cat].examples.push(agent.name);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
for (const [category, data] of Object.entries(categories)) {
|
|
42
|
+
const examples = data.examples.join(', ');
|
|
43
|
+
const more = data.count > 3 ? `, +${data.count - 3} more` : '';
|
|
44
|
+
lines.push(`**${category}** (${data.count}): ${examples}${more}`);
|
|
35
45
|
}
|
|
36
46
|
|
|
47
|
+
lines.push('');
|
|
48
|
+
lines.push('Browse all: `ls .agileflow/agents/` or run `/agileflow:help agents`');
|
|
49
|
+
|
|
37
50
|
return lines.join('\n');
|
|
38
51
|
}
|
|
39
52
|
|
|
@@ -13,9 +13,11 @@ const path = require('path');
|
|
|
13
13
|
const { scanCommands } = require('./command-registry');
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* Generate command list content
|
|
16
|
+
* Generate command list content as category summary with counts and examples.
|
|
17
|
+
* Uses compact format with discovery pointer instead of listing every command.
|
|
18
|
+
* Research (arXiv:2602.11988): Full lists increase context cost without improving performance.
|
|
17
19
|
* @param {Array} commands - Array of command metadata
|
|
18
|
-
* @returns {string} Formatted command
|
|
20
|
+
* @returns {string} Formatted command category summary
|
|
19
21
|
*/
|
|
20
22
|
function generateCommandList(commands) {
|
|
21
23
|
const lines = [];
|
|
@@ -29,16 +31,24 @@ function generateCommandList(commands) {
|
|
|
29
31
|
categories[cmd.category].push(cmd);
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
lines.push(
|
|
35
|
+
`**${commands.length} commands** across ${Object.keys(categories).length} categories:`
|
|
36
|
+
);
|
|
37
|
+
lines.push('');
|
|
38
|
+
|
|
39
|
+
// Generate compact category summary with examples
|
|
33
40
|
for (const [category, cmds] of Object.entries(categories)) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
lines.push(
|
|
41
|
+
const examples = cmds
|
|
42
|
+
.slice(0, 3)
|
|
43
|
+
.map(c => c.name)
|
|
44
|
+
.join(', ');
|
|
45
|
+
const more = cmds.length > 3 ? `, +${cmds.length - 3} more` : '';
|
|
46
|
+
lines.push(`- **${category}** (${cmds.length}): ${examples}${more}`);
|
|
40
47
|
}
|
|
41
48
|
|
|
49
|
+
lines.push('');
|
|
50
|
+
lines.push('Browse all: `ls .agileflow/commands/` or run `/agileflow:help`');
|
|
51
|
+
|
|
42
52
|
return lines.join('\n');
|
|
43
53
|
}
|
|
44
54
|
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* audit-cleanup.js - Orphan cleanup for ULTRADEEP audit sessions
|
|
3
|
+
*
|
|
4
|
+
* Cleans up abandoned tmux sessions and incomplete sentinel directories
|
|
5
|
+
* from ULTRADEEP audit runs. Designed to be called from Stop hooks or
|
|
6
|
+
* manually for maintenance.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* const { cleanupOrphanSessions } = require('./audit-cleanup');
|
|
10
|
+
* cleanupOrphanSessions(rootDir);
|
|
11
|
+
*
|
|
12
|
+
* CLI:
|
|
13
|
+
* node scripts/lib/audit-cleanup.js [--max-age=60] [--dry-run]
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const { execFileSync } = require('child_process');
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
|
|
20
|
+
const MAX_AGE_MINUTES = 60;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Find all ultradeep trace directories.
|
|
24
|
+
* @param {string} rootDir - Project root
|
|
25
|
+
* @returns {Array<{ traceId: string, dir: string, status: object|null }>}
|
|
26
|
+
*/
|
|
27
|
+
function findTraceDirectories(rootDir) {
|
|
28
|
+
const ultradeepDir = path.join(rootDir, 'docs', '09-agents', 'ultradeep');
|
|
29
|
+
|
|
30
|
+
if (!fs.existsSync(ultradeepDir)) {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const traces = [];
|
|
35
|
+
try {
|
|
36
|
+
const entries = fs.readdirSync(ultradeepDir, { withFileTypes: true });
|
|
37
|
+
for (const entry of entries) {
|
|
38
|
+
if (!entry.isDirectory()) continue;
|
|
39
|
+
|
|
40
|
+
const traceDir = path.join(ultradeepDir, entry.name);
|
|
41
|
+
const statusFile = path.join(traceDir, '_status.json');
|
|
42
|
+
let status = null;
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
if (fs.existsSync(statusFile)) {
|
|
46
|
+
status = JSON.parse(fs.readFileSync(statusFile, 'utf8'));
|
|
47
|
+
}
|
|
48
|
+
} catch (_) {
|
|
49
|
+
// Corrupt status file
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
traces.push({
|
|
53
|
+
traceId: entry.name,
|
|
54
|
+
dir: traceDir,
|
|
55
|
+
status,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
} catch (_) {
|
|
59
|
+
// Directory read failure
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return traces;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Check if a trace is stale (older than maxAge).
|
|
67
|
+
* @param {object} trace - Trace info from findTraceDirectories
|
|
68
|
+
* @param {number} maxAgeMinutes - Maximum age in minutes
|
|
69
|
+
* @returns {boolean}
|
|
70
|
+
*/
|
|
71
|
+
function isStaleTrace(trace, maxAgeMinutes) {
|
|
72
|
+
if (!trace.status || !trace.status.started_at) {
|
|
73
|
+
// No status = assume stale
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const startedAt = new Date(trace.status.started_at).getTime();
|
|
78
|
+
if (isNaN(startedAt)) return true; // Invalid date = treat as stale
|
|
79
|
+
const age = Date.now() - startedAt;
|
|
80
|
+
return age > maxAgeMinutes * 60 * 1000;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Check if a trace is incomplete (not all analyzers have findings).
|
|
85
|
+
* @param {object} trace - Trace info from findTraceDirectories
|
|
86
|
+
* @returns {boolean}
|
|
87
|
+
*/
|
|
88
|
+
function isIncompleteTrace(trace) {
|
|
89
|
+
if (!trace.status || !trace.status.analyzers) return true;
|
|
90
|
+
|
|
91
|
+
const expected = trace.status.analyzers;
|
|
92
|
+
const completed = trace.status.completed || [];
|
|
93
|
+
|
|
94
|
+
return completed.length < expected.length;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Find orphaned tmux sessions matching audit pattern.
|
|
99
|
+
* @returns {string[]} Array of session names
|
|
100
|
+
*/
|
|
101
|
+
function findOrphanedTmuxSessions() {
|
|
102
|
+
try {
|
|
103
|
+
const output = execFileSync('tmux', ['list-sessions', '-F', '#{session_name}'], {
|
|
104
|
+
encoding: 'utf8',
|
|
105
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
106
|
+
}).trim();
|
|
107
|
+
|
|
108
|
+
if (!output) return [];
|
|
109
|
+
|
|
110
|
+
return output.split('\n').filter(name => name.startsWith('audit-'));
|
|
111
|
+
} catch (_) {
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Kill a tmux session by name.
|
|
118
|
+
* @param {string} sessionName - Session name to kill
|
|
119
|
+
* @returns {boolean} True if killed successfully
|
|
120
|
+
*/
|
|
121
|
+
function killTmuxSession(sessionName) {
|
|
122
|
+
try {
|
|
123
|
+
execFileSync('tmux', ['kill-session', '-t', sessionName], {
|
|
124
|
+
stdio: 'pipe',
|
|
125
|
+
});
|
|
126
|
+
return true;
|
|
127
|
+
} catch (_) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Remove a sentinel directory.
|
|
134
|
+
* @param {string} dir - Directory to remove
|
|
135
|
+
* @returns {boolean} True if removed successfully
|
|
136
|
+
*/
|
|
137
|
+
function removeSentinelDir(dir) {
|
|
138
|
+
try {
|
|
139
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
140
|
+
return true;
|
|
141
|
+
} catch (_) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Clean up orphaned ULTRADEEP audit sessions and stale sentinel dirs.
|
|
148
|
+
*
|
|
149
|
+
* @param {string} rootDir - Project root directory
|
|
150
|
+
* @param {object} [options] - Options
|
|
151
|
+
* @param {number} [options.maxAgeMinutes] - Max age for stale traces (default: 60)
|
|
152
|
+
* @param {boolean} [options.dryRun] - If true, report but don't delete
|
|
153
|
+
* @returns {{ sessionsKilled: string[], tracesRemoved: string[], errors: string[] }}
|
|
154
|
+
*/
|
|
155
|
+
function cleanupOrphanSessions(rootDir, options) {
|
|
156
|
+
const maxAge = (options && options.maxAgeMinutes) || MAX_AGE_MINUTES;
|
|
157
|
+
const dryRun = (options && options.dryRun) || false;
|
|
158
|
+
|
|
159
|
+
const result = {
|
|
160
|
+
sessionsKilled: [],
|
|
161
|
+
tracesRemoved: [],
|
|
162
|
+
errors: [],
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// 1. Find and kill orphaned tmux sessions
|
|
166
|
+
const orphanedSessions = findOrphanedTmuxSessions();
|
|
167
|
+
for (const session of orphanedSessions) {
|
|
168
|
+
// Extract trace ID from session name: audit-{type}-{traceId}
|
|
169
|
+
const parts = session.split('-');
|
|
170
|
+
if (parts.length < 3) continue; // Malformed session name, skip
|
|
171
|
+
const traceId = parts.slice(2).join('-');
|
|
172
|
+
|
|
173
|
+
if (dryRun) {
|
|
174
|
+
result.sessionsKilled.push(`${session} (dry-run)`);
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (killTmuxSession(session)) {
|
|
179
|
+
result.sessionsKilled.push(session);
|
|
180
|
+
} else {
|
|
181
|
+
result.errors.push(`Failed to kill session: ${session}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// 2. Clean up stale sentinel directories
|
|
186
|
+
const traces = findTraceDirectories(rootDir);
|
|
187
|
+
for (const trace of traces) {
|
|
188
|
+
if (isStaleTrace(trace, maxAge) && isIncompleteTrace(trace)) {
|
|
189
|
+
if (dryRun) {
|
|
190
|
+
result.tracesRemoved.push(`${trace.traceId} (dry-run)`);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (removeSentinelDir(trace.dir)) {
|
|
195
|
+
result.tracesRemoved.push(trace.traceId);
|
|
196
|
+
} else {
|
|
197
|
+
result.errors.push(`Failed to remove trace dir: ${trace.traceId}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// CLI
|
|
206
|
+
if (require.main === module) {
|
|
207
|
+
const args = process.argv.slice(2);
|
|
208
|
+
let maxAge = MAX_AGE_MINUTES;
|
|
209
|
+
let dryRun = false;
|
|
210
|
+
|
|
211
|
+
for (const arg of args) {
|
|
212
|
+
if (arg.startsWith('--max-age=')) {
|
|
213
|
+
const parsed = parseInt(arg.split('=')[1], 10);
|
|
214
|
+
maxAge = isNaN(parsed) ? MAX_AGE_MINUTES : parsed;
|
|
215
|
+
}
|
|
216
|
+
if (arg === '--dry-run') dryRun = true;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const rootDir = process.cwd();
|
|
220
|
+
const result = cleanupOrphanSessions(rootDir, { maxAgeMinutes: maxAge, dryRun });
|
|
221
|
+
|
|
222
|
+
if (result.sessionsKilled.length > 0) {
|
|
223
|
+
console.log(`Killed ${result.sessionsKilled.length} orphaned session(s):`);
|
|
224
|
+
result.sessionsKilled.forEach(s => console.log(` - ${s}`));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (result.tracesRemoved.length > 0) {
|
|
228
|
+
console.log(`Removed ${result.tracesRemoved.length} stale trace(s):`);
|
|
229
|
+
result.tracesRemoved.forEach(t => console.log(` - ${t}`));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (result.errors.length > 0) {
|
|
233
|
+
console.error(`${result.errors.length} error(s):`);
|
|
234
|
+
result.errors.forEach(e => console.error(` - ${e}`));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (result.sessionsKilled.length === 0 && result.tracesRemoved.length === 0) {
|
|
238
|
+
console.log('No orphaned sessions or stale traces found.');
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
module.exports = {
|
|
243
|
+
findTraceDirectories,
|
|
244
|
+
isStaleTrace,
|
|
245
|
+
isIncompleteTrace,
|
|
246
|
+
findOrphanedTmuxSessions,
|
|
247
|
+
killTmuxSession,
|
|
248
|
+
removeSentinelDir,
|
|
249
|
+
cleanupOrphanSessions,
|
|
250
|
+
};
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* audit-registry.js - Static registry mapping audit types to analyzers
|
|
3
|
+
*
|
|
4
|
+
* Centralizes the mapping of 6 audit commands to their analyzer agents,
|
|
5
|
+
* consensus coordinators, and depth configurations. Previously this info
|
|
6
|
+
* was duplicated across 6 .md command files.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* const { getAuditType, getAnalyzersForAudit } = require('./audit-registry');
|
|
10
|
+
* const security = getAuditType('security');
|
|
11
|
+
* const focused = getAnalyzersForAudit('security', 'deep', ['injection', 'auth']);
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Complete audit type registry.
|
|
16
|
+
* Each entry defines: name, short prefix for tmux, color for tab groups,
|
|
17
|
+
* all analyzers with their subagent_type, which are quick vs deep,
|
|
18
|
+
* and the consensus coordinator.
|
|
19
|
+
*/
|
|
20
|
+
const AUDIT_TYPES = {
|
|
21
|
+
logic: {
|
|
22
|
+
name: 'Logic Analysis',
|
|
23
|
+
prefix: 'Logic',
|
|
24
|
+
color: '#7aa2f7', // sky
|
|
25
|
+
command: 'code/logic',
|
|
26
|
+
analyzers: {
|
|
27
|
+
edge: { subagent_type: 'logic-analyzer-edge', label: 'Edge Cases' },
|
|
28
|
+
invariant: { subagent_type: 'logic-analyzer-invariant', label: 'Invariants' },
|
|
29
|
+
flow: { subagent_type: 'logic-analyzer-flow', label: 'Control Flow' },
|
|
30
|
+
type: { subagent_type: 'logic-analyzer-type', label: 'Type Safety' },
|
|
31
|
+
race: { subagent_type: 'logic-analyzer-race', label: 'Race Conditions' },
|
|
32
|
+
},
|
|
33
|
+
consensus: { subagent_type: 'logic-consensus', label: 'Logic Consensus' },
|
|
34
|
+
quick_analyzers: ['edge', 'invariant', 'flow', 'type', 'race'],
|
|
35
|
+
deep_analyzers: ['edge', 'invariant', 'flow', 'type', 'race'],
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
security: {
|
|
39
|
+
name: 'Security Vulnerability',
|
|
40
|
+
prefix: 'Sec',
|
|
41
|
+
color: '#f7768e', // coral
|
|
42
|
+
command: 'code/security',
|
|
43
|
+
analyzers: {
|
|
44
|
+
injection: { subagent_type: 'security-analyzer-injection', label: 'Injection' },
|
|
45
|
+
auth: { subagent_type: 'security-analyzer-auth', label: 'Authentication' },
|
|
46
|
+
authz: { subagent_type: 'security-analyzer-authz', label: 'Authorization' },
|
|
47
|
+
secrets: { subagent_type: 'security-analyzer-secrets', label: 'Secrets' },
|
|
48
|
+
input: { subagent_type: 'security-analyzer-input', label: 'Input Validation' },
|
|
49
|
+
deps: { subagent_type: 'security-analyzer-deps', label: 'Dependencies' },
|
|
50
|
+
infra: { subagent_type: 'security-analyzer-infra', label: 'Infrastructure' },
|
|
51
|
+
api: { subagent_type: 'security-analyzer-api', label: 'API Security' },
|
|
52
|
+
},
|
|
53
|
+
consensus: { subagent_type: 'security-consensus', label: 'Security Consensus' },
|
|
54
|
+
quick_analyzers: ['injection', 'auth', 'authz', 'secrets', 'input'],
|
|
55
|
+
deep_analyzers: ['injection', 'auth', 'authz', 'secrets', 'input', 'deps', 'infra', 'api'],
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
performance: {
|
|
59
|
+
name: 'Performance Bottleneck',
|
|
60
|
+
prefix: 'Perf',
|
|
61
|
+
color: '#73daca', // mint
|
|
62
|
+
command: 'code/performance',
|
|
63
|
+
analyzers: {
|
|
64
|
+
queries: { subagent_type: 'perf-analyzer-queries', label: 'Queries' },
|
|
65
|
+
rendering: { subagent_type: 'perf-analyzer-rendering', label: 'Rendering' },
|
|
66
|
+
memory: { subagent_type: 'perf-analyzer-memory', label: 'Memory' },
|
|
67
|
+
bundle: { subagent_type: 'perf-analyzer-bundle', label: 'Bundle Size' },
|
|
68
|
+
compute: { subagent_type: 'perf-analyzer-compute', label: 'Compute' },
|
|
69
|
+
network: { subagent_type: 'perf-analyzer-network', label: 'Network' },
|
|
70
|
+
caching: { subagent_type: 'perf-analyzer-caching', label: 'Caching' },
|
|
71
|
+
assets: { subagent_type: 'perf-analyzer-assets', label: 'Assets' },
|
|
72
|
+
},
|
|
73
|
+
consensus: { subagent_type: 'perf-consensus', label: 'Performance Consensus' },
|
|
74
|
+
quick_analyzers: ['queries', 'rendering', 'memory', 'bundle', 'compute'],
|
|
75
|
+
deep_analyzers: [
|
|
76
|
+
'queries',
|
|
77
|
+
'rendering',
|
|
78
|
+
'memory',
|
|
79
|
+
'bundle',
|
|
80
|
+
'compute',
|
|
81
|
+
'network',
|
|
82
|
+
'caching',
|
|
83
|
+
'assets',
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
test: {
|
|
88
|
+
name: 'Test Quality',
|
|
89
|
+
prefix: 'Test',
|
|
90
|
+
color: '#e0af68', // amber
|
|
91
|
+
command: 'code/test',
|
|
92
|
+
analyzers: {
|
|
93
|
+
coverage: { subagent_type: 'test-analyzer-coverage', label: 'Coverage' },
|
|
94
|
+
fragility: { subagent_type: 'test-analyzer-fragility', label: 'Fragility' },
|
|
95
|
+
mocking: { subagent_type: 'test-analyzer-mocking', label: 'Mocking' },
|
|
96
|
+
assertions: { subagent_type: 'test-analyzer-assertions', label: 'Assertions' },
|
|
97
|
+
structure: { subagent_type: 'test-analyzer-structure', label: 'Structure' },
|
|
98
|
+
integration: { subagent_type: 'test-analyzer-integration', label: 'Integration' },
|
|
99
|
+
maintenance: { subagent_type: 'test-analyzer-maintenance', label: 'Maintenance' },
|
|
100
|
+
patterns: { subagent_type: 'test-analyzer-patterns', label: 'Anti-Patterns' },
|
|
101
|
+
},
|
|
102
|
+
consensus: { subagent_type: 'test-consensus', label: 'Test Consensus' },
|
|
103
|
+
quick_analyzers: ['coverage', 'fragility', 'mocking', 'assertions', 'structure'],
|
|
104
|
+
deep_analyzers: [
|
|
105
|
+
'coverage',
|
|
106
|
+
'fragility',
|
|
107
|
+
'mocking',
|
|
108
|
+
'assertions',
|
|
109
|
+
'structure',
|
|
110
|
+
'integration',
|
|
111
|
+
'maintenance',
|
|
112
|
+
'patterns',
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
completeness: {
|
|
117
|
+
name: 'Completeness',
|
|
118
|
+
prefix: 'Comp',
|
|
119
|
+
color: '#bb9af7', // violet
|
|
120
|
+
command: 'code/completeness',
|
|
121
|
+
analyzers: {
|
|
122
|
+
handlers: { subagent_type: 'completeness-analyzer-handlers', label: 'Handlers' },
|
|
123
|
+
routes: { subagent_type: 'completeness-analyzer-routes', label: 'Routes' },
|
|
124
|
+
api: { subagent_type: 'completeness-analyzer-api', label: 'API Endpoints' },
|
|
125
|
+
stubs: { subagent_type: 'completeness-analyzer-stubs', label: 'Stubs' },
|
|
126
|
+
state: { subagent_type: 'completeness-analyzer-state', label: 'State' },
|
|
127
|
+
imports: { subagent_type: 'completeness-analyzer-imports', label: 'Imports' },
|
|
128
|
+
conditional: { subagent_type: 'completeness-analyzer-conditional', label: 'Conditionals' },
|
|
129
|
+
},
|
|
130
|
+
consensus: { subagent_type: 'completeness-consensus', label: 'Completeness Consensus' },
|
|
131
|
+
quick_analyzers: ['handlers', 'routes', 'api', 'stubs', 'state'],
|
|
132
|
+
deep_analyzers: ['handlers', 'routes', 'api', 'stubs', 'state', 'imports', 'conditional'],
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
legal: {
|
|
136
|
+
name: 'Legal Risk',
|
|
137
|
+
prefix: 'Legal',
|
|
138
|
+
color: '#9ece6a', // lime
|
|
139
|
+
command: 'code/legal',
|
|
140
|
+
analyzers: {
|
|
141
|
+
privacy: { subagent_type: 'legal-analyzer-privacy', label: 'Privacy' },
|
|
142
|
+
terms: { subagent_type: 'legal-analyzer-terms', label: 'Terms' },
|
|
143
|
+
a11y: { subagent_type: 'legal-analyzer-a11y', label: 'Accessibility' },
|
|
144
|
+
licensing: { subagent_type: 'legal-analyzer-licensing', label: 'Licensing' },
|
|
145
|
+
consumer: { subagent_type: 'legal-analyzer-consumer', label: 'Consumer' },
|
|
146
|
+
security: { subagent_type: 'legal-analyzer-security', label: 'Security' },
|
|
147
|
+
ai: { subagent_type: 'legal-analyzer-ai', label: 'AI Compliance' },
|
|
148
|
+
content: { subagent_type: 'legal-analyzer-content', label: 'Content' },
|
|
149
|
+
international: { subagent_type: 'legal-analyzer-international', label: 'International' },
|
|
150
|
+
},
|
|
151
|
+
consensus: { subagent_type: 'legal-consensus', label: 'Legal Consensus' },
|
|
152
|
+
quick_analyzers: ['privacy', 'terms', 'a11y', 'licensing', 'consumer'],
|
|
153
|
+
deep_analyzers: [
|
|
154
|
+
'privacy',
|
|
155
|
+
'terms',
|
|
156
|
+
'a11y',
|
|
157
|
+
'licensing',
|
|
158
|
+
'consumer',
|
|
159
|
+
'security',
|
|
160
|
+
'ai',
|
|
161
|
+
'content',
|
|
162
|
+
'international',
|
|
163
|
+
],
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Get audit type configuration.
|
|
169
|
+
*
|
|
170
|
+
* @param {string} type - Audit type key (logic, security, performance, test, completeness, legal)
|
|
171
|
+
* @returns {object|null} Audit type config or null if invalid
|
|
172
|
+
*/
|
|
173
|
+
function getAuditType(type) {
|
|
174
|
+
return AUDIT_TYPES[type] || null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Get all valid audit type keys.
|
|
179
|
+
*
|
|
180
|
+
* @returns {string[]} Array of audit type keys
|
|
181
|
+
*/
|
|
182
|
+
function getAuditTypeKeys() {
|
|
183
|
+
return Object.keys(AUDIT_TYPES);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Get analyzers for a given audit type, depth, and focus.
|
|
188
|
+
*
|
|
189
|
+
* @param {string} type - Audit type key
|
|
190
|
+
* @param {string} [depth='quick'] - 'quick', 'deep', or 'ultradeep'
|
|
191
|
+
* @param {string[]} [focus] - Array of focus areas, or null/['all'] for all
|
|
192
|
+
* @returns {{ analyzers: Array<{ key: string, subagent_type: string, label: string }>, consensus: object }|null}
|
|
193
|
+
*/
|
|
194
|
+
function getAnalyzersForAudit(type, depth, focus) {
|
|
195
|
+
const audit = AUDIT_TYPES[type];
|
|
196
|
+
if (!audit) return null;
|
|
197
|
+
|
|
198
|
+
const effectiveDepth = depth === 'ultradeep' ? 'deep' : depth || 'quick';
|
|
199
|
+
const analyzerKeys = effectiveDepth === 'deep' ? audit.deep_analyzers : audit.quick_analyzers;
|
|
200
|
+
|
|
201
|
+
// Filter by focus if specified
|
|
202
|
+
let selectedKeys = analyzerKeys;
|
|
203
|
+
if (focus && focus.length > 0 && !focus.includes('all')) {
|
|
204
|
+
selectedKeys = analyzerKeys.filter(key => focus.includes(key));
|
|
205
|
+
// If focus specifies keys not in current depth, include them anyway
|
|
206
|
+
for (const f of focus) {
|
|
207
|
+
if (audit.analyzers[f] && !selectedKeys.includes(f)) {
|
|
208
|
+
selectedKeys.push(f);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const analyzers = selectedKeys.map(key => ({
|
|
214
|
+
key,
|
|
215
|
+
subagent_type: audit.analyzers[key].subagent_type,
|
|
216
|
+
label: audit.analyzers[key].label,
|
|
217
|
+
}));
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
analyzers,
|
|
221
|
+
consensus: audit.consensus,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Get analyzer count for a given audit type at each depth.
|
|
227
|
+
*
|
|
228
|
+
* @param {string} type - Audit type key
|
|
229
|
+
* @returns {{ quick: number, deep: number, total: number }|null}
|
|
230
|
+
*/
|
|
231
|
+
function getAnalyzerCounts(type) {
|
|
232
|
+
const audit = AUDIT_TYPES[type];
|
|
233
|
+
if (!audit) return null;
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
quick: audit.quick_analyzers.length,
|
|
237
|
+
deep: audit.deep_analyzers.length,
|
|
238
|
+
total: Object.keys(audit.analyzers).length,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
module.exports = {
|
|
243
|
+
AUDIT_TYPES,
|
|
244
|
+
getAuditType,
|
|
245
|
+
getAuditTypeKeys,
|
|
246
|
+
getAnalyzersForAudit,
|
|
247
|
+
getAnalyzerCounts,
|
|
248
|
+
};
|
|
@@ -116,7 +116,7 @@ const FEATURE_CATALOG = [
|
|
|
116
116
|
feature: 'discovery',
|
|
117
117
|
name: 'Discovery',
|
|
118
118
|
description: 'Brainstorm, research, and synthesize findings into a Product Brief',
|
|
119
|
-
how_to_use: '/agileflow:
|
|
119
|
+
how_to_use: '/agileflow:ideate:discover "<topic>"',
|
|
120
120
|
category: 'workflow',
|
|
121
121
|
detector: null,
|
|
122
122
|
auto_mode: null,
|
|
@@ -168,7 +168,7 @@ const FEATURE_CATALOG = [
|
|
|
168
168
|
feature: 'logic-audit',
|
|
169
169
|
name: 'Logic Audit',
|
|
170
170
|
description: 'Multi-agent analysis for edge cases, race conditions, type bugs, and dead code',
|
|
171
|
-
how_to_use: '/agileflow:
|
|
171
|
+
how_to_use: '/agileflow:code:logic',
|
|
172
172
|
category: 'analysis',
|
|
173
173
|
detector: null,
|
|
174
174
|
auto_mode: null,
|
|
@@ -179,7 +179,7 @@ const FEATURE_CATALOG = [
|
|
|
179
179
|
name: 'Completeness Audit',
|
|
180
180
|
description:
|
|
181
181
|
'Multi-agent analysis for forgotten features, dead handlers, stub code, and incomplete implementations',
|
|
182
|
-
how_to_use: '/agileflow:
|
|
182
|
+
how_to_use: '/agileflow:code:completeness',
|
|
183
183
|
category: 'analysis',
|
|
184
184
|
detector: null,
|
|
185
185
|
auto_mode: null,
|