5-phase-workflow 1.8.7 → 1.8.8

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