5-phase-workflow 3.0.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -104
- package/bin/install.js +163 -178
- package/bin/sync-agents.js +59 -54
- package/docs/workflow-guide.md +35 -79
- package/package.json +1 -1
- package/src/agents/step-executor-agent.md +3 -3
- package/src/agents/step-orchestrator-agent.md +12 -12
- package/src/agents/verification-agent.md +5 -8
- package/src/codex-commands/plan.md +65 -0
- package/src/commands/5/address-review-findings.md +43 -52
- package/src/commands/5/analyze-feature.md +1 -1
- package/src/commands/5/configure.md +75 -179
- package/src/commands/5/eject.md +0 -1
- package/src/commands/5/implement.md +68 -74
- package/src/commands/5/lean-check.md +7 -5
- package/src/commands/5/reconfigure.md +48 -129
- package/src/commands/5/review.md +42 -14
- package/src/commands/5/synchronize-agents.md +1 -1
- package/src/commands/5/update.md +2 -2
- package/src/hooks/statusline.js +5 -3
- package/src/references/configure-tables.md +0 -33
- package/src/settings.json +0 -12
- package/src/skills/baseline-conventions/SKILL.md +37 -0
- package/src/skills/cognitive-load/SKILL.md +52 -0
- package/src/skills/configure-agents-md/SKILL.md +72 -0
- package/src/skills/configure-rules/SKILL.md +146 -0
- package/src/skills/documentation-style/SKILL.md +32 -0
- package/src/skills/fowler-code-smells/SKILL.md +25 -0
- package/src/skills/review-style/SKILL.md +142 -0
- package/src/templates/AGENTS.md +19 -27
- package/src/templates/workflow/REVIEW-FINDINGS.md +2 -9
- package/src/workflows/5-implement.js +53 -91
- package/docs/findings.md +0 -361
- package/docs/progress.md +0 -102
- package/src/commands/5/apply-review-findings.md +0 -66
- package/src/commands/5/commit.md +0 -43
- package/src/commands/5/plan.md +0 -190
- package/src/commands/5/reply-pr-comments.md +0 -48
- package/src/commands/5/split.md +0 -86
- package/src/commands/5/triage-pr-comments.md +0 -70
- package/src/hooks/config-guard.js +0 -30
- package/src/skills/configure-docs-index/SKILL.md +0 -243
- package/src/skills/configure-skills/SKILL.md +0 -311
- package/src/skills/generate-readme/EXAMPLES.md +0 -168
- package/src/skills/generate-readme/SKILL.md +0 -122
- package/src/skills/generate-readme/TEMPLATE.md +0 -141
- package/src/skills/use-index/SKILL.md +0 -49
- package/src/templates/ARCHITECTURE.md +0 -33
- package/src/templates/CONCERNS.md +0 -33
- package/src/templates/CONVENTIONS.md +0 -74
- package/src/templates/TESTING.md +0 -24
- package/src/templates/workflow/FIX-PLAN.md +0 -55
- package/src/templates/workflow/PLAN-COMPACT.md +0 -42
- package/src/templates/workflow/PLAN.md +0 -76
- package/src/templates/workflow/REVIEW-SUMMARY.md +0 -53
package/bin/install.js
CHANGED
|
@@ -323,27 +323,15 @@ function copyWorkflowHelperBins(targetPath) {
|
|
|
323
323
|
}
|
|
324
324
|
}
|
|
325
325
|
|
|
326
|
-
// Remove directory recursively
|
|
326
|
+
// Remove a directory recursively. fs.rmSync removes a symlink itself and never follows it,
|
|
327
|
+
// so a link planted in a checkout cannot redirect the deletion outside the project.
|
|
327
328
|
function removeDir(dir) {
|
|
328
|
-
|
|
329
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
330
|
-
|
|
331
|
-
for (const entry of entries) {
|
|
332
|
-
const fullPath = path.join(dir, entry.name);
|
|
333
|
-
|
|
334
|
-
if (entry.isDirectory()) {
|
|
335
|
-
removeDir(fullPath);
|
|
336
|
-
} else {
|
|
337
|
-
fs.unlinkSync(fullPath);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
fs.rmdirSync(dir);
|
|
342
|
-
}
|
|
329
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
343
330
|
}
|
|
344
331
|
|
|
345
|
-
// Files removed from the package
|
|
346
|
-
//
|
|
332
|
+
// Files removed from the package over time. Upgrades from installs with a manifest find
|
|
333
|
+
// removals by manifest diffing; this list covers installs that predate the manifest, and
|
|
334
|
+
// uninstall uses it to clear leftovers.
|
|
347
335
|
const LEGACY_REMOVED_FILES = [
|
|
348
336
|
'agents/feature-planner.md',
|
|
349
337
|
'agents/implementation-planner.md',
|
|
@@ -379,7 +367,35 @@ const LEGACY_REMOVED_FILES = [
|
|
|
379
367
|
'commands/5/discuss-feature.md',
|
|
380
368
|
'templates/workflow/STATE.json',
|
|
381
369
|
'skills/5-unlock',
|
|
382
|
-
'skills/5-discuss-feature'
|
|
370
|
+
'skills/5-discuss-feature',
|
|
371
|
+
// Plans live in .5/planning/; no codebase index, scan cache, generated docs, or split
|
|
372
|
+
'commands/5/split.md',
|
|
373
|
+
'skills/5-split',
|
|
374
|
+
'skills/use-index',
|
|
375
|
+
'skills/configure-docs-index',
|
|
376
|
+
'templates/ARCHITECTURE.md',
|
|
377
|
+
'templates/CONCERNS.md',
|
|
378
|
+
'templates/CONVENTIONS.md',
|
|
379
|
+
'templates/TESTING.md',
|
|
380
|
+
// Lean core: Claude Code covers commits, READMEs, PR replies, and per-pattern skills natively
|
|
381
|
+
'commands/5/commit.md',
|
|
382
|
+
// Claude Code plans in native plan mode under the AGENTS.md Planning rules; $5-plan stays for Codex
|
|
383
|
+
'commands/5/plan.md',
|
|
384
|
+
'commands/5/apply-review-findings.md',
|
|
385
|
+
'commands/5/triage-pr-comments.md',
|
|
386
|
+
'commands/5/reply-pr-comments.md',
|
|
387
|
+
'skills/5-commit',
|
|
388
|
+
'skills/5-apply-review-findings',
|
|
389
|
+
'skills/5-triage-pr-comments',
|
|
390
|
+
'skills/5-reply-pr-comments',
|
|
391
|
+
'skills/generate-readme',
|
|
392
|
+
'skills/configure-skills',
|
|
393
|
+
'hooks/config-guard.js',
|
|
394
|
+
'templates/workflow/FIX-PLAN.md',
|
|
395
|
+
// Plans have no fixed shape; plan mode and $5-plan decide it
|
|
396
|
+
'templates/workflow/PLAN.md',
|
|
397
|
+
'templates/workflow/PLAN-COMPACT.md',
|
|
398
|
+
'templates/workflow/REVIEW-SUMMARY.md'
|
|
383
399
|
];
|
|
384
400
|
|
|
385
401
|
// Get list of workflow-owned files/directories (not user-created)
|
|
@@ -388,6 +404,9 @@ function getWorkflowManagedFiles() {
|
|
|
388
404
|
// Commands: only the 5/ namespace
|
|
389
405
|
commands: ['5'],
|
|
390
406
|
|
|
407
|
+
// Codex-only commands, installed as skills/5-{name}: Claude Code covers them natively
|
|
408
|
+
codexCommands: ['plan.md'],
|
|
409
|
+
|
|
391
410
|
// Agents: separate agent files referenced by commands via agent: frontmatter
|
|
392
411
|
agents: [
|
|
393
412
|
'step-executor-agent.md',
|
|
@@ -402,10 +421,14 @@ function getWorkflowManagedFiles() {
|
|
|
402
421
|
|
|
403
422
|
// Skills: specific skill directories
|
|
404
423
|
skills: [
|
|
405
|
-
'configure-
|
|
406
|
-
'configure-
|
|
407
|
-
|
|
408
|
-
'
|
|
424
|
+
'configure-agents-md',
|
|
425
|
+
'configure-rules',
|
|
426
|
+
// Review styles: review-style runs one reviewer per style listed in its SKILL.md
|
|
427
|
+
'review-style',
|
|
428
|
+
'fowler-code-smells',
|
|
429
|
+
'cognitive-load',
|
|
430
|
+
'documentation-style',
|
|
431
|
+
'baseline-conventions'
|
|
409
432
|
],
|
|
410
433
|
|
|
411
434
|
// Hooks: specific hook files
|
|
@@ -413,7 +436,6 @@ function getWorkflowManagedFiles() {
|
|
|
413
436
|
'statusline.js',
|
|
414
437
|
'check-updates.js',
|
|
415
438
|
'check-reconfig.js',
|
|
416
|
-
'config-guard.js',
|
|
417
439
|
'dependency-guard.js'
|
|
418
440
|
],
|
|
419
441
|
|
|
@@ -429,18 +451,10 @@ function getWorkflowManagedFiles() {
|
|
|
429
451
|
|
|
430
452
|
// Templates: specific template files
|
|
431
453
|
templates: [
|
|
432
|
-
// Project
|
|
454
|
+
// Project instructions template
|
|
433
455
|
'AGENTS.md',
|
|
434
|
-
'ARCHITECTURE.md',
|
|
435
|
-
'CONCERNS.md',
|
|
436
|
-
'CONVENTIONS.md',
|
|
437
|
-
'TESTING.md',
|
|
438
456
|
// Workflow output templates
|
|
439
|
-
'workflow/
|
|
440
|
-
'workflow/PLAN-COMPACT.md',
|
|
441
|
-
'workflow/REVIEW-FINDINGS.md',
|
|
442
|
-
'workflow/REVIEW-SUMMARY.md',
|
|
443
|
-
'workflow/FIX-PLAN.md'
|
|
457
|
+
'workflow/REVIEW-FINDINGS.md'
|
|
444
458
|
]
|
|
445
459
|
};
|
|
446
460
|
}
|
|
@@ -479,7 +493,7 @@ function getFileManifest() {
|
|
|
479
493
|
manifest.push(`hooks/${hook}`);
|
|
480
494
|
}
|
|
481
495
|
|
|
482
|
-
// Templates are files (may include nested paths like workflow/
|
|
496
|
+
// Templates are files (may include nested paths like workflow/REVIEW-FINDINGS.md)
|
|
483
497
|
for (const template of managed.templates) {
|
|
484
498
|
manifest.push(`templates/${template}`);
|
|
485
499
|
}
|
|
@@ -539,14 +553,6 @@ function convertClaudeSetupCommandsToCodexNotes(content) {
|
|
|
539
553
|
.replace(
|
|
540
554
|
/- If user selects "Install now": execute the install command/g,
|
|
541
555
|
'- 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'
|
|
542
|
-
)
|
|
543
|
-
.replace(
|
|
544
|
-
/1\. "Install now \(recommended\)" — run `claude plugin install skill-creator@claude-plugins-official` via Bash/g,
|
|
545
|
-
'1. "Install now" — not supported automatically in Codex; install an equivalent skill authoring workflow outside this command, then rerun configuration'
|
|
546
|
-
)
|
|
547
|
-
.replace(
|
|
548
|
-
/- If user selects "Install now": execute the install command, then set `tools\.skillCreator\.available = true` in the config/g,
|
|
549
|
-
'- 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'
|
|
550
556
|
);
|
|
551
557
|
}
|
|
552
558
|
|
|
@@ -567,6 +573,7 @@ This skill was authored for Claude Code. Map these tool references:
|
|
|
567
573
|
| \`Agent(subagent_type="Explore")\` | \`spawn_agent(agent_type="explorer", model="gpt-5.4-mini", reasoning_effort="low", message="...")\` |
|
|
568
574
|
| \`Agent(prompt="...", model="haiku")\` | \`spawn_agent(model="gpt-5.4-mini", reasoning_effort="low", message="...")\` |
|
|
569
575
|
| \`Agent(prompt="...", model="sonnet")\` | \`spawn_agent(model="gpt-5.4", reasoning_effort="medium", message="...")\` |
|
|
576
|
+
| \`Agent(prompt="...", model="opus", effort="medium")\` | \`spawn_agent(model="gpt-5.4", reasoning_effort="high", message="...")\` |
|
|
570
577
|
| \`Agent(prompt="...")\` | \`spawn_agent(model="gpt-5.4-mini", reasoning_effort="low", message="...")\` unless the prompt explicitly requires complex reasoning |
|
|
571
578
|
| \`Read\` | \`read_file\` |
|
|
572
579
|
| \`Write\` | \`write_file\` |
|
|
@@ -574,9 +581,10 @@ This skill was authored for Claude Code. Map these tool references:
|
|
|
574
581
|
| \`Bash\` | \`shell\` |
|
|
575
582
|
| \`Glob\` | \`glob\` / \`list_directory\` |
|
|
576
583
|
| \`Grep\` | \`grep\` / \`search\` |
|
|
577
|
-
| \`TaskCreate/TaskUpdate\` | Track progress internally |
|
|
578
584
|
| \`Workflow\` | Not available — run the command's prose fallback loop instead |
|
|
579
585
|
| \`Skill(skill="code-review")\` | Not available — run the command's prose fallback loop instead |
|
|
586
|
+
| \`Skill(skill="security-review")\` | Not available — skip it; the prose review fallback of \`$5-review\` covers security |
|
|
587
|
+
| \`Skill(skill="review-style", args="...")\` | Read \`.codex/skills/review-style/SKILL.md\` and follow it with the same arguments |
|
|
580
588
|
| \`EnterPlanMode\` | Not available — run the command's prose fallback loop instead |
|
|
581
589
|
|
|
582
590
|
## Model Mapping (single source of truth)
|
|
@@ -586,28 +594,30 @@ When a skill, plan, or execution-graph component names a model, map it to Codex
|
|
|
586
594
|
|-------------|-------------|------------------|
|
|
587
595
|
| \`haiku\` (or unset) | \`gpt-5.4-mini\` | \`low\` |
|
|
588
596
|
| \`sonnet\` | \`gpt-5.4\` | \`medium\` |
|
|
597
|
+
| \`opus\` | \`gpt-5.4\` | \`high\` |
|
|
589
598
|
| Explore / explorer agent | \`gpt-5.4-mini\` (\`agent_type: explorer\`) | \`low\` |
|
|
590
599
|
|
|
591
600
|
This table is authoritative — skill bodies do not repeat per-call model mappings.
|
|
592
601
|
|
|
593
602
|
## Codex Token Budget
|
|
594
603
|
- Default to \`gpt-5.4-mini\` with \`reasoning_effort: low\` for exploration, orchestration, simple implementation, and mechanical file edits.
|
|
595
|
-
- Use \`gpt-5.4\` with \`reasoning_effort: medium\`
|
|
604
|
+
- Use \`gpt-5.4\` with \`reasoning_effort: medium\` for ordinary logic and final verification with meaningful logic review.
|
|
605
|
+
- Use \`gpt-5.4\` with \`reasoning_effort: high\` only for complex logic, cross-module behavior, security-sensitive changes, data migrations, public API contracts, or retries after failure.
|
|
596
606
|
- Use stronger models only when a previous cheaper attempt failed for reasoning reasons.
|
|
597
607
|
- 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.
|
|
598
608
|
|
|
599
609
|
## Guard Rules (Codex has no plan mode)
|
|
600
610
|
Claude Code enforces these at the harness level via native plan mode. Codex has no equivalent, so honour them yourself while running \`$5-plan\`, **until the user approves the plan**:
|
|
601
|
-
- Do NOT write
|
|
602
|
-
- Do NOT write source code
|
|
611
|
+
- Do NOT write any file — the plan is written only after approval
|
|
612
|
+
- Do NOT write source code
|
|
603
613
|
- Do NOT spawn implementation agents — only Explore/research agents
|
|
604
614
|
|
|
605
|
-
After approval, \`$5-plan\`
|
|
615
|
+
After approval, \`$5-plan\` saves the plan in \`.5/planning/\` and hands it to \`$5-implement\`.
|
|
606
616
|
|
|
607
617
|
## Update & Migration Notices (replaces statusline hooks)
|
|
608
618
|
At the very start of this skill, before doing anything else, read these two files if they exist:
|
|
609
619
|
- \`.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."
|
|
610
|
-
- \`.5/.migration-
|
|
620
|
+
- \`.5/.migration-v*\` — if a file such as \`.5/.migration-v4\` exists, tell the user: "You upgraded foifi to a new major version. Run \`$5-reconfigure\` to update your project configuration."
|
|
611
621
|
|
|
612
622
|
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.
|
|
613
623
|
</codex_skill_adapter>`;
|
|
@@ -645,20 +655,29 @@ function convertClaudeSkillToCodexSkill(content) {
|
|
|
645
655
|
return convertClaudeToCodexMarkdown(content);
|
|
646
656
|
}
|
|
647
657
|
|
|
658
|
+
// Command files that become Codex skills: the shared commands/5/ plus the Codex-only codex-commands/
|
|
659
|
+
// (Claude Code covers those natively, e.g. plan mode replaces /5:plan).
|
|
660
|
+
function getCodexCommandFiles(sourcePath) {
|
|
661
|
+
const toEntry = (dir, file) => ({ name: file.replace('.md', ''), file: path.join(dir, file) });
|
|
662
|
+
const sharedDir = path.join(sourcePath, 'commands', '5');
|
|
663
|
+
const shared = fs.existsSync(sharedDir)
|
|
664
|
+
? fs.readdirSync(sharedDir).filter(f => f.endsWith('.md')).map(f => toEntry(sharedDir, f))
|
|
665
|
+
: [];
|
|
666
|
+
const codexDir = path.join(sourcePath, 'codex-commands');
|
|
667
|
+
const codexOnly = getWorkflowManagedFiles().codexCommands
|
|
668
|
+
.filter(f => fs.existsSync(path.join(codexDir, f)))
|
|
669
|
+
.map(f => toEntry(codexDir, f));
|
|
670
|
+
return [...shared, ...codexOnly];
|
|
671
|
+
}
|
|
672
|
+
|
|
648
673
|
// Get file manifest for Codex installs (skills-based structure)
|
|
649
674
|
function getCodexFileManifest() {
|
|
650
675
|
const managed = getWorkflowManagedFiles();
|
|
651
676
|
const manifest = [];
|
|
652
677
|
|
|
653
|
-
// Commands become skills
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
if (fs.existsSync(commandsSrc)) {
|
|
657
|
-
const files = fs.readdirSync(commandsSrc).filter(f => f.endsWith('.md'));
|
|
658
|
-
for (const file of files) {
|
|
659
|
-
const name = file.replace('.md', '');
|
|
660
|
-
manifest.push(`skills/5-${name}`);
|
|
661
|
-
}
|
|
678
|
+
// Commands become skills: each command file becomes skills/5-{name}/SKILL.md
|
|
679
|
+
for (const { name } of getCodexCommandFiles(getSourcePath())) {
|
|
680
|
+
manifest.push(`skills/5-${name}`);
|
|
662
681
|
}
|
|
663
682
|
|
|
664
683
|
// Original skills also become Codex skills
|
|
@@ -689,9 +708,6 @@ function getCodexFileManifest() {
|
|
|
689
708
|
}
|
|
690
709
|
}
|
|
691
710
|
|
|
692
|
-
// Instructions file
|
|
693
|
-
manifest.push('instructions.md');
|
|
694
|
-
|
|
695
711
|
return manifest;
|
|
696
712
|
}
|
|
697
713
|
|
|
@@ -791,7 +807,7 @@ function selectiveUpdate(targetPath, sourcePath) {
|
|
|
791
807
|
const src = path.join(templatesSrc, template);
|
|
792
808
|
const dest = path.join(templatesDest, template);
|
|
793
809
|
if (fs.existsSync(src)) {
|
|
794
|
-
// Ensure parent directory exists for nested paths (e.g., workflow/
|
|
810
|
+
// Ensure parent directory exists for nested paths (e.g., workflow/REVIEW-FINDINGS.md)
|
|
795
811
|
const destDir = path.dirname(dest);
|
|
796
812
|
if (!fs.existsSync(destDir)) {
|
|
797
813
|
fs.mkdirSync(destDir, { recursive: true });
|
|
@@ -857,9 +873,12 @@ function cleanupOrphanedFiles(targetPath, dataDir) {
|
|
|
857
873
|
|
|
858
874
|
if (oldManifest) {
|
|
859
875
|
// Manifest exists: diff old vs current, delete orphans
|
|
876
|
+
const installRoot = path.resolve(targetPath) + path.sep;
|
|
860
877
|
for (const entry of oldManifest) {
|
|
861
878
|
if (!currentSet.has(entry)) {
|
|
862
|
-
const fullPath = path.
|
|
879
|
+
const fullPath = path.resolve(targetPath, entry);
|
|
880
|
+
// version.json may come from the checkout, so an entry must stay inside the install dir
|
|
881
|
+
if (!fullPath.startsWith(installRoot)) continue;
|
|
863
882
|
if (fs.existsSync(fullPath)) {
|
|
864
883
|
const stat = fs.statSync(fullPath);
|
|
865
884
|
if (stat.isDirectory()) {
|
|
@@ -1048,7 +1067,7 @@ function mergeSettings(targetPath, sourcePath) {
|
|
|
1048
1067
|
|
|
1049
1068
|
if (fs.existsSync(targetSettings)) {
|
|
1050
1069
|
const existingSettings = JSON.parse(fs.readFileSync(targetSettings, 'utf8'));
|
|
1051
|
-
const merged = deepMerge(
|
|
1070
|
+
const merged = deepMerge(existingSettings, newSettings);
|
|
1052
1071
|
fs.writeFileSync(targetSettings, JSON.stringify(merged, null, 2));
|
|
1053
1072
|
log.info('Merged settings with existing configuration');
|
|
1054
1073
|
} else {
|
|
@@ -1065,37 +1084,35 @@ function checkExistingInstallation(targetPath) {
|
|
|
1065
1084
|
const legacyMarkerFile = path.join(targetPath, 'skills', '5-plan-feature', 'SKILL.md');
|
|
1066
1085
|
return fs.existsSync(markerFile) || fs.existsSync(legacyMarkerFile);
|
|
1067
1086
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1087
|
+
// plan.md and plan-feature.md mark installs from before plan mode replaced /5:plan
|
|
1088
|
+
return ['implement.md', 'plan.md', 'plan-feature.md']
|
|
1089
|
+
.some(file => fs.existsSync(path.join(targetPath, 'commands', '5', file)));
|
|
1071
1090
|
}
|
|
1072
1091
|
|
|
1073
1092
|
// Helper to show commands
|
|
1074
1093
|
function showCommandsHelp(isGlobal) {
|
|
1075
1094
|
if (activeRuntime === 'codex') {
|
|
1076
1095
|
log.info('Available skills (invoke with $ prefix in Codex):');
|
|
1077
|
-
log.info(' $5-plan - Create or refine a
|
|
1078
|
-
log.info(' $5-split - Split plan into smaller plans');
|
|
1096
|
+
log.info(' $5-plan - Create or refine a plan');
|
|
1079
1097
|
log.info(' $5-implement - Execute implementation + verification');
|
|
1080
|
-
log.info(' $5-review - Code review');
|
|
1098
|
+
log.info(' $5-review - Code and standards review');
|
|
1081
1099
|
log.info(' $5-lean-check - Check a diff for scope drift/over-engineering');
|
|
1082
|
-
log.info(' $5-
|
|
1083
|
-
log.info(' $5-
|
|
1100
|
+
log.info(' $5-address-review-findings - Decide on review findings, apply the fixes');
|
|
1101
|
+
log.info(' $5-analyze-feature - Document a feature with mermaid diagrams');
|
|
1084
1102
|
log.info(' $5-configure - Interactive project setup');
|
|
1085
|
-
log.info(' $5-reconfigure - Refresh
|
|
1103
|
+
log.info(' $5-reconfigure - Refresh the AGENTS.md block and rules (no Q&A)');
|
|
1086
1104
|
log.info(' $5-eject - Eject from update mechanism');
|
|
1087
1105
|
log.info(' $5-synchronize-agents - Sync user content between runtimes');
|
|
1088
1106
|
} else {
|
|
1107
|
+
log.info('Plan in native plan mode (shift+tab); AGENTS.md shapes the plan.');
|
|
1089
1108
|
log.info('Available commands:');
|
|
1090
|
-
log.info(' /5:plan - Create or refine a unified plan');
|
|
1091
|
-
log.info(' /5:split - Split plan into smaller plans');
|
|
1092
1109
|
log.info(' /5:implement - Execute implementation + verification');
|
|
1093
|
-
log.info(' /5:review - Code review');
|
|
1110
|
+
log.info(' /5:review - Code and standards review');
|
|
1094
1111
|
log.info(' /5:lean-check - Check a diff for scope drift/over-engineering');
|
|
1095
|
-
log.info(' /5:
|
|
1096
|
-
log.info(' /5:
|
|
1112
|
+
log.info(' /5:address-review-findings - Decide on review findings, apply the fixes');
|
|
1113
|
+
log.info(' /5:analyze-feature - Document a feature with mermaid diagrams');
|
|
1097
1114
|
log.info(' /5:configure - Interactive project setup');
|
|
1098
|
-
log.info(' /5:reconfigure - Refresh
|
|
1115
|
+
log.info(' /5:reconfigure - Refresh the AGENTS.md block and rules (no Q&A)');
|
|
1099
1116
|
log.info(' /5:eject - Eject from update mechanism');
|
|
1100
1117
|
log.info(' /5:synchronize-agents - Sync user content between runtimes');
|
|
1101
1118
|
}
|
|
@@ -1141,10 +1158,8 @@ function performFreshInstall(targetPath, sourcePath, isGlobal) {
|
|
|
1141
1158
|
log.info('This will:');
|
|
1142
1159
|
log.info(' • Detect your project type and build commands');
|
|
1143
1160
|
log.info(' • Set up ticket tracking conventions');
|
|
1144
|
-
log.info(' •
|
|
1145
|
-
log.info(' • Create
|
|
1146
|
-
log.info('');
|
|
1147
|
-
log.info('Tip: Configure will offer to install helpful plugins like skill-creator');
|
|
1161
|
+
log.info(' • Add the workflow rules to AGENTS.md as one marked block, linking your repository standards');
|
|
1162
|
+
log.info(' • Create file-scoped rules from your conventions');
|
|
1148
1163
|
|
|
1149
1164
|
showCommandsHelp(isGlobal);
|
|
1150
1165
|
}
|
|
@@ -1195,24 +1210,31 @@ function removeContextForkFromSkills(targetPath) {
|
|
|
1195
1210
|
} catch (e) {}
|
|
1196
1211
|
}
|
|
1197
1212
|
|
|
1198
|
-
// Remove
|
|
1199
|
-
//
|
|
1200
|
-
//
|
|
1201
|
-
|
|
1213
|
+
// Remove retired PreToolUse hook entries from an existing settings.json. Native plan mode
|
|
1214
|
+
// replaced plan-guard; config-guard blocked every Agent call in sessions outside the workflow.
|
|
1215
|
+
// Claude Code only — Codex never had a settings.json.
|
|
1216
|
+
const RETIRED_HOOKS = ['plan-guard.js', 'config-guard.js'];
|
|
1217
|
+
|
|
1218
|
+
function removeRetiredHooks(targetPath) {
|
|
1202
1219
|
const settingsFile = path.join(targetPath, 'settings.json');
|
|
1203
1220
|
if (!fs.existsSync(settingsFile)) return;
|
|
1204
1221
|
try {
|
|
1205
1222
|
const settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
|
|
1206
1223
|
const pre = settings.hooks && settings.hooks.PreToolUse;
|
|
1207
1224
|
if (!Array.isArray(pre)) return;
|
|
1208
|
-
const
|
|
1209
|
-
|
|
1210
|
-
|
|
1225
|
+
const isRetired = h => typeof h.command === 'string' && RETIRED_HOOKS.some(hook => h.command.includes(hook));
|
|
1226
|
+
if (!pre.some(entry => (entry.hooks || []).some(isRetired))) return;
|
|
1227
|
+
// Drop only the retired hooks; an entry survives while it still holds the user's own hooks
|
|
1228
|
+
const kept = pre
|
|
1229
|
+
.map(entry => (entry.hooks || []).some(isRetired)
|
|
1230
|
+
? { ...entry, hooks: entry.hooks.filter(h => !isRetired(h)) }
|
|
1231
|
+
: entry)
|
|
1232
|
+
.filter(entry => !Array.isArray(entry.hooks) || entry.hooks.length);
|
|
1211
1233
|
if (kept.length) settings.hooks.PreToolUse = kept;
|
|
1212
1234
|
else delete settings.hooks.PreToolUse;
|
|
1213
1235
|
if (settings.hooks && !Object.keys(settings.hooks).length) delete settings.hooks;
|
|
1214
1236
|
fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2));
|
|
1215
|
-
log.info('Removed
|
|
1237
|
+
log.info('Removed retired guard hooks from settings.json');
|
|
1216
1238
|
} catch (e) {}
|
|
1217
1239
|
}
|
|
1218
1240
|
|
|
@@ -1227,6 +1249,25 @@ function removePlanningActiveMarker(dataDir) {
|
|
|
1227
1249
|
} catch (e) {}
|
|
1228
1250
|
}
|
|
1229
1251
|
|
|
1252
|
+
// Move .5/features/{name}/plan.md to .5/planning/{name}.md. Plans now live where native plan
|
|
1253
|
+
// mode saves them, and /5:implement finds them by their `feature` frontmatter. The .5/ data
|
|
1254
|
+
// is shared, so performUpdate() and performCodexUpdate() both run this.
|
|
1255
|
+
function movePlansToPlanningDir(dataDir) {
|
|
1256
|
+
const featuresDir = path.join(dataDir, 'features');
|
|
1257
|
+
if (!fs.existsSync(featuresDir)) return;
|
|
1258
|
+
const planningDir = path.join(dataDir, 'planning');
|
|
1259
|
+
try {
|
|
1260
|
+
for (const feature of fs.readdirSync(featuresDir)) {
|
|
1261
|
+
const planFile = path.join(featuresDir, feature, 'plan.md');
|
|
1262
|
+
const target = path.join(planningDir, `${feature}.md`);
|
|
1263
|
+
if (!fs.existsSync(planFile) || fs.existsSync(target)) continue;
|
|
1264
|
+
fs.mkdirSync(planningDir, { recursive: true });
|
|
1265
|
+
fs.renameSync(planFile, target);
|
|
1266
|
+
log.info(`Moved plan: features/${feature}/plan.md → planning/${feature}.md`);
|
|
1267
|
+
}
|
|
1268
|
+
} catch (e) {}
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1230
1271
|
// Perform update (preserves user-created files, updates .5/ data directory)
|
|
1231
1272
|
function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
|
|
1232
1273
|
log.header(`Updating from ${versionInfo.installed || 'legacy'} to ${versionInfo.available}`);
|
|
@@ -1248,10 +1289,13 @@ function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
|
|
|
1248
1289
|
// Strip `context: fork` from generated skills — caused infinite loops
|
|
1249
1290
|
removeContextForkFromSkills(targetPath);
|
|
1250
1291
|
|
|
1251
|
-
// Native plan mode replaces the plan-guard hook and its marker file
|
|
1252
|
-
|
|
1292
|
+
// Native plan mode replaces the plan-guard hook and its marker file; config-guard is retired
|
|
1293
|
+
removeRetiredHooks(targetPath);
|
|
1253
1294
|
removePlanningActiveMarker(dataDir);
|
|
1254
1295
|
|
|
1296
|
+
// Plans moved from .5/features/{name}/plan.md to .5/planning/{name}.md
|
|
1297
|
+
movePlansToPlanningDir(dataDir);
|
|
1298
|
+
|
|
1255
1299
|
// Flag v1 → v2 major upgrade so statusline can prompt for reconfigure
|
|
1256
1300
|
const prevMajor = versionInfo.installed ? parseInt(versionInfo.installed.split('.')[0], 10) : 0;
|
|
1257
1301
|
const newMajor = versionInfo.available ? parseInt(versionInfo.available.split('.')[0], 10) : 0;
|
|
@@ -1281,69 +1325,15 @@ function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
|
|
|
1281
1325
|
|
|
1282
1326
|
// ── Codex install/update/uninstall ──────────────────────────────────────────
|
|
1283
1327
|
|
|
1284
|
-
// Generate instructions.md for Codex (replaces hooks + settings.json)
|
|
1285
|
-
function generateCodexInstructions(targetPath) {
|
|
1286
|
-
const content = `# dev-workflow — Codex Instructions
|
|
1287
|
-
|
|
1288
|
-
This file is managed by the dev-workflow installer. It provides Codex with
|
|
1289
|
-
the context it needs to run the workflow skills correctly.
|
|
1290
|
-
|
|
1291
|
-
## Workflow Overview
|
|
1292
|
-
|
|
1293
|
-
The workflow provides structured feature development:
|
|
1294
|
-
|
|
1295
|
-
1. **Plan** (\`$5-plan\`) — Requirements, discovery, and unified plan
|
|
1296
|
-
2. **Implement** (\`$5-implement\`) — Orchestrated implementation with inline verification
|
|
1297
|
-
3. **Review** (\`$5-review\`) — Code review
|
|
1298
|
-
|
|
1299
|
-
## Data Directory
|
|
1300
|
-
|
|
1301
|
-
All workflow state lives in \`.5/\` at the project root:
|
|
1302
|
-
- \`.5/config.json\` — Project configuration
|
|
1303
|
-
- \`.5/features/{name}/plan.md\` — Unified plan
|
|
1304
|
-
- \`.5/features/{name}/state.json\` — Implementation resume state
|
|
1305
|
-
|
|
1306
|
-
## Guard Rules
|
|
1307
|
-
|
|
1308
|
-
During the planning phase ($5-plan), until the user approves the plan:
|
|
1309
|
-
- Do NOT write files outside \`.5/\`
|
|
1310
|
-
- Do NOT write source code — only the unified plan and scan cache
|
|
1311
|
-
|
|
1312
|
-
## Scope Discipline (replaces the dependency-guard Stop hook)
|
|
1313
|
-
|
|
1314
|
-
Before you report any task as done — inside or outside the workflow skills — check the uncommitted diff of dependency manifests (\`package.json\`, \`requirements*.txt\`, \`pyproject.toml\`, \`go.mod\`, \`Cargo.toml\`, \`Gemfile\`, \`composer.json\`, \`pom.xml\`, \`build.gradle\`, \`*.csproj\`). For every added dependency: keep it and name it in your reply if the user asked for it; otherwise remove it with the package manager and use existing code, the standard library, a native platform feature, or an installed dependency instead. For a deeper check, run \`$5-lean-check\`.
|
|
1315
|
-
|
|
1316
|
-
## Configuration
|
|
1317
|
-
|
|
1318
|
-
Run \`$5-configure\` after installation to set up your project.
|
|
1319
|
-
|
|
1320
|
-
## Codex Token Budget
|
|
1321
|
-
|
|
1322
|
-
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.
|
|
1323
|
-
|
|
1324
|
-
## Templates & References
|
|
1325
|
-
|
|
1326
|
-
Templates are in \`.codex/templates/\` and references in \`.codex/references/\`.
|
|
1327
|
-
Skills reference these paths for output formatting.
|
|
1328
|
-
`;
|
|
1329
|
-
|
|
1330
|
-
fs.writeFileSync(path.join(targetPath, 'instructions.md'), content);
|
|
1331
|
-
log.success('Generated instructions.md');
|
|
1332
|
-
}
|
|
1333
|
-
|
|
1334
1328
|
// Install commands as Codex skills
|
|
1335
1329
|
function installCodexSkills(targetPath, sourcePath) {
|
|
1336
|
-
const commandsSrc = path.join(sourcePath, 'commands', '5');
|
|
1337
1330
|
const skillsDest = path.join(targetPath, 'skills');
|
|
1331
|
+
const files = getCodexCommandFiles(sourcePath);
|
|
1332
|
+
if (files.length === 0) return;
|
|
1338
1333
|
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
const files = fs.readdirSync(commandsSrc).filter(f => f.endsWith('.md'));
|
|
1342
|
-
|
|
1343
|
-
for (const file of files) {
|
|
1344
|
-
const name = file.replace('.md', '');
|
|
1334
|
+
for (const { name, file } of files) {
|
|
1345
1335
|
const skillName = `5-${name}`;
|
|
1346
|
-
const content = fs.readFileSync(
|
|
1336
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
1347
1337
|
const converted = convertClaudeCommandToCodexSkill(content, skillName);
|
|
1348
1338
|
|
|
1349
1339
|
const skillDir = path.join(skillsDest, skillName);
|
|
@@ -1354,7 +1344,7 @@ function installCodexSkills(targetPath, sourcePath) {
|
|
|
1354
1344
|
}
|
|
1355
1345
|
log.success(`Installed ${files.length} workflow skills`);
|
|
1356
1346
|
|
|
1357
|
-
// Also convert and install
|
|
1347
|
+
// Also convert and install the workflow's own skills (configure-*, review styles)
|
|
1358
1348
|
const managed = getWorkflowManagedFiles();
|
|
1359
1349
|
for (const skill of managed.skills) {
|
|
1360
1350
|
const skillSrc = path.join(sourcePath, 'skills', skill);
|
|
@@ -1428,9 +1418,6 @@ function performCodexFreshInstall(targetPath, sourcePath, isGlobal) {
|
|
|
1428
1418
|
copyWorkflowHelperBins(targetPath);
|
|
1429
1419
|
log.success('Installed bin/ (workflow helper binaries)');
|
|
1430
1420
|
|
|
1431
|
-
// Generate instructions.md (replaces hooks + settings.json)
|
|
1432
|
-
generateCodexInstructions(targetPath);
|
|
1433
|
-
|
|
1434
1421
|
// Initialize version tracking (shared .5/ directory)
|
|
1435
1422
|
initializeVersionJson(isGlobal);
|
|
1436
1423
|
|
|
@@ -1442,8 +1429,7 @@ function performCodexFreshInstall(targetPath, sourcePath, isGlobal) {
|
|
|
1442
1429
|
log.info('This will:');
|
|
1443
1430
|
log.info(' • Detect your project type and build commands');
|
|
1444
1431
|
log.info(' • Set up ticket tracking conventions');
|
|
1445
|
-
log.info(' •
|
|
1446
|
-
log.info(' • Create project-specific skills');
|
|
1432
|
+
log.info(' • Add the workflow rules to AGENTS.md as one marked block, linking your repository standards');
|
|
1447
1433
|
|
|
1448
1434
|
showCommandsHelp(isGlobal);
|
|
1449
1435
|
}
|
|
@@ -1455,14 +1441,9 @@ function codexSelectiveUpdate(targetPath, sourcePath) {
|
|
|
1455
1441
|
const skillsDest = path.join(targetPath, 'skills');
|
|
1456
1442
|
|
|
1457
1443
|
// Remove workflow command skills (5-*)
|
|
1458
|
-
const
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
for (const file of files) {
|
|
1462
|
-
const name = file.replace('.md', '');
|
|
1463
|
-
const skillDir = path.join(skillsDest, `5-${name}`);
|
|
1464
|
-
if (fs.existsSync(skillDir)) removeDir(skillDir);
|
|
1465
|
-
}
|
|
1444
|
+
for (const { name } of getCodexCommandFiles(sourcePath)) {
|
|
1445
|
+
const skillDir = path.join(skillsDest, `5-${name}`);
|
|
1446
|
+
if (fs.existsSync(skillDir)) removeDir(skillDir);
|
|
1466
1447
|
}
|
|
1467
1448
|
|
|
1468
1449
|
// Remove utility skills
|
|
@@ -1489,9 +1470,6 @@ function codexSelectiveUpdate(targetPath, sourcePath) {
|
|
|
1489
1470
|
// Update helper binaries used by runtime commands
|
|
1490
1471
|
copyWorkflowHelperBins(targetPath);
|
|
1491
1472
|
log.success('Updated bin/ helper binaries');
|
|
1492
|
-
|
|
1493
|
-
// Regenerate instructions.md
|
|
1494
|
-
generateCodexInstructions(targetPath);
|
|
1495
1473
|
}
|
|
1496
1474
|
|
|
1497
1475
|
// Codex update
|
|
@@ -1511,6 +1489,9 @@ function performCodexUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
|
|
|
1511
1489
|
// The plan-guard marker is shared .5/ state; Codex has no settings.json hook to remove
|
|
1512
1490
|
removePlanningActiveMarker(dataDir);
|
|
1513
1491
|
|
|
1492
|
+
// Plans moved from .5/features/{name}/plan.md to .5/planning/{name}.md
|
|
1493
|
+
movePlansToPlanningDir(dataDir);
|
|
1494
|
+
|
|
1514
1495
|
// Flag v1 → v2 major upgrade so skills can prompt for reconfigure
|
|
1515
1496
|
const prevMajor = versionInfo.installed ? parseInt(versionInfo.installed.split('.')[0], 10) : 0;
|
|
1516
1497
|
const newMajor = versionInfo.available ? parseInt(versionInfo.available.split('.')[0], 10) : 0;
|
|
@@ -1547,17 +1528,21 @@ function codexUninstall() {
|
|
|
1547
1528
|
return;
|
|
1548
1529
|
}
|
|
1549
1530
|
|
|
1531
|
+
// Remove workflow files retired from the package, which the current source no longer lists
|
|
1532
|
+
for (const entry of LEGACY_REMOVED_FILES) {
|
|
1533
|
+
const fullPath = path.join(targetPath, entry);
|
|
1534
|
+
if (!fs.existsSync(fullPath)) continue;
|
|
1535
|
+
if (fs.statSync(fullPath).isDirectory()) removeDir(fullPath);
|
|
1536
|
+
else fs.unlinkSync(fullPath);
|
|
1537
|
+
log.info(`Removed legacy orphan: ${entry}`);
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1550
1540
|
// Remove workflow command skills (5-*)
|
|
1551
|
-
const
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
for (const file of files) {
|
|
1555
|
-
const name = file.replace('.md', '');
|
|
1556
|
-
const skillDir = path.join(targetPath, 'skills', `5-${name}`);
|
|
1557
|
-
if (fs.existsSync(skillDir)) removeDir(skillDir);
|
|
1558
|
-
}
|
|
1559
|
-
log.success('Removed workflow skills');
|
|
1541
|
+
for (const { name } of getCodexCommandFiles(getSourcePath())) {
|
|
1542
|
+
const skillDir = path.join(targetPath, 'skills', `5-${name}`);
|
|
1543
|
+
if (fs.existsSync(skillDir)) removeDir(skillDir);
|
|
1560
1544
|
}
|
|
1545
|
+
log.success('Removed workflow skills');
|
|
1561
1546
|
|
|
1562
1547
|
// Remove utility skills
|
|
1563
1548
|
const managed = getWorkflowManagedFiles();
|
|
@@ -1603,7 +1588,7 @@ function codexUninstall() {
|
|
|
1603
1588
|
log.success('Removed workflow helper binaries');
|
|
1604
1589
|
}
|
|
1605
1590
|
|
|
1606
|
-
// Remove instructions.md
|
|
1591
|
+
// Remove instructions.md left by earlier versions (Codex never read it; AGENTS.md carries the rules)
|
|
1607
1592
|
const instructionsPath = path.join(targetPath, 'instructions.md');
|
|
1608
1593
|
if (fs.existsSync(instructionsPath)) {
|
|
1609
1594
|
fs.unlinkSync(instructionsPath);
|