5-phase-workflow 1.9.5 → 2.0.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 (44) hide show
  1. package/README.md +81 -410
  2. package/bin/install.js +385 -70
  3. package/bin/sync-agents.js +50 -11
  4. package/docs/findings.md +3 -3
  5. package/docs/workflow-guide.md +110 -1046
  6. package/package.json +6 -5
  7. package/src/agents/step-executor-agent.md +49 -0
  8. package/src/agents/step-orchestrator-agent.md +111 -0
  9. package/src/agents/verification-agent.md +78 -0
  10. package/src/commands/5/address-review-findings.md +69 -403
  11. package/src/commands/5/apply-review-findings.md +66 -0
  12. package/src/commands/5/configure.md +110 -76
  13. package/src/commands/5/discuss-feature.md +47 -57
  14. package/src/commands/5/eject.md +7 -6
  15. package/src/commands/5/implement.md +202 -0
  16. package/src/commands/5/plan.md +164 -0
  17. package/src/commands/5/reconfigure.md +32 -31
  18. package/src/commands/5/reply-pr-comments.md +46 -0
  19. package/src/commands/5/review.md +95 -0
  20. package/src/commands/5/split.md +190 -0
  21. package/src/commands/5/synchronize-agents.md +4 -4
  22. package/src/commands/5/triage-pr-comments.md +70 -0
  23. package/src/commands/5/update.md +8 -8
  24. package/src/hooks/check-updates.js +50 -7
  25. package/src/hooks/plan-guard.js +28 -22
  26. package/src/hooks/statusline.js +55 -4
  27. package/src/skills/configure-docs-index/SKILL.md +16 -21
  28. package/src/skills/configure-skills/SKILL.md +21 -24
  29. package/src/templates/AGENTS.md +94 -0
  30. package/src/templates/workflow/FIX-PLAN.md +1 -1
  31. package/src/templates/workflow/PLAN-COMPACT.md +42 -0
  32. package/src/templates/workflow/PLAN.md +58 -34
  33. package/src/templates/workflow/REVIEW-FINDINGS.md +7 -16
  34. package/src/templates/workflow/REVIEW-SUMMARY.md +5 -0
  35. package/src/templates/workflow/STATE.json +32 -3
  36. package/src/agents/component-executor.md +0 -57
  37. package/src/commands/5/implement-feature.md +0 -381
  38. package/src/commands/5/plan-feature.md +0 -293
  39. package/src/commands/5/plan-implementation.md +0 -333
  40. package/src/commands/5/quick-implement.md +0 -375
  41. package/src/commands/5/review-code.md +0 -212
  42. package/src/commands/5/verify-implementation.md +0 -277
  43. package/src/templates/workflow/FEATURE-SPEC.md +0 -100
  44. package/src/templates/workflow/VERIFICATION-REPORT.md +0 -103
package/bin/install.js CHANGED
@@ -25,15 +25,60 @@ const log = {
25
25
  header: (msg) => console.log(`\n${colors.bright}${msg}${colors.reset}\n`)
26
26
  };
27
27
 
28
- // Version comparison (semver)
29
- // Uses parseInt to handle pre-release tags (e.g., "2-beta" → 2)
28
+ // Version comparison (semver, including pre-release ordering)
30
29
  function compareVersions(v1, v2) {
31
- const parts1 = v1.split('.').map(p => parseInt(p, 10) || 0);
32
- const parts2 = v2.split('.').map(p => parseInt(p, 10) || 0);
30
+ const parsed1 = parseSemver(v1);
31
+ const parsed2 = parseSemver(v2);
32
+
33
33
  for (let i = 0; i < 3; i++) {
34
- if (parts1[i] > parts2[i]) return 1;
35
- if (parts1[i] < parts2[i]) return -1;
34
+ if (parsed1.core[i] > parsed2.core[i]) return 1;
35
+ if (parsed1.core[i] < parsed2.core[i]) return -1;
36
36
  }
37
+
38
+ return comparePrerelease(parsed1.prerelease, parsed2.prerelease);
39
+ }
40
+
41
+ function parseSemver(version) {
42
+ const normalized = String(version || '').trim().replace(/^v/, '').split('+')[0];
43
+ const prereleaseIndex = normalized.indexOf('-');
44
+ const corePart = prereleaseIndex === -1 ? normalized : normalized.slice(0, prereleaseIndex);
45
+ const prereleasePart = prereleaseIndex === -1 ? '' : normalized.slice(prereleaseIndex + 1);
46
+ const core = corePart.split('.').slice(0, 3).map(part => parseInt(part, 10) || 0);
47
+ while (core.length < 3) core.push(0);
48
+
49
+ return {
50
+ core,
51
+ prerelease: prereleasePart ? prereleasePart.split(/[.-]/) : []
52
+ };
53
+ }
54
+
55
+ function comparePrerelease(pre1, pre2) {
56
+ if (pre1.length === 0 && pre2.length === 0) return 0;
57
+ if (pre1.length === 0) return 1;
58
+ if (pre2.length === 0) return -1;
59
+
60
+ const length = Math.max(pre1.length, pre2.length);
61
+ for (let i = 0; i < length; i++) {
62
+ const id1 = pre1[i];
63
+ const id2 = pre2[i];
64
+ if (id1 === undefined) return -1;
65
+ if (id2 === undefined) return 1;
66
+ if (id1 === id2) continue;
67
+
68
+ const id1Numeric = /^[0-9]+$/.test(id1);
69
+ const id2Numeric = /^[0-9]+$/.test(id2);
70
+ if (id1Numeric && id2Numeric) {
71
+ const n1 = parseInt(id1, 10);
72
+ const n2 = parseInt(id2, 10);
73
+ if (n1 > n2) return 1;
74
+ if (n1 < n2) return -1;
75
+ continue;
76
+ }
77
+ if (id1Numeric) return -1;
78
+ if (id2Numeric) return 1;
79
+ return id1 > id2 ? 1 : -1;
80
+ }
81
+
37
82
  return 0;
38
83
  }
