@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.
Files changed (46) hide show
  1. package/README.md +301 -0
  2. package/dist/cli.d.ts +9 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +649 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/generators/agents-md.d.ts +12 -0
  7. package/dist/generators/agents-md.d.ts.map +1 -0
  8. package/dist/generators/agents-md.js +641 -0
  9. package/dist/generators/agents-md.js.map +1 -0
  10. package/dist/generators/config-toml.d.ts +74 -0
  11. package/dist/generators/config-toml.d.ts.map +1 -0
  12. package/dist/generators/config-toml.js +910 -0
  13. package/dist/generators/config-toml.js.map +1 -0
  14. package/dist/generators/index.d.ts +9 -0
  15. package/dist/generators/index.d.ts.map +1 -0
  16. package/dist/generators/index.js +9 -0
  17. package/dist/generators/index.js.map +1 -0
  18. package/dist/generators/skill-md.d.ts +20 -0
  19. package/dist/generators/skill-md.d.ts.map +1 -0
  20. package/dist/generators/skill-md.js +946 -0
  21. package/dist/generators/skill-md.js.map +1 -0
  22. package/dist/index.d.ts +45 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +46 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/initializer.d.ts +87 -0
  27. package/dist/initializer.d.ts.map +1 -0
  28. package/dist/initializer.js +666 -0
  29. package/dist/initializer.js.map +1 -0
  30. package/dist/migrations/index.d.ts +114 -0
  31. package/dist/migrations/index.d.ts.map +1 -0
  32. package/dist/migrations/index.js +856 -0
  33. package/dist/migrations/index.js.map +1 -0
  34. package/dist/templates/index.d.ts +92 -0
  35. package/dist/templates/index.d.ts.map +1 -0
  36. package/dist/templates/index.js +284 -0
  37. package/dist/templates/index.js.map +1 -0
  38. package/dist/types.d.ts +218 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +8 -0
  41. package/dist/types.js.map +1 -0
  42. package/dist/validators/index.d.ts +42 -0
  43. package/dist/validators/index.d.ts.map +1 -0
  44. package/dist/validators/index.js +929 -0
  45. package/dist/validators/index.js.map +1 -0
  46. package/package.json +88 -0
