5-phase-workflow 1.8.7 → 1.8.9

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/bin/install.js CHANGED
@@ -4,6 +4,9 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
  const readline = require('readline');
6
6
 
7
+ // Active runtime ('claude' or 'codex') — set once in main()
8
+ let activeRuntime = 'claude';
9
+
7
10
  // ANSI colors for terminal output
8
11
  const colors = {
9
12
  reset: '\x1b[0m',
@@ -94,7 +97,8 @@ function parseArgs() {
94
97
  uninstall: false,
95
98
  upgrade: false,
96
99
  check: false,
97
- help: false
100
+ help: false,
101
+ runtime: 'claude' // 'claude' or 'codex'
98
102
  };
99
103
 
100
104
  for (const arg of args) {
@@ -104,6 +108,7 @@ function parseArgs() {
104
108
  else if (arg === '--upgrade' || arg === '--force' || arg === '-U') options.upgrade = true;
105
109
  else if (arg === '--check') options.check = true;
106
110
  else if (arg === '--help' || arg === '-h') options.help = true;
111
+ else if (arg === '--codex') options.runtime = 'codex';
107
112
  }
108
113
 
109
114
  // Default to local if neither specified
@@ -124,6 +129,7 @@ Usage: npx 5-phase-workflow [options]
124
129
  Options:
125
130
  --global, -g Install to ~/.claude/ (available across all projects)
126
131
  --local, -l Install to ./.claude/ (project-specific, default)
132
+ --codex Install for Codex CLI (to ~/.codex/ or ./.codex/)
127
133
  --upgrade, -U Upgrade to latest version (auto-update, no prompt)
128
134
  --force Alias for --upgrade
129
135
  --check Check installed version and available updates
@@ -131,26 +137,38 @@ Options:
131
137
  --help, -h Show this help message
132
138
 
133
139
  Examples:
134
- npx 5-phase-workflow # Install locally or prompt for update
135
- npx 5-phase-workflow --global # Install globally
140
+ npx 5-phase-workflow # Install locally for Claude Code
141
+ npx 5-phase-workflow --global # Install globally for Claude Code
142
+ npx 5-phase-workflow --codex # Install locally for Codex CLI
143
+ npx 5-phase-workflow --codex -g # Install globally for Codex CLI
136
144
  npx 5-phase-workflow --upgrade # Auto-update to latest version
137
145
  npx 5-phase-workflow --check # Check version without updating
138
146
  npx 5-phase-workflow --uninstall # Remove from current directory
139
147
  `);
140
148
  }
141
149
 
142
- // Get installation target path (.claude/ directory)
150
+ // Get config directory name for active runtime
151
+ function getRuntimeDirName() {
152
+ if (activeRuntime === 'codex') return '.codex';
153
+ return '.claude';
154
+ }
155
+
156
+ // Get installation target path (.claude/ or .codex/ directory)
143
157
  function getTargetPath(isGlobal) {
158
+ const dirName = getRuntimeDirName();
144
159
  if (isGlobal) {
160
+ if (activeRuntime === 'codex' && process.env.CODEX_HOME) {
161
+ return process.env.CODEX_HOME;
162
+ }
145
163
  const homeDir = process.env.HOME || process.env.USERPROFILE;
146
- return path.join(homeDir, '.claude');
164
+ return path.join(homeDir, dirName);
147
165
  }
148
- return path.join(process.cwd(), '.claude');
166
+ return path.join(process.cwd(), dirName);
149
167
  }
150
168
 
151
169
  // Get data path (.5/ directory for config, version, features)
152
170
  // Local installs: <project>/.5 (project root)
153
- // Global installs: ~/.claude/.5 (alongside global install)
171
+ // Global installs: ~/<runtime-dir>/.5 (alongside global install)
154
172
  function getDataPath(isGlobal) {
155
173
  if (isGlobal) {
156
174
  return path.join(getTargetPath(true), '.5');
@@ -262,7 +280,8 @@ const LEGACY_REMOVED_FILES = [
262
280
  'templates/STACK.md',
263
281
  'templates/STRUCTURE.md',
264
282
  'templates/CONVENTIONS.md',
265
- 'templates/INTEGRATIONS.md'
283
+ 'templates/INTEGRATIONS.md',
284
+ 'skills/configure-project'
266
285
  ];
267
286
 
268
287
  // Get list of workflow-owned files/directories (not user-created)
@@ -278,7 +297,8 @@ function getWorkflowManagedFiles() {
278
297
 
279
298
  // Skills: specific skill directories
280
299
  skills: [
281
- 'configure-project',
300
+ 'configure-docs-index',
301
+ 'configure-skills',
282
302
  'generate-readme'
283
303
  ],
284
304
 
@@ -314,8 +334,10 @@ function getWorkflowManagedFiles() {
314
334
  };
315
335
  }
316
336
 
317
- // Flatten getWorkflowManagedFiles() into a list of relative paths (relative to .claude/)
337
+ // Flatten getWorkflowManagedFiles() into a list of relative paths (relative to target dir)
318
338
  function getFileManifest() {
339
+ if (activeRuntime === 'codex') return getCodexFileManifest();
340
+
319
341
  const managed = getWorkflowManagedFiles();
320
342
  const manifest = [];
321
343
 
@@ -354,6 +376,141 @@ function getFileManifest() {
354
376
  return manifest;
355
377
  }
356
378
 
379
+ // ── Codex conversion functions ──────────────────────────────────────────────
380
+
381
+ // Extract YAML frontmatter and body from a markdown file
382
+ function extractFrontmatterAndBody(content) {
383
+ const match = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
384
+ if (!match) return { frontmatter: null, body: content };
385
+ return { frontmatter: match[1], body: match[2] };
386
+ }
387
+
388
+ // Extract a single field value from YAML frontmatter (simple key: value)
389
+ function extractFrontmatterField(frontmatter, field) {
390
+ if (!frontmatter) return null;
391
+ const match = frontmatter.match(new RegExp(`^${field}:\\s*(.+)$`, 'm'));
392
+ return match ? match[1].trim() : null;
393
+ }
394
+
395
+ // Convert /5:command-name references to $5-command-name (Codex skill mentions)
396
+ function convertSlashCommandsToCodexMentions(content) {
397
+ return content.replace(/\/5:([a-z0-9-]+)/g, (_, name) => `$5-${name}`);
398
+ }
399
+
400
+ // Convert Claude command markdown to Codex-compatible content
401
+ function convertClaudeToCodexMarkdown(content) {
402
+ let converted = convertSlashCommandsToCodexMentions(content);
403
+ // Replace .claude/ path references with .codex/
404
+ converted = converted.replace(/\.claude\//g, '.codex/');
405
+ return converted;
406
+ }
407
+
408
+ // Generate the adapter header that teaches Codex how to map Claude Code concepts
409
+ function getCodexSkillAdapterHeader(skillName) {
410
+ const invocation = `$${skillName}`;
411
+ return `<codex_skill_adapter>
412
+ ## Skill Invocation
413
+ - This skill is invoked by mentioning \`${invocation}\`.
414
+ - Treat all user text after \`${invocation}\` as the skill argument.
415
+
416
+ ## Tool Mapping (Claude Code → Codex)
417
+ This skill was authored for Claude Code. Map these tool references:
418
+
419
+ | Claude Code | Codex Equivalent |
420
+ |-------------|------------------|
421
+ | \`AskUserQuestion\` | Ask the user directly in conversation |
422
+ | \`Task(subagent_type="Explore")\` | Research the codebase yourself using available tools |
423
+ | \`Task(prompt="...")\` | \`spawn_agent(message="...")\` |
424
+ | \`Read\` | \`read_file\` |
425
+ | \`Write\` | \`write_file\` |
426
+ | \`Edit\` | \`patch\` |
427
+ | \`Bash\` | \`shell\` |
428
+ | \`Glob\` | \`glob\` / \`list_directory\` |
429
+ | \`Grep\` | \`grep\` / \`search\` |
430
+ | \`TaskCreate/TaskUpdate\` | Track progress internally |
431
+ | \`EnterPlanMode\` | Not available — use structured output instead |
432
+
433
+ ## Guard Rules (replaces plan-guard hook)
434
+ During planning phases (plan-feature, plan-implementation):
435
+ - Do NOT write to any file outside \`.5/\`
436
+ - Do NOT write source code — only specifications and plans
437
+ - Do NOT spawn implementation agents — only Explore/research agents
438
+ </codex_skill_adapter>`;
439
+ }
440
+
441
+ // Convert a Claude command .md file into a Codex SKILL.md
442
+ function convertClaudeCommandToCodexSkill(content, skillName) {
443
+ const converted = convertClaudeToCodexMarkdown(content);
444
+ const { frontmatter, body } = extractFrontmatterAndBody(converted);
445
+
446
+ let description = `Run 5-Phase Workflow: ${skillName}`;
447
+ if (frontmatter) {
448
+ const maybeDesc = extractFrontmatterField(frontmatter, 'description');
449
+ if (maybeDesc) description = maybeDesc;
450
+ }
451
+
452
+ // Truncate description for metadata
453
+ const shortDesc = description.length > 180 ? `${description.slice(0, 177)}...` : description;
454
+ const adapter = getCodexSkillAdapterHeader(skillName);
455
+
456
+ return `---
457
+ name: ${skillName}
458
+ description: ${description}
459
+ metadata:
460
+ short-description: ${shortDesc}
461
+ ---
462
+
463
+ ${adapter}
464
+
465
+ ${body.trimStart()}`;
466
+ }
467
+
468
+ // Convert a Claude SKILL.md to Codex-compatible SKILL.md (lighter conversion, no adapter needed for skills)
469
+ function convertClaudeSkillToCodexSkill(content) {
470
+ return convertClaudeToCodexMarkdown(content);
471
+ }
472
+
473
+ // Get file manifest for Codex installs (skills-based structure)
474
+ function getCodexFileManifest() {
475
+ const managed = getWorkflowManagedFiles();
476
+ const manifest = [];
477
+
478
+ // Commands become skills
479
+ // Each command file in commands/5/ becomes skills/5-{name}/SKILL.md
480
+ const commandsSrc = path.join(getSourcePath(), 'commands', '5');
481
+ if (fs.existsSync(commandsSrc)) {
482
+ const files = fs.readdirSync(commandsSrc).filter(f => f.endsWith('.md'));
483
+ for (const file of files) {
484
+ const name = file.replace('.md', '');
485
+ manifest.push(`skills/5-${name}`);
486
+ }
487
+ }
488
+
489
+ // Original skills also become Codex skills
490
+ for (const skill of managed.skills) {
491
+ manifest.push(`skills/${skill}`);
492
+ }
493
+
494
+ // Templates are copied as-is
495
+ for (const template of managed.templates) {
496
+ manifest.push(`templates/${template}`);
497
+ }
498
+
499
+ // References are copied as-is
500
+ if (managed.references) {
501
+ for (const ref of managed.references) {
502
+ manifest.push(`references/${ref}`);
503
+ }
504
+ }
505
+
506
+ // Instructions file
507
+ manifest.push('instructions.md');
508
+
509
+ return manifest;
510
+ }
511
+
512
+ // ── End Codex conversion functions ──────────────────────────────────────────
513
+
357
514
  // Selectively update only workflow-managed files, preserve user content
358
515
  function selectiveUpdate(targetPath, sourcePath) {
359
516
  const managed = getWorkflowManagedFiles();
@@ -609,23 +766,42 @@ function mergeSettings(targetPath, sourcePath) {
609
766
 
610
767
  // Check if installation exists
611
768
  function checkExistingInstallation(targetPath) {
769
+ if (activeRuntime === 'codex') {
770
+ // Codex: commands are installed as skills/5-plan-feature/SKILL.md
771
+ const markerFile = path.join(targetPath, 'skills', '5-plan-feature', 'SKILL.md');
772
+ return fs.existsSync(markerFile);
773
+ }
612
774
  const markerFile = path.join(targetPath, 'commands', '5', 'plan-feature.md');
613
775
  return fs.existsSync(markerFile);
614
776
  }
615
777
 
616
778
  // Helper to show commands
617
779
  function showCommandsHelp(isGlobal) {
618
- log.info('Available commands:');
619
- log.info(' /5:plan-feature - Start feature planning (Phase 1)');
620
- log.info(' /5:plan-implementation - Create implementation plan (Phase 2)');
621
- log.info(' /5:implement-feature - Execute implementation (Phase 3)');
622
- log.info(' /5:verify-implementation - Verify implementation (Phase 4)');
623
- log.info(' /5:review-code - Code review (Phase 5)');
624
- log.info(' /5:address-review-findings - Apply review findings & PR comments');
625
- log.info(' /5:configure - Interactive project setup');
626
- log.info(' /5:reconfigure - Refresh docs/skills (no Q&A)');
627
- log.info(' /5:eject - Eject from update mechanism');
628
- log.info(' /5:unlock - Remove planning guard lock');
780
+ if (activeRuntime === 'codex') {
781
+ log.info('Available skills (invoke with $ prefix in Codex):');
782
+ log.info(' $5-plan-feature - Start feature planning (Phase 1)');
783
+ log.info(' $5-plan-implementation - Create implementation plan (Phase 2)');
784
+ log.info(' $5-implement-feature - Execute implementation (Phase 3)');
785
+ log.info(' $5-verify-implementation - Verify implementation (Phase 4)');
786
+ log.info(' $5-review-code - Code review (Phase 5)');
787
+ log.info(' $5-address-review-findings - Apply review findings & PR comments');
788
+ log.info(' $5-configure - Interactive project setup');
789
+ log.info(' $5-reconfigure - Refresh docs/skills (no Q&A)');
790
+ log.info(' $5-eject - Eject from update mechanism');
791
+ log.info(' $5-unlock - Remove planning guard lock');
792
+ } else {
793
+ log.info('Available commands:');
794
+ log.info(' /5:plan-feature - Start feature planning (Phase 1)');
795
+ log.info(' /5:plan-implementation - Create implementation plan (Phase 2)');
796
+ log.info(' /5:implement-feature - Execute implementation (Phase 3)');
797
+ log.info(' /5:verify-implementation - Verify implementation (Phase 4)');
798
+ log.info(' /5:review-code - Code review (Phase 5)');
799
+ log.info(' /5:address-review-findings - Apply review findings & PR comments');
800
+ log.info(' /5:configure - Interactive project setup');
801
+ log.info(' /5:reconfigure - Refresh docs/skills (no Q&A)');
802
+ log.info(' /5:eject - Eject from update mechanism');
803
+ log.info(' /5:unlock - Remove planning guard lock');
804
+ }
629
805
  log.info('');
630
806
  log.info(`Config file: ${path.join(getDataPath(isGlobal), 'config.json')}`);
631
807
  }
@@ -721,26 +897,320 @@ function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
721
897
  showCommandsHelp(isGlobal);
722
898
  }
723
899
 
900
+ // ── Codex install/update/uninstall ──────────────────────────────────────────
901
+
902
+ // Generate instructions.md for Codex (replaces hooks + settings.json)
903
+ function generateCodexInstructions(targetPath) {
904
+ const content = `# 5-Phase Workflow — Codex Instructions
905
+
906
+ This file is managed by the 5-Phase Workflow installer. It provides Codex with
907
+ the context it needs to run the workflow skills correctly.
908
+
909
+ ## Workflow Overview
910
+
911
+ The 5-Phase Workflow provides structured feature development:
912
+
913
+ 1. **Plan Feature** (\`$5-plan-feature\`) — Requirements gathering & feature spec
914
+ 2. **Plan Implementation** (\`$5-plan-implementation\`) — Technical planning
915
+ 3. **Implement Feature** (\`$5-implement-feature\`) — Orchestrated implementation
916
+ 4. **Verify Implementation** (\`$5-verify-implementation\`) — Build & test verification
917
+ 5. **Review Code** (\`$5-review-code\`) — Code review
918
+
919
+ ## Data Directory
920
+
921
+ All workflow state lives in \`.5/\` at the project root:
922
+ - \`.5/config.json\` — Project configuration
923
+ - \`.5/features/{name}/feature.md\` — Feature specifications
924
+ - \`.5/features/{name}/plan.md\` — Implementation plans
925
+ - \`.5/features/{name}/state.json\` — Implementation state
926
+
927
+ ## Guard Rules
928
+
929
+ During planning phases (plan-feature, plan-implementation):
930
+ - Do NOT write files outside \`.5/\`
931
+ - Do NOT write source code — only specifications and plans
932
+ - The \`.5/.planning-active\` marker indicates planning is in progress
933
+
934
+ ## Configuration
935
+
936
+ Run \`$5-configure\` after installation to set up your project.
937
+
938
+ ## Templates & References
939
+
940
+ Templates are in \`.codex/templates/\` and references in \`.codex/references/\`.
941
+ Skills reference these paths for output formatting.
942
+ `;
943
+
944
+ fs.writeFileSync(path.join(targetPath, 'instructions.md'), content);
945
+ log.success('Generated instructions.md');
946
+ }
947
+
948
+ // Install commands as Codex skills
949
+ function installCodexSkills(targetPath, sourcePath) {
950
+ const commandsSrc = path.join(sourcePath, 'commands', '5');
951
+ const skillsDest = path.join(targetPath, 'skills');
952
+
953
+ if (!fs.existsSync(commandsSrc)) return;
954
+
955
+ const files = fs.readdirSync(commandsSrc).filter(f => f.endsWith('.md'));
956
+
957
+ for (const file of files) {
958
+ const name = file.replace('.md', '');
959
+ const skillName = `5-${name}`;
960
+ const content = fs.readFileSync(path.join(commandsSrc, file), 'utf8');
961
+ const converted = convertClaudeCommandToCodexSkill(content, skillName);
962
+
963
+ const skillDir = path.join(skillsDest, skillName);
964
+ if (!fs.existsSync(skillDir)) {
965
+ fs.mkdirSync(skillDir, { recursive: true });
966
+ }
967
+ fs.writeFileSync(path.join(skillDir, 'SKILL.md'), converted);
968
+ }
969
+ log.success(`Installed ${files.length} workflow skills`);
970
+
971
+ // Also convert and install original workflow skills (configure-docs-index, configure-skills, generate-readme)
972
+ const managed = getWorkflowManagedFiles();
973
+ for (const skill of managed.skills) {
974
+ const skillSrc = path.join(sourcePath, 'skills', skill);
975
+ if (!fs.existsSync(skillSrc)) continue;
976
+
977
+ const skillDestDir = path.join(skillsDest, skill);
978
+ if (!fs.existsSync(skillDestDir)) {
979
+ fs.mkdirSync(skillDestDir, { recursive: true });
980
+ }
981
+
982
+ // Copy all files in the skill directory, converting .md files
983
+ const skillFiles = fs.readdirSync(skillSrc);
984
+ for (const sf of skillFiles) {
985
+ const srcFile = path.join(skillSrc, sf);
986
+ const destFile = path.join(skillDestDir, sf);
987
+ if (sf.endsWith('.md')) {
988
+ const content = fs.readFileSync(srcFile, 'utf8');
989
+ fs.writeFileSync(destFile, convertClaudeSkillToCodexSkill(content));
990
+ } else {
991
+ fs.copyFileSync(srcFile, destFile);
992
+ }
993
+ }
994
+ }
995
+ log.success('Installed utility skills');
996
+ }
997
+
998
+ // Codex fresh installation
999
+ function performCodexFreshInstall(targetPath, sourcePath, isGlobal) {
1000
+ if (!fs.existsSync(targetPath)) {
1001
+ fs.mkdirSync(targetPath, { recursive: true });
1002
+ log.success(`Created ${targetPath}`);
1003
+ }
1004
+
1005
+ // Install commands as Codex skills
1006
+ installCodexSkills(targetPath, sourcePath);
1007
+
1008
+ // Copy templates and references as-is (just path conversion)
1009
+ for (const dir of ['templates', 'references']) {
1010
+ const src = path.join(sourcePath, dir);
1011
+ const dest = path.join(targetPath, dir);
1012
+ if (fs.existsSync(src)) {
1013
+ copyDir(src, dest);
1014
+ log.success(`Installed ${dir}/`);
1015
+ }
1016
+ }
1017
+
1018
+ // Generate instructions.md (replaces hooks + settings.json)
1019
+ generateCodexInstructions(targetPath);
1020
+
1021
+ // Initialize version tracking (shared .5/ directory)
1022
+ initializeVersionJson(isGlobal);
1023
+
1024
+ log.header('Codex Installation Complete!');
1025
+ log.info('');
1026
+ log.info('Next step: Configure your project');
1027
+ log.info('Mention: $5-configure');
1028
+ log.info('');
1029
+ log.info('This will:');
1030
+ log.info(' • Detect your project type and build commands');
1031
+ log.info(' • Set up ticket tracking conventions');
1032
+ log.info(' • Generate comprehensive documentation');
1033
+ log.info(' • Create project-specific skills');
1034
+
1035
+ showCommandsHelp(isGlobal);
1036
+ }
1037
+
1038
+ // Codex selective update
1039
+ function codexSelectiveUpdate(targetPath, sourcePath) {
1040
+ // Remove old skills and re-install
1041
+ const managed = getWorkflowManagedFiles();
1042
+ const skillsDest = path.join(targetPath, 'skills');
1043
+
1044
+ // Remove workflow command skills (5-*)
1045
+ const commandsSrc = path.join(sourcePath, 'commands', '5');
1046
+ if (fs.existsSync(commandsSrc)) {
1047
+ const files = fs.readdirSync(commandsSrc).filter(f => f.endsWith('.md'));
1048
+ for (const file of files) {
1049
+ const name = file.replace('.md', '');
1050
+ const skillDir = path.join(skillsDest, `5-${name}`);
1051
+ if (fs.existsSync(skillDir)) removeDir(skillDir);
1052
+ }
1053
+ }
1054
+
1055
+ // Remove utility skills
1056
+ for (const skill of managed.skills) {
1057
+ const skillDir = path.join(skillsDest, skill);
1058
+ if (fs.existsSync(skillDir)) removeDir(skillDir);
1059
+ }
1060
+
1061
+ // Re-install all skills
1062
+ installCodexSkills(targetPath, sourcePath);
1063
+
1064
+ // Update templates and references
1065
+ for (const dir of ['templates', 'references']) {
1066
+ const src = path.join(sourcePath, dir);
1067
+ const dest = path.join(targetPath, dir);
1068
+ if (fs.existsSync(src)) {
1069
+ if (fs.existsSync(dest)) removeDir(dest);
1070
+ copyDir(src, dest);
1071
+ }
1072
+ }
1073
+ log.success('Updated templates and references');
1074
+
1075
+ // Regenerate instructions.md
1076
+ generateCodexInstructions(targetPath);
1077
+ }
1078
+
1079
+ // Codex update
1080
+ function performCodexUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
1081
+ log.header(`Updating Codex install from ${versionInfo.installed || 'legacy'} to ${versionInfo.available}`);
1082
+ log.info('Preserving user-created skills');
1083
+
1084
+ codexSelectiveUpdate(targetPath, sourcePath);
1085
+
1086
+ // Clean up orphaned files
1087
+ const dataDir = getDataPath(isGlobal);
1088
+ cleanupOrphanedFiles(targetPath, dataDir);
1089
+
1090
+ // Update version.json
1091
+ const versionFile = path.join(dataDir, 'version.json');
1092
+ const now = new Date().toISOString();
1093
+ const existing = fs.existsSync(versionFile)
1094
+ ? JSON.parse(fs.readFileSync(versionFile, 'utf8'))
1095
+ : {};
1096
+ const versionData = {
1097
+ packageVersion: versionInfo.available,
1098
+ installedAt: existing.installedAt || now,
1099
+ lastUpdated: now,
1100
+ installationType: existing.installationType || (isGlobal ? 'global' : 'local'),
1101
+ manifest: getFileManifest()
1102
+ };
1103
+
1104
+ if (!fs.existsSync(dataDir)) {
1105
+ fs.mkdirSync(dataDir, { recursive: true });
1106
+ }
1107
+ fs.writeFileSync(versionFile, JSON.stringify(versionData, null, 2));
1108
+ ensureDotFiveGitignore(dataDir);
1109
+
1110
+ const featuresDir = path.join(dataDir, 'features');
1111
+ if (!fs.existsSync(featuresDir)) {
1112
+ fs.mkdirSync(featuresDir, { recursive: true });
1113
+ }
1114
+
1115
+ log.header('Update Complete!');
1116
+ log.success(`Now running version ${versionInfo.available}`);
1117
+ showCommandsHelp(isGlobal);
1118
+ }
1119
+
1120
+ // Codex uninstallation
1121
+ function codexUninstall() {
1122
+ const targetPath = getTargetPath(false);
1123
+
1124
+ log.header('5-Phase Workflow Uninstallation (Codex)');
1125
+ log.info(`Target: ${targetPath}`);
1126
+
1127
+ if (!checkExistingInstallation(targetPath)) {
1128
+ log.warn('No Codex installation found at this location');
1129
+ return;
1130
+ }
1131
+
1132
+ // Remove workflow command skills (5-*)
1133
+ const commandsSrc = path.join(getSourcePath(), 'commands', '5');
1134
+ if (fs.existsSync(commandsSrc)) {
1135
+ const files = fs.readdirSync(commandsSrc).filter(f => f.endsWith('.md'));
1136
+ for (const file of files) {
1137
+ const name = file.replace('.md', '');
1138
+ const skillDir = path.join(targetPath, 'skills', `5-${name}`);
1139
+ if (fs.existsSync(skillDir)) removeDir(skillDir);
1140
+ }
1141
+ log.success('Removed workflow skills');
1142
+ }
1143
+
1144
+ // Remove utility skills
1145
+ const managed = getWorkflowManagedFiles();
1146
+ for (const skill of managed.skills) {
1147
+ const skillDir = path.join(targetPath, 'skills', skill);
1148
+ if (fs.existsSync(skillDir)) removeDir(skillDir);
1149
+ }
1150
+ log.success('Removed utility skills (preserved user-created skills)');
1151
+
1152
+ // Remove templates
1153
+ for (const template of managed.templates) {
1154
+ const templatePath = path.join(targetPath, 'templates', template);
1155
+ if (fs.existsSync(templatePath)) fs.unlinkSync(templatePath);
1156
+ }
1157
+ log.success('Removed workflow templates');
1158
+
1159
+ // Remove references
1160
+ if (managed.references) {
1161
+ for (const ref of managed.references) {
1162
+ const refPath = path.join(targetPath, 'references', ref);
1163
+ if (fs.existsSync(refPath)) fs.unlinkSync(refPath);
1164
+ }
1165
+ log.success('Removed workflow references');
1166
+ }
1167
+
1168
+ // Remove instructions.md
1169
+ const instructionsPath = path.join(targetPath, 'instructions.md');
1170
+ if (fs.existsSync(instructionsPath)) {
1171
+ fs.unlinkSync(instructionsPath);
1172
+ log.success('Removed instructions.md');
1173
+ }
1174
+
1175
+ // Remove data directory (.5/)
1176
+ const dataDir = getDataPath(false);
1177
+ if (fs.existsSync(dataDir)) {
1178
+ removeDir(dataDir);
1179
+ log.success('Removed .5/ data directory');
1180
+ }
1181
+
1182
+ log.header('Uninstallation Complete!');
1183
+ }
1184
+
1185
+ // ── End Codex install/update/uninstall ──────────────────────────────────────
1186
+
724
1187
  // Perform installation
725
1188
  function install(isGlobal, forceUpgrade = false) {
726
1189
  const targetPath = getTargetPath(isGlobal);
727
1190
  const sourcePath = getSourcePath();
728
1191
 
729
- log.header('5-Phase Workflow Installation');
1192
+ const runtimeLabel = activeRuntime === 'codex' ? 'Codex' : 'Claude Code';
1193
+ log.header(`5-Phase Workflow Installation (${runtimeLabel})`);
730
1194
  log.info(`Target: ${targetPath}`);
731
1195
  log.info(`Source: ${sourcePath}`);
732
1196
 
733
- // Migrate data from old .claude/.5/ to new .5/ location
734
- migrateDataDir(isGlobal);
1197
+ // Migrate data from old .claude/.5/ to new .5/ location (Claude only)
1198
+ if (activeRuntime === 'claude') {
1199
+ migrateDataDir(isGlobal);
1200
+ }
735
1201
 
736
1202
  // Check for existing installation and version
737
1203
  const versionInfo = getVersionInfo(targetPath, isGlobal);
738
1204
 
1205
+ // Select the right install/update functions for this runtime
1206
+ const freshInstall = activeRuntime === 'codex' ? performCodexFreshInstall : performFreshInstall;
1207
+ const update = activeRuntime === 'codex' ? performCodexUpdate : performUpdate;
1208
+
739
1209
  if (versionInfo.exists) {
740
1210
  if (versionInfo.legacy) {
741
1211
  log.warn('Detected legacy installation (no version tracking)');
742
1212
  log.info(`Upgrading from legacy install to ${versionInfo.available}`);
743
- performUpdate(targetPath, sourcePath, isGlobal, versionInfo);
1213
+ update(targetPath, sourcePath, isGlobal, versionInfo);
744
1214
  return;
745
1215
  } else if (versionInfo.needsUpdate) {
746
1216
  log.info(`Installed: ${versionInfo.installed}`);
@@ -759,12 +1229,12 @@ function install(isGlobal, forceUpgrade = false) {
759
1229
  log.info('Update cancelled');
760
1230
  return;
761
1231
  }
762
- performUpdate(targetPath, sourcePath, isGlobal, versionInfo);
1232
+ update(targetPath, sourcePath, isGlobal, versionInfo);
763
1233
  });
764
1234
  return; // Wait for user input
765
1235
  }
766
1236
  // Force upgrade, no prompt
767
- performUpdate(targetPath, sourcePath, isGlobal, versionInfo);
1237
+ update(targetPath, sourcePath, isGlobal, versionInfo);
768
1238
  return;
769
1239
  } else {
770
1240
  // Same version
@@ -774,11 +1244,16 @@ function install(isGlobal, forceUpgrade = false) {
774
1244
  }
775
1245
 
776
1246
  // Fresh install (no existing installation)
777
- performFreshInstall(targetPath, sourcePath, isGlobal);
1247
+ freshInstall(targetPath, sourcePath, isGlobal);
778
1248
  }
