agileflow 3.1.0 → 3.2.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 +57 -85
- package/lib/dashboard-automations.js +130 -0
- package/lib/dashboard-git.js +254 -0
- package/lib/dashboard-inbox.js +64 -0
- package/lib/dashboard-protocol.js +1 -0
- package/lib/dashboard-server.js +114 -924
- package/lib/dashboard-session.js +136 -0
- package/lib/dashboard-status.js +72 -0
- package/lib/dashboard-terminal.js +354 -0
- package/lib/dashboard-websocket.js +88 -0
- package/lib/drivers/codex-driver.ts +4 -4
- package/lib/logger.js +106 -0
- package/package.json +4 -2
- package/scripts/agileflow-configure.js +2 -2
- package/scripts/agileflow-welcome.js +409 -434
- package/scripts/claude-tmux.sh +80 -2
- package/scripts/context-loader.js +4 -9
- package/scripts/lib/command-prereqs.js +280 -0
- package/scripts/lib/configure-detect.js +92 -2
- package/scripts/lib/configure-features.js +295 -1
- package/scripts/lib/context-formatter.js +468 -233
- package/scripts/lib/context-loader.js +27 -15
- package/scripts/lib/damage-control-utils.js +8 -1
- package/scripts/lib/feature-catalog.js +321 -0
- package/scripts/lib/portable-tasks-cli.js +274 -0
- package/scripts/lib/portable-tasks.js +479 -0
- package/scripts/lib/signal-detectors.js +1 -1
- package/scripts/lib/team-events.js +86 -1
- package/scripts/obtain-context.js +28 -4
- package/scripts/smart-detect.js +17 -0
- package/scripts/strip-ai-attribution.js +63 -0
- package/scripts/team-manager.js +7 -2
- package/scripts/welcome-deferred.js +437 -0
- package/src/core/agents/perf-analyzer-assets.md +174 -0
- package/src/core/agents/perf-analyzer-bundle.md +165 -0
- package/src/core/agents/perf-analyzer-caching.md +160 -0
- package/src/core/agents/perf-analyzer-compute.md +165 -0
- package/src/core/agents/perf-analyzer-memory.md +182 -0
- package/src/core/agents/perf-analyzer-network.md +157 -0
- package/src/core/agents/perf-analyzer-queries.md +155 -0
- package/src/core/agents/perf-analyzer-rendering.md +156 -0
- package/src/core/agents/perf-consensus.md +280 -0
- package/src/core/agents/security-analyzer-api.md +199 -0
- package/src/core/agents/security-analyzer-auth.md +160 -0
- package/src/core/agents/security-analyzer-authz.md +168 -0
- package/src/core/agents/security-analyzer-deps.md +147 -0
- package/src/core/agents/security-analyzer-infra.md +176 -0
- package/src/core/agents/security-analyzer-injection.md +148 -0
- package/src/core/agents/security-analyzer-input.md +191 -0
- package/src/core/agents/security-analyzer-secrets.md +175 -0
- package/src/core/agents/security-consensus.md +276 -0
- package/src/core/agents/test-analyzer-assertions.md +181 -0
- package/src/core/agents/test-analyzer-coverage.md +183 -0
- package/src/core/agents/test-analyzer-fragility.md +185 -0
- package/src/core/agents/test-analyzer-integration.md +155 -0
- package/src/core/agents/test-analyzer-maintenance.md +173 -0
- package/src/core/agents/test-analyzer-mocking.md +178 -0
- package/src/core/agents/test-analyzer-patterns.md +189 -0
- package/src/core/agents/test-analyzer-structure.md +177 -0
- package/src/core/agents/test-consensus.md +294 -0
- package/src/core/commands/{legal/audit.md → audit/legal.md} +13 -13
- package/src/core/commands/{logic/audit.md → audit/logic.md} +12 -12
- package/src/core/commands/audit/performance.md +443 -0
- package/src/core/commands/audit/security.md +443 -0
- package/src/core/commands/audit/test.md +442 -0
- package/src/core/commands/babysit.md +505 -463
- package/src/core/commands/configure.md +8 -8
- package/src/core/commands/research/ask.md +42 -9
- package/src/core/commands/research/import.md +14 -8
- package/src/core/commands/research/list.md +17 -16
- package/src/core/commands/research/synthesize.md +8 -8
- package/src/core/commands/research/view.md +28 -4
- package/src/core/commands/whats-new.md +2 -2
- package/src/core/experts/devops/expertise.yaml +13 -2
- package/src/core/experts/documentation/expertise.yaml +26 -4
- package/src/core/profiles/COMPARISON.md +170 -0
- package/src/core/profiles/README.md +178 -0
- package/src/core/profiles/claude-code.yaml +111 -0
- package/src/core/profiles/codex.yaml +103 -0
- package/src/core/profiles/cursor.yaml +134 -0
- package/src/core/profiles/examples.js +250 -0
- package/src/core/profiles/loader.js +235 -0
- package/src/core/profiles/windsurf.yaml +159 -0
- package/src/core/teams/logic-audit.json +6 -0
- package/src/core/teams/perf-audit.json +71 -0
- package/src/core/teams/security-audit.json +71 -0
- package/src/core/teams/test-audit.json +71 -0
- package/src/core/templates/command-prerequisites.yaml +169 -0
- package/src/core/templates/damage-control-patterns.yaml +9 -0
- package/tools/cli/installers/ide/_base-ide.js +33 -3
- package/tools/cli/installers/ide/claude-code.js +2 -69
- package/tools/cli/installers/ide/codex.js +9 -9
- package/tools/cli/installers/ide/cursor.js +165 -4
- package/tools/cli/installers/ide/windsurf.js +237 -6
- package/tools/cli/lib/content-transformer.js +234 -9
- package/tools/cli/lib/docs-setup.js +1 -1
- package/tools/cli/lib/ide-generator.js +357 -0
- package/tools/cli/lib/ide-registry.js +2 -2
- package/scripts/tmux-task-name.sh +0 -105
- package/scripts/tmux-task-watcher.sh +0 -344
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IDE Capability Profile - Usage Examples
|
|
3
|
+
*
|
|
4
|
+
* This file demonstrates how to use the profile loader
|
|
5
|
+
* in installers, generators, and feature-detection code.
|
|
6
|
+
*
|
|
7
|
+
* Run: node examples.js
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const loader = require('./loader');
|
|
11
|
+
|
|
12
|
+
console.log('IDE Capability Profile - Usage Examples\n');
|
|
13
|
+
console.log('='.repeat(60) + '\n');
|
|
14
|
+
|
|
15
|
+
// ============================================================
|
|
16
|
+
// Example 1: Load a single profile
|
|
17
|
+
// ============================================================
|
|
18
|
+
console.log('1. LOAD A SINGLE PROFILE\n');
|
|
19
|
+
|
|
20
|
+
const claudeCodeProfile = loader.load('claude-code');
|
|
21
|
+
console.log(`Loaded: ${claudeCodeProfile.ide.displayName}`);
|
|
22
|
+
console.log(`Config dir: ${claudeCodeProfile.paths.commands}`);
|
|
23
|
+
console.log(`Instructions: ${claudeCodeProfile.paths.instructionsFile}`);
|
|
24
|
+
console.log();
|
|
25
|
+
|
|
26
|
+
// ============================================================
|
|
27
|
+
// Example 2: Load all profiles
|
|
28
|
+
// ============================================================
|
|
29
|
+
console.log('2. LOAD ALL PROFILES\n');
|
|
30
|
+
|
|
31
|
+
const allProfiles = loader.loadAll();
|
|
32
|
+
console.log('Available IDEs:');
|
|
33
|
+
Object.keys(allProfiles).sort().forEach(ide => {
|
|
34
|
+
const profile = allProfiles[ide];
|
|
35
|
+
console.log(` - ${profile.ide.displayName}`);
|
|
36
|
+
});
|
|
37
|
+
console.log();
|
|
38
|
+
|
|
39
|
+
// ============================================================
|
|
40
|
+
// Example 3: List available profiles
|
|
41
|
+
// ============================================================
|
|
42
|
+
console.log('3. LIST AVAILABLE PROFILES\n');
|
|
43
|
+
|
|
44
|
+
const available = loader.listAvailable();
|
|
45
|
+
console.log(`Supported IDEs: ${available.join(', ')}`);
|
|
46
|
+
console.log();
|
|
47
|
+
|
|
48
|
+
// ============================================================
|
|
49
|
+
// Example 4: Check if IDE is supported
|
|
50
|
+
// ============================================================
|
|
51
|
+
console.log('4. CHECK IDE SUPPORT\n');
|
|
52
|
+
|
|
53
|
+
['claude-code', 'cursor', 'unknown-ide'].forEach(ide => {
|
|
54
|
+
const supported = loader.isSupported(ide);
|
|
55
|
+
console.log(`${ide}: ${supported ? '✓ supported' : '✗ not supported'}`);
|
|
56
|
+
});
|
|
57
|
+
console.log();
|
|
58
|
+
|
|
59
|
+
// ============================================================
|
|
60
|
+
// Example 5: Check specific capability
|
|
61
|
+
// ============================================================
|
|
62
|
+
console.log('5. CHECK SPECIFIC CAPABILITIES\n');
|
|
63
|
+
|
|
64
|
+
const capabilities = [
|
|
65
|
+
{ ide: 'claude-code', group: 'core', cap: 'planMode' },
|
|
66
|
+
{ ide: 'cursor', group: 'core', cap: 'planMode' },
|
|
67
|
+
{ ide: 'windsurf', group: 'collaboration', cap: 'taskTracking' },
|
|
68
|
+
{ ide: 'codex', group: 'planning', cap: 'planMode' },
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
capabilities.forEach(({ ide, group, cap }) => {
|
|
72
|
+
const has = loader.hasCapability(ide, group, cap);
|
|
73
|
+
const status = has ? '✅' : '❌';
|
|
74
|
+
console.log(`${ide}: ${cap} ${status}`);
|
|
75
|
+
});
|
|
76
|
+
console.log();
|
|
77
|
+
|
|
78
|
+
// ============================================================
|
|
79
|
+
// Example 6: Get tool name mapping
|
|
80
|
+
// ============================================================
|
|
81
|
+
console.log('6. TOOL NAME MAPPINGS (IDE-specific equivalents)\n');
|
|
82
|
+
|
|
83
|
+
const toolAlias = 'bash';
|
|
84
|
+
console.log(`Standard tool alias: "${toolAlias}"`);
|
|
85
|
+
console.log('IDE-specific names:');
|
|
86
|
+
available.forEach(ide => {
|
|
87
|
+
const toolName = loader.getToolName(ide, toolAlias);
|
|
88
|
+
console.log(` ${ide}: ${toolName || '(not available)'}`);
|
|
89
|
+
});
|
|
90
|
+
console.log();
|
|
91
|
+
|
|
92
|
+
// ============================================================
|
|
93
|
+
// Example 7: Get all capabilities for an IDE
|
|
94
|
+
// ============================================================
|
|
95
|
+
console.log('7. ALL CAPABILITIES FOR CURSOR\n');
|
|
96
|
+
|
|
97
|
+
const cursorCaps = loader.getAllCapabilities('cursor');
|
|
98
|
+
const enabledCaps = Object.entries(cursorCaps)
|
|
99
|
+
.filter(([_, enabled]) => enabled)
|
|
100
|
+
.map(([name, _]) => name);
|
|
101
|
+
|
|
102
|
+
console.log(`Cursor has ${enabledCaps.length} capabilities enabled:`);
|
|
103
|
+
enabledCaps.slice(0, 8).forEach(cap => console.log(` ✓ ${cap}`));
|
|
104
|
+
console.log(` ... and ${enabledCaps.length - 8} more`);
|
|
105
|
+
console.log();
|
|
106
|
+
|
|
107
|
+
// ============================================================
|
|
108
|
+
// Example 8: Find IDEs with a capability
|
|
109
|
+
// ============================================================
|
|
110
|
+
console.log('8. FIND IDEs WITH SPECIFIC CAPABILITY\n');
|
|
111
|
+
|
|
112
|
+
const idsWithPlanMode = loader.findIDEsWithCapability('planning', 'planMode');
|
|
113
|
+
console.log(`IDEs with plan mode: ${idsWithPlanMode.join(', ')}`);
|
|
114
|
+
|
|
115
|
+
const idsWithTasks = loader.findIDEsWithCapability('collaboration', 'taskTracking');
|
|
116
|
+
console.log(`IDEs with task tracking: ${idsWithTasks.join(', ')}`);
|
|
117
|
+
|
|
118
|
+
const idsWithMCP = loader.findIDEsWithCapability('external', 'mcp');
|
|
119
|
+
console.log(`IDEs with MCP: ${idsWithMCP.join(', ')}`);
|
|
120
|
+
console.log();
|
|
121
|
+
|
|
122
|
+
// ============================================================
|
|
123
|
+
// Example 9: Compare capability across IDEs
|
|
124
|
+
// ============================================================
|
|
125
|
+
console.log('9. COMPARE CAPABILITY ACROSS ALL IDEs\n');
|
|
126
|
+
|
|
127
|
+
const subAgentComparison = loader.compareCapability('core', 'subAgents');
|
|
128
|
+
console.log('Sub-agent support:');
|
|
129
|
+
Object.entries(subAgentComparison).forEach(([ide, supported]) => {
|
|
130
|
+
console.log(` ${ide}: ${supported ? '✅' : '❌'}`);
|
|
131
|
+
});
|
|
132
|
+
console.log();
|
|
133
|
+
|
|
134
|
+
// ============================================================
|
|
135
|
+
// Example 10: Design pattern - Feature detection in installer
|
|
136
|
+
// ============================================================
|
|
137
|
+
console.log('10. DESIGN PATTERN: FEATURE-BASED INSTALLATION\n');
|
|
138
|
+
|
|
139
|
+
function installForIDE(ideId) {
|
|
140
|
+
console.log(`Installing for ${ideId}...\n`);
|
|
141
|
+
|
|
142
|
+
const profile = loader.load(ideId);
|
|
143
|
+
|
|
144
|
+
// Install commands if supported
|
|
145
|
+
if (profile.paths.commands) {
|
|
146
|
+
console.log(` → Install commands to: ${profile.paths.commands}`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Install hooks if supported
|
|
150
|
+
if (loader.hasCapability(ideId, 'lifecycle', 'hooks')) {
|
|
151
|
+
console.log(` → Install lifecycle hooks (${profile.capabilities.lifecycle.hookEvents.length} events)`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Install MCP if supported
|
|
155
|
+
if (loader.hasCapability(ideId, 'external', 'mcp')) {
|
|
156
|
+
const limit = profile.capabilities.external.mcpToolLimit;
|
|
157
|
+
if (limit === 0) {
|
|
158
|
+
console.log(` → Install MCP tools (unlimited)`);
|
|
159
|
+
} else {
|
|
160
|
+
console.log(` → Install MCP tools (cap: ${limit})`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Install plan mode prompts if supported
|
|
165
|
+
if (loader.hasCapability(ideId, 'planning', 'planMode')) {
|
|
166
|
+
console.log(` → Install plan mode instructions`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
console.log();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
installForIDE('claude-code');
|
|
173
|
+
installForIDE('windsurf');
|
|
174
|
+
installForIDE('codex');
|
|
175
|
+
|
|
176
|
+
// ============================================================
|
|
177
|
+
// Example 11: Design pattern - Capability fallback chain
|
|
178
|
+
// ============================================================
|
|
179
|
+
console.log('11. DESIGN PATTERN: CAPABILITY FALLBACK\n');
|
|
180
|
+
|
|
181
|
+
function getInteractiveInputMethod(ideId) {
|
|
182
|
+
const profile = loader.load(ideId);
|
|
183
|
+
|
|
184
|
+
if (loader.hasCapability(ideId, 'core', 'interactiveInput')) {
|
|
185
|
+
if (loader.getToolName(ideId, 'askUser') === 'AskUserQuestion') {
|
|
186
|
+
return 'Structured menus (AskUserQuestion)';
|
|
187
|
+
} else if (loader.getToolName(ideId, 'askUser')) {
|
|
188
|
+
return `Text input (${loader.getToolName(ideId, 'askUser')})`;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return 'Conversational clarification';
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
console.log('Interactive input methods by IDE:');
|
|
196
|
+
available.forEach(ide => {
|
|
197
|
+
const method = getInteractiveInputMethod(ide);
|
|
198
|
+
console.log(` ${ide}: ${method}`);
|
|
199
|
+
});
|
|
200
|
+
console.log();
|
|
201
|
+
|
|
202
|
+
// ============================================================
|
|
203
|
+
// Example 12: Design pattern - Multi-IDE constraint analysis
|
|
204
|
+
// ============================================================
|
|
205
|
+
console.log('12. DESIGN PATTERN: MULTI-IDE CONSTRAINT ANALYSIS\n');
|
|
206
|
+
|
|
207
|
+
console.log('Planning a multi-IDE deployment...\n');
|
|
208
|
+
|
|
209
|
+
const allCaps = loader.loadAll();
|
|
210
|
+
const mpcConstraints = [];
|
|
211
|
+
|
|
212
|
+
available.forEach(ide => {
|
|
213
|
+
const limit = allCaps[ide].capabilities.external.mcpToolLimit;
|
|
214
|
+
if (limit > 0) {
|
|
215
|
+
mpcConstraints.push({ ide, limit });
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
mpcConstraints.sort((a, b) => a.limit - b.limit);
|
|
220
|
+
|
|
221
|
+
if (mpcConstraints.length > 0) {
|
|
222
|
+
const minLimit = mpcConstraints[0].limit;
|
|
223
|
+
console.log(`Binding constraint (most restrictive IDE): ${minLimit} MCP tools`);
|
|
224
|
+
console.log(`Affected IDEs:`);
|
|
225
|
+
mpcConstraints.forEach(({ ide, limit }) => {
|
|
226
|
+
const marker = limit === minLimit ? '🔴 (CONSTRAINT)' : '🟢';
|
|
227
|
+
console.log(` ${marker} ${ide}: ${limit} tools`);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
console.log();
|
|
231
|
+
|
|
232
|
+
// ============================================================
|
|
233
|
+
// Summary
|
|
234
|
+
// ============================================================
|
|
235
|
+
console.log('='.repeat(60));
|
|
236
|
+
console.log('Profile System Ready for Use');
|
|
237
|
+
console.log('='.repeat(60));
|
|
238
|
+
console.log(`
|
|
239
|
+
Available utilities:
|
|
240
|
+
loader.load(ideId) - Load single profile
|
|
241
|
+
loader.loadAll() - Load all profiles
|
|
242
|
+
loader.listAvailable() - List IDE names
|
|
243
|
+
loader.isSupported(ideId) - Check if IDE supported
|
|
244
|
+
loader.hasCapability(ideId, group, cap) - Check feature support
|
|
245
|
+
loader.getToolName(ideId, alias) - Get IDE-specific tool name
|
|
246
|
+
loader.getAllCapabilities(ideId) - Get all IDE capabilities
|
|
247
|
+
loader.findIDEsWithCapability(group, cap) - Find IDEs with feature
|
|
248
|
+
loader.compareCapability(group, cap) - Compare across all IDEs
|
|
249
|
+
loader.clearCache() - Clear cached profiles
|
|
250
|
+
`);
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IDE Capability Profile Loader
|
|
3
|
+
*
|
|
4
|
+
* Loads YAML capability profiles with validation and caching.
|
|
5
|
+
* Used by installers, generators, and feature-detection code.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const loader = require('./profiles/loader');
|
|
9
|
+
* const profile = loader.load('claude-code');
|
|
10
|
+
* if (profile.capabilities.core.planMode) { ... }
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const yaml = require('js-yaml');
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
|
|
17
|
+
const PROFILES_DIR = __dirname;
|
|
18
|
+
const CACHE = {};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Load a profile by IDE name
|
|
22
|
+
* @param {string} ideId - IDE identifier (claude-code, cursor, windsurf, codex)
|
|
23
|
+
* @returns {Object} Profile object
|
|
24
|
+
* @throws {Error} If profile not found or invalid YAML
|
|
25
|
+
*/
|
|
26
|
+
function load(ideId) {
|
|
27
|
+
if (CACHE[ideId]) {
|
|
28
|
+
return CACHE[ideId];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const filePath = path.join(PROFILES_DIR, `${ideId}.yaml`);
|
|
32
|
+
|
|
33
|
+
if (!fs.existsSync(filePath)) {
|
|
34
|
+
throw new Error(`Profile not found: ${ideId}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
39
|
+
const profile = yaml.load(content);
|
|
40
|
+
|
|
41
|
+
// Validate profile structure
|
|
42
|
+
validateProfile(profile, ideId);
|
|
43
|
+
|
|
44
|
+
CACHE[ideId] = profile;
|
|
45
|
+
return profile;
|
|
46
|
+
} catch (e) {
|
|
47
|
+
if (e instanceof yaml.YAMLException) {
|
|
48
|
+
throw new Error(`Invalid YAML in profile ${ideId}: ${e.message}`);
|
|
49
|
+
}
|
|
50
|
+
throw e;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Load all available profiles
|
|
56
|
+
* @returns {Object} Map of IDE ID to profile
|
|
57
|
+
*/
|
|
58
|
+
function loadAll() {
|
|
59
|
+
const profiles = {};
|
|
60
|
+
const files = fs.readdirSync(PROFILES_DIR)
|
|
61
|
+
.filter(f => f.endsWith('.yaml'));
|
|
62
|
+
|
|
63
|
+
files.forEach(file => {
|
|
64
|
+
const ideId = file.replace('.yaml', '');
|
|
65
|
+
try {
|
|
66
|
+
profiles[ideId] = load(ideId);
|
|
67
|
+
} catch (e) {
|
|
68
|
+
console.error(`Failed to load profile ${ideId}: ${e.message}`);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return profiles;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Get list of available profiles
|
|
77
|
+
* @returns {Array<string>} List of IDE IDs
|
|
78
|
+
*/
|
|
79
|
+
function listAvailable() {
|
|
80
|
+
return fs.readdirSync(PROFILES_DIR)
|
|
81
|
+
.filter(f => f.endsWith('.yaml'))
|
|
82
|
+
.map(f => f.replace('.yaml', ''))
|
|
83
|
+
.sort();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Check if IDE is supported
|
|
88
|
+
* @param {string} ideId - IDE identifier
|
|
89
|
+
* @returns {boolean} True if IDE profile exists
|
|
90
|
+
*/
|
|
91
|
+
function isSupported(ideId) {
|
|
92
|
+
return fs.existsSync(path.join(PROFILES_DIR, `${ideId}.yaml`));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Validate profile structure
|
|
97
|
+
* @private
|
|
98
|
+
* @param {Object} profile - Profile object
|
|
99
|
+
* @param {string} ideId - IDE identifier
|
|
100
|
+
* @throws {Error} If validation fails
|
|
101
|
+
*/
|
|
102
|
+
function validateProfile(profile, ideId) {
|
|
103
|
+
const required = ['ide', 'paths', 'capabilities', 'toolNames'];
|
|
104
|
+
|
|
105
|
+
for (const field of required) {
|
|
106
|
+
if (!profile[field]) {
|
|
107
|
+
throw new Error(`Missing required field: ${field}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Validate ide object
|
|
112
|
+
if (!profile.ide.id || !profile.ide.name) {
|
|
113
|
+
throw new Error('ide object must have id and name fields');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Validate capabilities structure
|
|
117
|
+
const validCapGroups = ['core', 'planning', 'lifecycle', 'external', 'collaboration'];
|
|
118
|
+
for (const group of Object.keys(profile.capabilities)) {
|
|
119
|
+
if (!validCapGroups.includes(group)) {
|
|
120
|
+
console.warn(`Unknown capability group in ${ideId}: ${group}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get capability status for an IDE
|
|
127
|
+
* @param {string} ideId - IDE identifier
|
|
128
|
+
* @param {string} group - Capability group (core, planning, lifecycle, external, collaboration)
|
|
129
|
+
* @param {string} capability - Capability name
|
|
130
|
+
* @returns {boolean|null} True if supported, false if not, null if unknown
|
|
131
|
+
*/
|
|
132
|
+
function hasCapability(ideId, group, capability) {
|
|
133
|
+
const profile = load(ideId);
|
|
134
|
+
const groupCapabilities = profile.capabilities[group];
|
|
135
|
+
|
|
136
|
+
if (!groupCapabilities) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return groupCapabilities[capability] === true;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get tool name for an IDE
|
|
145
|
+
* Returns the tool name used by the IDE, or null if not supported
|
|
146
|
+
*
|
|
147
|
+
* @param {string} ideId - IDE identifier
|
|
148
|
+
* @param {string} toolAlias - Standard tool alias (askUser, bash, read, etc.)
|
|
149
|
+
* @returns {string|null} IDE-specific tool name or null
|
|
150
|
+
*/
|
|
151
|
+
function getToolName(ideId, toolAlias) {
|
|
152
|
+
const profile = load(ideId);
|
|
153
|
+
return profile.toolNames[toolAlias] || null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Get all capabilities for an IDE (flattened)
|
|
158
|
+
* @param {string} ideId - IDE identifier
|
|
159
|
+
* @returns {Object} Map of capability name to boolean
|
|
160
|
+
*/
|
|
161
|
+
function getAllCapabilities(ideId) {
|
|
162
|
+
const profile = load(ideId);
|
|
163
|
+
const capabilities = {};
|
|
164
|
+
|
|
165
|
+
for (const [group, groupCaps] of Object.entries(profile.capabilities)) {
|
|
166
|
+
if (typeof groupCaps === 'object' && !Array.isArray(groupCaps)) {
|
|
167
|
+
for (const [cap, value] of Object.entries(groupCaps)) {
|
|
168
|
+
if (typeof value === 'boolean') {
|
|
169
|
+
capabilities[`${group}.${cap}`] = value;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return capabilities;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Find all IDEs supporting a capability
|
|
180
|
+
* @param {string} group - Capability group
|
|
181
|
+
* @param {string} capability - Capability name
|
|
182
|
+
* @returns {Array<string>} List of IDE IDs that support this capability
|
|
183
|
+
*/
|
|
184
|
+
function findIDEsWithCapability(group, capability) {
|
|
185
|
+
const ides = [];
|
|
186
|
+
const all = loadAll();
|
|
187
|
+
|
|
188
|
+
for (const [ideId, profile] of Object.entries(all)) {
|
|
189
|
+
if (profile.capabilities[group] && profile.capabilities[group][capability] === true) {
|
|
190
|
+
ides.push(ideId);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return ides.sort();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Get comparison table for a specific capability across all IDEs
|
|
199
|
+
* @param {string} group - Capability group
|
|
200
|
+
* @param {string} capability - Capability name
|
|
201
|
+
* @returns {Object} Map of IDE ID to boolean
|
|
202
|
+
*/
|
|
203
|
+
function compareCapability(group, capability) {
|
|
204
|
+
const result = {};
|
|
205
|
+
const all = loadAll();
|
|
206
|
+
|
|
207
|
+
for (const [ideId, profile] of Object.entries(all)) {
|
|
208
|
+
result[ideId] = profile.capabilities[group] && profile.capabilities[group][capability] === true;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Clear profile cache
|
|
216
|
+
* Useful for testing or reloading profiles after updates
|
|
217
|
+
*/
|
|
218
|
+
function clearCache() {
|
|
219
|
+
for (const key of Object.keys(CACHE)) {
|
|
220
|
+
delete CACHE[key];
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
module.exports = {
|
|
225
|
+
load,
|
|
226
|
+
loadAll,
|
|
227
|
+
listAvailable,
|
|
228
|
+
isSupported,
|
|
229
|
+
hasCapability,
|
|
230
|
+
getToolName,
|
|
231
|
+
getAllCapabilities,
|
|
232
|
+
findIDEsWithCapability,
|
|
233
|
+
compareCapability,
|
|
234
|
+
clearCache,
|
|
235
|
+
};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# Windsurf IDE Capability Profile
|
|
2
|
+
# Wave 13+ - Most comprehensive hooks but no true sub-agent spawning
|
|
3
|
+
# Reference: Cross-IDE Compatibility Findings (20260220)
|
|
4
|
+
|
|
5
|
+
ide:
|
|
6
|
+
id: windsurf
|
|
7
|
+
name: Windsurf
|
|
8
|
+
displayName: Windsurf
|
|
9
|
+
description: Codeium's AI editor with native worktrees and 11 lifecycle hooks
|
|
10
|
+
configDir: .windsurf
|
|
11
|
+
configDirGlobal: ~/.codeium/windsurf
|
|
12
|
+
instructionsFile: WINDSURF.md
|
|
13
|
+
fileFormat: markdown
|
|
14
|
+
commandPrefix: "/"
|
|
15
|
+
agentPrefix: "agileflow-"
|
|
16
|
+
|
|
17
|
+
paths:
|
|
18
|
+
commands: .windsurf/workflows/
|
|
19
|
+
agents: null # Uses workflows + cascades instead
|
|
20
|
+
skills: .windsurf/skills/*/SKILL.md
|
|
21
|
+
rules: .windsurf/rules/
|
|
22
|
+
workflows: .windsurf/workflows/
|
|
23
|
+
hooks: .windsurf/hooks.json
|
|
24
|
+
hooksGlobal: ~/.codeium/windsurf/hooks.json
|
|
25
|
+
mcp: ~/.codeium/windsurf/mcp_config.json
|
|
26
|
+
mcpGlobal: true # MCP config is global-only
|
|
27
|
+
|
|
28
|
+
capabilities:
|
|
29
|
+
core:
|
|
30
|
+
fileOperations: true # Native file read/write
|
|
31
|
+
shell: true # Native shell (4-level auto-execution)
|
|
32
|
+
fileSearch: true # Native search + analyze tools
|
|
33
|
+
interactiveInput: true # Conversational only (no structured menus)
|
|
34
|
+
subAgents: false # No true sub-agent spawning
|
|
35
|
+
nestedSubAgents: false # Parallel Cascades via worktrees instead
|
|
36
|
+
planning:
|
|
37
|
+
planMode: true # Native via "megaplan" keyword
|
|
38
|
+
planModeEditable: true # Editable plans in ~/.windsurf/plans/
|
|
39
|
+
lifecycle:
|
|
40
|
+
hooks: true # 9 lifecycle events (per official docs Feb 2026)
|
|
41
|
+
hookEvents:
|
|
42
|
+
- pre_read_code
|
|
43
|
+
- post_read_code
|
|
44
|
+
- pre_write_code
|
|
45
|
+
- post_write_code
|
|
46
|
+
- pre_run_command
|
|
47
|
+
- post_run_command
|
|
48
|
+
- pre_mcp_tool_use
|
|
49
|
+
- post_mcp_tool_use
|
|
50
|
+
- pre_user_prompt
|
|
51
|
+
external:
|
|
52
|
+
webSearch: true # Web Search tool
|
|
53
|
+
webFetch: true # URL Read and View Chunk
|
|
54
|
+
mcp: true # Full MCP support
|
|
55
|
+
mcpToolLimit: 100 # 100-tool cap
|
|
56
|
+
browser: true # Browser Preview (in-IDE)
|
|
57
|
+
collaboration:
|
|
58
|
+
taskTracking: false # Conversation-embedded only (not persistent)
|
|
59
|
+
persistentTasks: false
|
|
60
|
+
worktrees: true # Native worktrees (up to 20 per workspace)
|
|
61
|
+
maxWorktrees: 20
|
|
62
|
+
|
|
63
|
+
toolNames:
|
|
64
|
+
# Interactive
|
|
65
|
+
askUser: null # Conversational only
|
|
66
|
+
# Delegation
|
|
67
|
+
spawnAgent: null # Use workflows + cascades instead
|
|
68
|
+
# Planning
|
|
69
|
+
planModeEnter: null # Native, use "megaplan" keyword
|
|
70
|
+
planModeExit: null # Native
|
|
71
|
+
# Execution
|
|
72
|
+
bash: run_command
|
|
73
|
+
# Files
|
|
74
|
+
read: read_file
|
|
75
|
+
write: write_file
|
|
76
|
+
edit: edit_file
|
|
77
|
+
# Search
|
|
78
|
+
glob: search_files
|
|
79
|
+
grep: search_codebase
|
|
80
|
+
# Web
|
|
81
|
+
webSearch: web_search
|
|
82
|
+
webFetch: url_read
|
|
83
|
+
# Cascades
|
|
84
|
+
cascade: null # Use /workflow-name chaining
|
|
85
|
+
|
|
86
|
+
workflowModel:
|
|
87
|
+
format: markdown
|
|
88
|
+
maxCharacters: 12000 # Hard limit per workflow file
|
|
89
|
+
splitStrategy: "Split large workflows into multiple files"
|
|
90
|
+
chaining: "Use /workflow-name in instructions to chain workflows"
|
|
91
|
+
cascades: "Use @cascade to run multiple workflows in parallel"
|
|
92
|
+
|
|
93
|
+
skillModel:
|
|
94
|
+
format: markdown
|
|
95
|
+
frontmatterFormat: yaml
|
|
96
|
+
spec: "agentskills.io"
|
|
97
|
+
fields:
|
|
98
|
+
- name
|
|
99
|
+
- description
|
|
100
|
+
- model
|
|
101
|
+
- requiredCapabilities
|
|
102
|
+
|
|
103
|
+
frontmatter:
|
|
104
|
+
workflows:
|
|
105
|
+
format: null # Workflows are commands, not structured prompts
|
|
106
|
+
rules:
|
|
107
|
+
format: markdown
|
|
108
|
+
fields:
|
|
109
|
+
- description
|
|
110
|
+
- globs
|
|
111
|
+
- alwaysApply
|
|
112
|
+
skills:
|
|
113
|
+
format: yaml
|
|
114
|
+
fields:
|
|
115
|
+
- name
|
|
116
|
+
- description
|
|
117
|
+
- model
|
|
118
|
+
- requiredCapabilities
|
|
119
|
+
|
|
120
|
+
limits:
|
|
121
|
+
maxFileSize: 0 # 0 = unlimited
|
|
122
|
+
maxCommandLength: 0 # 0 = unlimited
|
|
123
|
+
maxWorkflowSize: 12000 # Hard limit per workflow file
|
|
124
|
+
maxToolsPerMCP: 100 # MCP tool limit
|
|
125
|
+
maxWorktreesPerWorkspace: 20
|
|
126
|
+
autoExecutionLevels: 4 # Shell auto-execution levels
|
|
127
|
+
|
|
128
|
+
installation:
|
|
129
|
+
supportsFileOps: true
|
|
130
|
+
supportsHooks: true # Native
|
|
131
|
+
supportsMCP: true # Global-only config
|
|
132
|
+
commandsRequireApproval: false
|
|
133
|
+
skillsCanBeNestedDirs: true
|
|
134
|
+
projectLevelMCP: false # MCP config is global-only
|
|
135
|
+
|
|
136
|
+
worktreeModel:
|
|
137
|
+
supported: true
|
|
138
|
+
maxConcurrent: 20
|
|
139
|
+
useCase: "Parallel feature branches or multi-task execution"
|
|
140
|
+
gitIntegration: "Native git worktree support"
|
|
141
|
+
hostedOn: "Wave 13+"
|
|
142
|
+
|
|
143
|
+
cascadeModel:
|
|
144
|
+
description: "Run multiple workflows in parallel"
|
|
145
|
+
syntax: "@cascade /workflow1 /workflow2"
|
|
146
|
+
useCase: "Execute independent tasks without blocking"
|
|
147
|
+
limitSubstitution: "Use cascades instead of Task tool"
|
|
148
|
+
|
|
149
|
+
notes:
|
|
150
|
+
- "Windsurf has the most comprehensive hooks (11 events)"
|
|
151
|
+
- "NO true sub-agent spawning; use workflow chaining or cascades"
|
|
152
|
+
- "12,000 character limit per workflow - split large commands"
|
|
153
|
+
- "MCP config is global-only (in ~/.codeium/windsurf/mcp_config.json)"
|
|
154
|
+
- "Conversational input, no structured menus"
|
|
155
|
+
- "Native worktrees enable parallel development (up to 20 per workspace)"
|
|
156
|
+
- "Skills follow agentskills.io specification"
|
|
157
|
+
- "Use 'megaplan' keyword for advanced planning"
|
|
158
|
+
- "100-tool MCP limit; good balance between capability and performance"
|
|
159
|
+
- "Plan files stored in ~/.windsurf/plans/ (user's home, not project)"
|
|
@@ -20,6 +20,12 @@
|
|
|
20
20
|
"domain": "control-flow",
|
|
21
21
|
"description": "Analyzes dead code, unreachable branches, and missing returns"
|
|
22
22
|
},
|
|
23
|
+
{
|
|
24
|
+
"agent": "agileflow-logic-analyzer-invariant",
|
|
25
|
+
"role": "analyzer",
|
|
26
|
+
"domain": "invariants",
|
|
27
|
+
"description": "Analyzes pre/post conditions, state consistency, and contract violations"
|
|
28
|
+
},
|
|
23
29
|
{
|
|
24
30
|
"agent": "agileflow-logic-analyzer-race",
|
|
25
31
|
"role": "analyzer",
|