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
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ide-generator.js - Build-time IDE-specific prompt/skill/agent generator
|
|
3
|
+
*
|
|
4
|
+
* Integrates IDE capability profiles with content transformer to produce
|
|
5
|
+
* IDE-native commands and agents during the install process.
|
|
6
|
+
*
|
|
7
|
+
* Main entry points:
|
|
8
|
+
* - generateForIde(content, targetIde, options) - Base transformation
|
|
9
|
+
* - generateCommandForIde(content, commandName, targetIde, options) - Command-specific
|
|
10
|
+
* - generateAgentForIde(content, agentName, targetIde, options) - Agent-specific
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
transformForIde,
|
|
15
|
+
transformToolReferences,
|
|
16
|
+
replaceReferences,
|
|
17
|
+
stripFrontmatter,
|
|
18
|
+
getFrontmatter,
|
|
19
|
+
convertFrontmatter,
|
|
20
|
+
} = require('./content-transformer');
|
|
21
|
+
|
|
22
|
+
// Lazy-load profile loader - only if profiles are needed
|
|
23
|
+
let profileLoader = null;
|
|
24
|
+
|
|
25
|
+
function getProfileLoader() {
|
|
26
|
+
if (!profileLoader) {
|
|
27
|
+
try {
|
|
28
|
+
profileLoader = require('../../../src/core/profiles/loader');
|
|
29
|
+
} catch (e) {
|
|
30
|
+
// Profiles not available - return null to indicate fallback mode
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return profileLoader;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get the IDE prefix style for commands
|
|
39
|
+
* Claude Code uses "/agileflow:", others use "/" or "$" as prefix
|
|
40
|
+
* @param {string} targetIde - Target IDE: 'claude-code', 'cursor', 'windsurf', 'codex'
|
|
41
|
+
* @returns {string} Command prefix pattern
|
|
42
|
+
* @private
|
|
43
|
+
*/
|
|
44
|
+
function getCommandPrefix(targetIde) {
|
|
45
|
+
const prefixes = {
|
|
46
|
+
'claude-code': '/agileflow:',
|
|
47
|
+
cursor: '/',
|
|
48
|
+
windsurf: '/',
|
|
49
|
+
codex: '$agileflow-',
|
|
50
|
+
};
|
|
51
|
+
return prefixes[targetIde] || '/agileflow:';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Convert /agileflow:style:commands to IDE-specific format
|
|
56
|
+
* - Claude Code: /agileflow:foo:bar → /agileflow:foo:bar (unchanged)
|
|
57
|
+
* - Cursor: /agileflow:foo:bar → /foo-bar
|
|
58
|
+
* - Windsurf: /agileflow:foo:bar → /agileflow-foo-bar
|
|
59
|
+
* - Codex: /agileflow:foo:bar → $agileflow-foo-bar
|
|
60
|
+
*
|
|
61
|
+
* @param {string} content - Content with command references
|
|
62
|
+
* @param {string} targetIde - Target IDE
|
|
63
|
+
* @returns {string} Content with converted command prefixes
|
|
64
|
+
* @private
|
|
65
|
+
*/
|
|
66
|
+
function convertCommandPrefixes(content, targetIde) {
|
|
67
|
+
if (targetIde === 'claude-code') {
|
|
68
|
+
return content; // No conversion needed
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let result = content;
|
|
72
|
+
|
|
73
|
+
if (targetIde === 'cursor') {
|
|
74
|
+
// /agileflow:foo:bar → /foo-bar
|
|
75
|
+
result = result.replace(/\/agileflow:([a-zA-Z0-9:_-]+)/g, (_match, rest) => {
|
|
76
|
+
return '/' + rest.replace(/:/g, '-');
|
|
77
|
+
});
|
|
78
|
+
} else if (targetIde === 'windsurf') {
|
|
79
|
+
// /agileflow:foo:bar → /agileflow-foo-bar
|
|
80
|
+
result = result.replace(/\/agileflow:([a-zA-Z0-9:_-]+)/g, (_match, rest) => {
|
|
81
|
+
return '/agileflow-' + rest.replace(/:/g, '-');
|
|
82
|
+
});
|
|
83
|
+
} else if (targetIde === 'codex') {
|
|
84
|
+
// /agileflow:foo:bar → $agileflow-foo-bar
|
|
85
|
+
result = result.replace(/\/agileflow:([a-zA-Z0-9:_-]+)/g, (_match, rest) => {
|
|
86
|
+
return '$agileflow-' + rest.replace(/:/g, '-');
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Main entry point for IDE-specific content generation
|
|
95
|
+
* Takes canonical Claude Code markdown content and transforms it for a target IDE
|
|
96
|
+
*
|
|
97
|
+
* @param {string} content - Source content (Claude Code format)
|
|
98
|
+
* @param {string} targetIde - Target IDE: 'claude-code', 'cursor', 'windsurf', 'codex'
|
|
99
|
+
* @param {Object} [options] - Generation options
|
|
100
|
+
* @param {string} [options.docsFolder] - Custom docs folder name
|
|
101
|
+
* @param {boolean} [options.transformTools] - Apply tool reference transformations (default: true)
|
|
102
|
+
* @param {boolean} [options.transformPrefixes] - Convert command prefixes (default: true)
|
|
103
|
+
* @param {Object} [options.additionalReplacements] - Extra IDE-specific replacements
|
|
104
|
+
* @returns {string} Transformed content for target IDE
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* const content = await fs.readFile('command.md', 'utf8');
|
|
108
|
+
* const cursorVersion = generateForIde(content, 'cursor', { transformTools: true });
|
|
109
|
+
*/
|
|
110
|
+
function generateForIde(content, targetIde, options = {}) {
|
|
111
|
+
if (!content || typeof content !== 'string') {
|
|
112
|
+
return content || '';
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Claude Code is canonical format - return as-is
|
|
116
|
+
if (targetIde === 'claude-code') {
|
|
117
|
+
return content;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const {
|
|
121
|
+
docsFolder,
|
|
122
|
+
transformTools = true,
|
|
123
|
+
transformPrefixes = true,
|
|
124
|
+
additionalReplacements = {},
|
|
125
|
+
} = options;
|
|
126
|
+
|
|
127
|
+
// Step 1: Apply IDE-specific replacements and docs folder updates
|
|
128
|
+
let result = transformForIde(content, targetIde, {
|
|
129
|
+
docsFolder,
|
|
130
|
+
additionalReplacements,
|
|
131
|
+
transformTools: false, // Will apply separately
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Step 2: Apply tool reference transformations if requested
|
|
135
|
+
if (transformTools) {
|
|
136
|
+
result = transformToolReferences(result, targetIde);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Step 3: Convert command prefixes if requested
|
|
140
|
+
if (transformPrefixes) {
|
|
141
|
+
result = convertCommandPrefixes(result, targetIde);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Generate IDE-specific command content with IDE-native wrapping
|
|
149
|
+
*
|
|
150
|
+
* For Codex, adds {{input}} placeholder at end for context injection.
|
|
151
|
+
* For other IDEs, uses base generateForIde() transformation.
|
|
152
|
+
*
|
|
153
|
+
* @param {string} content - Source command content (Claude Code format)
|
|
154
|
+
* @param {string} commandName - Command name for display
|
|
155
|
+
* @param {string} targetIde - Target IDE
|
|
156
|
+
* @param {Object} [options] - Generation options (same as generateForIde)
|
|
157
|
+
* @returns {string} IDE-native command content
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* const cmd = await fs.readFile('commands/deploy.md', 'utf8');
|
|
161
|
+
* const codexPrompt = generateCommandForIde(cmd, 'deploy', 'codex');
|
|
162
|
+
*/
|
|
163
|
+
function generateCommandForIde(content, commandName, targetIde, options = {}) {
|
|
164
|
+
// Handle null/undefined content
|
|
165
|
+
if (content === null || content === undefined || typeof content !== 'string') {
|
|
166
|
+
return '';
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Start with base transformation
|
|
170
|
+
let result = generateForIde(content, targetIde, options);
|
|
171
|
+
|
|
172
|
+
// Codex-specific wrapping: Add {{input}} placeholder
|
|
173
|
+
if (targetIde === 'codex' && result !== '') {
|
|
174
|
+
// Strip frontmatter for Codex format
|
|
175
|
+
const bodyContent = stripFrontmatter(result);
|
|
176
|
+
const frontmatter = getFrontmatter(content);
|
|
177
|
+
const description = frontmatter.description || `AgileFlow ${commandName} command`;
|
|
178
|
+
|
|
179
|
+
const header = `# AgileFlow: ${commandName}
|
|
180
|
+
|
|
181
|
+
> ${description}
|
|
182
|
+
|
|
183
|
+
## Instructions
|
|
184
|
+
|
|
185
|
+
`;
|
|
186
|
+
|
|
187
|
+
const footer = `
|
|
188
|
+
|
|
189
|
+
## Context
|
|
190
|
+
|
|
191
|
+
{{input}}
|
|
192
|
+
`;
|
|
193
|
+
|
|
194
|
+
result = header + bodyContent + footer;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return result;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Generate IDE-specific agent/skill content
|
|
202
|
+
*
|
|
203
|
+
* Performs IDE-specific transformations including:
|
|
204
|
+
* - For Codex: Converts to SKILL.md format with skill-specific frontmatter
|
|
205
|
+
* - For Windsurf: Converts to agentskills.io format with skill-specific frontmatter
|
|
206
|
+
* - For Cursor: Adds agent-specific frontmatter for spawnable agents
|
|
207
|
+
* - For Claude Code: Returns unchanged (canonical format)
|
|
208
|
+
*
|
|
209
|
+
* @param {string} content - Source agent content (Claude Code format)
|
|
210
|
+
* @param {string} agentName - Agent name (e.g., 'database', 'security')
|
|
211
|
+
* @param {string} targetIde - Target IDE: 'claude-code', 'cursor', 'windsurf', 'codex'
|
|
212
|
+
* @param {Object} [options] - Generation options
|
|
213
|
+
* @param {string} [options.docsFolder] - Custom docs folder name
|
|
214
|
+
* @param {boolean} [options.transformTools] - Apply tool reference transformations (default: true)
|
|
215
|
+
* @returns {string} IDE-native agent/skill content
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* const agent = await fs.readFile('agents/security.md', 'utf8');
|
|
219
|
+
* const windsurfSkill = generateAgentForIde(agent, 'security', 'windsurf');
|
|
220
|
+
*/
|
|
221
|
+
function generateAgentForIde(content, agentName, targetIde, options = {}) {
|
|
222
|
+
if (!content || typeof content !== 'string') {
|
|
223
|
+
return content || '';
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Claude Code is canonical format
|
|
227
|
+
if (targetIde === 'claude-code') {
|
|
228
|
+
return content;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const { docsFolder, transformTools = true } = options;
|
|
232
|
+
|
|
233
|
+
// Get base transformations
|
|
234
|
+
const baseContent = generateForIde(content, targetIde, {
|
|
235
|
+
docsFolder,
|
|
236
|
+
transformTools,
|
|
237
|
+
transformPrefixes: false, // Don't convert prefixes in agent bodies
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// Extract frontmatter and body
|
|
241
|
+
const frontmatter = getFrontmatter(content);
|
|
242
|
+
const description = frontmatter.description || `AgileFlow ${agentName} agent`;
|
|
243
|
+
|
|
244
|
+
// Apply IDE-specific formatting
|
|
245
|
+
if (targetIde === 'codex') {
|
|
246
|
+
return formatAgentForCodex(baseContent, agentName, description);
|
|
247
|
+
} else if (targetIde === 'windsurf') {
|
|
248
|
+
return formatAgentForWindsurf(baseContent, agentName, description);
|
|
249
|
+
} else if (targetIde === 'cursor') {
|
|
250
|
+
return formatAgentForCursor(baseContent, agentName, description);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return baseContent;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Format agent content for Codex SKILL.md format
|
|
258
|
+
* @private
|
|
259
|
+
*/
|
|
260
|
+
function formatAgentForCodex(content, agentName, description) {
|
|
261
|
+
const yaml = require('../../../lib/yaml-utils').yaml;
|
|
262
|
+
|
|
263
|
+
const bodyContent = stripFrontmatter(content);
|
|
264
|
+
|
|
265
|
+
// Create SKILL.md with YAML frontmatter
|
|
266
|
+
const skillFrontmatter = yaml
|
|
267
|
+
.dump({
|
|
268
|
+
name: `agileflow-${agentName}`,
|
|
269
|
+
description: description,
|
|
270
|
+
version: '1.0.0',
|
|
271
|
+
})
|
|
272
|
+
.trim();
|
|
273
|
+
|
|
274
|
+
const codexHeader = `# AgileFlow: ${agentName.charAt(0).toUpperCase() + agentName.slice(1)} Agent
|
|
275
|
+
|
|
276
|
+
> Invoke with \`$agileflow-${agentName}\` or via \`/skills\`
|
|
277
|
+
|
|
278
|
+
`;
|
|
279
|
+
|
|
280
|
+
return `---
|
|
281
|
+
${skillFrontmatter}
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
${codexHeader}${bodyContent}`;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Format agent content for Windsurf SKILL.md (agentskills.io spec)
|
|
289
|
+
* @private
|
|
290
|
+
*/
|
|
291
|
+
function formatAgentForWindsurf(content, agentName, description) {
|
|
292
|
+
const yaml = require('../../../lib/yaml-utils').yaml;
|
|
293
|
+
|
|
294
|
+
const bodyContent = stripFrontmatter(content);
|
|
295
|
+
|
|
296
|
+
// Create SKILL.md with YAML frontmatter (agentskills.io spec)
|
|
297
|
+
const skillFrontmatter = yaml
|
|
298
|
+
.dump({
|
|
299
|
+
name: `agileflow-${agentName}`,
|
|
300
|
+
description: description,
|
|
301
|
+
})
|
|
302
|
+
.trim();
|
|
303
|
+
|
|
304
|
+
const windsurfHeader = `# AgileFlow: ${agentName.charAt(0).toUpperCase() + agentName.slice(1)} Skill
|
|
305
|
+
|
|
306
|
+
> Use this skill via \`@agileflow-${agentName}\` or /cascade
|
|
307
|
+
|
|
308
|
+
`;
|
|
309
|
+
|
|
310
|
+
return `---
|
|
311
|
+
${skillFrontmatter}
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
${windsurfHeader}${bodyContent}`;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Format agent content for Cursor spawnable agent
|
|
319
|
+
* Cursor agents use YAML frontmatter with name, description, and model fields
|
|
320
|
+
* @private
|
|
321
|
+
*/
|
|
322
|
+
function formatAgentForCursor(content, agentName, description) {
|
|
323
|
+
const yaml = require('../../../lib/yaml-utils').yaml;
|
|
324
|
+
|
|
325
|
+
// Extract frontmatter from source
|
|
326
|
+
const sourceFrontmatter = getFrontmatter(content);
|
|
327
|
+
const bodyContent = stripFrontmatter(content);
|
|
328
|
+
|
|
329
|
+
// Create agent frontmatter for Cursor
|
|
330
|
+
const agentFrontmatter = yaml
|
|
331
|
+
.dump({
|
|
332
|
+
name: `agileflow-${agentName}`,
|
|
333
|
+
description: description,
|
|
334
|
+
model: sourceFrontmatter.model || 'claude-3-5-sonnet',
|
|
335
|
+
readonly: false,
|
|
336
|
+
})
|
|
337
|
+
.trim();
|
|
338
|
+
|
|
339
|
+
return `---
|
|
340
|
+
${agentFrontmatter}
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
${bodyContent}`;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
module.exports = {
|
|
347
|
+
generateForIde,
|
|
348
|
+
generateCommandForIde,
|
|
349
|
+
generateAgentForIde,
|
|
350
|
+
getCommandPrefix,
|
|
351
|
+
// Export private functions for testing
|
|
352
|
+
_convertCommandPrefixes: convertCommandPrefixes,
|
|
353
|
+
_getProfileLoader: getProfileLoader,
|
|
354
|
+
_formatAgentForCodex: formatAgentForCodex,
|
|
355
|
+
_formatAgentForWindsurf: formatAgentForWindsurf,
|
|
356
|
+
_formatAgentForCursor: formatAgentForCursor,
|
|
357
|
+
};
|
|
@@ -98,13 +98,13 @@ const IDE_REGISTRY = {
|
|
|
98
98
|
},
|
|
99
99
|
codex: {
|
|
100
100
|
name: 'codex',
|
|
101
|
-
displayName: 'OpenAI Codex
|
|
101
|
+
displayName: 'OpenAI Codex',
|
|
102
102
|
configDir: '.codex',
|
|
103
103
|
commandsSubdir: 'skills',
|
|
104
104
|
agileflowFolder: 'agileflow',
|
|
105
105
|
targetSubdir: 'skills', // Codex uses skills directory
|
|
106
106
|
preferred: false,
|
|
107
|
-
description: "OpenAI's Codex
|
|
107
|
+
description: "OpenAI's Codex",
|
|
108
108
|
handler: 'CodexSetup',
|
|
109
109
|
labels: {
|
|
110
110
|
commands: 'prompts',
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# tmux-task-name.sh - Rename current tmux window based on task/work description
|
|
3
|
-
#
|
|
4
|
-
# Called by Claude Code when starting work on a task (via TaskCreate/TaskUpdate).
|
|
5
|
-
# Reads the task subject from ~/.claude/tasks/ or accepts it as an argument.
|
|
6
|
-
#
|
|
7
|
-
# Usage:
|
|
8
|
-
# tmux-task-name.sh "Fix auth middleware" # Rename to task subject
|
|
9
|
-
# tmux-task-name.sh --scan # Auto-detect from task files
|
|
10
|
-
# tmux-task-name.sh --scan --session <UUID> # Scan only one session's tasks
|
|
11
|
-
# tmux-task-name.sh --reset # Reset to default "claude-N"
|
|
12
|
-
#
|
|
13
|
-
# The script is best-effort: silently exits if not inside tmux.
|
|
14
|
-
|
|
15
|
-
set -euo pipefail
|
|
16
|
-
|
|
17
|
-
# Exit silently if not in tmux
|
|
18
|
-
[ -n "${TMUX:-}" ] || exit 0
|
|
19
|
-
|
|
20
|
-
MAX_LEN=30
|
|
21
|
-
|
|
22
|
-
truncate_name() {
|
|
23
|
-
local name="$1"
|
|
24
|
-
if [ ${#name} -gt $MAX_LEN ]; then
|
|
25
|
-
echo "${name:0:$((MAX_LEN - 1))}…"
|
|
26
|
-
else
|
|
27
|
-
echo "$name"
|
|
28
|
-
fi
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
# Mode: reset to default sequential name
|
|
32
|
-
if [ "${1:-}" = "--reset" ]; then
|
|
33
|
-
N=$(( $(tmux list-windows -F '#{window_name}' 2>/dev/null | grep -c '^claude') ))
|
|
34
|
-
[ "$N" -eq 0 ] && N=1
|
|
35
|
-
tmux rename-window "claude-$N" 2>/dev/null || true
|
|
36
|
-
exit 0
|
|
37
|
-
fi
|
|
38
|
-
|
|
39
|
-
# Mode: scan ~/.claude/tasks/ for most recently modified in-progress task
|
|
40
|
-
if [ "${1:-}" = "--scan" ]; then
|
|
41
|
-
TASKS_BASE="${HOME}/.claude/tasks"
|
|
42
|
-
[ -d "$TASKS_BASE" ] || exit 0
|
|
43
|
-
|
|
44
|
-
# Determine session scope: --session param, pane option, or global scan
|
|
45
|
-
SESSION_ID=""
|
|
46
|
-
if [ "${2:-}" = "--session" ] && [ -n "${3:-}" ]; then
|
|
47
|
-
# Validate session ID is alphanumeric + hyphens only (prevent path traversal)
|
|
48
|
-
if [[ "$3" =~ ^[a-zA-Z0-9_-]+$ ]]; then
|
|
49
|
-
SESSION_ID="$3"
|
|
50
|
-
fi
|
|
51
|
-
elif [ -n "${TMUX:-}" ]; then
|
|
52
|
-
SESSION_ID=$(tmux show-options -pqv @claude_session_id 2>/dev/null || true)
|
|
53
|
-
fi
|
|
54
|
-
|
|
55
|
-
BEST_SUBJECT=""
|
|
56
|
-
BEST_MTIME=0
|
|
57
|
-
|
|
58
|
-
if [ -n "$SESSION_ID" ]; then
|
|
59
|
-
# Scoped scan: only look at this session's tasks
|
|
60
|
-
SCAN_DIR="$TASKS_BASE/$SESSION_ID"
|
|
61
|
-
if [ -d "$SCAN_DIR" ]; then
|
|
62
|
-
for f in "$SCAN_DIR"/*.json; do
|
|
63
|
-
[ -f "$f" ] || continue
|
|
64
|
-
status=$(python3 -c "import json,sys; d=json.load(open('$f')); print(d.get('status',''))" 2>/dev/null || echo "")
|
|
65
|
-
if [ "$status" = "in_progress" ]; then
|
|
66
|
-
mtime=$(stat -c %Y "$f" 2>/dev/null || stat -f %m "$f" 2>/dev/null || echo "0")
|
|
67
|
-
if [ "$mtime" -gt "$BEST_MTIME" ]; then
|
|
68
|
-
BEST_MTIME=$mtime
|
|
69
|
-
BEST_SUBJECT=$(python3 -c "import json; d=json.load(open('$f')); print(d.get('subject',''))" 2>/dev/null || echo "")
|
|
70
|
-
fi
|
|
71
|
-
fi
|
|
72
|
-
done
|
|
73
|
-
fi
|
|
74
|
-
else
|
|
75
|
-
# Global scan: all sessions (fallback for no session context)
|
|
76
|
-
for dir in "$TASKS_BASE"/*/; do
|
|
77
|
-
[ -d "$dir" ] || continue
|
|
78
|
-
for f in "$dir"*.json; do
|
|
79
|
-
[ -f "$f" ] || continue
|
|
80
|
-
status=$(python3 -c "import json,sys; d=json.load(open('$f')); print(d.get('status',''))" 2>/dev/null || echo "")
|
|
81
|
-
if [ "$status" = "in_progress" ]; then
|
|
82
|
-
mtime=$(stat -c %Y "$f" 2>/dev/null || stat -f %m "$f" 2>/dev/null || echo "0")
|
|
83
|
-
if [ "$mtime" -gt "$BEST_MTIME" ]; then
|
|
84
|
-
BEST_MTIME=$mtime
|
|
85
|
-
BEST_SUBJECT=$(python3 -c "import json; d=json.load(open('$f')); print(d.get('subject',''))" 2>/dev/null || echo "")
|
|
86
|
-
fi
|
|
87
|
-
fi
|
|
88
|
-
done
|
|
89
|
-
done
|
|
90
|
-
fi
|
|
91
|
-
|
|
92
|
-
if [ -n "$BEST_SUBJECT" ]; then
|
|
93
|
-
tmux rename-window "$(truncate_name "$BEST_SUBJECT")" 2>/dev/null || true
|
|
94
|
-
fi
|
|
95
|
-
exit 0
|
|
96
|
-
fi
|
|
97
|
-
|
|
98
|
-
# Mode: direct - rename to provided argument
|
|
99
|
-
if [ -n "${1:-}" ]; then
|
|
100
|
-
tmux rename-window "$(truncate_name "$1")" 2>/dev/null || true
|
|
101
|
-
exit 0
|
|
102
|
-
fi
|
|
103
|
-
|
|
104
|
-
echo "Usage: tmux-task-name.sh <task-subject> | --scan | --reset" >&2
|
|
105
|
-
exit 1
|