5-phase-workflow 3.1.0 → 3.1.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/bin/install.js CHANGED
@@ -1254,8 +1254,9 @@ function removePlanningActiveMarker(dataDir) {
1254
1254
  // is shared, so performUpdate() and performCodexUpdate() both run this.
1255
1255
  function movePlansToPlanningDir(dataDir) {
1256
1256
  const featuresDir = path.join(dataDir, 'features');
1257
- if (!fs.existsSync(featuresDir)) return;
1257
+ if (!fs.existsSync(featuresDir)) return 0;
1258
1258
  const planningDir = path.join(dataDir, 'planning');
1259
+ let moved = 0;
1259
1260
  try {
1260
1261
  for (const feature of fs.readdirSync(featuresDir)) {
1261
1262
  const planFile = path.join(featuresDir, feature, 'plan.md');
@@ -1263,9 +1264,53 @@ function movePlansToPlanningDir(dataDir) {
1263
1264
  if (!fs.existsSync(planFile) || fs.existsSync(target)) continue;
1264
1265
  fs.mkdirSync(planningDir, { recursive: true });
1265
1266
  fs.renameSync(planFile, target);
1267
+ moved++;
1266
1268
  log.info(`Moved plan: features/${feature}/plan.md → planning/${feature}.md`);
1267
1269
  }
1268
1270
  } catch (e) {}
1271
+ return moved;
1272
+ }
1273
+
1274
+ // Before .5/planning/ existed, plans lived in .5/features/, so a project that git-ignored
1275
+ // .5/features/ also ignored its plans. Carry that choice over to .5/planning/, but only for
1276
+ // projects that come from that layout: plans moved by this upgrade, or an install that was
1277
+ // upgraded into 3.1.0 (whose migration moved them without this). A project configured on 3.1
1278
+ // may have chosen "Only .5/features/" on purpose; /5:configure now marks that with
1279
+ // `!.5/planning/`, and any .5/planning rule or plan tracked in git (checked before the move) is left alone.
1280
+ // Shared .5/ data, so both update paths run this.
1281
+ // True when git tracks any plan, in the old or the new location. Call it before plans move:
1282
+ // afterwards the index still lists them only under .5/features/.
1283
+ function hasTrackedPlans(dataDir) {
1284
+ try {
1285
+ return require('child_process')
1286
+ .execFileSync('git', ['ls-files', '--', '.5/features/*/plan.md', '.5/planning'],
1287
+ { cwd: path.dirname(dataDir), encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] })
1288
+ .trim() !== '';
1289
+ } catch (e) {
1290
+ return false; // not a git checkout: nothing is tracked
1291
+ }
1292
+ }
1293
+
1294
+ function ignorePlanningLikeFeatures(dataDir, movedPlans, previousVersion, plansTracked) {
1295
+ const projectRoot = path.dirname(dataDir);
1296
+ const gitignorePath = path.join(projectRoot, '.gitignore');
1297
+ if (!fs.existsSync(gitignorePath)) return;
1298
+ try {
1299
+ if (!movedPlans) {
1300
+ if (previousVersion !== '3.1.0') return;
1301
+ // A fresh 3.1.0 install has installedAt === lastUpdated; an upgraded one does not
1302
+ const versionData = JSON.parse(fs.readFileSync(path.join(dataDir, 'version.json'), 'utf8'));
1303
+ if (!versionData.installedAt || versionData.installedAt === versionData.lastUpdated) return;
1304
+ }
1305
+ if (plansTracked) return;
1306
+ const content = fs.readFileSync(gitignorePath, 'utf8');
1307
+ const rules = content.split('\n').map(l => l.trim()).filter(l => l && !l.startsWith('#'));
1308
+ const ignoresFeatures = rules.some(l => /^\/?\.5\/features\/?(\*\*?)?$/.test(l));
1309
+ const hasPlanningRule = rules.some(l => /^!?\/?\.5\/planning\/?(\*\*?)?$/.test(l));
1310
+ if (!ignoresFeatures || hasPlanningRule) return;
1311
+ fs.writeFileSync(gitignorePath, content.trimEnd() + '\n.5/planning/\n');
1312
+ log.info('Added .5/planning/ to .gitignore (plans were ignored under .5/features/)');
1313
+ } catch (e) {}
1269
1314
  }
1270
1315
 
1271
1316
  // Perform update (preserves user-created files, updates .5/ data directory)
@@ -1294,7 +1339,8 @@ function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
1294
1339
  removePlanningActiveMarker(dataDir);
1295
1340
 
1296
1341
  // Plans moved from .5/features/{name}/plan.md to .5/planning/{name}.md
1297
- movePlansToPlanningDir(dataDir);
1342
+ const plansTracked = hasTrackedPlans(dataDir);
1343
+ ignorePlanningLikeFeatures(dataDir, movePlansToPlanningDir(dataDir), versionInfo.installed, plansTracked);
1298
1344
 
1299
1345
  // Flag v1 → v2 major upgrade so statusline can prompt for reconfigure
1300
1346
  const prevMajor = versionInfo.installed ? parseInt(versionInfo.installed.split('.')[0], 10) : 0;
@@ -1490,7 +1536,8 @@ function performCodexUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
1490
1536
  removePlanningActiveMarker(dataDir);
1491
1537
 
1492
1538
  // Plans moved from .5/features/{name}/plan.md to .5/planning/{name}.md
1493
- movePlansToPlanningDir(dataDir);
1539
+ const plansTracked = hasTrackedPlans(dataDir);
1540
+ ignorePlanningLikeFeatures(dataDir, movePlansToPlanningDir(dataDir), versionInfo.installed, plansTracked);
1494
1541
 
1495
1542
  // Flag v1 → v2 major upgrade so skills can prompt for reconfigure
1496
1543
  const prevMajor = versionInfo.installed ? parseInt(versionInfo.installed.split('.')[0], 10) : 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "5-phase-workflow",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "description": "A dev-workflow for Claude Code and Codex",
5
5
  "bin": {
6
6
  "foifi": "bin/install.js"
@@ -216,7 +216,8 @@ Native plan mode must save its plans in `.5/planning/`, where `/5:implement` fin
216
216
  For each folder the user chose to ignore in step 2l (`.5/planning/`, `.5/features/`):
217
217
  1. Check if `.gitignore` exists in the project root — create it if not
218
218
  2. Check if the folder is already listed — if not, append it on a new line
219
- 3. Inform the user which folders were added to `.gitignore`
219
+ 3. When the user chose "Only `.5/features/`", also append `!.5/planning/`, so upgrades know the plans are shared on purpose and do not ignore them
220
+ 4. Inform the user which folders were added to `.gitignore`
220
221
 
221
222
  **Always gitignore `.5/.reconfig-reminder`:**
222
223