pubz 0.6.0 → 0.7.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.
Files changed (3) hide show
  1. package/README.md +69 -113
  2. package/dist/cli.js +176 -214
  3. package/package.json +2 -1
package/README.md CHANGED
@@ -179,118 +179,74 @@ jobs:
179
179
  bunx pubz
180
180
  ```
181
181
 
182
+ <!-- demo-output-start -->
182
183
  ```
183
- pubz - npm package publisher
184
- ══════════════════════════════
185
-
186
- Discovering packages...
187
-
188
- Found 1 publishable package(s):
189
-
190
- pubz@0.4.0
191
-
192
- Step 1: Version Management
193
- ──────────────────────────────
194
-
195
- Current version: 0.4.0
196
-
197
- ? Bump version before publishing? [Y/n] n
198
- ? Select publish target:
199
-
200
- > 1) Public npm registry (https://registry.npmjs.org)
201
- 2) GitHub Packages (https://npm.pkg.github.com)
202
-
203
- Enter choice [1-2] (default: 1):
204
-
205
- Publishing to: https://registry.npmjs.org
206
-
207
- Verifying npm authentication...
208
- Authenticated as zdavison
209
-
210
- Step 2: Building Packages
211
- ──────────────────────────────
212
-
213
- Running build...
214
-
215
- $ bun build src/cli.ts --outdir dist --target node
216
- Bundled 10 modules in 5ms
217
-
218
- cli.js 41.27 KB (entry point)
219
-
220
-
221
- Build completed successfully
222
-
223
- Verifying builds...
224
-
225
- ✓ pubz build verified
226
-
227
- Step 3: Publishing to npm
228
- ──────────────────────────────
229
-
230
- About to publish the following packages:
231
-
232
- • pubz@0.4.0
233
-
234
- Registry: https://registry.npmjs.org
235
-
236
- ? Continue? [Y/n]
237
-
238
- Preparing packages for publish...
239
-
240
- Publishing packages...
241
-
242
- Publishing pubz@0.4.0...
243
- npm notice
244
- npm notice 📦 pubz@0.4.0
245
- npm notice === Tarball Contents ===
246
- npm notice 7.1kB README.md
247
- npm notice 41.3kB dist/cli.js
248
- npm notice 697B package.json
249
- npm notice === Tarball Details ===
250
- npm notice name: pubz
251
- npm notice version: 0.4.0
252
- npm notice filename: pubz-0.4.0.tgz
253
- npm notice package size: 12.0 kB
254
- npm notice unpacked size: 49.1 kB
255
- npm notice shasum: 3026a7936458dcaa84030a0ce2e206b9f74aa65d
256
- npm notice integrity: sha512-6vKMOsC7sZa87[...]w8KNx1fD45u/A==
257
- npm notice total files: 3
258
- npm notice
259
- npm notice Publishing to https://registry.npmjs.org/ with tag latest and public access
260
- Authenticate your account at:
261
- https://www.npmjs.com/auth/cli/c47d9bee-2a1e-4adf-9aab-63d15acfade2
262
- Press ENTER to open in the browser...
263
-
264
- + pubz@0.4.0
265
- pubz published successfully
266
-
267
- ══════════════════════════════
268
- Publishing complete!
269
-
270
- Published version: 0.4.0
271
-
272
- Changes since v0.2.12:
273
- 5553c95 Fix ENTER to open browser not working.
274
- 9aaddff Fix tag/push/release branch when using --yes.
275
- 0ce3ab8 Generate changlog and attach it to release page / print it out during publish.
276
- 5a29ca4 Merge branch 'main' of github.com:mm-zacharydavison/pubz
277
- b4c47fc Clean up README.md formatting
278
- 2da403c Update README.md
279
- 88a4211 Update README with image and usage instructions
280
- 8a8148a Update README.md
281
- 2b45d21 Transform 'workspace:' definitions on publish, and restore them before any commit.
282
-
283
- ? Create a git tag for v0.4.0? [Y/n]
284
-
285
- Tag v0.4.0 created
286
- ? Push tag to origin? [Y/n]
287
- remote: This repository moved. Please use the new location:
288
- remote: git@github.com:zdavison/pubz.git
289
- To github.com:mm-zacharydavison/pubz.git
290
- * [new tag] v0.4.0 -> v0.4.0
291
- Tag v0.4.0 pushed to origin
292
- ? Create a GitHub release? [Y/n]
293
- Release created: https://github.com/zdavison/pubz/releases/tag/v0.4.0
294
-
295
- Done!
184
+ 📦 pubz npm package publisher
185
+
186
+ ┌─ Packages ─────────────────────────────────────────
187
+ my-app@1.2.0
188
+ └────────────────────────────────────────────────────
189
+
190
+ ┌─ 🔖 Version ───────────────────────────────────────
191
+ Bumping (minor): 1.2.0 → 1.3.0
192
+ Updating all packages...
193
+ chore: release v1.3.0
194
+ └────────────────────────────────────────────────────
195
+
196
+ ┌─ 🏗️ Build ───────────────────────────────────────
197
+ Running bun run build...
198
+
199
+ $ bun build.js
200
+ Bundled 3 modules in 2ms
201
+
202
+ index.js 4.12 KB (entry point)
203
+
204
+ └────────────────────────────────────────────────────
205
+
206
+ Publishing to https://registry.npmjs.org:
207
+
208
+ my-app@1.3.0
209
+
210
+ ┌─ 🚀 Publish ───────────────────────────────────────
211
+ Preparing packages...
212
+ npm notice
213
+ npm notice Publishing to https://registry.npmjs.org
214
+ npm notice
215
+ └────────────────────────────────────────────────────
216
+
217
+ Published v1.3.0!
218
+
219
+ ┌─ 📋 Changelog ─────────────────────────────────────
220
+ Since v1.2.0
221
+ 4e215fd docs: update README
222
+ 5cbdd88 fix: fix edge case in parser
223
+ 6142990 feat: add feature A
224
+ └────────────────────────────────────────────────────
225
+
226
+
227
+ ┌─ ✨ AI Release Notes ───────────────────────────────
228
+ Generating...
229
+
230
+ ### Features
231
+
232
+ - Added feature A.
233
+
234
+ ### Bug Fixes
235
+
236
+ - Fixed an edge case in the parser.
237
+
238
+ ### Documentation
239
+
240
+ - Updated README.
241
+ └────────────────────────────────────────────────────
242
+
243
+ ┌─ 🏷️ Release ─────────────────────────────────────
244
+ Creating tag v1.3.0...
245
+ Pushing tag to origin...
246
+ * [new tag] v1.3.0 -> v1.3.0
247
+ Creating GitHub release...
248
+ └────────────────────────────────────────────────────
249
+
250
+ 🎉 Done!
296
251
  ```
252
+ <!-- demo-output-end -->
package/dist/cli.js CHANGED
@@ -32,6 +32,18 @@ var bgGreen = fmt("42", "49");
32
32
  var bgYellow = fmt("43", "49");
33
33
  var bgBlue = fmt("44", "49");
34
34
  var muted = gray;
35
+ var FRAME_WIDTH = 52;
36
+ function frameHeader(title) {
37
+ const inner = `─ ${title} `;
38
+ const padding = "─".repeat(Math.max(2, FRAME_WIDTH - inner.length));
39
+ console.log(dim(`┌${inner}${padding}`));
40
+ }
41
+ function frameFooter() {
42
+ console.log(dim(`└${"─".repeat(FRAME_WIDTH)}`));
43
+ }
44
+ function frameLine(text = "") {
45
+ console.log(" " + text);
46
+ }
35
47
 
36
48
  // src/discovery.ts
37
49
  import { readFile, readdir as readdir2, stat as stat2 } from "node:fs/promises";
@@ -386,6 +398,8 @@ import { spawn as spawn2 } from "node:child_process";
386
398
  import { readFile as readFile2, stat as stat3 } from "node:fs/promises";
387
399
  import { homedir as homedir2 } from "node:os";
388
400
  import { join as join3 } from "node:path";
401
+ var DIM_ON = "\x1B[90m";
402
+ var DIM_OFF = "\x1B[39m";
389
403
  function run(command, args, cwd) {
390
404
  return new Promise((resolve2) => {
391
405
  const proc = spawn2(command, args, {
@@ -395,11 +409,11 @@ function run(command, args, cwd) {
395
409
  let output = "";
396
410
  proc.stdout?.on("data", (data) => {
397
411
  output += data.toString();
398
- process.stdout.write(data);
412
+ process.stdout.write(DIM_ON + data.toString() + DIM_OFF);
399
413
  });
400
414
  proc.stderr?.on("data", (data) => {
401
415
  output += data.toString();
402
- process.stderr.write(data);
416
+ process.stderr.write(DIM_ON + data.toString() + DIM_OFF);
403
417
  });
404
418
  proc.on("close", (code) => {
405
419
  resolve2({ code: code ?? 1, output });
@@ -419,17 +433,12 @@ function runInteractive(command, args, cwd) {
419
433
  }
420
434
  async function runBuild(cwd, dryRun) {
421
435
  if (dryRun) {
422
- console.log("[DRY RUN] Would run: bun run build");
423
436
  return { success: true };
424
437
  }
425
- console.log("Running build...");
426
- console.log("");
427
438
  const result = await run("bun", ["run", "build"], cwd);
428
439
  if (result.code !== 0) {
429
440
  return { success: false, error: "Build failed" };
430
441
  }
431
- console.log("");
432
- console.log("Build completed successfully");
433
442
  return { success: true };
434
443
  }
435
444
  async function verifyBuild(pkg) {
@@ -472,10 +481,8 @@ function isOtpError(output) {
472
481
  var NPM_COMMAND = process.env.PUBZ_NPM_COMMAND ?? "npm";
473
482
  async function publishPackage(pkg, registry, context, dryRun) {
474
483
  if (dryRun) {
475
- console.log(` [DRY RUN] Would publish ${pkg.name}@${pkg.version} to ${registry}`);
476
484
  return { success: true };
477
485
  }
478
- console.log(`Publishing ${pkg.name}@${pkg.version}...`);
479
486
  const args = ["publish", "--registry", registry, "--access", "public"];
480
487
  if (context.otp) {
481
488
  args.push("--otp", context.otp);
@@ -500,7 +507,6 @@ async function publishPackage(pkg, registry, context, dryRun) {
500
507
  }
501
508
  return { success: false, error: `Failed to publish ${pkg.name}` };
502
509
  }
503
- console.log(` ${pkg.name} published successfully`);
504
510
  return { success: true };
505
511
  }
506
512
  async function hasUncommittedChanges(cwd) {
@@ -516,29 +522,25 @@ async function hasUncommittedChanges(cwd) {
516
522
  async function commitVersionBump(version, cwd, dryRun) {
517
523
  const tagName = `v${version}`;
518
524
  if (dryRun) {
519
- console.log(`[DRY RUN] Would commit version bump for ${tagName}`);
520
525
  return { success: true };
521
526
  }
522
527
  const statusResult = await run("git", ["status", "--porcelain"], cwd);
523
528
  if (!statusResult.output.trim()) {
524
529
  return { success: true };
525
530
  }
526
- console.log("Committing version bump...");
527
531
  const addResult = await run("git", ["add", "-A"], cwd);
528
532
  if (addResult.code !== 0) {
529
533
  return { success: false, error: "Failed to stage changes" };
530
534
  }
531
- const commitResult = await run("git", ["commit", "-m", `chore: release ${tagName}`], cwd);
535
+ const commitResult = await run("git", ["commit", "-m", `chore: release ${tagName}`], cwd, { silent: true });
532
536
  if (commitResult.code !== 0) {
533
537
  return { success: false, error: "Failed to commit changes" };
534
538
  }
535
- console.log(" Changes committed");
536
539
  return { success: true };
537
540
  }
538
541
  async function createGitTag(version, cwd, dryRun) {
539
542
  const tagName = `v${version}`;
540
543
  if (dryRun) {
541
- console.log(`[DRY RUN] Would create git tag: ${tagName}`);
542
544
  return { success: true };
543
545
  }
544
546
  const tagResult = await run("git", ["tag", tagName], cwd);
@@ -548,13 +550,11 @@ async function createGitTag(version, cwd, dryRun) {
548
550
  error: `Failed to create tag ${tagName} (may already exist)`
549
551
  };
550
552
  }
551
- console.log(` Tag ${tagName} created`);
552
553
  return { success: true };
553
554
  }
554
555
  async function pushGitTag(version, cwd, dryRun) {
555
556
  const tagName = `v${version}`;
556
557
  if (dryRun) {
557
- console.log(`[DRY RUN] Would push git tag: ${tagName}`);
558
558
  return { success: true };
559
559
  }
560
560
  const branchResult = await run("git", ["push"], cwd);
@@ -565,7 +565,6 @@ async function pushGitTag(version, cwd, dryRun) {
565
565
  if (result.code !== 0) {
566
566
  return { success: false, error: `Failed to push tag ${tagName}` };
567
567
  }
568
- console.log(` Tag ${tagName} pushed to origin`);
569
568
  return { success: true };
570
569
  }
571
570
 
@@ -678,6 +677,7 @@ async function runClaudePrompt(prompt2) {
678
677
  }
679
678
 
680
679
  // src/changelog.ts
680
+ var GH_COMMAND = process.env.PUBZ_GH_COMMAND ?? "gh";
681
681
  function parseGitRemoteUrl(remoteUrl) {
682
682
  const sshMatch = remoteUrl.match(/^git@([^:]+):(.+?)(?:\.git)?$/);
683
683
  if (sshMatch) {
@@ -794,7 +794,7 @@ async function createGitHubRelease(version, body, cwd, dryRun) {
794
794
  console.log(`[DRY RUN] Would create GitHub release for ${tagName}`);
795
795
  return { success: true };
796
796
  }
797
- const result = await runSilent("gh", ["release", "create", tagName, "--title", tagName, "--notes", body], cwd);
797
+ const result = await runSilent(GH_COMMAND, ["release", "create", tagName, "--title", tagName, "--notes", body], cwd);
798
798
  if (result.code !== 0) {
799
799
  return {
800
800
  success: false,
@@ -828,9 +828,7 @@ async function transformWorkspaceProtocolForPublish(packages, newVersion, dryRun
828
828
  if (oldVersion.startsWith("workspace:")) {
829
829
  const modifier = oldVersion.replace("workspace:", "");
830
830
  const newVersionSpec = modifier === "*" || modifier === "" ? newVersion : `${modifier}${newVersion}`;
831
- if (dryRun) {
832
- console.log(` [DRY RUN] Would temporarily transform ${pkg.name} ${depType}.${depName}: ${oldVersion} -> ${newVersionSpec}`);
833
- } else {
831
+ if (!dryRun) {
834
832
  transforms.push({
835
833
  packageJsonPath: pkg.packageJsonPath,
836
834
  depType,
@@ -847,7 +845,6 @@ async function transformWorkspaceProtocolForPublish(packages, newVersion, dryRun
847
845
  if (modified && !dryRun) {
848
846
  await writeFile(pkg.packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
849
847
  `);
