codebyplan 1.13.43 → 1.13.44

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/dist/cli.js CHANGED
@@ -39,7 +39,7 @@ var VERSION, PACKAGE_NAME;
39
39
  var init_version = __esm({
40
40
  "src/lib/version.ts"() {
41
41
  "use strict";
42
- VERSION = "1.13.43";
42
+ VERSION = "1.13.44";
43
43
  PACKAGE_NAME = "codebyplan";
44
44
  }
45
45
  });
@@ -29596,6 +29596,35 @@ function patchBump(version3) {
29596
29596
  const patch = parseInt(coreMatch[3], 10);
29597
29597
  return `${hasV ? "v" : ""}${major}.${minor}.${patch + 1}`;
29598
29598
  }
29599
+ function prereleaseBump(version3, id) {
29600
+ const hasV = version3.startsWith("v");
29601
+ const stripped = hasV ? version3.slice(1) : version3;
29602
+ const coreMatch = stripped.match(/^(\d+)\.(\d+)\.(\d+)/);
29603
+ if (!coreMatch) {
29604
+ return version3;
29605
+ }
29606
+ const major = parseInt(coreMatch[1], 10);
29607
+ const minor = parseInt(coreMatch[2], 10);
29608
+ const patchSeg = coreMatch[3];
29609
+ const prefix = hasV ? "v" : "";
29610
+ const preMatch = stripped.match(/^\d+\.\d+\.\d+-(.+)$/);
29611
+ if (preMatch) {
29612
+ const preSuffix = preMatch[1];
29613
+ const idDotPrefix = id + ".";
29614
+ if (preSuffix.startsWith(idDotPrefix)) {
29615
+ const nStr = preSuffix.slice(idDotPrefix.length);
29616
+ const n = parseInt(nStr, 10);
29617
+ if (!isNaN(n) && /^\d+$/.test(nStr)) {
29618
+ return `${prefix}${coreMatch[1]}.${coreMatch[2]}.${patchSeg}-${id}.${n + 1}`;
29619
+ }
29620
+ }
29621
+ if (preSuffix === id) {
29622
+ return `${prefix}${coreMatch[1]}.${coreMatch[2]}.${patchSeg}-${id}.1`;
29623
+ }
29624
+ return `${prefix}${major}.${minor + 1}.0-${id}.1`;
29625
+ }
29626
+ return `${prefix}${major}.${minor + 1}.0-${id}.1`;
29627
+ }
29599
29628
  function compareSemver(a, b) {
29600
29629
  const parseCore = (v) => {
29601
29630
  const stripped = v.startsWith("v") ? v.slice(1) : v;
@@ -29676,6 +29705,7 @@ async function runBump(opts) {
29676
29705
  const cwd = resolve3(opts?.cwd ?? process.cwd());
29677
29706
  const dryRun = opts?.dryRun ?? false;
29678
29707
  const now = opts?.now ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
29708
+ const prereleaseId = opts?.prereleaseId;
29679
29709
  const baseBranch = await readBaseBranch(cwd);
29680
29710
  const baseRef = resolveBaseRef(cwd, baseBranch);
29681
29711
  const diffResult = spawnSync5(
@@ -29749,7 +29779,7 @@ async function runBump(opts) {
29749
29779
  }
29750
29780
  const pkgJsonRelPath = relative5(cwd, pkgJsonPath).replace(/\\/g, "/");
29751
29781
  const baseRaw = gitShowFile(cwd, baseRef, pkgJsonRelPath);
29752
- if (baseRaw !== null) {
29782
+ if (baseRaw !== null && !prereleaseId) {
29753
29783
  const baseVersion = extractVersion(baseRaw, pkgJsonPath);
29754
29784
  if (baseVersion !== null && compareSemver(currentVersion, baseVersion) > 0) {
29755
29785
  entries.push({
@@ -29765,7 +29795,7 @@ async function runBump(opts) {
29765
29795
  continue;
29766
29796
  }
29767
29797
  }
29768
- const nextVersion = patchBump(currentVersion);
29798
+ const nextVersion = prereleaseId ? prereleaseBump(currentVersion, prereleaseId) : patchBump(currentVersion);
29769
29799
  const updatedVersionFiles = [];
29770
29800
  const skippedVersionFiles = [];
29771
29801
  for (const { abs, rel } of versionFileCandidates) {
@@ -29842,7 +29872,7 @@ function parseFlagsFromArgs6(args) {
29842
29872
  }
29843
29873
  function printBumpHelp() {
29844
29874
  process.stdout.write(
29845
- "\n codebyplan bump\n\n Detect changed workspace packages and patch-bump their versions.\n Does NOT commit or push \u2014 pure version-file + changelog edits.\n\n Flags:\n --dry-run Preview planned bumps without writing any files\n --json Write structured JSON output to stdout\n\n"
29875
+ "\n codebyplan bump [--prerelease <id>]\n\n Detect changed workspace packages and patch-bump their versions.\n Does NOT commit or push \u2014 pure version-file + changelog edits.\n\n Flags:\n --dry-run Preview planned bumps without writing any files\n --json Write structured JSON output to stdout\n --prerelease <id> Cut/iterate a prerelease (X.Y.Z \u2192 X.(Y+1).0-id.1; id.N \u2192 id.N+1). Default id: beta\n\n"
29846
29876
  );
29847
29877
  }
29848
29878
  function printHumanResult(result) {
@@ -29883,12 +29913,18 @@ async function runBumpCommand(args) {
29883
29913
  printBumpHelp();
29884
29914
  process.exit(0);
29885
29915
  }
29886
- const { booleans } = parseFlagsFromArgs6(args);
29916
+ const { flags, booleans } = parseFlagsFromArgs6(args);
29887
29917
  const dryRun = booleans.has("dry-run");
29888
29918
  const jsonOutput = booleans.has("json");
29919
+ let prereleaseId;
29920
+ if (flags["prerelease"] !== void 0) {
29921
+ prereleaseId = flags["prerelease"] || "beta";
29922
+ } else if (booleans.has("prerelease")) {
29923
+ prereleaseId = "beta";
29924
+ }
29889
29925
  let result;
29890
29926
  try {
29891
- result = await runBump({ dryRun });
29927
+ result = await runBump({ dryRun, prereleaseId });
29892
29928
  } catch (err) {
29893
29929
  process.stderr.write(
29894
29930
  `bump: ${err instanceof Error ? err.message : String(err)}
@@ -35518,7 +35554,7 @@ void (async () => {
35518
35554
  codebyplan watch status Show daemon status (--json for machine-readable)
35519
35555
  codebyplan watch run Run daemon in foreground (used internally by start)
35520
35556
  codebyplan round sync-approvals Sync git diff and approvals with round/task state
35521
- codebyplan bump Detect changed packages and patch-bump versions
35557
+ codebyplan bump [--prerelease <id>] Detect changed packages and patch-bump versions
35522
35558
  codebyplan ship Ship current feat branch to production via PR
35523
35559
  codebyplan upload-e2e-images Upload new/changed committed e2e PNGs for a checkpoint
35524
35560
  codebyplan scaffold-publish-workflow Write the publish-on-main GitHub workflow into ./.github/workflows/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebyplan",
3
- "version": "1.13.43",
3
+ "version": "1.13.44",
4
4
  "description": "CLI for CodeByPlan — AI-powered development planning and tracking",
5
5
  "type": "module",
6
6
  "bin": {
@@ -2,14 +2,16 @@
2
2
  #
3
3
  # This workflow publishes the codebyplan npm package on every merge to main
4
4
  # where the committed package.json version exceeds the version currently on npm.
5
- # No release PR, no conventional-commit parsing the version committed in the
6
- # feat branch is the version that ships.
5
+ # It also auto-publishes prerelease versions (e.g. 1.14.0-beta.1) from feat/**
6
+ # branches to a scoped dist-tag (e.g. --tag beta) — see the beta channel docs
7
+ # for the full workflow. No release PR, no conventional-commit parsing — the
8
+ # version committed in the feat branch is the version that ships.
7
9
  #
8
10
  # Two values a consuming repo must adjust:
9
11
  # 1. paths: — set to the package directory whose package.json drives versioning
10
12
  # (current value: 'packages/codebyplan-package/**')
11
13
  # 2. npm view <package-name> — replace `codebyplan` with the actual package name
12
- # in the "Check version vs published" step
14
+ # in the "Check version vs published" and exact-version check steps
13
15
  #
14
16
  # Everything else (OIDC auth, pnpm 10.12.4, Node 20, build:npm → publish) is
15
17
  # intentionally generic and works as-is for any single-package npm publish.
@@ -20,6 +22,7 @@ on:
20
22
  push:
21
23
  branches:
22
24
  - main
25
+ - "feat/**"
23
26
  paths:
24
27
  - "packages/codebyplan-package/**"
25
28
  workflow_dispatch:
@@ -40,6 +43,7 @@ jobs:
40
43
  outputs:
41
44
  should_publish: ${{ steps.check.outputs.should_publish }}
42
45
  version: ${{ steps.check.outputs.version }}
46
+ dist_tag: ${{ steps.check.outputs.dist_tag }}
43
47
  steps:
44
48
  - name: Checkout
45
49
  uses: actions/checkout@v4
@@ -54,27 +58,80 @@ jobs:
54
58
  fi
55
59
  echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
56
60
 
57
- # Pre-release versions (e.g. 1.2.3-beta.1) must never auto-publish to the
58
- # 'latest' dist-tag sort -V is not semver-aware for pre-release suffixes,
59
- # and this workflow always publishes to latest. Publish pre-releases
60
- # manually with `npm publish --tag <pre-id>`. The version core (X.Y.Z) has
61
- # no hyphen, so any '-' marks a pre-release.
61
+ # Compute dist-tag from version:
62
+ # prerelease (contains hyphen) extract id between '-' and first '.'
63
+ # e.g. 1.14.0-beta.1 "beta"; 1.14.0-rc.1 "rc"
64
+ # stable "latest"
62
65
  case "$VERSION" in
63
66
  *-*)
64
- echo "VERSION=${VERSION} is a pre-release — skipping auto-publish."
65
- echo "should_publish=false" >> "$GITHUB_OUTPUT"
66
- exit 0
67
+ PRE_ID="${VERSION#*-}"
68
+ DIST_TAG="${PRE_ID%%.*}"
69
+ ;;
70
+ *)
71
+ DIST_TAG="latest"
67
72
  ;;
68
73
  esac
74
+ echo "dist_tag=${DIST_TAG}" >> "$GITHUB_OUTPUT"
69
75
 
70
- # Manual dispatch: always publish (recovery / forced re-publish path).
76
+ # ── workflow_dispatch ──────────────────────────────────────────────
77
+ # Manual trigger: always publish (recovery / forced re-publish path).
78
+ # Uses the computed dist_tag so manual prerelease publishes are tagged
79
+ # correctly.
71
80
  if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
72
- echo "Manual dispatch — skipping gt check, will publish."
81
+ echo "Manual dispatch — will publish (dist-tag: ${DIST_TAG})."
73
82
  echo "should_publish=true" >> "$GITHUB_OUTPUT"
74
83
  exit 0
75
84
  fi
76
85
 
77
- # Push path: compare committed version against the npm registry.
86
+ # ── feat/** push ───────────────────────────────────────────────────
87
+ # C4 guard: three conditions must hold before publishing from feat/**:
88
+ # (1) prerelease-required: stable versions on feat/** are skipped.
89
+ # (2) exact-version check: if this exact version is already on npm, skip.
90
+ # (3) path filter: already enforced by on.push.paths above.
91
+ case "${{ github.ref }}" in
92
+ refs/heads/feat/*)
93
+ case "$VERSION" in
94
+ *-*)
95
+ # Prerelease — check if this exact version already exists on npm.
96
+ EXACT_OUT=$(npm view "codebyplan@${VERSION}" version 2>&1)
97
+ EXACT_EXIT=$?
98
+ if [ "$EXACT_EXIT" -eq 0 ]; then
99
+ echo "VERSION=${VERSION} already published — skipping (exact-version guard)."
100
+ echo "should_publish=false" >> "$GITHUB_OUTPUT"
101
+ exit 0
102
+ fi
103
+ if echo "$EXACT_OUT" | grep -q "E404"; then
104
+ echo "VERSION=${VERSION} not yet published — will publish (dist-tag: ${DIST_TAG})."
105
+ echo "should_publish=true" >> "$GITHUB_OUTPUT"
106
+ exit 0
107
+ fi
108
+ # Non-E404 failure: transient registry error — abort to avoid
109
+ # a duplicate publish in a degraded state.
110
+ echo "ERROR: npm view codebyplan@${VERSION} failed (exit ${EXACT_EXIT}): ${EXACT_OUT}"
111
+ exit 1
112
+ ;;
113
+ *)
114
+ # C4 prerelease-required gate: stable versions on feat/** skip.
115
+ echo "VERSION=${VERSION} is not a prerelease — feat/** branches require a prerelease version (e.g. run 'codebyplan bump --prerelease beta'). Skipping."
116
+ echo "should_publish=false" >> "$GITHUB_OUTPUT"
117
+ exit 0
118
+ ;;
119
+ esac
120
+ ;;
121
+ esac
122
+
123
+ # ── main push ──────────────────────────────────────────────────────
124
+ # Prerelease versions must never auto-publish to latest from main.
125
+ # The version core (X.Y.Z) has no hyphen, so any '-' marks a prerelease.
126
+ case "$VERSION" in
127
+ *-*)
128
+ echo "VERSION=${VERSION} is a pre-release — skipping auto-publish on main (use a feat/** branch or workflow_dispatch)."
129
+ echo "should_publish=false" >> "$GITHUB_OUTPUT"
130
+ exit 0
131
+ ;;
132
+ esac
133
+
134
+ # Stable on main: compare committed version against the npm registry.
78
135
  # Distinguish "never published" (E404 → first publish) from a transient
79
136
  # registry/network error (abort rather than blindly publish).
80
137
  NPM_OUT=$(npm view codebyplan version 2>&1)
@@ -88,7 +145,9 @@ jobs:
88
145
  echo "ERROR: npm view failed (exit ${NPM_EXIT}): ${NPM_OUT}"
89
146
  exit 1
90
147
  fi
91
- PUBLISHED="$NPM_OUT"
148
+ # Extract the first semver-looking line so a registry deprecation/advisory
149
+ # notice in NPM_OUT cannot corrupt the sort -V comparison below.
150
+ PUBLISHED=$(printf '%s\n' "$NPM_OUT" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+' | head -n1)
92
151
 
93
152
  # sort -V: version-aware sort. If VERSION sorts AFTER PUBLISHED, it is greater.
94
153
  GREATER=$(printf '%s\n%s\n' "$PUBLISHED" "$VERSION" | sort -V | tail -n1)
@@ -147,7 +206,7 @@ jobs:
147
206
  working-directory: packages/codebyplan-package
148
207
  run: |
149
208
  echo "dry_run=true — skipping actual publish."
150
- echo "Would publish: codebyplan@${{ needs.check-version.outputs.version }}"
209
+ echo "Would publish: codebyplan@${{ needs.check-version.outputs.version }} (dist-tag: ${{ needs.check-version.outputs.dist_tag }})"
151
210
 
152
211
  # No NODE_AUTH_TOKEN: npm >= 11.5.1 exchanges the GitHub OIDC token for a
153
212
  # short-lived publish token. Requires a Trusted Publisher configured for
@@ -158,10 +217,14 @@ jobs:
158
217
  # source repository visibility: private" otherwise). This works for both
159
218
  # public and private repos. If your source repo is PUBLIC and you want
160
219
  # supply-chain attestation, add `--provenance` to the command below.
220
+ #
221
+ # --tag: routes stable publishes to "latest" and prerelease publishes to
222
+ # the prerelease id (e.g. "beta", "rc"). C1 guarantee: betas never land on
223
+ # "latest" because dist_tag is computed from the version string.
161
224
  - name: Publish to npm
162
225
  if: ${{ github.event_name != 'workflow_dispatch' || inputs.dry_run != true }}
163
226
  working-directory: packages/codebyplan-package
164
- run: npm publish --access public
227
+ run: npm publish --access public --tag ${{ needs.check-version.outputs.dist_tag }}
165
228
 
166
229
  tag-and-release:
167
230
  name: Tag + GitHub release
@@ -199,9 +262,18 @@ jobs:
199
262
  if gh release view "${TAG}" > /dev/null 2>&1; then
200
263
  echo "GitHub release ${TAG} already exists — skipping."
201
264
  else
202
- gh release create "${TAG}" \
203
- --title "codebyplan v${VERSION}" \
204
- --notes "codebyplan v${VERSION} published to npm: https://www.npmjs.com/package/codebyplan/v/${VERSION} (install: npm install -g codebyplan@${VERSION})" \
205
- --latest
265
+ # C1 guard: prerelease versions get --prerelease (NOT --latest);
266
+ # stable versions get --latest (existing behaviour preserved).
267
+ if echo "${VERSION}" | grep -q "-"; then
268
+ gh release create "${TAG}" \
269
+ --title "codebyplan v${VERSION}" \
270
+ --notes "codebyplan v${VERSION} — published to npm: https://www.npmjs.com/package/codebyplan/v/${VERSION} (install: npm install -g codebyplan@${VERSION})" \
271
+ --prerelease
272
+ else
273
+ gh release create "${TAG}" \
274
+ --title "codebyplan v${VERSION}" \
275
+ --notes "codebyplan v${VERSION} — published to npm: https://www.npmjs.com/package/codebyplan/v/${VERSION} (install: npm install -g codebyplan@${VERSION})" \
276
+ --latest
277
+ fi
206
278
  echo "Created GitHub release ${TAG}."
207
279
  fi