39
84
 
@@ -56,11 +101,15 @@ function getInstalledVersion(isGlobal) {
56
101
 
57
102
  // Get package version from package.json
58
103
  function getPackageVersion() {
59
- const pkgPath = path.join(__dirname, '..', 'package.json');
104
+ const pkgPath = path.join(getPackageRoot(), 'package.json');
60
105
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
61
106
  return pkg.version;
62
107
  }
63
108
 
109
+ function getPackageRoot() {
110
+ return path.join(__dirname, '..');
111
+ }
112
+
64
113
  // Get full version info
65
114
  function getVersionInfo(targetPath, isGlobal) {
66
115
  const exists = checkExistingInstallation(targetPath);
@@ -126,9 +175,9 @@ function parseArgs() {
126
175
  // Show help message
127
176
  function showHelp() {
128
177
  console.log(`
129
- ${colors.bright}5-Phase Workflow Installer${colors.reset}
178
+ ${colors.bright}dev-workflow Installer${colors.reset}
130
179
 
131
- Usage: npx 5-phase-workflow [options]
180
+ Usage: npx foifi [options]
132
181
 
133
182
  Options:
134
183
  --global, -g Install to ~/.claude/ (available across all projects)
@@ -141,13 +190,13 @@ Options:
141
190
  --help, -h Show this help message
142
191
 
143
192
  Examples:
144
- npx 5-phase-workflow # Install locally for Claude Code
145
- npx 5-phase-workflow --global # Install globally for Claude Code
146
- npx 5-phase-workflow --codex # Install locally for Codex CLI
147
- npx 5-phase-workflow --codex -g # Install globally for Codex CLI
148
- npx 5-phase-workflow --upgrade # Auto-update to latest version
149
- npx 5-phase-workflow --check # Check version without updating
150
- npx 5-phase-workflow --uninstall # Remove from current directory
193
+ npx foifi # Install locally for Claude Code
194
+ npx foifi --global # Install globally for Claude Code
195
+ npx foifi --codex # Install locally for Codex CLI
196
+ npx foifi --codex -g # Install globally for Codex CLI
197
+ npx foifi --upgrade # Auto-update to latest version
198
+ npx foifi --check # Check version without updating
199
+ npx foifi --uninstall # Remove from current directory
151
200
  `);
152
201
  }
153
202
 
@@ -228,7 +277,11 @@ function copyDirMerge(src, dest) {
228
277
  function getSourcePath() {
229
278
  // When installed via npm, __dirname is <install-location>/bin
230
279
  // Source files are in <install-location>/src
231
- return path.join(__dirname, '..', 'src');
280
+ return path.join(getPackageRoot(), 'src');
281
+ }
282
+
283
+ function getPackageBinPath() {
284
+ return path.join(getPackageRoot(), 'bin');
232
285
  }
233
286
 
234
287
  // Copy directory recursively
@@ -251,6 +304,25 @@ function copyDir(src, dest) {
251
304
  }
252
305
  }
253
306
 
307
+ function copyWorkflowHelperBins(targetPath) {
308
+ const managed = getWorkflowManagedFiles();
309
+ if (!managed.binHelpers || managed.binHelpers.length === 0) return;
310
+
311
+ const binSrc = getPackageBinPath();
312
+ const binDest = path.join(targetPath, 'bin');
313
+ if (!fs.existsSync(binDest)) {
314
+ fs.mkdirSync(binDest, { recursive: true });
315
+ }
316
+
317
+ for (const binHelper of managed.binHelpers) {
318
+ const src = path.join(binSrc, binHelper);
319
+ const dest = path.join(binDest, binHelper);
320
+ if (fs.existsSync(src)) {
321
+ fs.copyFileSync(src, dest);
322
+ }
323
+ }
324
+ }
325
+
254
326
  // Remove directory recursively
255
327
  function removeDir(dir) {
256
328
  if (fs.existsSync(dir)) {
@@ -280,11 +352,28 @@ const LEGACY_REMOVED_FILES = [
280
352
  'agents/integration-agent.md',
281
353
  'agents/step-fixer.md',
282
354
  'agents/step-verifier.md',
283
- 'agents/verification-agent.md',
284
355
  'templates/STACK.md',
285
356
  'templates/STRUCTURE.md',
286
357
  'templates/CONVENTIONS.md',
287
- 'templates/INTEGRATIONS.md'
358
+ 'templates/INTEGRATIONS.md',
359
+ 'commands/5/plan-feature.md',
360
+ 'commands/5/plan-implementation.md',
361
+ 'commands/5/implement-feature.md',
362
+ 'commands/5/verify.md',
363
+ 'commands/5/verify-implementation.md',
364
+ 'commands/5/review-code.md',
365
+ 'commands/5/quick-implement.md',
366
+ 'agents/component-executor.md',
367
+ 'templates/workflow/FEATURE-SPEC.md',
368
+ 'templates/workflow/VERIFICATION-REPORT.md',
369
+ 'skills/5-plan-feature',
370
+ 'skills/5-plan-implementation',
371
+ 'skills/5-implement-feature',
372
+ 'skills/5-verify',
373
+ 'skills/5-verify-implementation',
374
+ 'skills/5-review-code',
375
+ 'skills/5-quick-implement',
376
+ 'skills/configure-project'
288
377
  ];
289
378
 
290
379
  // Get list of workflow-owned files/directories (not user-created)
@@ -295,13 +384,14 @@ function getWorkflowManagedFiles() {
295
384
 
296
385
  // Agents: separate agent files referenced by commands via agent: frontmatter
297
386
  agents: [
298
- 'component-executor.md'
387
+ 'step-executor-agent.md',
388
+ 'step-orchestrator-agent.md',
389
+ 'verification-agent.md'
299
390
  ],
300
391
 
301
392
  // Skills: specific skill directories
302
393
  skills: [
303
394
  'configure-docs-index',
304
- 'configure-project',
305
395
  'configure-skills',
306
396
  'generate-readme'
307
397
  ],
@@ -320,17 +410,22 @@ function getWorkflowManagedFiles() {
320
410
  'configure-tables.md'
321
411
  ],
322
412
 
413
+ // Helper binaries: runtime scripts invoked by commands
414
+ binHelpers: [
415
+ 'sync-agents.js'
416
+ ],
417
+
323
418
  // Templates: specific template files
324
419
  templates: [
325
420
  // Project documentation templates
421
+ 'AGENTS.md',
326
422
  'ARCHITECTURE.md',
327
423
  'CONCERNS.md',
328
424
  'TESTING.md',
329
425
  // Workflow output templates
330
- 'workflow/FEATURE-SPEC.md',
331
426
  'workflow/PLAN.md',
427
+ 'workflow/PLAN-COMPACT.md',
332
428
  'workflow/STATE.json',
333
- 'workflow/VERIFICATION-REPORT.md',
334
429
  'workflow/REVIEW-FINDINGS.md',
335
430
  'workflow/REVIEW-SUMMARY.md',
336
431
  'workflow/FIX-PLAN.md'
@@ -365,7 +460,7 @@ function getFileManifest() {
365
460
  manifest.push(`hooks/${hook}`);
366
461
  }
367
462
 
368
- // Templates are files (may include nested paths like workflow/FEATURE-SPEC.md)
463
+ // Templates are files (may include nested paths like workflow/PLAN.md)
369
464
  for (const template of managed.templates) {
370
465
  manifest.push(`templates/${template}`);
371
466
  }
@@ -377,6 +472,12 @@ function getFileManifest() {
377
472
  }
378
473
  }
379
474
 
475
+ if (managed.binHelpers) {
476
+ for (const binHelper of managed.binHelpers) {
477
+ manifest.push(`bin/${binHelper}`);
478
+ }
479
+ }
480
+
380
481
  return manifest;
381
482
  }
382
483
 
@@ -406,9 +507,30 @@ function convertClaudeToCodexMarkdown(content) {
406
507
  let converted = convertSlashCommandsToCodexMentions(content);
407
508
  // Replace .claude/ path references with .codex/
408
509
  converted = converted.replace(/\.claude\//g, '.codex/');
510
+ converted = convertClaudeSetupCommandsToCodexNotes(converted);
409
511
  return converted;
410
512
  }
411
513
 
514
+ function convertClaudeSetupCommandsToCodexNotes(content) {
515
+ return content
516
+ .replace(
517
+ /1\. "Install now \(recommended\)" — run `claude mcp add context7 -- npx -y @anthropic-ai\/claude-code-mcp-server-context7` via Bash/g,
518
+ '1. "Install now" — not supported automatically in Codex; install Context7 using your Codex MCP setup outside this workflow, then rerun configuration'
519
+ )
520
+ .replace(
521
+ /- If user selects "Install now": execute the install command/g,
522
+ '- If user selects "Install now": explain that Codex cannot run the Claude Code installer command; leave `tools.context7.available = false` unless Context7 is already detected'
523
+ )
524
+ .replace(
525
+ /1\. "Install now \(recommended\)" — run `claude plugin install skill-creator@claude-plugins-official` via Bash/g,
526
+ '1. "Install now" — not supported automatically in Codex; install an equivalent skill authoring workflow outside this command, then rerun configuration'
527
+ )
528
+ .replace(
529
+ /- If user selects "Install now": execute the install command, then set `tools\.skillCreator\.available = true` in the config/g,
530
+ '- If user selects "Install now": explain that Codex cannot run the Claude Code plugin installer; leave `tools.skillCreator.available = false` unless an equivalent tool is already detected'
531
+ );
532
+ }
533
+
412
534
  // Generate the adapter header that teaches Codex how to map Claude Code concepts
413
535
  function getCodexSkillAdapterHeader(skillName) {
414
536
  const invocation = `$${skillName}`;
@@ -423,8 +545,10 @@ This skill was authored for Claude Code. Map these tool references:
423
545
  | Claude Code | Codex Equivalent |
424
546
  |-------------|------------------|
425
547
  | \`AskUserQuestion\` | Ask the user directly in conversation |
426
- | \`Agent(subagent_type="Explore")\` | Research the codebase yourself using available tools |
427
- | \`Agent(prompt="...")\` | \`spawn_agent(message="...")\` |
548
+ | \`Agent(subagent_type="Explore")\` | \`spawn_agent(agent_type="explorer", model="gpt-5.4-mini", reasoning_effort="low", message="...")\` |
549
+ | \`Agent(prompt="...", model="haiku")\` | \`spawn_agent(model="gpt-5.4-mini", reasoning_effort="low", message="...")\` |
550
+ | \`Agent(prompt="...", model="sonnet")\` | \`spawn_agent(model="gpt-5.4", reasoning_effort="medium", message="...")\` |
551
+ | \`Agent(prompt="...")\` | \`spawn_agent(model="gpt-5.4-mini", reasoning_effort="low", message="...")\` unless the prompt explicitly requires complex reasoning |
428
552
  | \`Read\` | \`read_file\` |
429
553
  | \`Write\` | \`write_file\` |
430
554
  | \`Edit\` | \`patch\` |
@@ -434,11 +558,24 @@ This skill was authored for Claude Code. Map these tool references:
434
558
  | \`TaskCreate/TaskUpdate\` | Track progress internally |
435
559
  | \`EnterPlanMode\` | Not available — use structured output instead |
436
560
 
561
+ ## Codex Token Budget
562
+ - Default to \`gpt-5.4-mini\` with \`reasoning_effort: low\` for exploration, orchestration, simple implementation, and mechanical file edits.
563
+ - Use \`gpt-5.4\` with \`reasoning_effort: medium\` only for complex logic, cross-module behavior, security-sensitive changes, data migrations, final verification with meaningful logic review, or retries after failure.
564
+ - Use stronger models only when a previous cheaper attempt failed for reasoning reasons.
565
+ - Keep the parent skill context lean: delegate read-heavy exploration to explorer agents and pass only compact findings, target paths, pattern references, and command summaries between agents.
566
+
437
567
  ## Guard Rules (replaces plan-guard hook)
438
- During planning phases (plan-feature, plan-implementation):
568
+ During the planning phase ($5-plan):
439
569
  - Do NOT write to any file outside \`.5/\`
440
- - Do NOT write source code — only specifications and plans
570
+ - Do NOT write source code — only the unified plan and scan cache
441
571
  - Do NOT spawn implementation agents — only Explore/research agents
572
+
573
+ ## Update & Migration Notices (replaces statusline hooks)
574
+ At the very start of this skill, before doing anything else, read these two files if they exist:
575
+ - \`.5/.update-cache.json\` — if \`latestAvailableVersion\` is set, compare it to \`packageVersion\` in \`.5/version.json\`. If a newer version is available, tell the user: "foifi update available: <version> — run \`npx foifi --codex --upgrade\` to update."
576
+ - \`.5/.migration-v2\` — if this file exists, tell the user: "You upgraded from foifi v1 to v2. Run \`$5-reconfigure\` to update your project configuration."
577
+
578
+ Show each applicable notice once at the top of your response, then continue with the skill normally. Do not abort the skill because of a notice.
442
579
  </codex_skill_adapter>`;
443
580
  }
444
581
 
@@ -447,7 +584,7 @@ function convertClaudeCommandToCodexSkill(content, skillName) {
447
584
  const converted = convertClaudeToCodexMarkdown(content);
448
585
  const { frontmatter, body } = extractFrontmatterAndBody(converted);
449
586
 
450
- let description = `Run 5-Phase Workflow: ${skillName}`;
587
+ let description = `Run dev-workflow: ${skillName}`;
451
588
  if (frontmatter) {
452
589
  const maybeDesc = extractFrontmatterField(frontmatter, 'description');
453
590
  if (maybeDesc) description = maybeDesc;
@@ -495,6 +632,11 @@ function getCodexFileManifest() {
495
632
  manifest.push(`skills/${skill}`);
496
633
  }
497
634
 
635
+ // Agents are copied as-is for Codex skills that reference .codex/agents/
636
+ for (const agent of managed.agents) {
637
+ manifest.push(`agents/${agent}`);
638
+ }
639
+
498
640
  // Templates are copied as-is
499
641
  for (const template of managed.templates) {
500
642
  manifest.push(`templates/${template}`);
@@ -507,6 +649,12 @@ function getCodexFileManifest() {
507
649
  }
508
650
  }
509
651
 
652
+ if (managed.binHelpers) {
653
+ for (const binHelper of managed.binHelpers) {
654
+ manifest.push(`bin/${binHelper}`);
655
+ }
656
+ }
657
+
510
658
  // Instructions file
511
659
  manifest.push('instructions.md');
512
660
 
@@ -590,7 +738,7 @@ function selectiveUpdate(targetPath, sourcePath) {
590
738
  const src = path.join(templatesSrc, template);
591
739
  const dest = path.join(templatesDest, template);
592
740
  if (fs.existsSync(src)) {
593
- // Ensure parent directory exists for nested paths (e.g., workflow/FEATURE-SPEC.md)
741
+ // Ensure parent directory exists for nested paths (e.g., workflow/PLAN.md)
594
742
  const destDir = path.dirname(dest);
595
743
  if (!fs.existsSync(destDir)) {
596
744
  fs.mkdirSync(destDir, { recursive: true });
@@ -616,6 +764,23 @@ function selectiveUpdate(targetPath, sourcePath) {
616
764
  }
617
765
  log.success('Updated references/ (workflow files only)');
618
766
  }
767
+
768
+ // Update helper binaries used by runtime commands
769
+ if (managed.binHelpers && managed.binHelpers.length > 0) {
770
+ const binSrc = getPackageBinPath();
771
+ const binDest = path.join(targetPath, 'bin');
772
+ if (!fs.existsSync(binDest)) {
773
+ fs.mkdirSync(binDest, { recursive: true });
774
+ }
775
+ for (const binHelper of managed.binHelpers) {
776
+ const src = path.join(binSrc, binHelper);
777
+ const dest = path.join(binDest, binHelper);
778
+ if (fs.existsSync(src)) {
779
+ fs.copyFileSync(src, dest);
780
+ }
781
+ }
782
+ log.success('Updated bin/ (workflow helper binaries)');
783
+ }
619
784
  }
620
785
 
621
786
  // Clean up files that were previously installed but are no longer managed
@@ -670,17 +835,20 @@ function cleanupOrphanedFiles(targetPath, dataDir) {
670
835
  }
671
836
  }
672
837
 
673
- // Ensure .5/.gitignore exists and contains .update-cache.json
838
+ // Ensure .5/.gitignore exists and contains transient runtime files
674
839
  function ensureDotFiveGitignore(dataDir) {
675
840
  const gitignorePath = path.join(dataDir, '.gitignore');
676
- const entry = '.update-cache.json';
841
+ const entries = ['.update-cache.json', '.migration-v*', '.reconfig-reminder'];
677
842
  if (fs.existsSync(gitignorePath)) {
678
- const content = fs.readFileSync(gitignorePath, 'utf8');
679
- if (!content.includes(entry)) {
680
- fs.appendFileSync(gitignorePath, '\n' + entry + '\n');
843
+ let content = fs.readFileSync(gitignorePath, 'utf8');
844
+ for (const entry of entries) {
845
+ if (!content.includes(entry)) {
846
+ content += '\n' + entry;
847
+ }
681
848
  }
849
+ fs.writeFileSync(gitignorePath, content.trimEnd() + '\n');
682
850
  } else {
683
- fs.writeFileSync(gitignorePath, entry + '\n');
851
+ fs.writeFileSync(gitignorePath, entries.join('\n') + '\n');
684
852
  }
685
853
  }
686
854
 
@@ -825,24 +993,25 @@ function mergeSettings(targetPath, sourcePath) {
825
993
  // Check if installation exists
826
994
  function checkExistingInstallation(targetPath) {
827
995
  if (activeRuntime === 'codex') {
828
- // Codex: commands are installed as skills/5-plan-feature/SKILL.md
829
- const markerFile = path.join(targetPath, 'skills', '5-plan-feature', 'SKILL.md');
830
- return fs.existsSync(markerFile);
831
- }
832
- const markerFile = path.join(targetPath, 'commands', '5', 'plan-feature.md');
833
- return fs.existsSync(markerFile);
996
+ // Codex: commands are installed as skills/5-plan/SKILL.md
997
+ const markerFile = path.join(targetPath, 'skills', '5-plan', 'SKILL.md');
998
+ const legacyMarkerFile = path.join(targetPath, 'skills', '5-plan-feature', 'SKILL.md');
999
+ return fs.existsSync(markerFile) || fs.existsSync(legacyMarkerFile);
1000
+ }
1001
+ const markerFile = path.join(targetPath, 'commands', '5', 'plan.md');
1002
+ const legacyMarkerFile = path.join(targetPath, 'commands', '5', 'plan-feature.md');
1003
+ return fs.existsSync(markerFile) || fs.existsSync(legacyMarkerFile);
834
1004
  }
835
1005
 
836
1006
  // Helper to show commands
837
1007
  function showCommandsHelp(isGlobal) {
838
1008
  if (activeRuntime === 'codex') {
839
1009
  log.info('Available skills (invoke with $ prefix in Codex):');
840
- log.info(' $5-plan-feature - Start feature planning (Phase 1)');
841
- log.info(' $5-plan-implementation - Create implementation plan (Phase 2)');
842
- log.info(' $5-implement-feature - Execute implementation (Phase 3)');
843
- log.info(' $5-verify-implementation - Verify implementation (Phase 4)');
844
- log.info(' $5-review-code - Code review (Phase 5)');
845
- log.info(' $5-address-review-findings - Apply review findings & PR comments');
1010
+ log.info(' $5-plan - Create unified plan');
1011
+ log.info(' $5-split - Split plan into smaller plans');
1012
+ log.info(' $5-implement - Execute implementation + verification');
1013
+ log.info(' $5-review - Code review');
1014
+ log.info(' $5-address-review-findings - Decide review findings & PR comments');
846
1015
  log.info(' $5-configure - Interactive project setup');
847
1016
  log.info(' $5-reconfigure - Refresh docs/skills (no Q&A)');
848
1017
  log.info(' $5-eject - Eject from update mechanism');
@@ -850,12 +1019,11 @@ function showCommandsHelp(isGlobal) {
850
1019
  log.info(' $5-synchronize-agents - Sync user content between runtimes');
851
1020
  } else {
852
1021
  log.info('Available commands:');
853
- log.info(' /5:plan-feature - Start feature planning (Phase 1)');
854
- log.info(' /5:plan-implementation - Create implementation plan (Phase 2)');
855
- log.info(' /5:implement-feature - Execute implementation (Phase 3)');
856
- log.info(' /5:verify-implementation - Verify implementation (Phase 4)');
857
- log.info(' /5:review-code - Code review (Phase 5)');
858
- log.info(' /5:address-review-findings - Apply review findings & PR comments');
1022
+ log.info(' /5:plan - Create unified plan');
1023
+ log.info(' /5:split - Split plan into smaller plans');
1024
+ log.info(' /5:implement - Execute implementation + verification');
1025
+ log.info(' /5:review - Code review');
1026
+ log.info(' /5:address-review-findings - Decide review findings & PR comments');
859
1027
  log.info(' /5:configure - Interactive project setup');
860
1028
  log.info(' /5:reconfigure - Refresh docs/skills (no Q&A)');
861
1029
  log.info(' /5:eject - Eject from update mechanism');
@@ -889,6 +1057,10 @@ function performFreshInstall(targetPath, sourcePath, isGlobal) {
889
1057
  // Merge settings
890
1058
  mergeSettings(targetPath, sourcePath);
891
1059
 
1060
+ // Install helper binaries used by runtime commands
1061
+ copyWorkflowHelperBins(targetPath);
1062
+ log.success('Installed bin/ (workflow helper binaries)');
1063
+
892
1064
  // Initialize version tracking
893
1065
  initializeVersionJson(isGlobal);
894
1066
 
@@ -908,6 +1080,52 @@ function performFreshInstall(targetPath, sourcePath, isGlobal) {
908
1080
  showCommandsHelp(isGlobal);
909
1081
  }
910
1082
 
1083
+ // Rename create-* generated skill directories to {pattern} (drop the create- prefix).
1084
+ // Earlier versions named them create-dto, create-service, etc. The new convention
1085
+ // uses the bare pattern name so skills work for both create and update.
1086
+ function renameCreateSkills(targetPath) {
1087
+ const skillsDir = path.join(targetPath, 'skills');
1088
+ if (!fs.existsSync(skillsDir)) return;
1089
+ try {
1090
+ for (const entry of fs.readdirSync(skillsDir)) {
1091
+ if (!entry.startsWith('create-')) continue;
1092
+ const oldPath = path.join(skillsDir, entry);
1093
+ const newName = entry.slice('create-'.length);
1094
+ const newPath = path.join(skillsDir, newName);
1095
+ if (fs.existsSync(newPath)) continue; // don't clobber a user-created skill
1096
+ const skillFile = path.join(oldPath, 'SKILL.md');
1097
+ if (!fs.existsSync(skillFile)) continue; // skip non-workflow dirs
1098
+ fs.renameSync(oldPath, newPath);
1099
+ // Update name: and description: in the frontmatter to match
1100
+ const content = fs.readFileSync(path.join(newPath, 'SKILL.md'), 'utf8');
1101
+ const updated = content
1102
+ .replace(/^name: create-/m, 'name: ')
1103
+ .replace(/^description: Creates a /m, 'description: Creates or updates a ');
1104
+ fs.writeFileSync(path.join(newPath, 'SKILL.md'), updated);
1105
+ log.info(`Renamed skill: ${entry} → ${newName}`);
1106
+ }
1107
+ } catch (e) {}
1108
+ }
1109
+
1110
+ // Remove `context: fork` from any skill SKILL.md files under .claude/skills/.
1111
+ // These were generated by earlier versions of configure-skills and cause loops.
1112
+ function removeContextForkFromSkills(targetPath) {
1113
+ const skillsDir = path.join(targetPath, 'skills');
1114
+ if (!fs.existsSync(skillsDir)) return;
1115
+ try {
1116
+ for (const entry of fs.readdirSync(skillsDir)) {
1117
+ const skillFile = path.join(skillsDir, entry, 'SKILL.md');
1118
+ if (!fs.existsSync(skillFile)) continue;
1119
+ const original = fs.readFileSync(skillFile, 'utf8');
1120
+ const updated = original.replace(/^context: fork\s*\n/m, '');
1121
+ if (updated !== original) {
1122
+ fs.writeFileSync(skillFile, updated);
1123
+ log.info(`Removed context: fork from skills/${entry}/SKILL.md`);
1124
+ }
1125
+ }
1126
+ } catch (e) {}
1127
+ }
1128
+
911
1129
  // Perform update (preserves user-created files, updates .5/ data directory)
912
1130
  function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
913
1131
  log.header(`Updating from ${versionInfo.installed || 'legacy'} to ${versionInfo.available}`);
@@ -923,6 +1141,22 @@ function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
923
1141
  // Merge settings (deep merge preserves user customizations)
924
1142
  mergeSettings(targetPath, sourcePath);
925
1143
 
1144
+ // Rename create-* skill dirs to bare pattern names (create-dto → dto)
1145
+ renameCreateSkills(targetPath);
1146
+
1147
+ // Strip `context: fork` from generated skills — caused infinite loops
1148
+ removeContextForkFromSkills(targetPath);
1149
+
1150
+ // Flag v1 → v2 major upgrade so statusline can prompt for reconfigure
1151
+ const prevMajor = versionInfo.installed ? parseInt(versionInfo.installed.split('.')[0], 10) : 0;
1152
+ const newMajor = versionInfo.available ? parseInt(versionInfo.available.split('.')[0], 10) : 0;
1153
+ if (!isNaN(prevMajor) && !isNaN(newMajor) && prevMajor < newMajor) {
1154
+ try {
1155
+ if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true });
1156
+ fs.writeFileSync(path.join(dataDir, '.migration-v' + newMajor), '1');
1157
+ } catch (e) {}
1158
+ }
1159
+
926
1160
  // Update version.json (per-runtime, preserving other runtime's state)
927
1161
  writeVersionJson(dataDir, isGlobal, versionInfo.available);
928
1162
  ensureDotFiveGitignore(dataDir);
@@ -944,40 +1178,41 @@ function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
944
1178
 
945
1179
  // Generate instructions.md for Codex (replaces hooks + settings.json)
946
1180
  function generateCodexInstructions(targetPath) {
947
- const content = `# 5-Phase Workflow — Codex Instructions
1181
+ const content = `# dev-workflow — Codex Instructions
948
1182
 
949
- This file is managed by the 5-Phase Workflow installer. It provides Codex with
1183
+ This file is managed by the dev-workflow installer. It provides Codex with
950
1184
  the context it needs to run the workflow skills correctly.
951
1185
 
952
1186
  ## Workflow Overview
953
1187
 
954
- The 5-Phase Workflow provides structured feature development:
1188
+ The workflow provides structured feature development:
955
1189
 
956
- 1. **Plan Feature** (\`$5-plan-feature\`) — Requirements gathering & feature spec
957
- 2. **Plan Implementation** (\`$5-plan-implementation\`) — Technical planning
958
- 3. **Implement Feature** (\`$5-implement-feature\`) — Orchestrated implementation
959
- 4. **Verify Implementation** (\`$5-verify-implementation\`) — Build & test verification
960
- 5. **Review Code** (\`$5-review-code\`) — Code review
1190
+ 1. **Plan** (\`$5-plan\`) — Requirements, discovery, and unified plan
1191
+ 2. **Implement** (\`$5-implement\`) — Orchestrated implementation with inline verification
1192
+ 3. **Review** (\`$5-review\`) — Code review
961
1193
 
962
1194
  ## Data Directory
963
1195
 
964
1196
  All workflow state lives in \`.5/\` at the project root:
965
1197
  - \`.5/config.json\` — Project configuration
966
- - \`.5/features/{name}/feature.md\` — Feature specifications
967
- - \`.5/features/{name}/plan.md\` — Implementation plans
1198
+ - \`.5/features/{name}/plan.md\` — Unified plan
968
1199
  - \`.5/features/{name}/state.json\` — Implementation state
969
1200
 
970
1201
  ## Guard Rules
971
1202
 
972
- During planning phases (plan-feature, plan-implementation):
1203
+ During the planning phase ($5-plan):
973
1204
  - Do NOT write files outside \`.5/\`
974
- - Do NOT write source code — only specifications and plans
1205
+ - Do NOT write source code — only the unified plan and scan cache
975
1206
  - The \`.5/.planning-active\` marker indicates planning is in progress
976
1207
 
977
1208
  ## Configuration
978
1209
 
979
1210
  Run \`$5-configure\` after installation to set up your project.
980
1211
 
1212
+ ## Codex Token Budget
1213
+
1214
+ Workflow skills use \`gpt-5.4-mini\` with low reasoning for exploration, orchestration, and simple executors by default. They escalate to \`gpt-5.4\` with medium reasoning only for complex logic, security-sensitive work, data migrations, public API changes, final verification that needs logic review, or retries after a cheaper attempt fails.
1215
+
981
1216
  ## Templates & References
982
1217
 
983
1218
  Templates are in \`.codex/templates/\` and references in \`.codex/references/\`.
@@ -1038,6 +1273,28 @@ function installCodexSkills(targetPath, sourcePath) {
1038
1273
  log.success('Installed utility skills');
1039
1274
  }
1040
1275
 
1276
+ // Install workflow agents for Codex skills that reference .codex/agents/
1277
+ function installCodexAgents(targetPath, sourcePath) {
1278
+ const managed = getWorkflowManagedFiles();
1279
+ const agentsSrc = path.join(sourcePath, 'agents');
1280
+ const agentsDest = path.join(targetPath, 'agents');
1281
+
1282
+ if (!fs.existsSync(agentsSrc) || managed.agents.length === 0) return;
1283
+
1284
+ if (!fs.existsSync(agentsDest)) {
1285
+ fs.mkdirSync(agentsDest, { recursive: true });
1286
+ }
1287
+
1288
+ for (const agent of managed.agents) {
1289
+ const src = path.join(agentsSrc, agent);
1290
+ const dest = path.join(agentsDest, agent);
1291
+ if (fs.existsSync(src)) {
1292
+ fs.copyFileSync(src, dest);
1293
+ }
1294
+ }
1295
+ log.success('Installed agents/');
1296
+ }
1297
+
1041
1298
  // Codex fresh installation
1042
1299
  function performCodexFreshInstall(targetPath, sourcePath, isGlobal) {
1043
1300
  if (!fs.existsSync(targetPath)) {
@@ -1047,6 +1304,7 @@ function performCodexFreshInstall(targetPath, sourcePath, isGlobal) {
1047
1304
 
1048
1305
  // Install commands as Codex skills
1049
1306
  installCodexSkills(targetPath, sourcePath);
1307
+ installCodexAgents(targetPath, sourcePath);
1050
1308
 
1051
1309
  // Copy templates and references as-is (just path conversion)
1052
1310
  for (const dir of ['templates', 'references']) {
@@ -1058,6 +1316,10 @@ function performCodexFreshInstall(targetPath, sourcePath, isGlobal) {
1058
1316
  }
1059
1317
  }
1060
1318
 
1319
+ // Install helper binaries used by runtime commands
1320
+ copyWorkflowHelperBins(targetPath);
1321
+ log.success('Installed bin/ (workflow helper binaries)');
1322
+
1061
1323
  // Generate instructions.md (replaces hooks + settings.json)
1062
1324
  generateCodexInstructions(targetPath);
1063
1325
 
@@ -1103,6 +1365,7 @@ function codexSelectiveUpdate(targetPath, sourcePath) {
1103
1365
 
1104
1366
  // Re-install all skills
1105
1367
  installCodexSkills(targetPath, sourcePath);
1368
+ installCodexAgents(targetPath, sourcePath);
1106
1369
 
1107
1370
  // Update templates and references
1108
1371
  for (const dir of ['templates', 'references']) {
@@ -1115,6 +1378,10 @@ function codexSelectiveUpdate(targetPath, sourcePath) {
1115
1378
  }
1116
1379
  log.success('Updated templates and references');
1117
1380
 
1381
+ // Update helper binaries used by runtime commands
1382
+ copyWorkflowHelperBins(targetPath);
1383
+ log.success('Updated bin/ helper binaries');
1384
+
1118
1385
  // Regenerate instructions.md
1119
1386
  generateCodexInstructions(targetPath);
1120
1387
  }
@@ -1130,6 +1397,19 @@ function performCodexUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
1130
1397
  const dataDir = getDataPath(isGlobal);
1131
1398
  cleanupOrphanedFiles(targetPath, dataDir);
1132
1399
 
1400
+ // Rename create-* skill dirs to bare pattern names (create-dto → dto)
1401
+ renameCreateSkills(targetPath);
1402
+
1403
+ // Flag v1 → v2 major upgrade so skills can prompt for reconfigure
1404
+ const prevMajor = versionInfo.installed ? parseInt(versionInfo.installed.split('.')[0], 10) : 0;
1405
+ const newMajor = versionInfo.available ? parseInt(versionInfo.available.split('.')[0], 10) : 0;
1406
+ if (!isNaN(prevMajor) && !isNaN(newMajor) && prevMajor < newMajor) {
1407
+ try {
1408
+ if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true });
1409
+ fs.writeFileSync(path.join(dataDir, '.migration-v' + newMajor), '1');
1410
+ } catch (e) {}
1411
+ }
1412
+
1133
1413
  // Update version.json (per-runtime, preserving other runtime's state)
1134
1414
  writeVersionJson(dataDir, isGlobal, versionInfo.available);
1135
1415
  ensureDotFiveGitignore(dataDir);
@@ -1148,7 +1428,7 @@ function performCodexUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
1148
1428
  function codexUninstall() {
1149
1429
  const targetPath = getTargetPath(false);
1150
1430
 
1151
- log.header('5-Phase Workflow Uninstallation (Codex)');
1431
+ log.header('dev-workflow Uninstallation (Codex)');
1152
1432
  log.info(`Target: ${targetPath}`);
1153
1433
 
1154
1434
  if (!checkExistingInstallation(targetPath)) {
@@ -1176,6 +1456,13 @@ function codexUninstall() {
1176
1456
  }
1177
1457
  log.success('Removed utility skills (preserved user-created skills)');
1178
1458
 
1459
+ // Remove agents
1460
+ for (const agent of managed.agents) {
1461
+ const agentPath = path.join(targetPath, 'agents', agent);
1462
+ if (fs.existsSync(agentPath)) fs.unlinkSync(agentPath);
1463
+ }
1464
+ log.success('Removed workflow agents');
1465
+
1179
1466
  // Remove templates
1180
1467
  for (const template of managed.templates) {
1181
1468
  const templatePath = path.join(targetPath, 'templates', template);
@@ -1192,6 +1479,19 @@ function codexUninstall() {
1192
1479
  log.success('Removed workflow references');
1193
1480
  }
1194
1481
 
1482
+ // Remove helper binaries
1483
+ if (managed.binHelpers) {
1484
+ for (const binHelper of managed.binHelpers) {
1485
+ const binPath = path.join(targetPath, 'bin', binHelper);
1486
+ if (fs.existsSync(binPath)) fs.unlinkSync(binPath);
1487
+ }
1488
+ const binDir = path.join(targetPath, 'bin');
1489
+ if (fs.existsSync(binDir) && fs.readdirSync(binDir).length === 0) {
1490
+ fs.rmdirSync(binDir);
1491
+ }
1492
+ log.success('Removed workflow helper binaries');
1493
+ }
1494
+
1195
1495
  // Remove instructions.md
1196
1496
  const instructionsPath = path.join(targetPath, 'instructions.md');
1197
1497
  if (fs.existsSync(instructionsPath)) {
@@ -1217,7 +1517,7 @@ function install(isGlobal, forceUpgrade = false) {
1217
1517
  const sourcePath = getSourcePath();
1218
1518
 
1219
1519
  const runtimeLabel = activeRuntime === 'codex' ? 'Codex' : 'Claude Code';
1220
- log.header(`5-Phase Workflow Installation (${runtimeLabel})`);
1520
+ log.header(`dev-workflow Installation (${runtimeLabel})`);
1221
1521
  log.info(`Target: ${targetPath}`);
1222
1522
  log.info(`Source: ${sourcePath}`);
1223
1523
 
@@ -1311,7 +1611,7 @@ function uninstall() {
1311
1611
 
1312
1612
  const targetPath = getTargetPath(false); // Always local for uninstall
1313
1613
 
1314
- log.header('5-Phase Workflow Uninstallation');
1614
+ log.header('dev-workflow Uninstallation');
1315
1615
  log.info(`Target: ${targetPath}`);
1316
1616
 
1317
1617
  if (!checkExistingInstallation(targetPath)) {
@@ -1389,6 +1689,21 @@ function uninstall() {
1389
1689
  log.success('Removed workflow references (preserved user-created references)');
1390
1690
  }
1391
1691
 
1692
+ // Remove only workflow-managed helper binaries
1693
+ if (managed.binHelpers) {
1694
+ for (const binHelper of managed.binHelpers) {
1695
+ const binPath = path.join(targetPath, 'bin', binHelper);
1696
+ if (fs.existsSync(binPath)) {
1697
+ fs.unlinkSync(binPath);
1698
+ }
1699
+ }
1700
+ const binDir = path.join(targetPath, 'bin');
1701
+ if (fs.existsSync(binDir) && fs.readdirSync(binDir).length === 0) {
1702
+ fs.rmdirSync(binDir);
1703
+ }
1704
+ log.success('Removed workflow helper binaries (preserved user-created binaries)');
1705
+ }
1706
+
1392
1707
  // Remove data directory (.5/)
1393
1708
  const dataDir = getDataPath(false);
1394
1709
  if (fs.existsSync(dataDir)) {
@@ -1457,7 +1772,7 @@ function main() {
1457
1772
  }
1458
1773
 
1459
1774
  if (anyUpdateAvailable) {
1460
- log.info('Run: npx 5-phase-workflow --upgrade');
1775
+ log.info('Run: npx foifi --upgrade');
1461
1776
  }
1462
1777
 
1463
1778
  activeRuntime = primaryRuntime;