@@ -0,0 +1,856 @@
1
+ /**
2
+ * @claude-flow/codex - Migrations
3
+ *
4
+ * Migration utilities for converting Claude Code configurations to Codex format
5
+ * Supports full CLAUDE.md parsing with section extraction, skill conversion,
6
+ * and proper AGENTS.md/config.toml generation.
7
+ */
8
+ /**
9
+ * Feature mappings between Claude Code and Codex
10
+ */
11
+ export const FEATURE_MAPPINGS = [
12
+ {
13
+ claudeCode: 'CLAUDE.md',
14
+ codex: 'AGENTS.md',
15
+ status: 'mapped',
16
+ notes: 'Main instruction file - content is portable',
17
+ },
18
+ {
19
+ claudeCode: 'CLAUDE.local.md',
20
+ codex: '.codex/AGENTS.override.md',
21
+ status: 'mapped',
22
+ notes: 'Local overrides - gitignored in both',
23
+ },
24
+ {
25
+ claudeCode: 'settings.json',
26
+ codex: 'config.toml',
27
+ status: 'mapped',
28
+ notes: 'Format conversion required (JSON to TOML)',
29
+ },
30
+ {
31
+ claudeCode: '/skill-name',
32
+ codex: '$skill-name',
33
+ status: 'mapped',
34
+ notes: 'Skill invocation syntax - search and replace',
35
+ },
36
+ {
37
+ claudeCode: 'TodoWrite',
38
+ codex: 'Task tracking',
39
+ status: 'mapped',
40
+ notes: 'Similar functionality with different API',
41
+ },
42
+ {
43
+ claudeCode: 'Task tool agents',
44
+ codex: 'Sub-agent collaboration',
45
+ status: 'partial',
46
+ notes: 'Codex sub-agents via CODEX_HANDOFF_TARGET env var',
47
+ },
48
+ {
49
+ claudeCode: 'MCP servers',
50
+ codex: '[mcp_servers]',
51
+ status: 'mapped',
52
+ notes: 'Configuration format differs but same functionality',
53
+ },
54
+ {
55
+ claudeCode: 'hooks system',
56
+ codex: 'Automations',
57
+ status: 'partial',
58
+ notes: 'Codex automations are scheduled, not event-driven',
59
+ },
60
+ {
61
+ claudeCode: 'EnterPlanMode',
62
+ codex: 'No direct equivalent',
63
+ status: 'unsupported',
64
+ notes: 'Codex uses different planning paradigm',
65
+ },
66
+ {
67
+ claudeCode: 'Permission modes',
68
+ codex: 'approval_policy + sandbox_mode',
69
+ status: 'mapped',
70
+ notes: 'Codex provides more granular control',
71
+ },
72
+ ];
73
+ /**
74
+ * Hook keywords recognized in CLAUDE.md
75
+ */
76
+ const HOOK_KEYWORDS = [
77
+ 'pre-task',
78
+ 'post-task',
79
+ 'pre-edit',
80
+ 'post-edit',
81
+ 'pre-command',
82
+ 'post-command',
83
+ 'session-start',
84
+ 'session-end',
85
+ 'session-restore',
86
+ 'route',
87
+ 'explain',
88
+ 'pretrain',
89
+ 'notify',
90
+ ];
91
+ /**
92
+ * Patterns that need migration warnings
93
+ */
94
+ const WARNING_PATTERNS = [
95
+ { pattern: 'EnterPlanMode', message: 'EnterPlanMode has no direct Codex equivalent - review planning workflow' },
96
+ { pattern: 'claude -p', message: 'claude -p headless mode - use Codex sub-agent patterns instead' },
97
+ { pattern: 'TodoWrite', message: 'TodoWrite - Codex uses different task tracking approach' },
98
+ { pattern: /--dangerously-skip-permissions/g, message: 'Dangerous permission skip detected - use Codex approval_policy instead' },
99
+ { pattern: /mcp__claude-flow__/g, message: 'MCP tool calls need migration to Codex MCP configuration' },
100
+ { pattern: /mcp__ruv-swarm__/g, message: 'Swarm MCP calls - ensure ruv-swarm MCP server is configured in config.toml' },
101
+ ];
102
+ /**
103
+ * Parse a CLAUDE.md file completely
104
+ */
105
+ export async function parseClaudeMd(content) {
106
+ const lines = content.split('\n');
107
+ const result = {
108
+ title: '',
109
+ sections: [],
110
+ skills: [],
111
+ hooks: [],
112
+ customInstructions: [],
113
+ codeBlocks: [],
114
+ mcpServers: [],
115
+ settings: {},
116
+ warnings: [],
117
+ };
118
+ // Extract title (first H1)
119
+ const titleMatch = content.match(/^#\s+(.+)$/m);
120
+ if (titleMatch && titleMatch[1]) {
121
+ result.title = titleMatch[1].trim();
122
+ result.settings.projectName = result.title;
123
+ }
124
+ // Parse sections
125
+ result.sections = parseSections(content, lines);
126
+ // Extract skills (both /skill-name and $skill-name syntax)
127
+ result.skills = extractSkills(content, lines);
128
+ // Extract hooks
129
+ result.hooks = extractHooks(content);
130
+ // Extract code blocks
131
+ result.codeBlocks = extractCodeBlocks(content, lines);
132
+ // Extract MCP server configurations from code blocks
133
+ result.mcpServers = extractMcpServers(result.codeBlocks);
134
+ // Extract settings from content
135
+ result.settings = {
136
+ ...result.settings,
137
+ ...extractSettings(content, result.sections),
138
+ };
139
+ // Extract custom instructions (behavioral rules)
140
+ result.customInstructions = extractBehavioralRules(content);
141
+ // Check for patterns that need warnings
142
+ for (const { pattern, message } of WARNING_PATTERNS) {
143
+ if (typeof pattern === 'string') {
144
+ if (content.includes(pattern)) {
145
+ result.warnings.push(message);
146
+ }
147
+ }
148
+ else {
149
+ if (pattern.test(content)) {
150
+ result.warnings.push(message);
151
+ }
152
+ }
153
+ }
154
+ return result;
155
+ }
156
+ /**
157
+ * Parse sections from markdown content
158
+ */
159
+ function parseSections(content, lines) {
160
+ const sections = [];
161
+ const sectionRegex = /^(#{1,6})\s+(.+)$/;
162
+ let currentSection = null;
163
+ let contentLines = [];
164
+ for (let i = 0; i < lines.length; i++) {
165
+ const line = lines[i];
166
+ const match = sectionRegex.exec(line);
167
+ if (match && match[1] && match[2]) {
168
+ // Save previous section
169
+ if (currentSection) {
170
+ currentSection.content = contentLines.join('\n').trim();
171
+ currentSection.endLine = i;
172
+ sections.push(currentSection);
173
+ }
174
+ // Start new section
175
+ currentSection = {
176
+ level: match[1].length,
177
+ title: match[2].trim(),
178
+ content: '',
179
+ startLine: i + 1,
180
+ endLine: i + 1,
181
+ };
182
+ contentLines = [];
183
+ }
184
+ else if (currentSection) {
185
+ contentLines.push(line);
186
+ }
187
+ }
188
+ // Save last section
189
+ if (currentSection) {
190
+ currentSection.content = contentLines.join('\n').trim();
191
+ currentSection.endLine = lines.length;
192
+ sections.push(currentSection);
193
+ }
194
+ return sections;
195
+ }
196
+ /**
197
+ * Extract skill references from content
198
+ */
199
+ function extractSkills(content, lines) {
200
+ const skills = [];
201
+ const seenSkills = new Set();
202
+ // Slash syntax: /skill-name
203
+ const slashRegex = /\/([a-z][a-z0-9-]*)/g;
204
+ let match;
205
+ while ((match = slashRegex.exec(content)) !== null) {
206
+ const name = match[1];
207
+ // Skip common false positives
208
+ if (['src', 'dist', 'docs', 'tests', 'config', 'scripts', 'examples', 'node_modules', 'workspaces'].includes(name)) {
209
+ continue;
210
+ }
211
+ if (!seenSkills.has(`slash:${name}`)) {
212
+ seenSkills.add(`slash:${name}`);
213
+ const lineNum = findLineNumber(content, match.index);
214
+ skills.push({
215
+ name,
216
+ syntax: 'slash',
217
+ context: getContextAroundMatch(lines, lineNum),
218
+ line: lineNum,
219
+ });
220
+ }
221
+ }
222
+ // Dollar syntax: $skill-name
223
+ const dollarRegex = /\$([a-z][a-z0-9-]+)/g;
224
+ while ((match = dollarRegex.exec(content)) !== null) {
225
+ const name = match[1];
226
+ if (!seenSkills.has(`dollar:${name}`)) {
227
+ seenSkills.add(`dollar:${name}`);
228
+ const lineNum = findLineNumber(content, match.index);
229
+ skills.push({
230
+ name,
231
+ syntax: 'dollar',
232
+ context: getContextAroundMatch(lines, lineNum),
233
+ line: lineNum,
234
+ });
235
+ }
236
+ }
237
+ return skills;
238
+ }
239
+ /**
240
+ * Extract hooks referenced in content
241
+ */
242
+ function extractHooks(content) {
243
+ const hooks = [];
244
+ const lowerContent = content.toLowerCase();
245
+ for (const hook of HOOK_KEYWORDS) {
246
+ if (lowerContent.includes(hook)) {
247
+ hooks.push(hook);
248
+ }
249
+ }
250
+ return hooks;
251
+ }
252
+ /**
253
+ * Extract code blocks from markdown
254
+ */
255
+ function extractCodeBlocks(content, lines) {
256
+ const blocks = [];
257
+ const codeBlockRegex = /```(\w*)\n([\s\S]*?)```/g;
258
+ let match;
259
+ while ((match = codeBlockRegex.exec(content)) !== null) {
260
+ blocks.push({
261
+ language: match[1] || 'text',
262
+ content: match[2].trim(),
263
+ line: findLineNumber(content, match.index),
264
+ });
265
+ }
266
+ return blocks;
267
+ }
268
+ /**
269
+ * Extract MCP server configurations from code blocks
270
+ */
271
+ function extractMcpServers(codeBlocks) {
272
+ const servers = [];
273
+ for (const block of codeBlocks) {
274
+ // Look for MCP server configurations in bash/shell blocks
275
+ if (['bash', 'shell', 'sh', 'zsh'].includes(block.language)) {
276
+ // Pattern: claude mcp add <name> <command> [args...]
277
+ const mcpAddRegex = /claude\s+mcp\s+add\s+(\S+)\s+(.+)/g;
278
+ let match;
279
+ while ((match = mcpAddRegex.exec(block.content)) !== null) {
280
+ const name = match[1];
281
+ const parts = match[2].trim().split(/\s+/);
282
+ servers.push({
283
+ name,
284
+ command: parts[0] || 'npx',
285
+ args: parts.slice(1),
286
+ enabled: true,
287
+ });
288
+ }
289
+ }
290
+ // Look for JSON MCP configurations
291
+ if (['json', 'jsonc'].includes(block.language)) {
292
+ try {
293
+ const parsed = JSON.parse(block.content);
294
+ if (parsed.mcpServers) {
295
+ for (const [name, config] of Object.entries(parsed.mcpServers)) {
296
+ const mcpConfig = config;
297
+ servers.push({
298
+ name,
299
+ command: mcpConfig.command || 'npx',
300
+ args: mcpConfig.args || [],
301
+ enabled: true,
302
+ });
303
+ }
304
+ }
305
+ }
306
+ catch {
307
+ // Not valid JSON, skip
308
+ }
309
+ }
310
+ // Look for JavaScript/TypeScript MCP tool calls
311
+ if (['javascript', 'typescript', 'js', 'ts'].includes(block.language)) {
312
+ // Pattern: mcp__<server>__<tool>
313
+ const mcpCallRegex = /mcp__([a-z-]+)__/g;
314
+ const seenServers = new Set();
315
+ let match;
316
+ while ((match = mcpCallRegex.exec(block.content)) !== null) {
317
+ const serverName = match[1].replace(/-/g, '_');
318
+ if (!seenServers.has(serverName)) {
319
+ seenServers.add(serverName);
320
+ // Don't add as full config, just note it exists
321
+ }
322
+ }
323
+ }
324
+ }
325
+ // Deduplicate
326
+ const seen = new Set();
327
+ return servers.filter((s) => {
328
+ if (seen.has(s.name))
329
+ return false;
330
+ seen.add(s.name);
331
+ return true;
332
+ });
333
+ }
334
+ /**
335
+ * Extract settings from content and sections
336
+ */
337
+ function extractSettings(content, sections) {
338
+ const settings = {};
339
+ // Look for tech stack
340
+ const techMatch = content.match(/(?:Tech\s*Stack|Technology|Stack)[:\s]+([^\n]+)/i);
341
+ if (techMatch && techMatch[1]) {
342
+ settings.techStack = techMatch[1].replace(/\*\*/g, '').trim();
343
+ }
344
+ // Look for build command
345
+ const buildMatch = content.match(/(?:Build|Compile)[:\s]*\n?```(?:bash|sh)?\n([^\n]+)/i);
346
+ if (buildMatch && buildMatch[1]) {
347
+ settings.buildCommand = buildMatch[1].trim();
348
+ }
349
+ else {
350
+ // Check for npm run build pattern
351
+ if (content.includes('npm run build')) {
352
+ settings.buildCommand = 'npm run build';
353
+ }
354
+ }
355
+ // Look for test command
356
+ const testMatch = content.match(/(?:Test)[:\s]*\n?```(?:bash|sh)?\n([^\n]+)/i);
357
+ if (testMatch && testMatch[1]) {
358
+ settings.testCommand = testMatch[1].trim();
359
+ }
360
+ else {
361
+ if (content.includes('npm test')) {
362
+ settings.testCommand = 'npm test';
363
+ }
364
+ }
365
+ // Look for dev command
366
+ if (content.includes('npm run dev')) {
367
+ settings.devCommand = 'npm run dev';
368
+ }
369
+ // Look for approval/permission settings
370
+ if (content.includes('auto-approve') || content.includes('autoApprove')) {
371
+ settings.approvalPolicy = 'never';
372
+ }
373
+ else if (content.includes('read-only')) {
374
+ settings.sandboxMode = 'read-only';
375
+ }
376
+ // Look for model specification
377
+ const modelMatch = content.match(/model[:\s]+["']?([^"'\n]+)["']?/i);
378
+ if (modelMatch && modelMatch[1]) {
379
+ settings.model = modelMatch[1].trim();
380
+ }
381
+ return settings;
382
+ }
383
+ /**
384
+ * Extract behavioral rules from content
385
+ */
386
+ function extractBehavioralRules(content) {
387
+ const rules = [];
388
+ // Look for Behavioral Rules section
389
+ const behavioralMatch = content.match(/##\s*Behavioral\s*Rules[^\n]*\n([\s\S]*?)(?=\n##|\n#\s|$)/i);
390
+ if (behavioralMatch && behavioralMatch[1]) {
391
+ const ruleLines = behavioralMatch[1].split('\n');
392
+ for (const line of ruleLines) {
393
+ const trimmed = line.trim();
394
+ if (trimmed.startsWith('- ')) {
395
+ rules.push(trimmed.substring(2));
396
+ }
397
+ else if (trimmed.startsWith('* ')) {
398
+ rules.push(trimmed.substring(2));
399
+ }
400
+ }
401
+ }
402
+ // Also look for Security Rules
403
+ const securityMatch = content.match(/##\s*Security\s*Rules?[^\n]*\n([\s\S]*?)(?=\n##|\n#\s|$)/i);
404
+ if (securityMatch && securityMatch[1]) {
405
+ const securityLines = securityMatch[1].split('\n');
406
+ for (const line of securityLines) {
407
+ const trimmed = line.trim();
408
+ if (trimmed.startsWith('- ')) {
409
+ rules.push(trimmed.substring(2));
410
+ }
411
+ else if (trimmed.startsWith('* ')) {
412
+ rules.push(trimmed.substring(2));
413
+ }
414
+ }
415
+ }
416
+ return rules;
417
+ }
418
+ /**
419
+ * Find line number for a character index
420
+ */
421
+ function findLineNumber(content, index) {
422
+ return content.substring(0, index).split('\n').length;
423
+ }
424
+ /**
425
+ * Get context around a match
426
+ */
427
+ function getContextAroundMatch(lines, lineNum) {
428
+ const start = Math.max(0, lineNum - 2);
429
+ const end = Math.min(lines.length, lineNum + 1);
430
+ return lines.slice(start, end).join('\n');
431
+ }
432
+ /**
433
+ * Analyze a CLAUDE.md file for migration (simplified interface)
434
+ */
435
+ export async function analyzeClaudeMd(content) {
436
+ const parsed = await parseClaudeMd(content);
437
+ return {
438
+ sections: parsed.sections.map((s) => s.title),
439
+ skills: [...new Set(parsed.skills.map((s) => s.name))],
440
+ hooks: parsed.hooks,
441
+ customInstructions: parsed.customInstructions,
442
+ warnings: parsed.warnings,
443
+ };
444
+ }
445
+ /**
446
+ * Convert skill invocation syntax from slash to dollar
447
+ */
448
+ export function convertSkillSyntax(content) {
449
+ // Convert /skill-name to $skill-name, but avoid path-like patterns
450
+ return content.replace(/(?<![a-zA-Z0-9_./])\/([a-z][a-z0-9-]*)(?![a-zA-Z0-9_./])/g, (match, skillName) => {
451
+ // Skip common directory names
452
+ const skipPatterns = ['src', 'dist', 'docs', 'tests', 'config', 'scripts', 'examples', 'node_modules', 'workspaces', 'data', 'logs', 'tmp', 'var', 'etc', 'usr', 'bin', 'lib'];
453
+ if (skipPatterns.includes(skillName)) {
454
+ return match;
455
+ }
456
+ return `$${skillName}`;
457
+ });
458
+ }
459
+ /**
460
+ * Generate AGENTS.md content from parsed CLAUDE.md
461
+ */
462
+ export function generateAgentsMdFromParsed(parsed) {
463
+ const lines = [];
464
+ // Title
465
+ lines.push(`# ${parsed.title || 'Project Agent Guide'}`);
466
+ lines.push('');
467
+ lines.push('> Migrated from CLAUDE.md by @claude-flow/codex');
468
+ lines.push('');
469
+ // Project Overview
470
+ lines.push('## Project Overview');
471
+ lines.push('');
472
+ if (parsed.settings.techStack) {
473
+ lines.push(`**Tech Stack**: ${parsed.settings.techStack}`);
474
+ }
475
+ lines.push('');
476
+ // Quick Start
477
+ lines.push('## Setup');
478
+ lines.push('');
479
+ if (parsed.settings.buildCommand) {
480
+ lines.push('### Build');
481
+ lines.push('```bash');
482
+ lines.push(parsed.settings.buildCommand);
483
+ lines.push('```');
484
+ lines.push('');
485
+ }
486
+ if (parsed.settings.testCommand) {
487
+ lines.push('### Test');
488
+ lines.push('```bash');
489
+ lines.push(parsed.settings.testCommand);
490
+ lines.push('```');
491
+ lines.push('');
492
+ }
493
+ if (parsed.settings.devCommand) {
494
+ lines.push('### Development');
495
+ lines.push('```bash');
496
+ lines.push(parsed.settings.devCommand);
497
+ lines.push('```');
498
+ lines.push('');
499
+ }
500
+ // Code Standards
501
+ lines.push('## Code Standards');
502
+ lines.push('');
503
+ lines.push('- Files under 500 lines');
504
+ lines.push('- No hardcoded secrets');
505
+ lines.push('- Input validation at boundaries');
506
+ lines.push('- Typed interfaces for public APIs');
507
+ lines.push('');
508
+ // Skills
509
+ if (parsed.skills.length > 0) {
510
+ lines.push('## Skills');
511
+ lines.push('');
512
+ lines.push('| Skill | Original Syntax |');
513
+ lines.push('|-------|-----------------|');
514
+ for (const skill of parsed.skills) {
515
+ const codexSyntax = `$${skill.name}`;
516
+ const originalSyntax = skill.syntax === 'slash' ? `/${skill.name}` : `$${skill.name}`;
517
+ lines.push(`| \`${codexSyntax}\` | \`${originalSyntax}\` |`);
518
+ }
519
+ lines.push('');
520
+ }
521
+ // Security
522
+ lines.push('## Security');
523
+ lines.push('');
524
+ if (parsed.customInstructions.length > 0) {
525
+ for (const rule of parsed.customInstructions.slice(0, 10)) {
526
+ lines.push(`- ${rule}`);
527
+ }
528
+ }
529
+ else {
530
+ lines.push('- NEVER commit secrets or credentials');
531
+ lines.push('- Validate all user inputs');
532
+ lines.push('- Prevent directory traversal attacks');
533
+ }
534
+ lines.push('');
535
+ // Hooks (as reference)
536
+ if (parsed.hooks.length > 0) {
537
+ lines.push('## Automation Hooks');
538
+ lines.push('');
539
+ lines.push('The following hooks were detected in the original configuration:');
540
+ lines.push('');
541
+ for (const hook of parsed.hooks) {
542
+ lines.push(`- \`${hook}\``);
543
+ }
544
+ lines.push('');
545
+ lines.push('> Note: Codex uses scheduled Automations instead of event-driven hooks.');
546
+ lines.push('');
547
+ }
548
+ // MCP Servers
549
+ if (parsed.mcpServers.length > 0) {
550
+ lines.push('## MCP Servers');
551
+ lines.push('');
552
+ lines.push('Configure in config.toml:');
553
+ lines.push('');
554
+ for (const server of parsed.mcpServers) {
555
+ lines.push(`- **${server.name}**: \`${server.command} ${(server.args || []).join(' ')}\``);
556
+ }
557
+ lines.push('');
558
+ }
559
+ // Migration notes
560
+ if (parsed.warnings.length > 0) {
561
+ lines.push('## Migration Notes');
562
+ lines.push('');
563
+ for (const warning of parsed.warnings) {
564
+ lines.push(`- ${warning}`);
565
+ }
566
+ lines.push('');
567
+ }
568
+ return lines.join('\n');
569
+ }
570
+ /**
571
+ * Convert settings.json to config.toml format
572
+ */
573
+ export function convertSettingsToToml(settings) {
574
+ const lines = [];
575
+ lines.push('# Migrated from settings.json');
576
+ lines.push('# Generated by @claude-flow/codex');
577
+ lines.push('');
578
+ // Model
579
+ if (settings.model) {
580
+ lines.push(`model = "${settings.model}"`);
581
+ }
582
+ else {
583
+ lines.push('model = "gpt-5.3-codex"');
584
+ }
585
+ lines.push('');
586
+ // Permissions mapping
587
+ if (settings.permissions) {
588
+ const perms = settings.permissions;
589
+ if (perms.autoApprove === true) {
590
+ lines.push('approval_policy = "never"');
591
+ lines.push('sandbox_mode = "danger-full-access"');
592
+ }
593
+ else if (perms.autoApprove === 'read-only') {
594
+ lines.push('approval_policy = "on-request"');
595
+ lines.push('sandbox_mode = "read-only"');
596
+ }
597
+ else {
598
+ lines.push('approval_policy = "on-request"');
599
+ lines.push('sandbox_mode = "workspace-write"');
600
+ }
601
+ }
602
+ else {
603
+ lines.push('approval_policy = "on-request"');
604
+ lines.push('sandbox_mode = "workspace-write"');
605
+ }
606
+ lines.push('');
607
+ // Web search
608
+ if (settings.webSearch !== undefined) {
609
+ const mode = settings.webSearch === true ? 'live' : settings.webSearch === false ? 'disabled' : 'cached';
610
+ lines.push(`web_search = "${mode}"`);
611
+ }
612
+ else {
613
+ lines.push('web_search = "cached"');
614
+ }
615
+ lines.push('');
616
+ // Features
617
+ lines.push('[features]');
618
+ lines.push('child_agents_md = true');
619
+ lines.push('shell_snapshot = true');
620
+ lines.push('request_rule = true');
621
+ lines.push('');
622
+ // MCP servers
623
+ if (settings.mcpServers && typeof settings.mcpServers === 'object') {
624
+ for (const [name, config] of Object.entries(settings.mcpServers)) {
625
+ const mcpConfig = config;
626
+ lines.push(`[mcp_servers.${name}]`);
627
+ if (mcpConfig.command) {
628
+ lines.push(`command = "${mcpConfig.command}"`);
629
+ }
630
+ if (mcpConfig.args && mcpConfig.args.length > 0) {
631
+ const argsStr = mcpConfig.args.map((a) => `"${a}"`).join(', ');
632
+ lines.push(`args = [${argsStr}]`);
633
+ }
634
+ lines.push('enabled = true');
635
+ if (mcpConfig.env && Object.keys(mcpConfig.env).length > 0) {
636
+ lines.push('');
637
+ lines.push(`[mcp_servers.${name}.env]`);
638
+ for (const [key, value] of Object.entries(mcpConfig.env)) {
639
+ lines.push(`${key} = "${value}"`);
640
+ }
641
+ }
642
+ lines.push('');
643
+ }
644
+ }
645
+ else {
646
+ // Add default claude-flow server
647
+ lines.push('[mcp_servers.claude-flow]');
648
+ lines.push('command = "npx"');
649
+ lines.push('args = ["-y", "@claude-flow/cli@latest"]');
650
+ lines.push('enabled = true');
651
+ lines.push('');
652
+ }
653
+ // History
654
+ lines.push('[history]');
655
+ lines.push('persistence = "save-all"');
656
+ lines.push('');
657
+ // Profiles
658
+ lines.push('# Development profile');
659
+ lines.push('[profiles.dev]');
660
+ lines.push('approval_policy = "never"');
661
+ lines.push('sandbox_mode = "danger-full-access"');
662
+ lines.push('');
663
+ lines.push('# Safe profile');
664
+ lines.push('[profiles.safe]');
665
+ lines.push('approval_policy = "untrusted"');
666
+ lines.push('sandbox_mode = "read-only"');
667
+ lines.push('');
668
+ return lines.join('\n');
669
+ }
670
+ /**
671
+ * Generate config.toml from parsed CLAUDE.md
672
+ */
673
+ export function generateConfigTomlFromParsed(parsed) {
674
+ const lines = [];
675
+ lines.push('# Migrated from CLAUDE.md');
676
+ lines.push('# Generated by @claude-flow/codex');
677
+ lines.push('');
678
+ // Model
679
+ lines.push(`model = "${parsed.settings.model || 'gpt-5.3-codex'}"`);
680
+ lines.push('');
681
+ // Approval policy
682
+ const approvalPolicy = parsed.settings.approvalPolicy || 'on-request';
683
+ lines.push(`approval_policy = "${approvalPolicy}"`);
684
+ lines.push('');
685
+ // Sandbox mode
686
+ const sandboxMode = parsed.settings.sandboxMode || 'workspace-write';
687
+ lines.push(`sandbox_mode = "${sandboxMode}"`);
688
+ lines.push('');
689
+ // Web search
690
+ lines.push('web_search = "cached"');
691
+ lines.push('');
692
+ // Features
693
+ lines.push('[features]');
694
+ lines.push('child_agents_md = true');
695
+ lines.push('shell_snapshot = true');
696
+ lines.push('request_rule = true');
697
+ lines.push('');
698
+ // MCP servers
699
+ if (parsed.mcpServers.length > 0) {
700
+ for (const server of parsed.mcpServers) {
701
+ lines.push(`[mcp_servers.${server.name.replace(/-/g, '_')}]`);
702
+ lines.push(`command = "${server.command}"`);
703
+ if (server.args && server.args.length > 0) {
704
+ const argsStr = server.args.map((a) => `"${a}"`).join(', ');
705
+ lines.push(`args = [${argsStr}]`);
706
+ }
707
+ lines.push(`enabled = ${server.enabled ?? true}`);
708
+ lines.push('');
709
+ }
710
+ }
711
+ else {
712
+ // Default claude-flow server
713
+ lines.push('[mcp_servers.claude_flow]');
714
+ lines.push('command = "npx"');
715
+ lines.push('args = ["-y", "@claude-flow/cli@latest"]');
716
+ lines.push('enabled = true');
717
+ lines.push('');
718
+ }
719
+ // Skills
720
+ if (parsed.skills.length > 0) {
721
+ lines.push('# Skills detected in original configuration');
722
+ for (const skill of parsed.skills) {
723
+ lines.push(`# - ${skill.name} (${skill.syntax} syntax)`);
724
+ }
725
+ lines.push('');
726
+ }
727
+ // History
728
+ lines.push('[history]');
729
+ lines.push('persistence = "save-all"');
730
+ lines.push('');
731
+ // Profiles
732
+ lines.push('[profiles.dev]');
733
+ lines.push('approval_policy = "never"');
734
+ lines.push('sandbox_mode = "danger-full-access"');
735
+ lines.push('');
736
+ lines.push('[profiles.safe]');
737
+ lines.push('approval_policy = "untrusted"');
738
+ lines.push('sandbox_mode = "read-only"');
739
+ lines.push('');
740
+ return lines.join('\n');
741
+ }
742
+ /**
743
+ * Migrate from Claude Code (CLAUDE.md) to Codex (AGENTS.md)
744
+ */
745
+ export async function migrateFromClaudeCode(options) {
746
+ const { sourcePath, targetPath, preserveComments = true, generateSkills = true } = options;
747
+ try {
748
+ // In actual implementation, this would read the file
749
+ // For now, we provide the structure for the migration
750
+ const result = {
751
+ success: true,
752
+ agentsMdPath: `${targetPath}/AGENTS.md`,
753
+ skillsCreated: generateSkills
754
+ ? ['swarm-orchestration', 'memory-management', 'security-audit']
755
+ : [],
756
+ configTomlPath: `${targetPath}/.agents/config.toml`,
757
+ mappings: FEATURE_MAPPINGS,
758
+ warnings: [
759
+ 'Review skill invocation syntax (changed from / to $)',
760
+ 'Check hook configurations for Automation compatibility',
761
+ 'Verify MCP server configurations in config.toml',
762
+ ],
763
+ };
764
+ return result;
765
+ }
766
+ catch (error) {
767
+ return {
768
+ success: false,
769
+ warnings: [`Migration failed: ${error instanceof Error ? error.message : 'Unknown error'}`],
770
+ };
771
+ }
772
+ }
773
+ /**
774
+ * Perform full migration with content
775
+ */
776
+ export async function performFullMigration(claudeMdContent, settingsJson) {
777
+ // Parse CLAUDE.md
778
+ const parsed = await parseClaudeMd(claudeMdContent);
779
+ // Generate AGENTS.md
780
+ let agentsMd = generateAgentsMdFromParsed(parsed);
781
+ // Convert skill syntax in the generated content
782
+ agentsMd = convertSkillSyntax(agentsMd);
783
+ // Generate config.toml
784
+ let configToml;
785
+ if (settingsJson) {
786
+ configToml = convertSettingsToToml(settingsJson);
787
+ }
788
+ else {
789
+ configToml = generateConfigTomlFromParsed(parsed);
790
+ }
791
+ // Collect skills to create
792
+ const skillsToCreate = [...new Set(parsed.skills.map((s) => s.name))];
793
+ return {
794
+ agentsMd,
795
+ configToml,
796
+ warnings: parsed.warnings,
797
+ skillsToCreate,
798
+ };
799
+ }
800
+ /**
801
+ * Generate migration report
802
+ */
803
+ export function generateMigrationReport(result) {
804
+ const lines = [];
805
+ lines.push('# Migration Report');
806
+ lines.push('');
807
+ lines.push(`**Status**: ${result.success ? 'Success' : 'Failed'}`);
808
+ lines.push(`**Generated**: ${new Date().toISOString()}`);
809
+ lines.push('');
810
+ if (result.agentsMdPath) {
811
+ lines.push('## Generated Files');
812
+ lines.push('');
813
+ lines.push(`- AGENTS.md: \`${result.agentsMdPath}\``);
814
+ if (result.configTomlPath) {
815
+ lines.push(`- config.toml: \`${result.configTomlPath}\``);
816
+ }
817
+ lines.push('');
818
+ }
819
+ if (result.skillsCreated && result.skillsCreated.length > 0) {
820
+ lines.push('## Skills Created');
821
+ lines.push('');
822
+ for (const skill of result.skillsCreated) {
823
+ lines.push(`- \`$${skill}\``);
824
+ }
825
+ lines.push('');
826
+ }
827
+ if (result.mappings) {
828
+ lines.push('## Feature Mappings');
829
+ lines.push('');
830
+ lines.push('| Claude Code | Codex | Status | Notes |');
831
+ lines.push('|-------------|-------|--------|-------|');
832
+ for (const mapping of result.mappings) {
833
+ const notes = mapping.notes || '';
834
+ lines.push(`| \`${mapping.claudeCode}\` | \`${mapping.codex}\` | ${mapping.status} | ${notes} |`);
835
+ }
836
+ lines.push('');
837
+ }
838
+ if (result.warnings && result.warnings.length > 0) {
839
+ lines.push('## Warnings');
840
+ lines.push('');
841
+ for (const warning of result.warnings) {
842
+ lines.push(`- ${warning}`);
843
+ }
844
+ lines.push('');
845
+ }
846
+ lines.push('## Next Steps');
847
+ lines.push('');
848
+ lines.push('1. Review generated AGENTS.md for accuracy');
849
+ lines.push('2. Update skill references from `/skill-name` to `$skill-name`');
850
+ lines.push('3. Configure MCP servers in config.toml');
851
+ lines.push('4. Create skill definitions in `.agents/skills/`');
852
+ lines.push('5. Test with `codex` CLI');
853
+ lines.push('');
854
+ return lines.join('\n');
855
+ }
856
+ //# sourceMappingURL=index.js.map