779
1249
 
780
1250
  // Perform uninstallation
781
1251
  function uninstall() {
1252
+ if (activeRuntime === 'codex') {
1253
+ codexUninstall();
1254
+ return;
1255
+ }
1256
+
782
1257
  const targetPath = getTargetPath(false); // Always local for uninstall
783
1258
 
784
1259
  log.header('5-Phase Workflow Uninstallation');
@@ -875,6 +1350,9 @@ function uninstall() {
875
1350
  function main() {
876
1351
  const options = parseArgs();
877
1352
 
1353
+ // Set module-level runtime before any path resolution
1354
+ activeRuntime = options.runtime;
1355
+
878
1356
  if (options.help) {
879
1357
  showHelp();
880
1358
  return;
@@ -886,16 +1364,17 @@ function main() {
886
1364
  const versionInfo = getVersionInfo(targetPath, options.global);
887
1365
 
888
1366
  if (!versionInfo.exists) {
889
- log.info('Not installed');
1367
+ log.info(`Not installed (${activeRuntime})`);
890
1368
  return;
891
1369
  }
892
1370
 
1371
+ log.info(`Runtime: ${activeRuntime}`);
893
1372
  log.info(`Installed: ${versionInfo.installed || 'legacy (no version)'}`);
894
1373
  log.info(`Available: ${versionInfo.available}`);
895
1374
 
896
1375
  if (versionInfo.needsUpdate) {
897
1376
  log.warn('Update available');
898
- log.info('Run: npx 5-phase-workflow --upgrade');
1377
+ log.info(`Run: npx 5-phase-workflow${activeRuntime === 'codex' ? ' --codex' : ''} --upgrade`);
899
1378
  } else {
900
1379
  log.success('Up to date');
901
1380
  }