pubz 0.6.0 → 0.7.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.
Files changed (3) hide show
  1. package/README.md +69 -113
  2. package/dist/cli.js +322 -272
  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
@@ -3,8 +3,8 @@ import { createRequire } from "node:module";
3
3
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
4
4
 
5
5
  // src/cli.ts
6
- import { readFileSync } from "node:fs";
7
- import { dirname, join as join5 } from "node:path";
6
+ import { readFileSync as readFileSync2 } from "node:fs";
7
+ import { dirname, join as join6 } from "node:path";
8
8
  import { fileURLToPath } from "node:url";
9
9
 
10
10
  // src/colors.ts
@@ -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,
@@ -805,6 +805,54 @@ async function createGitHubRelease(version, body, cwd, dryRun) {
805
805
  return { success: true, url };
806
806
  }
807
807
 
808
+ // src/config.ts
809
+ import { existsSync, readFileSync } from "node:fs";
810
+ import { join as join5 } from "node:path";
811
+ var CONFIG_FILENAME = ".pubz";
812
+ var VALID_KEYS = new Set(["skip-build", "skip-publish", "registry"]);
813
+ function loadConfig(cwd) {
814
+ const configPath = join5(cwd, CONFIG_FILENAME);
815
+ if (!existsSync(configPath)) {
816
+ debug(`No ${CONFIG_FILENAME} found at ${configPath}`);
817
+ return {};
818
+ }
819
+ const content = readFileSync(configPath, "utf-8");
820
+ const config = {};
821
+ for (const rawLine of content.split(`
822
+ `)) {
823
+ const line = rawLine.trim();
824
+ if (!line || line.startsWith("#"))
825
+ continue;
826
+ const eqIndex = line.indexOf("=");
827
+ let key;
828
+ let value;
829
+ if (eqIndex === -1) {
830
+ key = line;
831
+ } else {
832
+ key = line.slice(0, eqIndex).trim();
833
+ value = line.slice(eqIndex + 1).trim();
834
+ }
835
+ if (!VALID_KEYS.has(key)) {
836
+ debug(`Ignoring unknown config key: ${key}`);
837
+ continue;
838
+ }
839
+ if (key === "registry") {
840
+ config.registry = value ?? "";
841
+ } else {
842
+ const boolKey = key;
843
+ if (value === undefined || value === "true") {
844
+ config[boolKey] = true;
845
+ } else if (value === "false") {
846
+ config[boolKey] = false;
847
+ } else {
848
+ debug(`Invalid boolean value for ${key}: ${value}`);
849
+ }
850
+ }
851
+ }
852
+ debug(`Loaded ${CONFIG_FILENAME}: ${JSON.stringify(config)}`);
853
+ return config;
854
+ }
855
+
808
856
  // src/version.ts
809
857
  import { readFile as readFile4, writeFile } from "node:fs/promises";
