@sienklogic/plan-build-run 2.39.0 → 2.40.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/CHANGELOG.md CHANGED
@@ -5,6 +5,25 @@ All notable changes to Plan-Build-Run will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.40.1](https://github.com/SienkLogic/plan-build-run/compare/plan-build-run-v2.40.0...plan-build-run-v2.40.1) (2026-02-27)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **hooks:** use flexible regex for PLAN file detection in hooks ([402d602](https://github.com/SienkLogic/plan-build-run/commit/402d60286b9184aa0155c0840785a8e5872872d2))
14
+
15
+ ## [2.40.0](https://github.com/SienkLogic/plan-build-run/compare/plan-build-run-v2.39.0...plan-build-run-v2.40.0) (2026-02-27)
16
+
17
+
18
+ ### Features
19
+
20
+ * **milestone:** add push/publish step after milestone complete ([dc26503](https://github.com/SienkLogic/plan-build-run/commit/dc26503975691480e805893e1fb400cf41b01226))
21
+
22
+
23
+ ### Bug Fixes
24
+
25
+ * **tools:** find per-plan SUMMARY-{id}.md files in milestone-learnings aggregation ([2ecda9f](https://github.com/SienkLogic/plan-build-run/commit/2ecda9ff555d3787e2bea92f339d7abb9afc5e04))
26
+
8
27
  ## [2.39.0](https://github.com/SienkLogic/plan-build-run/compare/plan-build-run-v2.38.1...plan-build-run-v2.39.0) (2026-02-27)
9
28
 
10
29
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sienklogic/plan-build-run",
3
- "version": "2.39.0",
3
+ "version": "2.40.1",
4
4
  "description": "Plan it, Build it, Run it — structured development workflow for Claude Code",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pbr",
3
3
  "displayName": "Plan-Build-Run",
4
- "version": "2.39.0",
4
+ "version": "2.40.1",
5
5
  "description": "Plan-Build-Run — Structured development workflow for GitHub Copilot CLI. Solves context rot through disciplined agent delegation, structured planning, atomic execution, and goal-backward verification.",
6
6
  "author": {
7
7
  "name": "SienkLogic",
@@ -445,6 +445,22 @@ Note: Learnings threshold met — {key}: {trigger}. Consider implementing the de
445
445
  git commit -m "docs(planning): complete milestone {version}"
446
446
  ```
447
447
 
448
+ 9b. **Push milestone to remote:**
449
+
450
+ Use AskUserQuestion to ask the user how they want to publish the milestone:
451
+
452
+ ```
453
+ question: "How should this milestone be published to GitHub?"
454
+ header: "Publish"
455
+ options:
456
+ - label: "Push tag + commits" description: "Push the v{version} tag and any unpushed commits to origin"
457
+ - label: "Skip for now" description: "Keep everything local — push later manually"
458
+ ```
459
+
460
+ - If "Push tag + commits": run `git push origin main --follow-tags` to push both commits and the annotated tag in one command. Display success or error.
461
+ - If "Skip for now": display reminder: "Tag v{version} is local only. Push when ready: `git push origin main --follow-tags`"
462
+ - If "Other": follow user instructions (e.g., create a PR, push to a different branch, etc.)
463
+
448
464
  ### Post-Completion Smoke Test
449
465
 
450
466
  If `config.deployment.smoke_test_command` is set and non-empty:
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pbr",
3
3
  "displayName": "Plan-Build-Run",
4
- "version": "2.39.0",
4
+ "version": "2.40.1",
5
5
  "description": "Plan-Build-Run — Structured development workflow for Cursor. Solves context rot through disciplined subagent delegation, structured planning, atomic execution, and goal-backward verification.",
6
6
  "author": {
7
7
  "name": "SienkLogic",
@@ -446,6 +446,22 @@ Note: Learnings threshold met — {key}: {trigger}. Consider implementing the de
446
446
  git commit -m "docs(planning): complete milestone {version}"
447
447
  ```
448
448
 
449
+ 9b. **Push milestone to remote:**
450
+
451
+ Use AskUserQuestion to ask the user how they want to publish the milestone:
452
+
453
+ ```
454
+ question: "How should this milestone be published to GitHub?"
455
+ header: "Publish"
456
+ options:
457
+ - label: "Push tag + commits" description: "Push the v{version} tag and any unpushed commits to origin"
458
+ - label: "Skip for now" description: "Keep everything local — push later manually"
459
+ ```
460
+
461
+ - If "Push tag + commits": run `git push origin main --follow-tags` to push both commits and the annotated tag in one command. Display success or error.
462
+ - If "Skip for now": display reminder: "Tag v{version} is local only. Push when ready: `git push origin main --follow-tags`"
463
+ - If "Other": follow user instructions (e.g., create a PR, push to a different branch, etc.)
464
+
449
465
  ### Post-Completion Smoke Test
450
466
 
451
467
  If `config.deployment.smoke_test_command` is set and non-empty:
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pbr",
3
- "version": "2.39.0",
3
+ "version": "2.40.1",
4
4
  "description": "Plan-Build-Run — Structured development workflow for Claude Code. Solves context rot through disciplined subagent delegation, structured planning, atomic execution, and goal-backward verification.",
5
5
  "author": {
6
6
  "name": "SienkLogic",
@@ -56,7 +56,7 @@ async function main() {
56
56
 
57
57
  // Determine file type
58
58
  const basename = path.basename(filePath);
59
- const isPlan = basename.endsWith('PLAN.md');
59
+ const isPlan = /PLAN.*\.md$/i.test(basename);
60
60
  const isSummary = basename.includes('SUMMARY') && basename.endsWith('.md');
61
61
  const isVerification = basename === 'VERIFICATION.md';
62
62
  const isRoadmap = basename === 'ROADMAP.md';
@@ -276,7 +276,7 @@ function validateSummary(content, _filePath) {
276
276
  async function checkPlanWrite(data) {
277
277
  const filePath = data.tool_input?.file_path || data.tool_input?.path || '';
278
278
  const basename = path.basename(filePath);
279
- const isPlan = basename.endsWith('PLAN.md');
279
+ const isPlan = /PLAN.*\.md$/i.test(basename);
280
280
  const isSummary = basename.includes('SUMMARY') && basename.endsWith('.md');
281
281
  const isVerification = basename === 'VERIFICATION.md';
282
282
  const isRoadmap = basename === 'ROADMAP.md';
@@ -326,7 +326,7 @@ function checkStateSync(data) {
326
326
  // Determine if this is a SUMMARY, VERIFICATION, or PLAN write
327
327
  const isSummary = basename.includes('SUMMARY') && basename.endsWith('.md');
328
328
  const isVerification = basename === 'VERIFICATION.md';
329
- const isPlan = basename.endsWith('PLAN.md') && !basename.includes('SUMMARY');
329
+ const isPlan = /PLAN.*\.md$/i.test(basename) && !basename.includes('SUMMARY');
330
330
 
331
331
  if (!isSummary && !isVerification && !isPlan) return null;
332
332
 
@@ -185,8 +185,8 @@ function readCurrentPlan(planningDir, stateContent) {
185
185
 
186
186
  const phaseDir = path.join(phasesDir, dirs[0]);
187
187
 
188
- // Find PLAN.md files
189
- const planFiles = fs.readdirSync(phaseDir).filter(f => f.endsWith('PLAN.md'));
188
+ // Find PLAN*.md files (matches PLAN.md, PLAN-01.md, 01-PLAN.md, etc.)
189
+ const planFiles = fs.readdirSync(phaseDir).filter(f => /PLAN.*\.md$/i.test(f));
190
190
  if (planFiles.length === 0) return 'No PLAN.md found in current phase';
191
191
 
192
192
  // Read the last plan's objective only (frontmatter + objective tag)
@@ -161,9 +161,10 @@ function extractLearningsFromSummary(summaryContent, sourceProject) {
161
161
  }
162
162
 
163
163
  /**
164
- * Recursively find all SUMMARY.md files under a phases directory.
164
+ * Recursively find all SUMMARY*.md files under a phases directory.
165
+ * Matches both single-summary (SUMMARY.md) and per-plan (SUMMARY-45-01.md) patterns.
165
166
  * @param {string} phasesDir
166
- * @returns {string[]} absolute paths to SUMMARY.md files
167
+ * @returns {string[]} absolute paths to SUMMARY*.md files
167
168
  */
168
169
  function findSummaryFiles(phasesDir) {
169
170
  const results = [];
@@ -174,10 +175,16 @@ function findSummaryFiles(phasesDir) {
174
175
  for (const entry of entries) {
175
176
  const fullPath = path.join(phasesDir, entry.name);
176
177
  if (entry.isDirectory()) {
177
- // Check for SUMMARY.md in this phase directory
178
- const summaryPath = path.join(fullPath, 'SUMMARY.md');
179
- if (fs.existsSync(summaryPath)) {
180
- results.push(summaryPath);
178
+ // Find all SUMMARY*.md files in this phase directory
179
+ try {
180
+ const phaseFiles = fs.readdirSync(fullPath);
181
+ for (const file of phaseFiles) {
182
+ if (/^SUMMARY.*\.md$/i.test(file)) {
183
+ results.push(path.join(fullPath, file));
184
+ }
185
+ }
186
+ } catch (_e) {
187
+ // Ignore read errors for individual phase dirs
181
188
  }
182
189
  // Recurse in case of nested dirs
183
190
  results.push(...findSummaryFiles(fullPath));
@@ -450,6 +450,22 @@ Note: Learnings threshold met — {key}: {trigger}. Consider implementing the de
450
450
  git commit -m "docs(planning): complete milestone {version}"
451
451
  ```
452
452
 
453
+ 9b. **Push milestone to remote:**
454
+
455
+ Use AskUserQuestion to ask the user how they want to publish the milestone:
456
+
457
+ ```
458
+ question: "How should this milestone be published to GitHub?"
459
+ header: "Publish"
460
+ options:
461
+ - label: "Push tag + commits" description: "Push the v{version} tag and any unpushed commits to origin"
462
+ - label: "Skip for now" description: "Keep everything local — push later manually"
463
+ ```
464
+
465
+ - If "Push tag + commits": run `git push origin main --follow-tags` to push both commits and the annotated tag in one command. Display success or error.
466
+ - If "Skip for now": display reminder: "Tag v{version} is local only. Push when ready: `git push origin main --follow-tags`"
467
+ - If "Other": follow user instructions (e.g., create a PR, push to a different branch, etc.)
468
+
453
469
  ### Post-Completion Smoke Test
454
470
 
455
471
  If `config.deployment.smoke_test_command` is set and non-empty: