5-phase-workflow 2.0.0 → 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.
package/README.md CHANGED
@@ -1,6 +1,29 @@
1
1
  # foifi
2
2
 
3
- A structured AI-assisted development workflow for Claude Code and Codex.
3
+ **foifi** is an opinionated AI development workflow layer that sits on top of Claude Code and Codex. It handles project setup, structured feature implementation, and code review — so you spend less time managing the AI and more time shipping.
4
+
5
+ ### What it does
6
+
7
+ **Project setup** — The `/5:configure` command detects your stack, generates a `CLAUDE.md` / `AGENTS.md` tailored to your project, writes a `.5/index/` knowledge base, and installs project-specific skills and rules. This gives every AI session the right context from the start rather than letting the model guess.
8
+
9
+ **Status line** — foifi installs an informative Claude Code status line that surfaces the active feature, current workflow phase, and relevant state directly in the terminal footer. No more digging through files to remember where you left off.
10
+
11
+ **Structured implementation workflow** — Instead of asking Claude or Codex to "just implement this," foifi enforces a three-phase loop:
12
+ 1. **Plan** (`/5:plan`) — writes a single human-reviewed `plan.md` with scope, acceptance criteria, component checklist, and decisions.
13
+ 2. **Implement** (`/5:implement`) — an orchestrator agent turns the plan into a typed execution graph (`state.json`), then delegates each component to a focused executor agent. A verification agent checks completeness, correctness, and test coverage at the end of every run.
14
+ 3. **Review** (`/5:review`) — triages changed files, produces structured findings, and feeds them into `/5:address-review-findings` for interactive fix decisions and PR replies.
15
+
16
+ This separation keeps planning readable, implementation mechanical, and review structured.
17
+
18
+ **Code review and findings** — `/5:review` triages changed files and produces structured `review-findings-*.md`. `/5:address-review-findings` presents each finding interactively, records `fix`/`wont_fix`/`wait` decisions, applies approved local fixes, handles PR comment replies, and keeps a decision log — all without losing context between sessions.
19
+
20
+ **Plan management helpers** — `/5:discuss-feature` refines an existing plan in conversation. `/5:split` breaks a large plan into smaller linked child plans. `/5:unlock` clears a stale planning lock. `/5:reconfigure` refreshes docs and skills when the project evolves.
21
+
22
+ **Codex support** — Every command has a `$5-*` Codex equivalent. Codex runs are token-budgeted: simple steps use a lighter model and low reasoning, complex or security-sensitive steps escalate automatically.
23
+
24
+ ### The name
25
+
26
+ "foifi" is Swiss German for *five*. The name comes from the project's original 5-phase workflow. That workflow has since been streamlined into the current 3-phase plan → implement → review loop, but the name stuck — and all commands still carry the `/5:` prefix.
4
27
 
5
28
  ## Install
6
29
 
package/bin/install.js CHANGED
@@ -569,6 +569,13 @@ During the planning phase ($5-plan):
569
569
  - Do NOT write to any file outside \`.5/\`
570
570
  - Do NOT write source code — only the unified plan and scan cache
571
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.
572
579
  </codex_skill_adapter>`;
573
580
  }
574
581
 
@@ -828,17 +835,20 @@ function cleanupOrphanedFiles(targetPath, dataDir) {
828
835
  }
829
836
  }
830
837
 
831
- // Ensure .5/.gitignore exists and contains .update-cache.json
838
+ // Ensure .5/.gitignore exists and contains transient runtime files
832
839
  function ensureDotFiveGitignore(dataDir) {
833
840
  const gitignorePath = path.join(dataDir, '.gitignore');
834
- const entry = '.update-cache.json';
841
+ const entries = ['.update-cache.json', '.migration-v*', '.reconfig-reminder'];
835
842
  if (fs.existsSync(gitignorePath)) {
836
- const content = fs.readFileSync(gitignorePath, 'utf8');
837
- if (!content.includes(entry)) {
838
- 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
+ }
839
848
  }
849
+ fs.writeFileSync(gitignorePath, content.trimEnd() + '\n');
840
850
  } else {
841
- fs.writeFileSync(gitignorePath, entry + '\n');
851
+ fs.writeFileSync(gitignorePath, entries.join('\n') + '\n');
842
852
  }
843
853
  }
844
854
 
@@ -1070,6 +1080,52 @@ function performFreshInstall(targetPath, sourcePath, isGlobal) {
1070
1080
  showCommandsHelp(isGlobal);
1071
1081
  }
1072
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
+
1073
1129
  // Perform update (preserves user-created files, updates .5/ data directory)
1074
1130
  function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
1075
1131
  log.header(`Updating from ${versionInfo.installed || 'legacy'} to ${versionInfo.available}`);
@@ -1085,6 +1141,22 @@ function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
1085
1141
  // Merge settings (deep merge preserves user customizations)
1086
1142
  mergeSettings(targetPath, sourcePath);
1087
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
+
1088
1160
  // Update version.json (per-runtime, preserving other runtime's state)
1089
1161
  writeVersionJson(dataDir, isGlobal, versionInfo.available);
1090
1162
  ensureDotFiveGitignore(dataDir);
@@ -1325,6 +1397,19 @@ function performCodexUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
1325
1397
  const dataDir = getDataPath(isGlobal);
1326
1398
  cleanupOrphanedFiles(targetPath, dataDir);