850
- console.log(` Transformed workspace references in ${pkg.name}`);
851
848
  }
852
849
  }
853
850
  return transforms;
@@ -871,9 +868,6 @@ async function restoreWorkspaceProtocol(transforms) {
871
868
  await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
872
869
  `);
873
870
  }
874
- if (transforms.length > 0) {
875
- console.log(` Restored workspace references in ${byPath.size} package(s)`);
876
- }
877
871
  }
878
872
  function isValidVersion(version) {
879
873
  return /^\d+\.\d+\.\d+(-.+)?$/.test(version);
@@ -900,12 +894,10 @@ async function updatePackageVersion(pkg, newVersion, dryRun) {
900
894
  const packageJson = JSON.parse(content);
901
895
  packageJson.version = newVersion;
902
896
  if (dryRun) {
903
- console.log(` [DRY RUN] Would update ${pkg.name}: ${pkg.version} -> ${newVersion}`);
904
897
  return;
905
898
  }
906
899
  await writeFile(pkg.packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
907
900
  `);
908
- console.log(` Updated ${pkg.name}: ${pkg.version} -> ${newVersion}`);
909
901
  }
910
902
  async function updateLocalDependencyVersions(packages, newVersion, dryRun) {
911
903
  const packageNames = new Set(packages.map((p) => p.name));
@@ -928,13 +920,9 @@ async function updateLocalDependencyVersions(packages, newVersion, dryRun) {
928
920
  continue;
929
921
  }
930
922
  const newVersionSpec = oldVersion.startsWith("^") ? `^${newVersion}` : oldVersion.startsWith("~") ? `~${newVersion}` : newVersion;
931
- if (deps[depName] !== newVersionSpec) {
932
- if (dryRun) {
933
- console.log(` [DRY RUN] Would update ${pkg.name} ${depType}.${depName}: ${oldVersion} -> ${newVersionSpec}`);
934
- } else {
935
- deps[depName] = newVersionSpec;
936
- modified = true;
937
- }
923
+ if (deps[depName] !== newVersionSpec && !dryRun) {
924
+ deps[depName] = newVersionSpec;
925
+ modified = true;
938
926
  }
939
927
  }
940
928
  }
