@claude-flow/codex 3.0.0-alpha.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/README.md +301 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +649 -0
- package/dist/cli.js.map +1 -0
- package/dist/generators/agents-md.d.ts +12 -0
- package/dist/generators/agents-md.d.ts.map +1 -0
- package/dist/generators/agents-md.js +641 -0
- package/dist/generators/agents-md.js.map +1 -0
- package/dist/generators/config-toml.d.ts +74 -0
- package/dist/generators/config-toml.d.ts.map +1 -0
- package/dist/generators/config-toml.js +910 -0
- package/dist/generators/config-toml.js.map +1 -0
- package/dist/generators/index.d.ts +9 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +9 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/generators/skill-md.d.ts +20 -0
- package/dist/generators/skill-md.d.ts.map +1 -0
- package/dist/generators/skill-md.js +946 -0
- package/dist/generators/skill-md.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/initializer.d.ts +87 -0
- package/dist/initializer.d.ts.map +1 -0
- package/dist/initializer.js +666 -0
- package/dist/initializer.js.map +1 -0
- package/dist/migrations/index.d.ts +114 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +856 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/templates/index.d.ts +92 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +284 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/types.d.ts +218 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/validators/index.d.ts +42 -0
- package/dist/validators/index.d.ts.map +1 -0
- package/dist/validators/index.js +929 -0
- package/dist/validators/index.js.map +1 -0
- package/package.json +88 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @claude-flow/codex - CLI
|
|
4
|
+
*
|
|
5
|
+
* Command-line interface for Codex integration
|
|
6
|
+
* Part of the coflow rebranding initiative
|
|
7
|
+
*/
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import { CodexInitializer } from './initializer.js';
|
|
11
|
+
import { validateAgentsMd, validateSkillMd, validateConfigToml } from './validators/index.js';
|
|
12
|
+
import { migrateFromClaudeCode, analyzeClaudeMd, generateMigrationReport } from './migrations/index.js';
|
|
13
|
+
import { listTemplates, BUILT_IN_SKILLS } from './templates/index.js';
|
|
14
|
+
import { generateSkillMd } from './generators/skill-md.js';
|
|
15
|
+
import { VERSION, PACKAGE_INFO } from './index.js';
|
|
16
|
+
import fs from 'fs-extra';
|
|
17
|
+
import path from 'path';
|
|
18
|
+
const program = new Command();
|
|
19
|
+
// Custom error handler for better output
|
|
20
|
+
function handleError(error, message) {
|
|
21
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
22
|
+
console.error(chalk.red.bold('\nError:'), chalk.red(message ?? errorMessage));
|
|
23
|
+
if (error instanceof Error && error.stack && process.env.DEBUG) {
|
|
24
|
+
console.error(chalk.gray('\nStack trace:'));
|
|
25
|
+
console.error(chalk.gray(error.stack));
|
|
26
|
+
}
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
// Validate project path exists and is accessible
|
|
30
|
+
async function validatePath(projectPath) {
|
|
31
|
+
const resolvedPath = path.resolve(projectPath);
|
|
32
|
+
try {
|
|
33
|
+
const stats = await fs.stat(resolvedPath);
|
|
34
|
+
if (!stats.isDirectory()) {
|
|
35
|
+
throw new Error(`Path is not a directory: ${resolvedPath}`);
|
|
36
|
+
}
|
|
37
|
+
return resolvedPath;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error.code === 'ENOENT') {
|
|
41
|
+
// Directory doesn't exist, try to create it
|
|
42
|
+
console.log(chalk.yellow(`Creating directory: ${resolvedPath}`));
|
|
43
|
+
await fs.ensureDir(resolvedPath);
|
|
44
|
+
return resolvedPath;
|
|
45
|
+
}
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Validate skill name format
|
|
50
|
+
function validateSkillName(name) {
|
|
51
|
+
const validPattern = /^[a-z][a-z0-9-]*$/;
|
|
52
|
+
return validPattern.test(name);
|
|
53
|
+
}
|
|
54
|
+
// Print banner
|
|
55
|
+
function printBanner() {
|
|
56
|
+
console.log(chalk.cyan.bold('\n Claude Flow Codex'));
|
|
57
|
+
console.log(chalk.gray(' OpenAI Codex integration for Claude Flow'));
|
|
58
|
+
console.log(chalk.gray(' ----------------------------------------\n'));
|
|
59
|
+
}
|
|
60
|
+
program
|
|
61
|
+
.name('claude-flow-codex')
|
|
62
|
+
.description('OpenAI Codex integration for Claude Flow - Part of the coflow ecosystem')
|
|
63
|
+
.version(VERSION, '-v, --version', 'Display version number')
|
|
64
|
+
.option('--debug', 'Enable debug mode', false)
|
|
65
|
+
.hook('preAction', (thisCommand) => {
|
|
66
|
+
if (thisCommand.opts().debug) {
|
|
67
|
+
process.env.DEBUG = 'true';
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
// Init command
|
|
71
|
+
program
|
|
72
|
+
.command('init')
|
|
73
|
+
.description('Initialize a new Codex project with AGENTS.md and skills')
|
|
74
|
+
.option('-t, --template <template>', 'Template to use (minimal, default, full, enterprise)', 'default')
|
|
75
|
+
.option('-s, --skills <skills>', 'Comma-separated list of skills to include')
|
|
76
|
+
.option('-f, --force', 'Overwrite existing files', false)
|
|
77
|
+
.option('--dual', 'Generate both Codex and Claude Code configurations', false)
|
|
78
|
+
.option('-p, --path <path>', 'Project path', process.cwd())
|
|
79
|
+
.option('-q, --quiet', 'Suppress verbose output', false)
|
|
80
|
+
.action(async (options) => {
|
|
81
|
+
try {
|
|
82
|
+
if (!options.quiet) {
|
|
83
|
+
printBanner();
|
|
84
|
+
}
|
|
85
|
+
// Validate template
|
|
86
|
+
const validTemplates = ['minimal', 'default', 'full', 'enterprise'];
|
|
87
|
+
if (!validTemplates.includes(options.template)) {
|
|
88
|
+
console.error(chalk.red(`Invalid template: ${options.template}`));
|
|
89
|
+
console.log(chalk.gray(`Valid templates: ${validTemplates.join(', ')}`));
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
const projectPath = await validatePath(options.path);
|
|
93
|
+
console.log(chalk.blue('Initializing Codex project...'));
|
|
94
|
+
console.log(chalk.gray(` Path: ${projectPath}`));
|
|
95
|
+
console.log(chalk.gray(` Template: ${options.template}`));
|
|
96
|
+
if (options.skills) {
|
|
97
|
+
console.log(chalk.gray(` Skills: ${options.skills}`));
|
|
98
|
+
}
|
|
99
|
+
if (options.force) {
|
|
100
|
+
console.log(chalk.yellow(' Force: enabled (will overwrite existing files)'));
|
|
101
|
+
}
|
|
102
|
+
if (options.dual) {
|
|
103
|
+
console.log(chalk.gray(' Mode: dual (Codex + Claude Code)'));
|
|
104
|
+
}
|
|
105
|
+
const initializer = new CodexInitializer();
|
|
106
|
+
const skills = options.skills?.split(',').map((s) => s.trim()).filter(Boolean);
|
|
107
|
+
// Validate skill names if provided
|
|
108
|
+
if (skills) {
|
|
109
|
+
for (const skill of skills) {
|
|
110
|
+
if (!validateSkillName(skill)) {
|
|
111
|
+
console.error(chalk.red(`Invalid skill name: ${skill}`));
|
|
112
|
+
console.log(chalk.gray('Skill names must be kebab-case (lowercase letters, numbers, hyphens)'));
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const result = await initializer.initialize({
|
|
118
|
+
projectPath,
|
|
119
|
+
template: options.template,
|
|
120
|
+
skills,
|
|
121
|
+
force: options.force,
|
|
122
|
+
dual: options.dual,
|
|
123
|
+
});
|
|
124
|
+
if (result.success) {
|
|
125
|
+
console.log(chalk.green.bold('\n Project initialized successfully!'));
|
|
126
|
+
if (result.filesCreated.length > 0) {
|
|
127
|
+
console.log(chalk.white('\n Files created:'));
|
|
128
|
+
for (const file of result.filesCreated) {
|
|
129
|
+
console.log(chalk.gray(` ${chalk.green('+')} ${file}`));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (result.skillsGenerated.length > 0) {
|
|
133
|
+
console.log(chalk.white('\n Skills generated:'));
|
|
134
|
+
for (const skill of result.skillsGenerated) {
|
|
135
|
+
console.log(chalk.gray(` ${chalk.cyan('$')}${skill}`));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (result.warnings && result.warnings.length > 0) {
|
|
139
|
+
console.log(chalk.yellow('\n Warnings:'));
|
|
140
|
+
for (const warning of result.warnings) {
|
|
141
|
+
console.log(chalk.yellow(` ! ${warning}`));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
console.log(chalk.blue.bold('\n Next steps:'));
|
|
145
|
+
console.log(chalk.gray(' 1. Review AGENTS.md and customize for your project'));
|
|
146
|
+
console.log(chalk.gray(' 2. Review .agents/config.toml settings'));
|
|
147
|
+
console.log(chalk.gray(' 3. Start using skills with $skill-name syntax'));
|
|
148
|
+
console.log();
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
console.log(chalk.red.bold('\n Initialization failed'));
|
|
152
|
+
if (result.errors) {
|
|
153
|
+
for (const error of result.errors) {
|
|
154
|
+
console.log(chalk.red(` - ${error}`));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
handleError(error, 'Failed to initialize project');
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
// Generate skill command
|
|
165
|
+
program
|
|
166
|
+
.command('generate-skill')
|
|
167
|
+
.alias('gs')
|
|
168
|
+
.description('Generate a new SKILL.md file')
|
|
169
|
+
.requiredOption('-n, --name <name>', 'Skill name (kebab-case)')
|
|
170
|
+
.option('-d, --description <description>', 'Skill description')
|
|
171
|
+
.option('-t, --triggers <triggers>', 'Comma-separated trigger conditions')
|
|
172
|
+
.option('-s, --skip <skip>', 'Comma-separated skip conditions')
|
|
173
|
+
.option('-p, --path <path>', 'Output path', process.cwd())
|
|
174
|
+
.option('--dry-run', 'Show what would be generated without writing', false)
|
|
175
|
+
.action(async (options) => {
|
|
176
|
+
try {
|
|
177
|
+
printBanner();
|
|
178
|
+
// Validate skill name
|
|
179
|
+
if (!validateSkillName(options.name)) {
|
|
180
|
+
console.error(chalk.red(`Invalid skill name: ${options.name}`));
|
|
181
|
+
console.log(chalk.gray('Skill names must be kebab-case (lowercase letters, numbers, hyphens)'));
|
|
182
|
+
console.log(chalk.gray('Examples: my-skill, code-analyzer, data-processor'));
|
|
183
|
+
process.exit(1);
|
|
184
|
+
}
|
|
185
|
+
const projectPath = await validatePath(options.path);
|
|
186
|
+
console.log(chalk.blue(`Generating skill: ${chalk.white(options.name)}`));
|
|
187
|
+
const triggers = options.triggers?.split(',').map((s) => s.trim()).filter(Boolean);
|
|
188
|
+
const skipWhen = options.skip?.split(',').map((s) => s.trim()).filter(Boolean);
|
|
189
|
+
const skillMd = await generateSkillMd({
|
|
190
|
+
name: options.name,
|
|
191
|
+
description: options.description ?? `Custom skill: ${options.name}`,
|
|
192
|
+
triggers: triggers ?? ['Define when to trigger this skill'],
|
|
193
|
+
skipWhen: skipWhen ?? ['Define when to skip this skill'],
|
|
194
|
+
});
|
|
195
|
+
if (options.dryRun) {
|
|
196
|
+
console.log(chalk.yellow('\nDry run - would generate:'));
|
|
197
|
+
console.log(chalk.gray('---'));
|
|
198
|
+
console.log(skillMd);
|
|
199
|
+
console.log(chalk.gray('---'));
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const skillDir = path.join(projectPath, '.agents', 'skills', options.name);
|
|
203
|
+
await fs.ensureDir(skillDir);
|
|
204
|
+
const skillPath = path.join(skillDir, 'SKILL.md');
|
|
205
|
+
// Check if skill already exists
|
|
206
|
+
if (await fs.pathExists(skillPath)) {
|
|
207
|
+
console.log(chalk.yellow(`Skill already exists: ${skillPath}`));
|
|
208
|
+
console.log(chalk.gray('Use --force to overwrite (not yet implemented)'));
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
await fs.writeFile(skillPath, skillMd);
|
|
212
|
+
console.log(chalk.green.bold(`\n Skill created successfully!`));
|
|
213
|
+
console.log(chalk.gray(` Path: ${skillPath}`));
|
|
214
|
+
console.log(chalk.gray(` Use: ${chalk.cyan('$' + options.name)}`));
|
|
215
|
+
console.log();
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
handleError(error, 'Failed to generate skill');
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
// Validate command
|
|
222
|
+
program
|
|
223
|
+
.command('validate')
|
|
224
|
+
.alias('check')
|
|
225
|
+
.description('Validate AGENTS.md, SKILL.md, or config.toml files')
|
|
226
|
+
.option('-f, --file <file>', 'File to validate')
|
|
227
|
+
.option('-p, --path <path>', 'Project path to validate all files', process.cwd())
|
|
228
|
+
.option('--fix', 'Attempt to fix issues (not yet implemented)', false)
|
|
229
|
+
.option('--strict', 'Treat warnings as errors', false)
|
|
230
|
+
.action(async (options) => {
|
|
231
|
+
try {
|
|
232
|
+
printBanner();
|
|
233
|
+
const projectPath = path.resolve(options.path);
|
|
234
|
+
const filesToValidate = [];
|
|
235
|
+
if (options.file) {
|
|
236
|
+
// Validate specific file
|
|
237
|
+
const filePath = path.resolve(options.file);
|
|
238
|
+
if (!await fs.pathExists(filePath)) {
|
|
239
|
+
console.error(chalk.red(`File not found: ${filePath}`));
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
const fileName = path.basename(filePath).toLowerCase();
|
|
243
|
+
if (fileName === 'agents.md') {
|
|
244
|
+
filesToValidate.push({ path: filePath, type: 'agents' });
|
|
245
|
+
}
|
|
246
|
+
else if (fileName === 'skill.md') {
|
|
247
|
+
filesToValidate.push({ path: filePath, type: 'skill' });
|
|
248
|
+
}
|
|
249
|
+
else if (fileName === 'config.toml') {
|
|
250
|
+
filesToValidate.push({ path: filePath, type: 'config' });
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
console.error(chalk.red(`Unknown file type: ${fileName}`));
|
|
254
|
+
console.log(chalk.gray('Supported files: AGENTS.md, SKILL.md, config.toml'));
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
// Validate all files in project
|
|
260
|
+
console.log(chalk.blue(`Scanning project: ${projectPath}`));
|
|
261
|
+
const agentsMd = path.join(projectPath, 'AGENTS.md');
|
|
262
|
+
const configToml = path.join(projectPath, '.agents', 'config.toml');
|
|
263
|
+
if (await fs.pathExists(agentsMd)) {
|
|
264
|
+
filesToValidate.push({ path: agentsMd, type: 'agents' });
|
|
265
|
+
}
|
|
266
|
+
if (await fs.pathExists(configToml)) {
|
|
267
|
+
filesToValidate.push({ path: configToml, type: 'config' });
|
|
268
|
+
}
|
|
269
|
+
// Find skill files
|
|
270
|
+
const skillsDir = path.join(projectPath, '.agents', 'skills');
|
|
271
|
+
if (await fs.pathExists(skillsDir)) {
|
|
272
|
+
try {
|
|
273
|
+
const skills = await fs.readdir(skillsDir);
|
|
274
|
+
for (const skill of skills) {
|
|
275
|
+
const skillPath = path.join(skillsDir, skill);
|
|
276
|
+
const skillStats = await fs.stat(skillPath);
|
|
277
|
+
if (skillStats.isDirectory()) {
|
|
278
|
+
const skillMd = path.join(skillPath, 'SKILL.md');
|
|
279
|
+
if (await fs.pathExists(skillMd)) {
|
|
280
|
+
filesToValidate.push({ path: skillMd, type: 'skill' });
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
// Ignore errors reading skills directory
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (filesToValidate.length === 0) {
|
|
291
|
+
console.log(chalk.yellow('No files found to validate'));
|
|
292
|
+
console.log(chalk.gray('Run `claude-flow-codex init` to create a project'));
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
console.log(chalk.blue(`\nValidating ${filesToValidate.length} file(s)...\n`));
|
|
296
|
+
let hasErrors = false;
|
|
297
|
+
let hasWarnings = false;
|
|
298
|
+
let totalErrors = 0;
|
|
299
|
+
let totalWarnings = 0;
|
|
300
|
+
for (const file of filesToValidate) {
|
|
301
|
+
let content;
|
|
302
|
+
try {
|
|
303
|
+
content = await fs.readFile(file.path, 'utf-8');
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
console.log(chalk.red(` ! Cannot read: ${file.path}`));
|
|
307
|
+
hasErrors = true;
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
let result;
|
|
311
|
+
switch (file.type) {
|
|
312
|
+
case 'agents':
|
|
313
|
+
result = await validateAgentsMd(content);
|
|
314
|
+
break;
|
|
315
|
+
case 'skill':
|
|
316
|
+
result = await validateSkillMd(content);
|
|
317
|
+
break;
|
|
318
|
+
case 'config':
|
|
319
|
+
result = await validateConfigToml(content);
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
const relativePath = path.relative(projectPath, file.path);
|
|
323
|
+
if (result.valid && result.warnings.length === 0) {
|
|
324
|
+
console.log(chalk.green(` ${chalk.green.bold('PASS')} ${relativePath}`));
|
|
325
|
+
}
|
|
326
|
+
else if (result.valid) {
|
|
327
|
+
console.log(chalk.yellow(` ${chalk.yellow.bold('WARN')} ${relativePath}`));
|
|
328
|
+
hasWarnings = true;
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
console.log(chalk.red(` ${chalk.red.bold('FAIL')} ${relativePath}`));
|
|
332
|
+
hasErrors = true;
|
|
333
|
+
}
|
|
334
|
+
for (const error of result.errors) {
|
|
335
|
+
totalErrors++;
|
|
336
|
+
const lineInfo = error.line ? chalk.gray(` (line ${error.line})`) : '';
|
|
337
|
+
console.log(chalk.red(` ${chalk.red('x')} ${error.message}${lineInfo}`));
|
|
338
|
+
}
|
|
339
|
+
for (const warning of result.warnings) {
|
|
340
|
+
totalWarnings++;
|
|
341
|
+
console.log(chalk.yellow(` ${chalk.yellow('!')} ${warning.message}`));
|
|
342
|
+
if (warning.suggestion) {
|
|
343
|
+
console.log(chalk.gray(` ${warning.suggestion}`));
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
// Summary
|
|
348
|
+
console.log();
|
|
349
|
+
if (hasErrors) {
|
|
350
|
+
console.log(chalk.red.bold(` ${totalErrors} error(s), ${totalWarnings} warning(s)`));
|
|
351
|
+
process.exit(1);
|
|
352
|
+
}
|
|
353
|
+
else if (hasWarnings && options.strict) {
|
|
354
|
+
console.log(chalk.yellow.bold(` ${totalWarnings} warning(s) (strict mode)`));
|
|
355
|
+
process.exit(1);
|
|
356
|
+
}
|
|
357
|
+
else if (hasWarnings) {
|
|
358
|
+
console.log(chalk.yellow(` All files valid with ${totalWarnings} warning(s)`));
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
console.log(chalk.green.bold(' All files valid!'));
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
catch (error) {
|
|
365
|
+
handleError(error, 'Validation failed');
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
// Migrate command
|
|
369
|
+
program
|
|
370
|
+
.command('migrate')
|
|
371
|
+
.description('Migrate from Claude Code (CLAUDE.md) to Codex (AGENTS.md)')
|
|
372
|
+
.option('-f, --from <file>', 'Source CLAUDE.md file', 'CLAUDE.md')
|
|
373
|
+
.option('-o, --output <path>', 'Output directory', process.cwd())
|
|
374
|
+
.option('--analyze-only', 'Only analyze, do not generate files', false)
|
|
375
|
+
.option('--generate-skills', 'Generate skill files from detected patterns', true)
|
|
376
|
+
.option('--preserve-comments', 'Preserve comments from original file', true)
|
|
377
|
+
.action(async (options) => {
|
|
378
|
+
try {
|
|
379
|
+
printBanner();
|
|
380
|
+
const sourcePath = path.resolve(options.from);
|
|
381
|
+
if (!await fs.pathExists(sourcePath)) {
|
|
382
|
+
console.error(chalk.red(`Source file not found: ${sourcePath}`));
|
|
383
|
+
console.log(chalk.gray('\nLooking for CLAUDE.md in the current directory.'));
|
|
384
|
+
console.log(chalk.gray('Use --from <path> to specify a different source file.'));
|
|
385
|
+
process.exit(1);
|
|
386
|
+
}
|
|
387
|
+
let content;
|
|
388
|
+
try {
|
|
389
|
+
content = await fs.readFile(sourcePath, 'utf-8');
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
handleError(error, `Cannot read source file: ${sourcePath}`);
|
|
393
|
+
}
|
|
394
|
+
if (options.analyzeOnly) {
|
|
395
|
+
console.log(chalk.blue('Analyzing CLAUDE.md...'));
|
|
396
|
+
console.log(chalk.gray(`Source: ${sourcePath}\n`));
|
|
397
|
+
const analysis = await analyzeClaudeMd(content);
|
|
398
|
+
console.log(chalk.white.bold('Sections found:'));
|
|
399
|
+
if (analysis.sections.length > 0) {
|
|
400
|
+
for (const section of analysis.sections) {
|
|
401
|
+
console.log(chalk.gray(` - ${section}`));
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
console.log(chalk.gray(' (none)'));
|
|
406
|
+
}
|
|
407
|
+
console.log(chalk.white.bold('\nSkills detected:'));
|
|
408
|
+
if (analysis.skills.length > 0) {
|
|
409
|
+
for (const skill of analysis.skills) {
|
|
410
|
+
console.log(chalk.gray(` - /${skill} ${chalk.cyan('->')} $${skill}`));
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
console.log(chalk.gray(' (none)'));
|
|
415
|
+
}
|
|
416
|
+
console.log(chalk.white.bold('\nHooks used:'));
|
|
417
|
+
if (analysis.hooks.length > 0) {
|
|
418
|
+
for (const hook of analysis.hooks) {
|
|
419
|
+
console.log(chalk.gray(` - ${hook}`));
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
console.log(chalk.gray(' (none)'));
|
|
424
|
+
}
|
|
425
|
+
console.log(chalk.white.bold('\nCustom instructions:'));
|
|
426
|
+
if (analysis.customInstructions.length > 0) {
|
|
427
|
+
for (const instruction of analysis.customInstructions.slice(0, 5)) {
|
|
428
|
+
console.log(chalk.gray(` - ${instruction.substring(0, 60)}...`));
|
|
429
|
+
}
|
|
430
|
+
if (analysis.customInstructions.length > 5) {
|
|
431
|
+
console.log(chalk.gray(` ... and ${analysis.customInstructions.length - 5} more`));
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
console.log(chalk.gray(' (none)'));
|
|
436
|
+
}
|
|
437
|
+
if (analysis.warnings.length > 0) {
|
|
438
|
+
console.log(chalk.yellow.bold('\nMigration warnings:'));
|
|
439
|
+
for (const warning of analysis.warnings) {
|
|
440
|
+
console.log(chalk.yellow(` ! ${warning}`));
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
console.log();
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
console.log(chalk.blue('Migrating to Codex...'));
|
|
447
|
+
console.log(chalk.gray(`Source: ${sourcePath}`));
|
|
448
|
+
console.log(chalk.gray(`Output: ${path.resolve(options.output)}\n`));
|
|
449
|
+
const result = await migrateFromClaudeCode({
|
|
450
|
+
sourcePath,
|
|
451
|
+
targetPath: options.output,
|
|
452
|
+
generateSkills: options.generateSkills,
|
|
453
|
+
preserveComments: options.preserveComments,
|
|
454
|
+
});
|
|
455
|
+
const report = generateMigrationReport(result);
|
|
456
|
+
console.log(report);
|
|
457
|
+
if (result.success) {
|
|
458
|
+
console.log(chalk.green.bold('\n Migration completed successfully!'));
|
|
459
|
+
console.log(chalk.gray('\n Next steps:'));
|
|
460
|
+
console.log(chalk.gray(' 1. Review the generated AGENTS.md'));
|
|
461
|
+
console.log(chalk.gray(' 2. Check skill invocation syntax (/ -> $)'));
|
|
462
|
+
console.log(chalk.gray(' 3. Run `claude-flow-codex validate` to verify'));
|
|
463
|
+
console.log();
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
console.log(chalk.red.bold('\n Migration failed'));
|
|
467
|
+
process.exit(1);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
catch (error) {
|
|
472
|
+
handleError(error, 'Migration failed');
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
// Templates command
|
|
476
|
+
program
|
|
477
|
+
.command('templates')
|
|
478
|
+
.alias('list-templates')
|
|
479
|
+
.description('List available templates')
|
|
480
|
+
.option('--json', 'Output as JSON', false)
|
|
481
|
+
.action((options) => {
|
|
482
|
+
try {
|
|
483
|
+
const templates = listTemplates();
|
|
484
|
+
if (options.json) {
|
|
485
|
+
console.log(JSON.stringify(templates, null, 2));
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
printBanner();
|
|
489
|
+
console.log(chalk.white.bold('Available templates:\n'));
|
|
490
|
+
for (const template of templates) {
|
|
491
|
+
console.log(chalk.cyan.bold(` ${template.name}`));
|
|
492
|
+
console.log(chalk.gray(` ${template.description}`));
|
|
493
|
+
console.log(chalk.gray(` Skills: ${template.skillCount} included`));
|
|
494
|
+
console.log();
|
|
495
|
+
}
|
|
496
|
+
console.log(chalk.gray('Use: claude-flow-codex init --template <name>'));
|
|
497
|
+
console.log();
|
|
498
|
+
}
|
|
499
|
+
catch (error) {
|
|
500
|
+
handleError(error, 'Failed to list templates');
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
// Skills command
|
|
504
|
+
program
|
|
505
|
+
.command('skills')
|
|
506
|
+
.alias('list-skills')
|
|
507
|
+
.description('List available built-in skills')
|
|
508
|
+
.option('--json', 'Output as JSON', false)
|
|
509
|
+
.action((options) => {
|
|
510
|
+
try {
|
|
511
|
+
if (options.json) {
|
|
512
|
+
console.log(JSON.stringify(BUILT_IN_SKILLS, null, 2));
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
printBanner();
|
|
516
|
+
console.log(chalk.white.bold('Built-in skills:\n'));
|
|
517
|
+
for (const [name, info] of Object.entries(BUILT_IN_SKILLS)) {
|
|
518
|
+
console.log(chalk.cyan(` $${name}`));
|
|
519
|
+
console.log(chalk.gray(` ${info.description}`));
|
|
520
|
+
console.log(chalk.gray(` Category: ${info.category}`));
|
|
521
|
+
console.log();
|
|
522
|
+
}
|
|
523
|
+
console.log(chalk.gray('Use: claude-flow-codex generate-skill -n <name> to create a custom skill'));
|
|
524
|
+
console.log();
|
|
525
|
+
}
|
|
526
|
+
catch (error) {
|
|
527
|
+
handleError(error, 'Failed to list skills');
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
// Info command
|
|
531
|
+
program
|
|
532
|
+
.command('info')
|
|
533
|
+
.description('Show package information')
|
|
534
|
+
.option('--json', 'Output as JSON', false)
|
|
535
|
+
.action((options) => {
|
|
536
|
+
try {
|
|
537
|
+
if (options.json) {
|
|
538
|
+
console.log(JSON.stringify(PACKAGE_INFO, null, 2));
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
console.log(chalk.cyan.bold('\n @claude-flow/codex'));
|
|
542
|
+
console.log(chalk.gray(' ' + '='.repeat(40)));
|
|
543
|
+
console.log(chalk.white(` Version: ${PACKAGE_INFO.version}`));
|
|
544
|
+
console.log(chalk.white(` Description: ${PACKAGE_INFO.description}`));
|
|
545
|
+
console.log(chalk.white(` Future: ${PACKAGE_INFO.futureUmbrella} (umbrella package)`));
|
|
546
|
+
console.log(chalk.white(` Repository: ${PACKAGE_INFO.repository}`));
|
|
547
|
+
console.log(chalk.gray(' ' + '='.repeat(40)));
|
|
548
|
+
console.log(chalk.gray('\n Part of the coflow rebranding initiative'));
|
|
549
|
+
console.log();
|
|
550
|
+
}
|
|
551
|
+
catch (error) {
|
|
552
|
+
handleError(error, 'Failed to show info');
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
// Doctor command - check system health
|
|
556
|
+
program
|
|
557
|
+
.command('doctor')
|
|
558
|
+
.description('Check system health and dependencies')
|
|
559
|
+
.action(async () => {
|
|
560
|
+
try {
|
|
561
|
+
printBanner();
|
|
562
|
+
console.log(chalk.blue('Running health checks...\n'));
|
|
563
|
+
const checks = [];
|
|
564
|
+
// Check Node.js version
|
|
565
|
+
const nodeVersion = process.version;
|
|
566
|
+
const nodeMajor = parseInt(nodeVersion.slice(1).split('.')[0] ?? '0', 10);
|
|
567
|
+
if (nodeMajor >= 18) {
|
|
568
|
+
checks.push({ name: 'Node.js', status: 'pass', message: `${nodeVersion} (>= 18 required)` });
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
checks.push({ name: 'Node.js', status: 'fail', message: `${nodeVersion} (>= 18 required)` });
|
|
572
|
+
}
|
|
573
|
+
// Check for AGENTS.md in current directory
|
|
574
|
+
const agentsMdExists = await fs.pathExists(path.join(process.cwd(), 'AGENTS.md'));
|
|
575
|
+
if (agentsMdExists) {
|
|
576
|
+
checks.push({ name: 'AGENTS.md', status: 'pass', message: 'Found in current directory' });
|
|
577
|
+
}
|
|
578
|
+
else {
|
|
579
|
+
checks.push({ name: 'AGENTS.md', status: 'warn', message: 'Not found - run init to create' });
|
|
580
|
+
}
|
|
581
|
+
// Check for .agents directory
|
|
582
|
+
const agentsDir = await fs.pathExists(path.join(process.cwd(), '.agents'));
|
|
583
|
+
if (agentsDir) {
|
|
584
|
+
checks.push({ name: '.agents/', status: 'pass', message: 'Directory exists' });
|
|
585
|
+
}
|
|
586
|
+
else {
|
|
587
|
+
checks.push({ name: '.agents/', status: 'warn', message: 'Not found - run init to create' });
|
|
588
|
+
}
|
|
589
|
+
// Check for config.toml
|
|
590
|
+
const configExists = await fs.pathExists(path.join(process.cwd(), '.agents', 'config.toml'));
|
|
591
|
+
if (configExists) {
|
|
592
|
+
checks.push({ name: 'config.toml', status: 'pass', message: 'Found in .agents/' });
|
|
593
|
+
}
|
|
594
|
+
else {
|
|
595
|
+
checks.push({ name: 'config.toml', status: 'warn', message: 'Not found' });
|
|
596
|
+
}
|
|
597
|
+
// Check for git
|
|
598
|
+
try {
|
|
599
|
+
const gitExists = await fs.pathExists(path.join(process.cwd(), '.git'));
|
|
600
|
+
if (gitExists) {
|
|
601
|
+
checks.push({ name: 'Git', status: 'pass', message: 'Repository detected' });
|
|
602
|
+
}
|
|
603
|
+
else {
|
|
604
|
+
checks.push({ name: 'Git', status: 'warn', message: 'Not a git repository' });
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
catch {
|
|
608
|
+
checks.push({ name: 'Git', status: 'warn', message: 'Cannot check' });
|
|
609
|
+
}
|
|
610
|
+
// Print results
|
|
611
|
+
let hasFailures = false;
|
|
612
|
+
for (const check of checks) {
|
|
613
|
+
const icon = check.status === 'pass' ? chalk.green('PASS')
|
|
614
|
+
: check.status === 'warn' ? chalk.yellow('WARN')
|
|
615
|
+
: chalk.red('FAIL');
|
|
616
|
+
console.log(` ${icon} ${chalk.white(check.name)}`);
|
|
617
|
+
console.log(chalk.gray(` ${check.message}`));
|
|
618
|
+
if (check.status === 'fail') {
|
|
619
|
+
hasFailures = true;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
console.log();
|
|
623
|
+
if (hasFailures) {
|
|
624
|
+
console.log(chalk.red.bold(' Some checks failed'));
|
|
625
|
+
process.exit(1);
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
console.log(chalk.green.bold(' All checks passed!'));
|
|
629
|
+
}
|
|
630
|
+
console.log();
|
|
631
|
+
}
|
|
632
|
+
catch (error) {
|
|
633
|
+
handleError(error, 'Health check failed');
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
// Error handling for unknown commands
|
|
637
|
+
program.on('command:*', () => {
|
|
638
|
+
console.error(chalk.red(`Invalid command: ${program.args.join(' ')}`));
|
|
639
|
+
console.log(chalk.gray(`Run ${chalk.white('claude-flow-codex --help')} for available commands.`));
|
|
640
|
+
process.exit(1);
|
|
641
|
+
});
|
|
642
|
+
// Parse and run
|
|
643
|
+
program.parse();
|
|
644
|
+
// If no command provided, show help
|
|
645
|
+
if (!process.argv.slice(2).length) {
|
|
646
|
+
printBanner();
|
|
647
|
+
program.outputHelp();
|
|
648
|
+
}
|
|
649
|
+
//# sourceMappingURL=cli.js.map
|