agileflow 3.1.0 → 3.2.1
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 +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/browser-qa-evidence.js +409 -0
- package/scripts/lib/browser-qa-status.js +192 -0
- 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/browser-qa.md +328 -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/browser-qa.md +240 -0
- 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/browser-qa-spec.yaml +94 -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
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AgileFlow CLI - Windsurf IDE Installer
|
|
3
3
|
*
|
|
4
|
-
* Installs AgileFlow
|
|
5
|
-
*
|
|
4
|
+
* Installs AgileFlow for Windsurf IDE:
|
|
5
|
+
* - Commands as workflows to .windsurf/workflows/agileflow/
|
|
6
|
+
* - Agents as skills to .windsurf/skills/agileflow-<NAME>/SKILL.md
|
|
7
|
+
* - Damage control hooks to .windsurf/hooks.json
|
|
8
|
+
*
|
|
9
|
+
* Windsurf supports 11 lifecycle events and 12,000 character limit per workflow.
|
|
10
|
+
* Skills follow agentskills.io specification with YAML frontmatter.
|
|
6
11
|
*/
|
|
7
12
|
|
|
8
13
|
const path = require('node:path');
|
|
9
14
|
const fs = require('fs-extra');
|
|
10
15
|
const chalk = require('chalk');
|
|
16
|
+
const { yaml } = require('../../../../lib/yaml-utils');
|
|
11
17
|
const { BaseIdeSetup } = require('./_base-ide');
|
|
18
|
+
const {
|
|
19
|
+
getFrontmatter,
|
|
20
|
+
stripFrontmatter,
|
|
21
|
+
replaceReferences,
|
|
22
|
+
IDE_REPLACEMENTS,
|
|
23
|
+
} = require('../../lib/content-transformer');
|
|
12
24
|
|
|
13
25
|
/**
|
|
14
26
|
* Windsurf IDE setup handler
|
|
@@ -20,6 +32,187 @@ class WindsurfSetup extends BaseIdeSetup {
|
|
|
20
32
|
this.workflowsDir = 'workflows';
|
|
21
33
|
}
|
|
22
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Convert an AgileFlow agent markdown file to Windsurf SKILL.md format
|
|
37
|
+
* Windsurf skills follow the agentskills.io specification with YAML frontmatter
|
|
38
|
+
*
|
|
39
|
+
* @param {string} content - Original agent markdown content
|
|
40
|
+
* @param {string} agentName - Agent name (e.g., 'database')
|
|
41
|
+
* @returns {string} Windsurf SKILL.md content
|
|
42
|
+
*/
|
|
43
|
+
convertAgentToSkill(content, agentName) {
|
|
44
|
+
// Extract frontmatter using content-transformer
|
|
45
|
+
const frontmatter = getFrontmatter(content);
|
|
46
|
+
const description = frontmatter.description || `AgileFlow ${agentName} agent`;
|
|
47
|
+
|
|
48
|
+
// Create SKILL.md with YAML frontmatter (agentskills.io spec)
|
|
49
|
+
const skillFrontmatter = yaml
|
|
50
|
+
.dump({
|
|
51
|
+
name: `agileflow-${agentName}`,
|
|
52
|
+
description: description,
|
|
53
|
+
})
|
|
54
|
+
.trim();
|
|
55
|
+
|
|
56
|
+
// Remove original frontmatter from content using content-transformer
|
|
57
|
+
let bodyContent = stripFrontmatter(content);
|
|
58
|
+
|
|
59
|
+
// Add Windsurf-specific header
|
|
60
|
+
const windsurfHeader = `# AgileFlow: ${agentName.charAt(0).toUpperCase() + agentName.slice(1)} Skill
|
|
61
|
+
|
|
62
|
+
> Use this skill via \`@agileflow-${agentName}\` or /cascade
|
|
63
|
+
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
// Replace Claude-specific references using content-transformer
|
|
67
|
+
bodyContent = replaceReferences(bodyContent, IDE_REPLACEMENTS.windsurf);
|
|
68
|
+
|
|
69
|
+
// Add Windsurf-specific replacements
|
|
70
|
+
bodyContent = replaceReferences(bodyContent, {
|
|
71
|
+
'Task tool': 'workflow chaining',
|
|
72
|
+
AskUserQuestion: 'numbered list prompt',
|
|
73
|
+
'.claude/agents/agileflow': '.windsurf/skills/agileflow',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Replace /agileflow: prefix for Windsurf workflow chaining
|
|
77
|
+
// e.g., /agileflow:story:list → /agileflow-story-list
|
|
78
|
+
bodyContent = bodyContent.replace(/\/agileflow:([a-zA-Z0-9:_-]+)/g, (_match, rest) => {
|
|
79
|
+
return '/agileflow-' + rest.replace(/:/g, '-');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Warn if content exceeds Windsurf's 12,000 character limit
|
|
83
|
+
const totalLength = skillFrontmatter.length + windsurfHeader.length + bodyContent.length;
|
|
84
|
+
if (totalLength > 12000) {
|
|
85
|
+
console.warn(
|
|
86
|
+
chalk.yellow(
|
|
87
|
+
` ⚠ Skill '${agentName}' exceeds 12,000 character limit (${totalLength} chars). Consider splitting.`
|
|
88
|
+
)
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return `---
|
|
93
|
+
${skillFrontmatter}
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
${windsurfHeader}${bodyContent}`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Install AgileFlow agents as Windsurf skills
|
|
101
|
+
* Skills are installed to .windsurf/skills/agileflow-{name}/SKILL.md
|
|
102
|
+
*
|
|
103
|
+
* @param {string} projectDir - Project directory
|
|
104
|
+
* @param {string} agileflowDir - AgileFlow installation directory
|
|
105
|
+
* @returns {Promise<number>} Number of skills installed
|
|
106
|
+
*/
|
|
107
|
+
async installSkills(projectDir, agileflowDir) {
|
|
108
|
+
const agentsSource = path.join(agileflowDir, 'agents');
|
|
109
|
+
const skillsTarget = path.join(projectDir, this.configDir, 'skills');
|
|
110
|
+
|
|
111
|
+
if (!(await this.exists(agentsSource))) {
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
let skillCount = 0;
|
|
116
|
+
const agents = await this.scanDirectory(agentsSource, '.md');
|
|
117
|
+
|
|
118
|
+
for (const agent of agents) {
|
|
119
|
+
const content = await this.readFile(agent.path);
|
|
120
|
+
const skillContent = this.convertAgentToSkill(content, agent.name);
|
|
121
|
+
|
|
122
|
+
// Create skill directory: .windsurf/skills/agileflow-{name}/
|
|
123
|
+
const skillDir = path.join(skillsTarget, `agileflow-${agent.name}`);
|
|
124
|
+
await this.ensureDir(skillDir);
|
|
125
|
+
|
|
126
|
+
// Write SKILL.md
|
|
127
|
+
await this.writeFile(path.join(skillDir, 'SKILL.md'), skillContent);
|
|
128
|
+
skillCount++;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return skillCount;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Setup damage control hooks for Windsurf
|
|
136
|
+
* Maps Claude Code's PreToolUse hooks to Windsurf's lifecycle events:
|
|
137
|
+
* - pre_run_command (for bash commands)
|
|
138
|
+
* - post_write_code (for file edits)
|
|
139
|
+
* - pre_mcp_tool_use (for MCP tools)
|
|
140
|
+
*
|
|
141
|
+
* @param {string} projectDir - Project directory
|
|
142
|
+
* @param {string} agileflowDir - AgileFlow installation directory
|
|
143
|
+
* @param {string} windsurfDir - .windsurf directory path
|
|
144
|
+
* @param {Object} options - Setup options
|
|
145
|
+
*/
|
|
146
|
+
async setupDamageControlHooks(projectDir, agileflowDir, windsurfDir, options = {}) {
|
|
147
|
+
if (options.skipDamageControl) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const hooksPath = path.join(windsurfDir, 'hooks.json');
|
|
152
|
+
let hooks = [];
|
|
153
|
+
|
|
154
|
+
// Load existing hooks if they exist
|
|
155
|
+
if (fs.existsSync(hooksPath)) {
|
|
156
|
+
try {
|
|
157
|
+
const content = await fs.readFile(hooksPath, 'utf8');
|
|
158
|
+
const parsed = JSON.parse(content);
|
|
159
|
+
if (!Array.isArray(parsed)) {
|
|
160
|
+
console.warn(
|
|
161
|
+
'[AgileFlow] hooks.json exists but is not an array, preserving existing file'
|
|
162
|
+
);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
hooks = parsed;
|
|
166
|
+
} catch (e) {
|
|
167
|
+
console.warn(
|
|
168
|
+
`[AgileFlow] hooks.json exists but is malformed (${e.message}), preserving existing file`
|
|
169
|
+
);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Define damage control hooks for Windsurf
|
|
175
|
+
// Windsurf's hooks.json format differs from Cursor - it uses event, command, args
|
|
176
|
+
const damageControlHooks = [
|
|
177
|
+
{
|
|
178
|
+
event: 'pre_run_command',
|
|
179
|
+
command: 'node',
|
|
180
|
+
args: ['.agileflow/scripts/damage-control/damage-control-bash.js'],
|
|
181
|
+
description: 'AgileFlow damage control for shell commands',
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
event: 'post_write_code',
|
|
185
|
+
command: 'node',
|
|
186
|
+
args: ['.agileflow/scripts/damage-control/damage-control-edit.js'],
|
|
187
|
+
description: 'AgileFlow damage control for file edits',
|
|
188
|
+
},
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
// Check if damage control hooks already exist and merge
|
|
192
|
+
let hasUpdates = false;
|
|
193
|
+
for (const newHook of damageControlHooks) {
|
|
194
|
+
const existingIdx = hooks.findIndex(
|
|
195
|
+
h =>
|
|
196
|
+
h.event === newHook.event &&
|
|
197
|
+
h.command === newHook.command &&
|
|
198
|
+
(h.args?.join(' ') === newHook.args?.join(' ') ||
|
|
199
|
+
(h.args && h.args.some(arg => arg.includes('damage-control'))))
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
if (existingIdx === -1) {
|
|
203
|
+
hooks.push(newHook);
|
|
204
|
+
hasUpdates = true;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Only write if we have updates or if file didn't exist
|
|
209
|
+
if (hasUpdates || !fs.existsSync(hooksPath)) {
|
|
210
|
+
await fs.ensureDir(path.dirname(hooksPath));
|
|
211
|
+
await fs.writeFile(hooksPath, JSON.stringify(hooks, null, 2));
|
|
212
|
+
console.log(chalk.dim(` - Damage control: hooks enabled`));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
23
216
|
/**
|
|
24
217
|
* Setup Windsurf IDE configuration
|
|
25
218
|
* @param {string} projectDir - Project directory
|
|
@@ -27,12 +220,37 @@ class WindsurfSetup extends BaseIdeSetup {
|
|
|
27
220
|
* @param {Object} options - Setup options
|
|
28
221
|
*/
|
|
29
222
|
async setup(projectDir, agileflowDir, options = {}) {
|
|
30
|
-
|
|
223
|
+
console.log(chalk.hex('#e8683a')(` Setting up ${this.displayName}...`));
|
|
224
|
+
|
|
225
|
+
// Note: cleanup is handled inside setupStandard(), no need to call explicitly
|
|
226
|
+
|
|
227
|
+
// 1. Install workflows using standard setup
|
|
228
|
+
const workflowsResult = await this.setupStandard(projectDir, agileflowDir, {
|
|
31
229
|
targetSubdir: this.workflowsDir,
|
|
32
230
|
agileflowFolder: 'agileflow',
|
|
33
231
|
commandLabel: 'workflows',
|
|
34
232
|
agentLabel: 'agent workflows',
|
|
35
233
|
});
|
|
234
|
+
|
|
235
|
+
// 2. Install agents as skills
|
|
236
|
+
const skillCount = await this.installSkills(projectDir, agileflowDir);
|
|
237
|
+
if (skillCount > 0) {
|
|
238
|
+
console.log(chalk.dim(` - ${skillCount} skills installed to .windsurf/skills/`));
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// 3. Setup damage control hooks
|
|
242
|
+
const windsurfDir = path.join(projectDir, this.configDir);
|
|
243
|
+
await this.setupDamageControlHooks(projectDir, agileflowDir, windsurfDir, options);
|
|
244
|
+
|
|
245
|
+
console.log(chalk.green(` ✓ ${this.displayName} configured:`));
|
|
246
|
+
console.log(chalk.dim(` - Workflows: .windsurf/workflows/agileflow/`));
|
|
247
|
+
console.log(chalk.dim(` - Skills: .windsurf/skills/agileflow-*/`));
|
|
248
|
+
console.log(chalk.dim(` - Hooks: .windsurf/hooks.json`));
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
...workflowsResult,
|
|
252
|
+
skills: skillCount,
|
|
253
|
+
};
|
|
36
254
|
}
|
|
37
255
|
|
|
38
256
|
/**
|
|
@@ -40,11 +258,24 @@ class WindsurfSetup extends BaseIdeSetup {
|
|
|
40
258
|
* @param {string} projectDir - Project directory
|
|
41
259
|
*/
|
|
42
260
|
async cleanup(projectDir) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
261
|
+
// Remove old workflows directory
|
|
262
|
+
const workflowsPath = path.join(projectDir, this.configDir, this.workflowsDir, 'agileflow');
|
|
263
|
+
if (await this.exists(workflowsPath)) {
|
|
264
|
+
await fs.remove(workflowsPath);
|
|
46
265
|
console.log(chalk.dim(` Removed old AgileFlow workflows from ${this.displayName}`));
|
|
47
266
|
}
|
|
267
|
+
|
|
268
|
+
// Remove old skills directories
|
|
269
|
+
const skillsDir = path.join(projectDir, this.configDir, 'skills');
|
|
270
|
+
if (await this.exists(skillsDir)) {
|
|
271
|
+
const entries = await fs.readdir(skillsDir);
|
|
272
|
+
for (const entry of entries) {
|
|
273
|
+
if (entry.startsWith('agileflow-')) {
|
|
274
|
+
await fs.remove(path.join(skillsDir, entry));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
console.log(chalk.dim(` Removed old AgileFlow skills from ${this.displayName}`));
|
|
278
|
+
}
|
|
48
279
|
}
|
|
49
280
|
}
|
|
50
281
|
|
|
@@ -23,7 +23,7 @@ const { parseFrontmatter, extractBody } = require('../../../scripts/lib/frontmat
|
|
|
23
23
|
* @example
|
|
24
24
|
* // Object form (simple string replacement)
|
|
25
25
|
* replaceReferences(content, {
|
|
26
|
-
* 'Claude Code': 'Codex
|
|
26
|
+
* 'Claude Code': 'OpenAI Codex',
|
|
27
27
|
* '.claude/': '.codex/',
|
|
28
28
|
* 'CLAUDE.md': 'AGENTS.md'
|
|
29
29
|
* });
|
|
@@ -31,7 +31,7 @@ const { parseFrontmatter, extractBody } = require('../../../scripts/lib/frontmat
|
|
|
31
31
|
* @example
|
|
32
32
|
* // Array form (with regex flags)
|
|
33
33
|
* replaceReferences(content, [
|
|
34
|
-
* { pattern: 'Claude Code', replacement: 'Codex
|
|
34
|
+
* { pattern: 'Claude Code', replacement: 'OpenAI Codex', flags: 'gi' },
|
|
35
35
|
* { pattern: /\.claude\//g, replacement: '.codex/' }
|
|
36
36
|
* ]);
|
|
37
37
|
*/
|
|
@@ -54,7 +54,10 @@ function replaceReferences(content, replacements) {
|
|
|
54
54
|
const flags = item.flags || 'g';
|
|
55
55
|
regex = new RegExp(escapeRegex(item.pattern), flags);
|
|
56
56
|
}
|
|
57
|
-
result = result.replace(
|
|
57
|
+
result = result.replace(
|
|
58
|
+
regex,
|
|
59
|
+
item.replacement !== undefined && item.replacement !== null ? item.replacement : ''
|
|
60
|
+
);
|
|
58
61
|
}
|
|
59
62
|
} else if (typeof replacements === 'object' && replacements !== null) {
|
|
60
63
|
// Object form: {pattern: replacement}
|
|
@@ -176,11 +179,11 @@ function getFrontmatter(content) {
|
|
|
176
179
|
*/
|
|
177
180
|
const IDE_REPLACEMENTS = {
|
|
178
181
|
/**
|
|
179
|
-
* Claude Code to Codex
|
|
182
|
+
* Claude Code to OpenAI Codex conversions
|
|
180
183
|
*/
|
|
181
184
|
codex: {
|
|
182
|
-
'Claude Code': 'Codex
|
|
183
|
-
'claude code': 'Codex
|
|
185
|
+
'Claude Code': 'OpenAI Codex',
|
|
186
|
+
'claude code': 'OpenAI Codex',
|
|
184
187
|
CLAUDE_CODE: 'CODEX_CLI',
|
|
185
188
|
'CLAUDE.md': 'AGENTS.md',
|
|
186
189
|
'.claude/': '.codex/',
|
|
@@ -197,6 +200,10 @@ const IDE_REPLACEMENTS = {
|
|
|
197
200
|
'claude code': 'Cursor',
|
|
198
201
|
'.claude/': '.cursor/',
|
|
199
202
|
'.claude\\': '.cursor\\',
|
|
203
|
+
'.claude/agents/agileflow': '.cursor/agents/AgileFlow',
|
|
204
|
+
'Task tool': 'subagent spawning',
|
|
205
|
+
'Task agent': 'subagent',
|
|
206
|
+
AskUserQuestion: 'numbered list prompt',
|
|
200
207
|
},
|
|
201
208
|
|
|
202
209
|
/**
|
|
@@ -207,9 +214,173 @@ const IDE_REPLACEMENTS = {
|
|
|
207
214
|
'claude code': 'Windsurf',
|
|
208
215
|
'.claude/': '.windsurf/',
|
|
209
216
|
'.claude\\': '.windsurf\\',
|
|
217
|
+
'Task tool': 'workflow chaining',
|
|
218
|
+
'Task agent': 'workflow',
|
|
219
|
+
AskUserQuestion: 'numbered list prompt',
|
|
220
|
+
'.claude/agents/agileflow': '.windsurf/skills/agileflow',
|
|
210
221
|
},
|
|
211
222
|
};
|
|
212
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Tool reference replacements for IDE capability-aware transformation
|
|
226
|
+
* Maps Claude Code tool/pattern names to IDE-appropriate alternatives
|
|
227
|
+
*
|
|
228
|
+
* @private
|
|
229
|
+
*/
|
|
230
|
+
const TOOL_REFERENCE_REPLACEMENTS = {
|
|
231
|
+
/**
|
|
232
|
+
* Cursor: Has subagents but no structured AskUserQuestion
|
|
233
|
+
* Replaces abstract tool patterns with concrete instructions
|
|
234
|
+
*/
|
|
235
|
+
cursor: [
|
|
236
|
+
// AskUserQuestion references
|
|
237
|
+
{
|
|
238
|
+
pattern: /call the AskUserQuestion tool/gi,
|
|
239
|
+
replacement: 'ask the user to reply with their choice (as a numbered list)',
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
pattern: /\bAskUserQuestion\b/g,
|
|
243
|
+
replacement: 'numbered list prompt',
|
|
244
|
+
},
|
|
245
|
+
// Task-related references (keep Task, but clarify it's for subagents)
|
|
246
|
+
{
|
|
247
|
+
pattern: /Task\(\s*$/gm,
|
|
248
|
+
replacement: '/* Use Cursor subagents to spawn async work */',
|
|
249
|
+
},
|
|
250
|
+
// Task tracking references (not available in Cursor)
|
|
251
|
+
{
|
|
252
|
+
pattern: /TaskCreate\b/g,
|
|
253
|
+
replacement: '(not available - track progress in conversation)',
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
pattern: /TaskUpdate\b/g,
|
|
257
|
+
replacement: '(not available in Cursor)',
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
pattern: /TaskList\b/g,
|
|
261
|
+
replacement: '(not available in Cursor)',
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Windsurf: No subagents, suggests workflow chaining instead
|
|
267
|
+
* Uses "megaplan" for plan mode
|
|
268
|
+
*/
|
|
269
|
+
windsurf: [
|
|
270
|
+
// AskUserQuestion references
|
|
271
|
+
{
|
|
272
|
+
pattern: /call the AskUserQuestion tool/gi,
|
|
273
|
+
replacement: 'ask the user to reply with their choice (as a numbered list)',
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
pattern: /\bAskUserQuestion\b/g,
|
|
277
|
+
replacement: 'numbered list prompt',
|
|
278
|
+
},
|
|
279
|
+
// Task references - suggest workflows instead
|
|
280
|
+
{
|
|
281
|
+
pattern: /\bTask\s*tool\b/gi,
|
|
282
|
+
replacement: 'workflow chaining',
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
pattern: /call the Task tool/gi,
|
|
286
|
+
replacement: 'suggest running the relevant /workflow',
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
pattern: /Task\(\s*$/gm,
|
|
290
|
+
replacement: '/* Suggest running /agileflow workflow via cascade */',
|
|
291
|
+
},
|
|
292
|
+
// Subagent type references - convert to workflow
|
|
293
|
+
{
|
|
294
|
+
pattern: /subagent_type:\s*"agileflow-([^"]+)"/g,
|
|
295
|
+
replacement: 'workflow: "/agileflow-$1"',
|
|
296
|
+
},
|
|
297
|
+
// Task tracking (not available)
|
|
298
|
+
{
|
|
299
|
+
pattern: /TaskCreate\b/g,
|
|
300
|
+
replacement: '(not available - use conversation comments)',
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
pattern: /TaskUpdate\b/g,
|
|
304
|
+
replacement: '(not available)',
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
pattern: /TaskList\b/g,
|
|
308
|
+
replacement: '(not available)',
|
|
309
|
+
},
|
|
310
|
+
// Plan mode - use megaplan keyword
|
|
311
|
+
{
|
|
312
|
+
pattern: /EnterPlanMode/g,
|
|
313
|
+
replacement: 'megaplan',
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
pattern: /ExitPlanMode/g,
|
|
317
|
+
replacement: '(end megaplan)',
|
|
318
|
+
},
|
|
319
|
+
],
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Codex: Most limited - no plan mode, hooks, or subagents
|
|
323
|
+
* Suggests skills and text-only interaction instead
|
|
324
|
+
*/
|
|
325
|
+
codex: [
|
|
326
|
+
// AskUserQuestion references - use text-only function
|
|
327
|
+
{
|
|
328
|
+
pattern: /call the AskUserQuestion tool/gi,
|
|
329
|
+
replacement: 'call ask_user_question (text-only, no menus)',
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
pattern: /\bAskUserQuestion\b/g,
|
|
333
|
+
replacement: 'ask_user_question',
|
|
334
|
+
},
|
|
335
|
+
// Task/delegation references - suggest skills instead
|
|
336
|
+
{
|
|
337
|
+
pattern: /\bTask\s*tool\b/gi,
|
|
338
|
+
replacement: 'skill invocation',
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
pattern: /call the Task tool/gi,
|
|
342
|
+
replacement: 'invoke the relevant $agileflow skill',
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
pattern: /Task\(\s*$/gm,
|
|
346
|
+
replacement: '/* Invoke relevant skill via $agileflow-name */',
|
|
347
|
+
},
|
|
348
|
+
// Subagent type references - convert to skill syntax
|
|
349
|
+
{
|
|
350
|
+
pattern: /subagent_type:\s*"agileflow-([^"]+)"/g,
|
|
351
|
+
replacement: 'skill: "$agileflow-$1"',
|
|
352
|
+
},
|
|
353
|
+
// Task tracking (not available)
|
|
354
|
+
{
|
|
355
|
+
pattern: /TaskCreate\b/g,
|
|
356
|
+
replacement: '(not available in Codex)',
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
pattern: /TaskUpdate\b/g,
|
|
360
|
+
replacement: '(not available)',
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
pattern: /TaskList\b/g,
|
|
364
|
+
replacement: '(not available)',
|
|
365
|
+
},
|
|
366
|
+
// Plan mode (available in Codex since v0.96 - keep references)
|
|
367
|
+
// EnterPlanMode and ExitPlanMode are native in Codex, no transformation needed
|
|
368
|
+
// Hooks (not available)
|
|
369
|
+
{
|
|
370
|
+
pattern: /PreToolUse\b/g,
|
|
371
|
+
replacement: '(not available - no hooks)',
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
pattern: /PostToolUse\b/g,
|
|
375
|
+
replacement: '(not available - no hooks)',
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
pattern: /SessionStart\b/g,
|
|
379
|
+
replacement: '(not available - no hooks)',
|
|
380
|
+
},
|
|
381
|
+
],
|
|
382
|
+
};
|
|
383
|
+
|
|
213
384
|
/**
|
|
214
385
|
* Create docs folder reference replacements
|
|
215
386
|
*
|
|
@@ -231,18 +402,63 @@ function createDocsReplacements(targetFolder) {
|
|
|
231
402
|
};
|
|
232
403
|
}
|
|
233
404
|
|
|
405
|
+
/**
|
|
406
|
+
* Transform tool references in content based on IDE capabilities.
|
|
407
|
+
* Replaces Claude Code tool names and patterns with IDE-appropriate alternatives.
|
|
408
|
+
*
|
|
409
|
+
* For Claude Code (canonical format), returns content unchanged.
|
|
410
|
+
* For other IDEs, replaces tool references with alternatives based on capabilities:
|
|
411
|
+
* - Cursor: Converts AskUserQuestion to "numbered list prompt", Task stays as subagents
|
|
412
|
+
* - Windsurf: Converts to "megaplan" and workflow suggestions, removes Task references
|
|
413
|
+
* - Codex: Converts to skill invocations, text-only prompts, removes Plan mode
|
|
414
|
+
*
|
|
415
|
+
* @param {string} content - Content with Claude Code tool references
|
|
416
|
+
* @param {string} targetIde - Target IDE name: 'claude-code', 'cursor', 'windsurf', 'codex'
|
|
417
|
+
* @returns {string} Content with IDE-appropriate tool references
|
|
418
|
+
*
|
|
419
|
+
* @example
|
|
420
|
+
* const content = 'Use the AskUserQuestion tool to get user input';
|
|
421
|
+
* const cursor = transformToolReferences(content, 'cursor');
|
|
422
|
+
* // Returns: 'Use numbered list prompt to get user input'
|
|
423
|
+
*
|
|
424
|
+
* @example
|
|
425
|
+
* const content = 'Call the Task tool with subagent_type: "agileflow-test"';
|
|
426
|
+
* const windsurf = transformToolReferences(content, 'windsurf');
|
|
427
|
+
* // Returns: 'Suggest running the relevant /workflow with workflow: "/agileflow-test"'
|
|
428
|
+
*/
|
|
429
|
+
function transformToolReferences(content, targetIde) {
|
|
430
|
+
// Claude Code is the canonical format - return unchanged
|
|
431
|
+
if (targetIde === 'claude-code') {
|
|
432
|
+
return content;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (!content || typeof content !== 'string') {
|
|
436
|
+
return content || '';
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const replacements = TOOL_REFERENCE_REPLACEMENTS[targetIde];
|
|
440
|
+
if (!replacements) {
|
|
441
|
+
// Unknown IDE - return unchanged
|
|
442
|
+
return content;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Apply all replacements in order
|
|
446
|
+
return replaceReferences(content, replacements);
|
|
447
|
+
}
|
|
448
|
+
|
|
234
449
|
/**
|
|
235
450
|
* Transform content for a specific IDE target
|
|
236
451
|
*
|
|
237
452
|
* @param {string} content - Source content
|
|
238
|
-
* @param {string} targetIde - Target IDE: 'codex', 'cursor', 'windsurf'
|
|
453
|
+
* @param {string} targetIde - Target IDE: 'codex', 'cursor', 'windsurf', 'claude-code'
|
|
239
454
|
* @param {Object} [options] - Additional options
|
|
240
455
|
* @param {string} [options.docsFolder] - Custom docs folder name
|
|
241
456
|
* @param {Object} [options.additionalReplacements] - Extra replacements to apply
|
|
457
|
+
* @param {boolean} [options.transformTools] - Apply tool reference transformations (default: false for backward compatibility)
|
|
242
458
|
* @returns {string} Transformed content
|
|
243
459
|
*/
|
|
244
460
|
function transformForIde(content, targetIde, options = {}) {
|
|
245
|
-
const { docsFolder, additionalReplacements = {} } = options;
|
|
461
|
+
const { docsFolder, additionalReplacements = {}, transformTools = false } = options;
|
|
246
462
|
|
|
247
463
|
// Start with IDE-specific replacements
|
|
248
464
|
const replacements = { ...(IDE_REPLACEMENTS[targetIde] || {}) };
|
|
@@ -255,7 +471,14 @@ function transformForIde(content, targetIde, options = {}) {
|
|
|
255
471
|
// Add any additional custom replacements
|
|
256
472
|
Object.assign(replacements, additionalReplacements);
|
|
257
473
|
|
|
258
|
-
|
|
474
|
+
let result = replaceReferences(content, replacements);
|
|
475
|
+
|
|
476
|
+
// Apply tool reference transformations if requested
|
|
477
|
+
if (transformTools) {
|
|
478
|
+
result = transformToolReferences(result, targetIde);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return result;
|
|
259
482
|
}
|
|
260
483
|
|
|
261
484
|
module.exports = {
|
|
@@ -266,6 +489,8 @@ module.exports = {
|
|
|
266
489
|
getFrontmatter,
|
|
267
490
|
escapeRegex,
|
|
268
491
|
IDE_REPLACEMENTS,
|
|
492
|
+
TOOL_REFERENCE_REPLACEMENTS,
|
|
269
493
|
createDocsReplacements,
|
|
494
|
+
transformToolReferences,
|
|
270
495
|
transformForIde,
|
|
271
496
|
};
|
|
@@ -190,7 +190,7 @@ Project-level planning and tracking.
|
|
|
190
190
|
- **milestones.md**: Release milestones
|
|
191
191
|
- **risks.md**: Project risks and mitigation strategies
|
|
192
192
|
- **ideation/**: Ideation reports from \`/agileflow:ideate:new\`
|
|
193
|
-
- **logic-audits/**: Logic audit reports from \`/agileflow:logic
|
|
193
|
+
- **logic-audits/**: Logic audit reports from \`/agileflow:audit:logic\`
|
|
194
194
|
`,
|
|
195
195
|
|
|
196
196
|
[`${docsFolder}/09-agents/README.md`]: `# Agent Status Tracking
|