810
858
  async function transformWorkspaceProtocolForPublish(packages, newVersion, dryRun) {
@@ -828,9 +876,7 @@ async function transformWorkspaceProtocolForPublish(packages, newVersion, dryRun
828
876
  if (oldVersion.startsWith("workspace:")) {
829
877
  const modifier = oldVersion.replace("workspace:", "");
830
878
  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 {
879
+ if (!dryRun) {
834
880
  transforms.push({
835
881
  packageJsonPath: pkg.packageJsonPath,
836
882
  depType,
@@ -847,7 +893,6 @@ async function transformWorkspaceProtocolForPublish(packages, newVersion, dryRun
847
893
  if (modified && !dryRun) {
848
894
  await writeFile(pkg.packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
849
895
  `);
850
- console.log(` Transformed workspace references in ${pkg.name}`);
851
896
  }
852
897
  }
853
898
  return transforms;
@@ -871,9 +916,6 @@ async function restoreWorkspaceProtocol(transforms) {
871
916
  await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
872
917
  `);
873
918
  }
874
- if (transforms.length > 0) {
875
- console.log(` Restored workspace references in ${byPath.size} package(s)`);
876
- }
877
919
  }
878
920
  function isValidVersion(version) {
879
921
  return /^\d+\.\d+\.\d+(-.+)?$/.test(version);
@@ -900,12 +942,10 @@ async function updatePackageVersion(pkg, newVersion, dryRun) {
900
942
  const packageJson = JSON.parse(content);
901
943
  packageJson.version = newVersion;
902
944
  if (dryRun) {
903
- console.log(` [DRY RUN] Would update ${pkg.name}: ${pkg.version} -> ${newVersion}`);
904
945
  return;
905
946
  }
906
947
  await writeFile(pkg.packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
907
948
  `);
908
- console.log(` Updated ${pkg.name}: ${pkg.version} -> ${newVersion}`);
909
949
  }
910
950
  async function updateLocalDependencyVersions(packages, newVersion, dryRun) {
911
951
  const packageNames = new Set(packages.map((p) => p.name));
@@ -928,13 +968,9 @@ async function updateLocalDependencyVersions(packages, newVersion, dryRun) {
928
968
  continue;
929
969
  }
930
970
  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
- }
971
+ if (deps[depName] !== newVersionSpec && !dryRun) {
972
+ deps[depName] = newVersionSpec;
973
+ modified = true;
938
974
  }
939
975
  }
940
976
  }
@@ -942,7 +978,6 @@ async function updateLocalDependencyVersions(packages, newVersion, dryRun) {
942
978
  if (modified && !dryRun) {
943
979
  await writeFile(pkg.packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
944
980
  `);
945
- console.log(` Updated local dependency versions in ${pkg.name}`);
946
981
  }
947
982
  }
948
983
  }
@@ -954,13 +989,12 @@ var REGISTRIES = {
954
989
  };
955
990
  function getVersion() {
956
991
  const __dirname2 = dirname(fileURLToPath(import.meta.url));
957
- const pkgPath = join5(__dirname2, "..", "package.json");
958
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
992
+ const pkgPath = join6(__dirname2, "..", "package.json");
993
+ const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
959
994
  return pkg.version;
960
995
  }
961
996
  function printUsage() {
962
- console.log(`
963
- pubz - Interactive npm package publisher
997
+ console.log(`pubz - Interactive npm package publisher
964
998
 
965
999
  Usage: pubz [command] [options]
966
1000
 
@@ -972,6 +1006,7 @@ Options:
972
1006
  --registry <url> Specify npm registry URL (default: public npm)
973
1007
  --otp <code> One-time password for 2FA
974
1008
  --skip-build Skip the build step
1009
+ --skip-publish Skip npm publish (still does version bump, tag, and release)
975
1010
  --yes, -y Skip yes/no confirmation prompts (still asks for choices)
976
1011
  --ci CI mode: skip all prompts, auto-accept everything
977
1012
  --version <value> Version bump type (patch|minor|major) or explicit version (required with --ci)
@@ -982,8 +1017,18 @@ Examples:
982
1017
  pubz # Interactive publish
983
1018
  pubz --dry-run # Preview what would happen
984
1019
  pubz --registry https://npm.pkg.github.com # Publish to GitHub Packages
1020
+ pubz --skip-publish # Version bump, tag, release — no npm publish
985
1021
  pubz --ci --version patch # CI mode with patch bump
986
1022
  pubz --ci --version 1.2.3 # CI mode with explicit version
1023
+ pubz --ci --version patch --skip-publish # CI: bump, tag, release without npm publish
1024
+
1025
+ Config file:
1026
+ Place a .pubz file in your project root to set default options.
1027
+ CLI flags always override config values.
1028
+
1029
+ # .pubz
1030
+ skip-publish
1031
+ registry=https://npm.pkg.github.com
987
1032
  `);
988
1033
  }
989
1034
  function parseArgs(args) {
@@ -992,39 +1037,53 @@ function parseArgs(args) {
992
1037
  registry: "",
993
1038
  otp: "",
994
1039
  skipBuild: false,
1040
+ skipPublish: false,
995
1041
  skipConfirms: false,
996
1042
  ci: false,
997
1043
  version: "",
998
1044
  verbose: false,
999
1045
  help: false
1000
1046
  };
1047
+ const cliExplicit = new Set;
1001
1048
  for (let i = 0;i < args.length; i++) {
1002
1049
  const arg = args[i];
1003
1050
  switch (arg) {
1004
1051
  case "--dry-run":
1005
1052
  options.dryRun = true;
1053
+ cliExplicit.add("dryRun");
1006
1054
  break;
1007
1055
  case "--registry":
1008
1056
  options.registry = args[++i] || "";
1057
+ cliExplicit.add("registry");
1009
1058
  break;
1010
1059
  case "--otp":
1011
1060
  options.otp = args[++i] || "";
1061
+ cliExplicit.add("otp");
1012
1062
  break;
1013
1063
  case "--skip-build":
1014
1064
  options.skipBuild = true;
1065
+ cliExplicit.add("skipBuild");
1066
+ break;
1067
+ case "--skip-publish":
1068
+ options.skipPublish = true;
1069
+ cliExplicit.add("skipPublish");
1015
1070
  break;
1016
1071
  case "--yes":
1017
1072
  case "-y":
1018
1073
  options.skipConfirms = true;
1074
+ cliExplicit.add("skipConfirms");
1019
1075
  break;
1020
1076
  case "--ci":
1021
1077
  options.ci = true;
1078
+ cliExplicit.add("ci");
1022
1079
  break;
1023
1080
  case "--version":
1024
1081
  options.version = args[++i] || "";
1082
+ cliExplicit.add("version");
1025
1083
  break;
1026
1084
  case "--verbose":
1027
1085
  options.verbose = true;
1086
+ cliExplicit.add("verbose");
1028
1087
  break;
1029
1088
  case "-h":
1030
1089
  case "--help":
@@ -1032,19 +1091,30 @@ function parseArgs(args) {
1032
1091
  break;
1033
1092
  }
1034
1093
  }
1035
- return options;
1094
+ return { options, cliExplicit };
1036
1095
  }
1037
1096
  async function main() {
1038
1097
  if (process.argv[2] === "version") {
1039
1098
  console.log(getVersion());
1040
1099
  process.exit(0);
1041
1100
  }
1042
- const options = parseArgs(process.argv.slice(2));
1101
+ const { options, cliExplicit } = parseArgs(process.argv.slice(2));
1043
1102
  setVerbose(options.verbose);
1044
1103
  if (options.help) {
1045
1104
  printUsage();
1046
1105
  process.exit(0);
1047
1106
  }
1107
+ const cwd = process.cwd();
1108
+ const config = loadConfig(cwd);
1109
+ if (config["skip-build"] && !cliExplicit.has("skipBuild")) {
1110
+ options.skipBuild = config["skip-build"];
1111
+ }
1112
+ if (config["skip-publish"] && !cliExplicit.has("skipPublish")) {
1113
+ options.skipPublish = config["skip-publish"];
1114
+ }
1115
+ if (config.registry && !cliExplicit.has("registry")) {
1116
+ options.registry = config.registry;
1117
+ }
1048
1118
  if (options.ci && !options.version) {
1049
1119
  console.error(red(bold("Error:")) + " --ci requires --version to be specified");
1050
1120
  console.log("");
@@ -1057,17 +1127,15 @@ async function main() {
1057
1127
  }
1058
1128
  const skipConfirms = options.skipConfirms || options.ci;
1059
1129
  const skipAllPrompts = options.ci;
1060
- const cwd = process.cwd();
1061
1130
  if (options.dryRun) {
1062
- console.log(yellow(bold("DRY RUN MODE")) + dim(" - No actual changes will be made"));
1131
+ console.log(yellow(bold("⚠️ DRY RUN")) + dim(" no actual changes will be made"));
1063
1132
  console.log("");
1064
1133
  }
1065
- console.log(bold("pubz") + dim(" - npm package publisher"));
1066
- console.log(dim("═".repeat(30)));
1134
+ console.log("\uD83D\uDCE6 " + bold("pubz") + dim(" npm package publisher"));
1067
1135
  console.log("");
1068
1136
  const uncommitted = await hasUncommittedChanges(cwd);
1069
1137
  if (uncommitted.hasChanges && !options.dryRun) {
1070
- console.log(red(bold("Error:")) + " You have uncommitted changes:");
1138
+ console.error(red(bold("Error:")) + " You have uncommitted changes:");
1071
1139
  console.log("");
1072
1140
  for (const file of uncommitted.files.slice(0, 10)) {
1073
1141
  console.log(` ${yellow(file)}`);
@@ -1080,8 +1148,6 @@ async function main() {
1080
1148
  closePrompt();
1081
1149
  process.exit(1);
1082
1150
  }
1083
- console.log(cyan("Discovering packages..."));
1084
- console.log("");
1085
1151
  let packages = await discoverPackages(cwd);
1086
1152
  const publishablePackages = packages.filter((p) => !p.isPrivate);
1087
1153
  if (publishablePackages.length === 0) {
@@ -1094,12 +1160,12 @@ async function main() {
1094
1160
  process.exit(1);
1095
1161
  }
1096
1162
  packages = sortByDependencyOrder(publishablePackages);
1097
- console.log(`Found ${green(bold(String(packages.length)))} publishable package(s):`);
1098
- console.log("");
1163
+ frameHeader("Packages");
1099
1164
  for (const pkg of packages) {
1100
1165
  const deps = pkg.localDependencies.length > 0 ? dim(` (depends on: ${pkg.localDependencies.join(", ")})`) : "";
1101
- console.log(` ${dim("•")} ${cyan(pkg.name)}${dim("@")}${yellow(pkg.version)}${deps}`);
1166
+ frameLine(`${dim("•")} ${cyan(pkg.name)}${dim("@")}${yellow(pkg.version)}${deps}`);
1102
1167
  }
1168
+ frameFooter();
1103
1169
  console.log("");
1104
1170
  if (packages.length > 1 && !skipAllPrompts) {
1105
1171
  const selectedPackages = await multiSelect("Select packages to publish:", packages.map((pkg) => ({
@@ -1115,18 +1181,14 @@ async function main() {
1115
1181
  console.log("");
1116
1182
  }
1117
1183
  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
1184
  let newVersion = currentVersion;
1185
+ let didBump = false;
1124
1186
  if (options.version) {
1125
1187
  const bumpTypes = ["patch", "minor", "major"];
1126
1188
  const isBumpType = bumpTypes.includes(options.version);
1127
1189
  if (isBumpType) {
1128
1190
  newVersion = bumpVersion(currentVersion, options.version);
1129
- console.log(`Bumping version (${options.version}): ${yellow(currentVersion)} → ${green(newVersion)}`);
1191
+ didBump = true;
1130
1192
  } else {
1131
1193
  const cleaned = options.version.startsWith("v") ? options.version.slice(1) : options.version;
1132
1194
  if (!isValidVersion(cleaned)) {
@@ -1135,45 +1197,18 @@ async function main() {
1135
1197
  process.exit(1);
1136
1198
  }
1137
1199
  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);
1145
- }
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);
1200
+ didBump = true;
1155
1201
  }
1156
- console.log("");
1157
1202
  } else if (!skipAllPrompts) {
1203
+ console.log(`Current version: ${yellow(currentVersion)}`);
1204
+ console.log("");
1158
1205
  const shouldBump = skipConfirms || await confirm("Bump version before publishing?");
1159
1206
  if (shouldBump) {
1160
1207
  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
- }
1208
+ { label: `patch (${previewBump(currentVersion, "patch")})`, value: "patch" },
1209
+ { label: `minor (${previewBump(currentVersion, "minor")})`, value: "minor" },
1210
+ { label: `major (${previewBump(currentVersion, "major")})`, value: "major" },
1211
+ { label: "custom version", value: "custom" }
1177
1212
  ]);
1178
1213
  if (bumpChoice === "custom") {
1179
1214
  let customVersion = "";
@@ -1190,93 +1225,57 @@ async function main() {
1190
1225
  } else {
1191
1226
  newVersion = bumpVersion(currentVersion, bumpChoice);
1192
1227
  }
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("");
1228
+ didBump = true;
1210
1229
  }
1230
+ console.log("");
1211
1231
  }
1212
- let registry = options.registry;
1213
- if (!registry && !skipAllPrompts) {
1214
- registry = await select("Select publish target:", [
1215
- {
1216
- label: "Public npm registry (https://registry.npmjs.org)",
1217
- value: REGISTRIES.npm
1218
- },
1219
- {
1220
- label: "GitHub Packages (https://npm.pkg.github.com)",
1221
- value: REGISTRIES.github
1222
- }
1223
- ]);
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")}`);
1232
+ if (didBump) {
1233
+ frameHeader("\uD83D\uDD16 Version");
1234
+ if (options.version && ["patch", "minor", "major"].includes(options.version)) {
1235
+ frameLine(`Bumping (${options.version}): ${yellow(currentVersion)} → ${green(newVersion)}`);
1252
1236
  } else {
1253
- console.log(green("Authenticated as") + ` ${cyan(authResult.username ?? "unknown")}`);
1237
+ frameLine(`${yellow(currentVersion)} ${green(newVersion)}`);
1238
+ }
1239
+ frameLine(dim("Updating all packages..."));
1240
+ for (const pkg of packages) {
1241
+ await updatePackageVersion(pkg, newVersion, options.dryRun);
1254
1242
  }
1243
+ await updateLocalDependencyVersions(packages, newVersion, options.dryRun);
1244
+ for (const pkg of packages) {
1245
+ pkg.version = newVersion;
1246
+ }
1247
+ const commitResult = await commitVersionBump(newVersion, cwd, options.dryRun);
1248
+ if (!commitResult.success) {
1249
+ frameFooter();
1250
+ console.error(red(bold("Failed to commit version bump:")) + ` ${commitResult.error}`);
1251
+ closePrompt();
1252
+ process.exit(1);
1253
+ }
1254
+ frameFooter();
1255
1255
  console.log("");
1256
1256
  }
1257
1257
  if (!options.skipBuild) {
1258
- console.log(bold(cyan("Step 2:")) + " Building Packages");
1259
- console.log(dim("".repeat(30)));
1260
- console.log("");
1258
+ frameHeader("\uD83C\uDFD7️ Build");
1259
+ frameLine(dim("Running bun run build..."));
1260
+ frameLine();
1261
1261
  const buildResult = await runBuild(cwd, options.dryRun);
1262
1262
  if (!buildResult.success) {
1263
+ frameFooter();
1263
1264
  console.error(red(bold("Build failed:")) + ` ${buildResult.error}`);
1264
1265
  closePrompt();
1265
1266
  process.exit(1);
1266
1267
  }
1267
- console.log("");
1268
- console.log(cyan("Verifying builds..."));
1269
- console.log("");
1270
1268
  let allBuildsVerified = true;
1271
1269
  for (const pkg of packages) {
1272
1270
  const result = await verifyBuild(pkg);
1273
1271
  if (result.success) {
1274
- console.log(` ${green("✓")} ${pkg.name} build verified`);
1272
+ frameLine(` ${green("✓")} ${pkg.name}`);
1275
1273
  } else {
1276
- console.error(` ${red("✗")} ${pkg.name}: ${result.error}`);
1274
+ frameLine(` ${red("✗")} ${pkg.name}: ${result.error}`);
1277
1275
  allBuildsVerified = false;
1278
1276
  }
1279
1277
  }
1278
+ frameFooter();
1280
1279
  console.log("");
1281
1280
  if (!allBuildsVerified) {
1282
1281
  console.error(red("Build verification failed.") + muted(" Please fix the issues and try again."));
@@ -1284,157 +1283,208 @@ async function main() {
1284
1283
  process.exit(1);
1285
1284
  }
1286
1285
  }
1287
- console.log(bold(cyan("Step 3:")) + " Publishing to npm");
1288
- console.log(dim("".repeat(30)));
1289
- console.log("");
1290
- if (options.dryRun) {
1291
- console.log(yellow("[DRY RUN]") + ` Would publish the following packages to ${cyan(registry)}:`);
1286
+ if (options.skipPublish) {
1287
+ console.log(yellow(bold("⏭️ Skipping npm publish")) + dim(" — use without --skip-publish to publish to npm"));
1288
+ console.log("");
1292
1289
  } else {
1293
- console.log("About to publish the following packages:");
1294
- }
1295
- console.log("");
1296
- for (const pkg of packages) {
1297
- console.log(` ${dim("•")} ${cyan(pkg.name)}${dim("@")}${yellow(newVersion)}`);
1298
- }
1299
- console.log("");
1300
- console.log(`Registry: ${cyan(registry)}`);
1301
- console.log("");
1302
- if (!options.dryRun && !skipConfirms) {
1303
- const shouldContinue = await confirm("Continue?");
1304
- if (!shouldContinue) {
1305
- console.log(yellow("Publish cancelled."));
1306
- closePrompt();
1307
- process.exit(0);
1290
+ let registry = options.registry;
1291
+ if (!registry && !skipAllPrompts) {
1292
+ registry = await select("Select publish target:", [
1293
+ {
1294
+ label: "Public npm registry (https://registry.npmjs.org)",
1295
+ value: REGISTRIES.npm
1296
+ },
1297
+ {
1298
+ label: "GitHub Packages (https://npm.pkg.github.com)",
1299
+ value: REGISTRIES.github
1300
+ }
1301
+ ]);
1302
+ console.log("");
1303
+ }
1304
+ registry = registry || REGISTRIES.npm;
1305
+ if (options.dryRun) {
1306
+ console.log(yellow("[DRY RUN]") + ` Would publish to ${cyan(registry)}:`);
1307
+ } else {
1308
+ console.log(`Publishing to ${cyan(registry)}:`);
1308
1309
  }
1309
1310
  console.log("");
1310
- }
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("");
1316
- }
1317
- console.log(cyan("Publishing packages..."));
1318
- console.log("");
1319
- const publishContext = {
1320
- otp: options.otp,
1321
- useBrowserAuth: !options.ci,
1322
- onInteractiveStart: pausePrompt,
1323
- onInteractiveComplete: resetPrompt
1324
- };
1325
- let publishFailed = false;
1326
- let failedPackageName = "";
1327
- let failedError = "";
1328
- try {
1329
1311
  for (const pkg of packages) {
1330
- const result = await publishPackage(pkg, registry, publishContext, options.dryRun);
1331
- if (!result.success) {
1332
- publishFailed = true;
1333
- failedPackageName = pkg.name;
1334
- failedError = result.error ?? "Unknown error";
1335
- break;
1312
+ console.log(` ${dim("•")} ${cyan(pkg.name)}${dim("@")}${yellow(newVersion)}`);
1313
+ }
1314
+ console.log("");
1315
+ if (!options.dryRun && !skipConfirms) {
1316
+ const shouldContinue = await confirm("Continue?");
1317
+ if (!shouldContinue) {
1318
+ console.log(yellow("Publish cancelled."));
1319
+ closePrompt();
1320
+ process.exit(0);
1336
1321
  }
1322
+ console.log("");
1337
1323
  }
1338
- } finally {
1339
- if (workspaceTransforms.length > 0) {
1324
+ frameHeader("\uD83D\uDE80 Publish");
1325
+ if (!options.dryRun && !options.ci) {
1326
+ frameLine(dim("Verifying authentication..."));
1327
+ const authResult = await checkNpmAuth(registry);
1328
+ if (!authResult.authenticated) {
1329
+ frameLine(yellow("Not authenticated.") + dim(" Starting login..."));
1330
+ frameLine();
1331
+ pausePrompt();
1332
+ const loginResult = await npmLogin(registry);
1333
+ resetPrompt();
1334
+ if (!loginResult.success) {
1335
+ frameFooter();
1336
+ console.error(red(bold("Login failed:")) + ` ${loginResult.error}`);
1337
+ closePrompt();
1338
+ process.exit(1);
1339
+ }
1340
+ const verifyAuth = await checkNpmAuth(registry);
1341
+ if (!verifyAuth.authenticated) {
1342
+ frameFooter();
1343
+ console.error(red(bold("Error:")) + " Login did not complete successfully.");
1344
+ closePrompt();
1345
+ process.exit(1);
1346
+ }
1347
+ frameLine(green("Logged in as") + ` ${cyan(verifyAuth.username ?? "unknown")}`);
1348
+ frameLine();
1349
+ } else {
1350
+ frameLine(dim(`Authenticated as ${cyan(authResult.username ?? "unknown")}`));
1351
+ frameLine();
1352
+ }
1353
+ }
1354
+ frameLine(dim("Preparing packages..."));
1355
+ const workspaceTransforms = await transformWorkspaceProtocolForPublish(packages, newVersion, options.dryRun);
1356
+ const publishContext = {
1357
+ otp: options.otp,
1358
+ useBrowserAuth: !options.ci,
1359
+ onInteractiveStart: pausePrompt,
1360
+ onInteractiveComplete: resetPrompt
1361
+ };
1362
+ let publishFailed = false;
1363
+ let failedPackageName = "";
1364
+ let failedError = "";
1365
+ try {
1366
+ for (const pkg of packages) {
1367
+ if (options.dryRun) {
1368
+ frameLine(` ${dim("[dry run]")} ${cyan(pkg.name)}${dim("@")}${yellow(newVersion)}`);
1369
+ } else {
1370
+ frameLine(dim(` Publishing ${pkg.name}...`));
1371
+ }
1372
+ const result = await publishPackage(pkg, registry, publishContext, options.dryRun);
1373
+ if (!result.success) {
1374
+ publishFailed = true;
1375
+ failedPackageName = pkg.name;
1376
+ failedError = result.error ?? "Unknown error";
1377
+ break;
1378
+ }
1379
+ if (!options.dryRun) {
1380
+ frameLine(` ${green("✓")} ${cyan(pkg.name)}${dim("@")}${yellow(newVersion)}`);
1381
+ }
1382
+ }
1383
+ } finally {
1384
+ if (workspaceTransforms.length > 0) {
1385
+ await restoreWorkspaceProtocol(workspaceTransforms);
1386
+ }
1387
+ }
1388
+ if (publishFailed) {
1389
+ frameFooter();
1390
+ console.error(red(bold("Failed to publish")) + ` ${cyan(failedPackageName)}: ${failedError}`);
1340
1391
  console.log("");
1341
- await restoreWorkspaceProtocol(workspaceTransforms);
1392
+ console.error(red("Stopping publish process."));
1393
+ closePrompt();
1394
+ process.exit(1);
1342
1395
  }
1343
- }
1344
- if (publishFailed) {
1345
- console.error(red(bold("Failed to publish")) + ` ${cyan(failedPackageName)}: ${failedError}`);
1396
+ frameFooter();
1346
1397
  console.log("");
1347
- console.log(red("Stopping publish process."));
1348
- closePrompt();
1349
- process.exit(1);
1350
- }
1351
- if (options.dryRun) {
1352
- console.log("");
1353
- console.log(muted("Run without --dry-run to actually publish."));
1398
+ if (options.dryRun) {
1399
+ console.log(muted("Run without --dry-run to actually publish."));
1400
+ console.log("");
1401
+ }
1354
1402
  }
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))}`);
1403
+ console.log("" + green(bold(`Released v${newVersion}!`)));
1360
1404
  console.log("");
1361
1405
  const changelog = await generateChangelog(cwd);
1362
1406
  if (changelog.terminal) {
1363
- console.log(bold("Changes since ") + cyan(changelog.previousTag ?? "initial") + bold(":"));
1364
- console.log(changelog.terminal);
1407
+ frameHeader("\uD83D\uDCCB Changelog");
1408
+ frameLine(dim(`Since ${changelog.previousTag ?? "initial"}`));
1409
+ for (const line of changelog.terminal.split(`
1410
+ `)) {
1411
+ frameLine(line.trimStart());
1412
+ }
1413
+ frameFooter();
1365
1414
  console.log("");
1366
1415
  }
1367
1416
  let releaseNotes = changelog.markdown;
1368
- if (!options.ci && changelog.commits.length > 0) {
1417
+ if (changelog.commits.length > 0) {
1369
1418
  const claudeAvailable = await isClaudeAvailable();
1370
1419
  if (claudeAvailable) {
1371
- const useAI = await confirm("Generate release notes with AI (claude)?");
1420
+ const useAI = skipConfirms || await confirm("Generate release notes with AI (claude)?");
1372
1421
  if (useAI) {
1373
- console.log(cyan("Generating AI release notes..."));
1422
+ console.log("");
1423
+ frameHeader("✨ AI Release Notes");
1424
+ frameLine(dim("Generating..."));
1374
1425
  const aiNotes = await generateAIReleaseNotes(changelog.commits, newVersion);
1375
1426
  if (aiNotes) {
1376
1427
  releaseNotes = aiNotes;
1377
- console.log("");
1378
- console.log(bold("AI-generated release notes:"));
1379
- console.log(aiNotes);
1380
- console.log("");
1428
+ frameLine();
1429
+ for (const line of aiNotes.split(`
1430
+ `)) {
1431
+ frameLine(line);
1432
+ }
1381
1433
  } else {
1382
- console.log(yellow("AI generation failed, falling back to commit list.") + dim(" (run with --verbose for details)"));
1434
+ frameLine(yellow("Generation failed, falling back to commit list.") + dim(" (run with --verbose for details)"));
1383
1435
  }
1436
+ frameFooter();
1437
+ console.log("");
1384
1438
  }
1385
1439
  }
1386
1440
  }
1387
1441
  if (!options.dryRun) {
1442
+ let shouldTag;
1443
+ let shouldPush = false;
1444
+ let shouldRelease = false;
1388
1445
  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("");
1446
+ shouldTag = true;
1447
+ shouldPush = true;
1448
+ shouldRelease = !!releaseNotes;
1407
1449
  } else {
1408
- const shouldTag = skipConfirms || await confirm(`Create a git tag for ${cyan(`v${newVersion}`)}?`);
1450
+ shouldTag = skipConfirms || await confirm(`Create a git tag for ${cyan(`v${newVersion}`)}?`);
1409
1451
  if (shouldTag) {
1452
+ shouldPush = skipConfirms || await confirm("Push tag to origin?");
1453
+ if (shouldPush && releaseNotes) {
1454
+ shouldRelease = skipConfirms || await confirm("Create a GitHub release?");
1455
+ }
1456
+ }
1457
+ if (shouldTag)
1410
1458
  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
- }
1459
+ }
1460
+ if (shouldTag) {
1461
+ frameHeader("\uD83C\uDFF7️ Release");
1462
+ frameLine(dim(`Creating tag v${newVersion}...`));
1463
+ const tagResult = await createGitTag(newVersion, cwd, options.dryRun);
1464
+ if (tagResult.success) {
1465
+ if (shouldPush) {
1466
+ frameLine(dim("Pushing tag to origin..."));
1467
+ await pushGitTag(newVersion, cwd, options.dryRun);
1468
+ if (releaseNotes && shouldRelease) {
1469
+ frameLine(dim("Creating GitHub release..."));
1470
+ const releaseResult = await createGitHubRelease(newVersion, releaseNotes, cwd, options.dryRun);
1471
+ if (releaseResult.success && releaseResult.url) {
1472
+ frameLine(` Release: ${cyan(releaseResult.url)}`);
1473
+ } else if (!releaseResult.success) {
1474
+ frameLine(yellow(releaseResult.error ?? "Failed to create GitHub release"));
1426
1475
  }
1427
- } else {
1428
- console.log(`Tag created locally. Push manually with: ${dim(`git push origin v${newVersion}`)}`);
1429
1476
  }
1430
1477
  } else {
1431
- console.error(red(tagResult.error ?? "Failed to create git tag"));
1478
+ frameLine(`Push manually: ${dim(`git push origin v${newVersion}`)}`);
1432
1479
  }
1433
- console.log("");
1480
+ } else {
1481
+ frameLine(red(tagResult.error ?? "Failed to create git tag"));
1434
1482
  }
1483
+ frameFooter();
1484
+ console.log("");
1435
1485
  }
1436
1486
  }
1437
- console.log(green(bold("Done!")));
1487
+ console.log("\uD83C\uDF89 " + green(bold("Done!")));
1438
1488
  closePrompt();
1439
1489
  }
1440
1490
  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.1",
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/"