1327
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
+
1328
1413
  // Update version.json (per-runtime, preserving other runtime's state)
1329
1414
  writeVersionJson(dataDir, isGlobal, versionInfo.available);
1330
1415
  ensureDotFiveGitignore(dataDir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "5-phase-workflow",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "A dev-workflow for Claude Code and Codex",
5
5
  "bin": {
6
6
  "foifi": "bin/install.js"
@@ -177,9 +177,9 @@ After the skill completes, update `.5/version.json`:
177
177
 
178
178
  ### Step 8: Clean Up
179
179
 
180
- Remove the `.5/.reconfig-reminder` flag file if it exists:
180
+ Remove the `.5/.reconfig-reminder` and `.5/.migration-v2` flag files if they exist:
181
181
  ```bash
182
- rm -f .5/.reconfig-reminder
182
+ rm -f .5/.reconfig-reminder .5/.migration-v2
183
183
  ```
184
184
 
185
185
  ### Step 9: Report
@@ -113,6 +113,11 @@ process.stdin.on('end', () => {
113
113
  if (fs.existsSync(flagFile)) {
114
114
  parts.push(`\x1b[35m↻ /5:reconfigure\x1b[0m`);
115
115
  }
116
+
117
+ const migrationFlag = path.join(dir, '.5', '.migration-v2');
118
+ if (fs.existsSync(migrationFlag)) {
119
+ parts.push(`\x1b[31m⚠ v1→v2: /5:reconfigure\x1b[0m`);
120
+ }
116
121
  } catch (e) {}
117
122
 
118
123
  process.stdout.write(parts.join(' | '));
@@ -3,7 +3,6 @@ name: configure-docs-index
3
3
  description: Analyzes the codebase, creates project documentation, generates a rebuildable codebase index, and updates AGENTS.md. Used during /5:implement CONFIGURE.
4
4
  allowed-tools: Read, Write, Bash, Glob, Grep
5
5
  model: sonnet
6
- context: fork
7
6
  user-invocable: false
8
7
  ---
9
8
 
@@ -3,7 +3,6 @@ name: configure-skills
3
3
  description: Generates project-specific create-*/run-* skills and scoped rules from the current codebase. Used during /5:implement CONFIGURE.
4
4
  allowed-tools: Read, Write, Bash, Glob, Grep, create-skill, scaffold-skill
5
5
  model: sonnet
6
- context: fork
7
6
  user-invocable: false
8
7
  ---
9
8
 
@@ -77,24 +76,23 @@ For EACH pattern selected by the user in the unified plan:
77
76
 
78
77
  ### A2. Skill Template Structure
79
78
 
80
- For each skill, create `.claude/skills/create-{pattern}/SKILL.md`:
79
+ For each skill, create `.claude/skills/{pattern}/SKILL.md`:
81
80
 
82
81
  ```yaml
83
82
  ---
84
- name: create-{pattern}
85
- description: Creates a {Pattern} following project conventions at {location}.
83
+ name: {pattern}
84
+ description: Creates or updates a {Pattern} following project conventions at {location}.
86
85
  allowed-tools: Read, Write, Glob, Grep
87
86
  model: haiku
88
- context: fork
89
87
  user-invocable: true
90
88
  ---
91
89
  ```
92
90
 
93
91
  ```markdown
94
- # Create {Pattern}
92
+ # {Pattern}
95
93
 
96
- ## What This Skill Creates
97
- A {pattern} following this project's conventions.
94
+ ## What This Skill Does
95
+ Creates or updates a {pattern} following this project's conventions.
98
96
 
99
97
  ## Detected Conventions
100
98
  - **Location:** {detected-location}
@@ -103,14 +101,14 @@ A {pattern} following this project's conventions.
103
101
  - **Imports:** {detected-import-pattern}
104
102
 
105
103
  ## Template
106
- Based on {example-file}, new {patterns} should follow:
104
+ Based on {example-file}, {patterns} should follow:
107
105
 
108
106
  \`\`\`{language}
109
107
  {template-derived-from-analysis}
110
108
  \`\`\`
111
109
 
112
110
  ## Checklist
113
- - [ ] File created at correct location
111
+ - [ ] File at correct location
114
112
  - [ ] Naming convention followed
115
113
  - [ ] Required imports added
116
114
  - [ ] {pattern-specific-items}
@@ -118,7 +116,7 @@ Based on {example-file}, new {patterns} should follow:
118
116
 
119
117
  ### A3. Pattern to Skill Name Mapping
120
118
 
121
- **Rule:** Skill name is `create-{pattern}` (e.g., `controller` → `create-controller`, `component` → `create-component`, `dto` → `create-dto`). For compound patterns, use the short form: `model/entity` → `create-model`, `api-route` → `create-api-route`.
119
+ **Rule:** Skill name is `{pattern}` (e.g., `controller` → `controller`, `component` → `component`, `dto` → `dto`). For compound patterns, use the short form: `model/entity` → `model`, `api-route` → `api-route`.
122
120
 
123
121
  ---
124
122
 
@@ -153,7 +151,6 @@ name: run-{command}
153
151
  description: Runs {command} for this project using {source}.
154
152
  allowed-tools: Bash
155
153
  model: haiku
156
- context: fork
157
154
  user-invocable: true
158
155
  ---
159
156
  ```