@@ -942,7 +930,6 @@ async function updateLocalDependencyVersions(packages, newVersion, dryRun) {
942
930
  if (modified && !dryRun) {
943
931
  await writeFile(pkg.packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
944
932
  `);
945
- console.log(` Updated local dependency versions in ${pkg.name}`);
946
933
  }
947
934
  }
948
935
  }
@@ -959,8 +946,7 @@ function getVersion() {
959
946
  return pkg.version;
960
947
  }
961
948
  function printUsage() {
962
- console.log(`
963
- pubz - Interactive npm package publisher
949
+ console.log(`pubz - Interactive npm package publisher
964
950
 
965
951
  Usage: pubz [command] [options]
966
952
 
@@ -1059,15 +1045,14 @@ async function main() {
1059
1045
  const skipAllPrompts = options.ci;
1060
1046
  const cwd = process.cwd();
1061
1047
  if (options.dryRun) {
1062
- console.log(yellow(bold("DRY RUN MODE")) + dim(" - No actual changes will be made"));
1048
+ console.log(yellow(bold("⚠️ DRY RUN")) + dim(" no actual changes will be made"));
1063
1049
  console.log("");
1064
1050
  }
1065
- console.log(bold("pubz") + dim(" - npm package publisher"));
1066
- console.log(dim("═".repeat(30)));
1051
+ console.log("\uD83D\uDCE6 " + bold("pubz") + dim(" npm package publisher"));
1067
1052
  console.log("");
1068
1053
  const uncommitted = await hasUncommittedChanges(cwd);
1069
1054
  if (uncommitted.hasChanges && !options.dryRun) {
1070
- console.log(red(bold("Error:")) + " You have uncommitted changes:");
1055
+ console.error(red(bold("Error:")) + " You have uncommitted changes:");
1071
1056
  console.log("");
1072
1057
  for (const file of uncommitted.files.slice(0, 10)) {
1073
1058
  console.log(` ${yellow(file)}`);
@@ -1080,8 +1065,6 @@ async function main() {
1080
1065
  closePrompt();
1081
1066
  process.exit(1);
1082
1067
  }
1083
- console.log(cyan("Discovering packages..."));
1084
- console.log("");
1085
1068
  let packages = await discoverPackages(cwd);
1086
1069
  const publishablePackages = packages.filter((p) => !p.isPrivate);
1087
1070
  if (publishablePackages.length === 0) {
@@ -1094,12 +1077,12 @@ async function main() {
1094
1077
  process.exit(1);
1095
1078
  }
1096
1079
  packages = sortByDependencyOrder(publishablePackages);
1097
- console.log(`Found ${green(bold(String(packages.length)))} publishable package(s):`);
1098
- console.log("");
1080
+ frameHeader("Packages");
1099
1081
  for (const pkg of packages) {
1100
1082
  const deps = pkg.localDependencies.length > 0 ? dim(` (depends on: ${pkg.localDependencies.join(", ")})`) : "";
1101
- console.log(` ${dim("•")} ${cyan(pkg.name)}${dim("@")}${yellow(pkg.version)}${deps}`);
1083
+ frameLine(`${dim("•")} ${cyan(pkg.name)}${dim("@")}${yellow(pkg.version)}${deps}`);
1102
1084
  }
1085
+ frameFooter();
1103
1086
  console.log("");
1104
1087
  if (packages.length > 1 && !skipAllPrompts) {
1105
1088
  const selectedPackages = await multiSelect("Select packages to publish:", packages.map((pkg) => ({
@@ -1115,18 +1098,14 @@ async function main() {
1115
1098
  console.log("");
1116
1099
  }
1117
1100
  const currentVersion = packages[0].version;
1118
- console.log(bold(cyan("Step 1:")) + " Version Management");
1119
- console.log(dim("─".repeat(30)));
1120
- console.log("");
1121
- console.log(`Current version: ${yellow(currentVersion)}`);
1122
- console.log("");
1123
1101
  let newVersion = currentVersion;
1102
+ let didBump = false;
1124
1103
  if (options.version) {
1125
1104
  const bumpTypes = ["patch", "minor", "major"];
1126
1105
  const isBumpType = bumpTypes.includes(options.version);
1127
1106
  if (isBumpType) {
1128
1107
  newVersion = bumpVersion(currentVersion, options.version);
1129
- console.log(`Bumping version (${options.version}): ${yellow(currentVersion)} → ${green(newVersion)}`);
1108
+ didBump = true;
1130
1109
  } else {
1131
1110
  const cleaned = options.version.startsWith("v") ? options.version.slice(1) : options.version;
1132
1111
  if (!isValidVersion(cleaned)) {
@@ -1135,45 +1114,18 @@ async function main() {
1135
1114
  process.exit(1);
1136
1115
  }
1137
1116
  newVersion = cleaned;
1138
- console.log(`Using explicit version: ${green(newVersion)}`);
1139
- }
1140
- console.log("");
1141
- console.log(`Updating version to ${green(newVersion)} in all packages...`);
1142
- console.log("");
1143
- for (const pkg of packages) {
1144
- await updatePackageVersion(pkg, newVersion, options.dryRun);
1117
+ didBump = true;
1145
1118
  }
1146
- await updateLocalDependencyVersions(packages, newVersion, options.dryRun);
1147
- for (const pkg of packages) {
1148
- pkg.version = newVersion;
1149
- }
1150
- const commitResult = await commitVersionBump(newVersion, cwd, options.dryRun);
1151
- if (!commitResult.success) {
1152
- console.error(red(bold("Failed to commit version bump:")) + ` ${commitResult.error}`);
1153
- closePrompt();
1154
- process.exit(1);
1155
- }
1156
- console.log("");
1157
1119
  } else if (!skipAllPrompts) {
1120
+ console.log(`Current version: ${yellow(currentVersion)}`);
1121
+ console.log("");
1158
1122
  const shouldBump = skipConfirms || await confirm("Bump version before publishing?");
1159
1123
  if (shouldBump) {
1160
1124
  const bumpChoice = await select("Select version bump type:", [
1161
- {
1162
- label: `patch (${previewBump(currentVersion, "patch")})`,
1163
- value: "patch"
1164
- },
1165
- {
1166
- label: `minor (${previewBump(currentVersion, "minor")})`,
1167
- value: "minor"
1168
- },
1169
- {
1170
- label: `major (${previewBump(currentVersion, "major")})`,
1171
- value: "major"
1172
- },
1173
- {
1174
- label: "custom version",
1175
- value: "custom"
1176
- }
1125
+ { label: `patch (${previewBump(currentVersion, "patch")})`, value: "patch" },
1126
+ { label: `minor (${previewBump(currentVersion, "minor")})`, value: "minor" },
1127
+ { label: `major (${previewBump(currentVersion, "major")})`, value: "major" },
1128
+ { label: "custom version", value: "custom" }
1177
1129
  ]);
1178
1130
  if (bumpChoice === "custom") {
1179
1131
  let customVersion = "";
@@ -1190,24 +1142,34 @@ async function main() {
1190
1142
  } else {
1191
1143
  newVersion = bumpVersion(currentVersion, bumpChoice);
1192
1144
  }
1193
- console.log("");
1194
- console.log(`Updating version to ${green(newVersion)} in all packages...`);
1195
- console.log("");
1196
- for (const pkg of packages) {
1197
- await updatePackageVersion(pkg, newVersion, options.dryRun);
1198
- }
1199
- await updateLocalDependencyVersions(packages, newVersion, options.dryRun);
1200
- for (const pkg of packages) {
1201
- pkg.version = newVersion;
1202
- }
1203
- const commitResult = await commitVersionBump(newVersion, cwd, options.dryRun);
1204
- if (!commitResult.success) {
1205
- console.error(red(bold("Failed to commit version bump:")) + ` ${commitResult.error}`);
1206
- closePrompt();
1207
- process.exit(1);
1208
- }
1209
- console.log("");
1145
+ didBump = true;
1210
1146
  }
1147
+ console.log("");
1148
+ }
1149
+ if (didBump) {
1150
+ frameHeader("\uD83D\uDD16 Version");
1151
+ if (options.version && ["patch", "minor", "major"].includes(options.version)) {
1152
+ frameLine(`Bumping (${options.version}): ${yellow(currentVersion)} → ${green(newVersion)}`);
1153
+ } else {
1154
+ frameLine(`${yellow(currentVersion)} → ${green(newVersion)}`);
1155
+ }
1156
+ frameLine(dim("Updating all packages..."));
1157
+ for (const pkg of packages) {
1158
+ await updatePackageVersion(pkg, newVersion, options.dryRun);
1159
+ }
1160
+ await updateLocalDependencyVersions(packages, newVersion, options.dryRun);
1161
+ for (const pkg of packages) {
1162
+ pkg.version = newVersion;
1163
+ }
1164
+ const commitResult = await commitVersionBump(newVersion, cwd, options.dryRun);
1165
+ if (!commitResult.success) {
1166
+ frameFooter();
1167
+ console.error(red(bold("Failed to commit version bump:")) + ` ${commitResult.error}`);
1168
+ closePrompt();
1169
+ process.exit(1);
1170
+ }
1171
+ frameFooter();
1172
+ console.log("");
1211
1173
  }
1212
1174
  let registry = options.registry;
1213
1175
  if (!registry && !skipAllPrompts) {
@@ -1221,62 +1183,31 @@ async function main() {
1221
1183
  value: REGISTRIES.github
1222
1184
  }
1223
1185
  ]);
1224
- }
1225
- registry = registry || REGISTRIES.npm;
1226
- console.log("");
1227
- console.log(`Publishing to: ${cyan(registry)}`);
1228
- console.log("");
1229
- if (!options.dryRun && !options.ci) {
1230
- console.log(cyan("Verifying npm authentication..."));
1231
- const authResult = await checkNpmAuth(registry);
1232
- if (!authResult.authenticated) {
1233
- console.log("");
1234
- console.log(yellow("Not logged in to npm.") + " Starting login...");
1235
- console.log("");
1236
- pausePrompt();
1237
- const loginResult = await npmLogin(registry);
1238
- resetPrompt();
1239
- if (!loginResult.success) {
1240
- console.error(red(bold("Login failed:")) + ` ${loginResult.error}`);
1241
- closePrompt();
1242
- process.exit(1);
1243
- }
1244
- const verifyAuth = await checkNpmAuth(registry);
1245
- if (!verifyAuth.authenticated) {
1246
- console.error(red(bold("Error:")) + " Login did not complete successfully.");
1247
- closePrompt();
1248
- process.exit(1);
1249
- }
1250
- console.log("");
1251
- console.log(green("Logged in as") + ` ${cyan(verifyAuth.username ?? "unknown")}`);
1252
- } else {
1253
- console.log(green("Authenticated as") + ` ${cyan(authResult.username ?? "unknown")}`);
1254
- }
1255
1186
  console.log("");
1256
1187
  }
1188
+ registry = registry || REGISTRIES.npm;
1257
1189
  if (!options.skipBuild) {
1258
- console.log(bold(cyan("Step 2:")) + " Building Packages");
1259
- console.log(dim("".repeat(30)));
1260
- console.log("");
1190
+ frameHeader("\uD83C\uDFD7️ Build");
1191
+ frameLine(dim("Running bun run build..."));
1192
+ frameLine();
1261
1193
  const buildResult = await runBuild(cwd, options.dryRun);
1262
1194
  if (!buildResult.success) {
1195
+ frameFooter();
1263
1196
  console.error(red(bold("Build failed:")) + ` ${buildResult.error}`);
1264
1197
  closePrompt();
1265
1198
  process.exit(1);
1266
1199
  }
1267
- console.log("");
1268
- console.log(cyan("Verifying builds..."));
1269
- console.log("");
1270
1200
  let allBuildsVerified = true;
1271
1201
  for (const pkg of packages) {
1272
1202
  const result = await verifyBuild(pkg);
1273
1203
  if (result.success) {
1274
- console.log(` ${green("✓")} ${pkg.name} build verified`);
1204
+ frameLine(` ${green("✓")} ${pkg.name}`);
1275
1205
  } else {
1276
- console.error(` ${red("✗")} ${pkg.name}: ${result.error}`);
1206
+ frameLine(` ${red("✗")} ${pkg.name}: ${result.error}`);
1277
1207
  allBuildsVerified = false;
1278
1208
  }
1279
1209
  }
1210
+ frameFooter();
1280
1211
  console.log("");
1281
1212
  if (!allBuildsVerified) {
1282
1213
  console.error(red("Build verification failed.") + muted(" Please fix the issues and try again."));
@@ -1284,21 +1215,16 @@ async function main() {
1284
1215
  process.exit(1);
1285
1216
  }
1286
1217
  }
1287
- console.log(bold(cyan("Step 3:")) + " Publishing to npm");
1288
- console.log(dim("─".repeat(30)));
1289
- console.log("");
1290
1218
  if (options.dryRun) {
1291
- console.log(yellow("[DRY RUN]") + ` Would publish the following packages to ${cyan(registry)}:`);
1219
+ console.log(yellow("[DRY RUN]") + ` Would publish to ${cyan(registry)}:`);
1292
1220
  } else {
1293
- console.log("About to publish the following packages:");
1221
+ console.log(`Publishing to ${cyan(registry)}:`);
1294
1222
  }
1295
1223
  console.log("");
1296
1224
  for (const pkg of packages) {
1297
1225
  console.log(` ${dim("•")} ${cyan(pkg.name)}${dim("@")}${yellow(newVersion)}`);
1298
1226
  }
1299
1227
  console.log("");
1300
- console.log(`Registry: ${cyan(registry)}`);
1301
- console.log("");
1302
1228
  if (!options.dryRun && !skipConfirms) {
1303
1229
  const shouldContinue = await confirm("Continue?");
1304
1230
  if (!shouldContinue) {
@@ -1308,14 +1234,38 @@ async function main() {
1308
1234
  }
1309
1235
  console.log("");
1310
1236
  }
1311
- console.log(cyan("Preparing packages for publish..."));
1312
- console.log("");
1313
- const workspaceTransforms = await transformWorkspaceProtocolForPublish(packages, newVersion, options.dryRun);
1314
- if (workspaceTransforms.length > 0 || options.dryRun) {
1315
- console.log("");
1237
+ frameHeader("\uD83D\uDE80 Publish");
1238
+ if (!options.dryRun && !options.ci) {
1239
+ frameLine(dim("Verifying authentication..."));
1240
+ const authResult = await checkNpmAuth(registry);
1241
+ if (!authResult.authenticated) {
1242
+ frameLine(yellow("Not authenticated.") + dim(" Starting login..."));
1243
+ frameLine();
1244
+ pausePrompt();
1245
+ const loginResult = await npmLogin(registry);
1246
+ resetPrompt();
1247
+ if (!loginResult.success) {
1248
+ frameFooter();
1249
+ console.error(red(bold("Login failed:")) + ` ${loginResult.error}`);
1250
+ closePrompt();
1251
+ process.exit(1);
1252
+ }
1253
+ const verifyAuth = await checkNpmAuth(registry);
1254
+ if (!verifyAuth.authenticated) {
1255
+ frameFooter();
1256
+ console.error(red(bold("Error:")) + " Login did not complete successfully.");
1257
+ closePrompt();
1258
+ process.exit(1);
1259
+ }
1260
+ frameLine(green("Logged in as") + ` ${cyan(verifyAuth.username ?? "unknown")}`);
1261
+ frameLine();
1262
+ } else {
1263
+ frameLine(dim(`Authenticated as ${cyan(authResult.username ?? "unknown")}`));
1264
+ frameLine();
1265
+ }
1316
1266
  }
1317
- console.log(cyan("Publishing packages..."));
1318
- console.log("");
1267
+ frameLine(dim("Preparing packages..."));
1268
+ const workspaceTransforms = await transformWorkspaceProtocolForPublish(packages, newVersion, options.dryRun);
1319
1269
  const publishContext = {
1320
1270
  otp: options.otp,
1321
1271
  useBrowserAuth: !options.ci,
@@ -1327,6 +1277,11 @@ async function main() {
1327
1277
  let failedError = "";
1328
1278
  try {
1329
1279
  for (const pkg of packages) {
1280
+ if (options.dryRun) {
1281
+ frameLine(` ${dim("[dry run]")} ${cyan(pkg.name)}${dim("@")}${yellow(newVersion)}`);
1282
+ } else {
1283
+ frameLine(dim(` Publishing ${pkg.name}...`));
1284
+ }
1330
1285
  const result = await publishPackage(pkg, registry, publishContext, options.dryRun);
1331
1286
  if (!result.success) {
1332
1287
  publishFailed = true;
@@ -1334,107 +1289,114 @@ async function main() {
1334
1289
  failedError = result.error ?? "Unknown error";
1335
1290
  break;
1336
1291
  }
1292
+ if (!options.dryRun) {
1293
+ frameLine(` ${green("✓")} ${cyan(pkg.name)}${dim("@")}${yellow(newVersion)}`);
1294
+ }
1337
1295
  }
1338
1296
  } finally {
1339
1297
  if (workspaceTransforms.length > 0) {
1340
- console.log("");
1341
1298
  await restoreWorkspaceProtocol(workspaceTransforms);
1342
1299
  }
1343
1300
  }
1344
1301
  if (publishFailed) {
1302
+ frameFooter();
1345
1303
  console.error(red(bold("Failed to publish")) + ` ${cyan(failedPackageName)}: ${failedError}`);
1346
1304
  console.log("");
1347
- console.log(red("Stopping publish process."));
1305
+ console.error(red("Stopping publish process."));
1348
1306
  closePrompt();
1349
1307
  process.exit(1);
1350
1308
  }
1309
+ frameFooter();
1310
+ console.log("");
1351
1311
  if (options.dryRun) {
1352
- console.log("");
1353
1312
  console.log(muted("Run without --dry-run to actually publish."));
1313
+ console.log("");
1354
1314
  }
1355
- console.log("");
1356
- console.log(dim("═".repeat(30)));
1357
- console.log(green(bold("Publishing complete!")));
1358
- console.log("");
1359
- console.log(`Published version: ${green(bold(newVersion))}`);
1315
+ console.log("" + green(bold(`Published v${newVersion}!`)));
1360
1316
  console.log("");
1361
1317
  const changelog = await generateChangelog(cwd);
1362
1318
  if (changelog.terminal) {
1363
- console.log(bold("Changes since ") + cyan(changelog.previousTag ?? "initial") + bold(":"));
1364
- console.log(changelog.terminal);
1319
+ frameHeader("\uD83D\uDCCB Changelog");
1320
+ frameLine(dim(`Since ${changelog.previousTag ?? "initial"}`));
1321
+ for (const line of changelog.terminal.split(`
1322
+ `)) {
1323
+ frameLine(line.trimStart());
1324
+ }
1325
+ frameFooter();
1365
1326
  console.log("");
1366
1327
  }
1367
1328
  let releaseNotes = changelog.markdown;
1368
- if (!options.ci && changelog.commits.length > 0) {
1329
+ if (changelog.commits.length > 0) {
1369
1330
  const claudeAvailable = await isClaudeAvailable();
1370
1331
  if (claudeAvailable) {
1371
- const useAI = await confirm("Generate release notes with AI (claude)?");
1332
+ const useAI = skipConfirms || await confirm("Generate release notes with AI (claude)?");
1372
1333
  if (useAI) {
1373
- console.log(cyan("Generating AI release notes..."));
1334
+ console.log("");
1335
+ frameHeader("✨ AI Release Notes");
1336
+ frameLine(dim("Generating..."));
1374
1337
  const aiNotes = await generateAIReleaseNotes(changelog.commits, newVersion);
1375
1338
  if (aiNotes) {
1376
1339
  releaseNotes = aiNotes;
1377
- console.log("");
1378
- console.log(bold("AI-generated release notes:"));
1379
- console.log(aiNotes);
1380
- console.log("");
1340
+ frameLine();
1341
+ for (const line of aiNotes.split(`
1342
+ `)) {
1343
+ frameLine(line);
1344
+ }
1381
1345
  } else {
1382
- console.log(yellow("AI generation failed, falling back to commit list.") + dim(" (run with --verbose for details)"));
1346
+ frameLine(yellow("Generation failed, falling back to commit list.") + dim(" (run with --verbose for details)"));
1383
1347
  }
1348
+ frameFooter();
1349
+ console.log("");
1384
1350
  }
1385
1351
  }
1386
1352
  }
1387
1353
  if (!options.dryRun) {
1354
+ let shouldTag;
1355
+ let shouldPush = false;
1356
+ let shouldRelease = false;
1388
1357
  if (options.ci) {
1389
- console.log(cyan("Creating git tag..."));
1390
- const tagResult = await createGitTag(newVersion, cwd, options.dryRun);
1391
- if (tagResult.success) {
1392
- console.log(cyan("Pushing tag to origin..."));
1393
- await pushGitTag(newVersion, cwd, options.dryRun);
1394
- if (releaseNotes) {
1395
- console.log(cyan("Creating GitHub release..."));
1396
- const releaseResult = await createGitHubRelease(newVersion, releaseNotes, cwd, options.dryRun);
1397
- if (releaseResult.success && releaseResult.url) {
1398
- console.log(` Release created: ${cyan(releaseResult.url)}`);
1399
- } else if (!releaseResult.success) {
1400
- console.error(yellow(releaseResult.error ?? "Failed to create GitHub release"));
1401
- }
1402
- }
1403
- } else {
1404
- console.error(red(tagResult.error ?? "Failed to create git tag"));
1405
- }
1406
- console.log("");
1358
+ shouldTag = true;
1359
+ shouldPush = true;
1360
+ shouldRelease = !!releaseNotes;
1407
1361
  } else {
1408
- const shouldTag = skipConfirms || await confirm(`Create a git tag for ${cyan(`v${newVersion}`)}?`);
1362
+ shouldTag = skipConfirms || await confirm(`Create a git tag for ${cyan(`v${newVersion}`)}?`);
1409
1363
  if (shouldTag) {
1364
+ shouldPush = skipConfirms || await confirm("Push tag to origin?");
1365
+ if (shouldPush && releaseNotes) {
1366
+ shouldRelease = skipConfirms || await confirm("Create a GitHub release?");
1367
+ }
1368
+ }
1369
+ if (shouldTag)
1410
1370
  console.log("");
1411
- const tagResult = await createGitTag(newVersion, cwd, options.dryRun);
1412
- if (tagResult.success) {
1413
- const shouldPush = skipConfirms || await confirm("Push tag to origin?");
1414
- if (shouldPush) {
1415
- await pushGitTag(newVersion, cwd, options.dryRun);
1416
- if (releaseNotes) {
1417
- const shouldRelease = skipConfirms || await confirm("Create a GitHub release?");
1418
- if (shouldRelease) {
1419
- const releaseResult = await createGitHubRelease(newVersion, releaseNotes, cwd, options.dryRun);
1420
- if (releaseResult.success && releaseResult.url) {
1421
- console.log(` Release created: ${cyan(releaseResult.url)}`);
1422
- } else if (!releaseResult.success) {
1423
- console.error(yellow(releaseResult.error ?? "Failed to create GitHub release"));
1424
- }
1425
- }
1371
+ }
1372
+ if (shouldTag) {
1373
+ frameHeader("\uD83C\uDFF7️ Release");
1374
+ frameLine(dim(`Creating tag v${newVersion}...`));
1375
+ const tagResult = await createGitTag(newVersion, cwd, options.dryRun);
1376
+ if (tagResult.success) {
1377
+ if (shouldPush) {
1378
+ frameLine(dim("Pushing tag to origin..."));
1379
+ await pushGitTag(newVersion, cwd, options.dryRun);
1380
+ if (releaseNotes && shouldRelease) {
1381
+ frameLine(dim("Creating GitHub release..."));
1382
+ const releaseResult = await createGitHubRelease(newVersion, releaseNotes, cwd, options.dryRun);
1383
+ if (releaseResult.success && releaseResult.url) {
1384
+ frameLine(` Release: ${cyan(releaseResult.url)}`);
1385
+ } else if (!releaseResult.success) {
1386
+ frameLine(yellow(releaseResult.error ?? "Failed to create GitHub release"));
1426
1387
  }
1427
- } else {
1428
- console.log(`Tag created locally. Push manually with: ${dim(`git push origin v${newVersion}`)}`);
1429
1388
  }
1430
1389
  } else {
1431
- console.error(red(tagResult.error ?? "Failed to create git tag"));
1390
+ frameLine(`Push manually: ${dim(`git push origin v${newVersion}`)}`);
1432
1391
  }
1433
- console.log("");
1392
+ } else {
1393
+ frameLine(red(tagResult.error ?? "Failed to create git tag"));
1434
1394
  }
1395
+ frameFooter();
1396
+ console.log("");
1435
1397
  }
1436
1398
  }
1437
- console.log(green(bold("Done!")));
1399
+ console.log("\uD83C\uDF89 " + green(bold("Done!")));
1438
1400
  closePrompt();
1439
1401
  }
1440
1402
  main().catch((error) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pubz",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Interactive CLI for publishing npm packages (single or monorepo)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,6 +12,7 @@
12
12
  "scripts": {
13
13
  "build": "bun build src/cli.ts --outdir dist --target node",
14
14
  "dev": "bun run src/cli.ts",
15
+ "demo": "bun .kadai/actions/gen-demo.ts",
15
16
  "typecheck": "tsc --noEmit",
16
17
  "lint": "bunx biome check src/",
17
18
  "lint:fix": "bunx biome check --write src/"