pubz 0.5.2 → 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 +292 -257
  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
@@ -4,7 +4,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
4
4
 
5
5
  // src/cli.ts
6
6
  import { readFileSync } from "node:fs";
7
- import { dirname, join as join4 } from "node:path";
7
+ import { dirname, join as join5 } 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,12 +565,119 @@ 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
 
572
571
  // src/changelog.ts
572
+ import { spawn as spawn4 } from "node:child_process";
573
+
574
+ // src/claude.ts
573
575
  import { spawn as spawn3 } from "node:child_process";
576
+ import { readFile as readFile3 } from "node:fs/promises";
577
+ import { join as join4 } from "node:path";
578
+ async function resolveCredentials() {
579
+ const home = process.env.HOME ?? "";
580
+ if (!process.env.CLAUDE_CODE_OAUTH_TOKEN) {
581
+ try {
582
+ const tokenFile = join4(home, ".claude", "agent-oauth-token");
583
+ const token = (await readFile3(tokenFile, "utf-8")).trim();
584
+ if (token) {
585
+ process.env.CLAUDE_CODE_OAUTH_TOKEN = token;
586
+ }
587
+ } catch {}
588
+ }
589
+ if (!process.env.CLAUDE_CODE_OAUTH_TOKEN && process.platform === "darwin") {
590
+ try {
591
+ const token = await new Promise((resolve2) => {
592
+ const proc = spawn3("security", [
593
+ "find-generic-password",
594
+ "-s",
595
+ "Claude Code-credentials",
596
+ "-w"
597
+ ], { stdio: ["ignore", "pipe", "pipe"] });
598
+ let stdout = "";
599
+ proc.stdout?.on("data", (d) => {
600
+ stdout += d.toString();
601
+ });
602
+ proc.on("close", (code) => {
603
+ if (code !== 0)
604
+ return resolve2(null);
605
+ try {
606
+ const creds = JSON.parse(stdout.trim());
607
+ const accessToken = creds?.claudeAiOauth?.accessToken;
608
+ resolve2(typeof accessToken === "string" && accessToken.length > 0 ? accessToken : null);
609
+ } catch {
610
+ resolve2(null);
611
+ }
612
+ });
613
+ proc.on("error", () => resolve2(null));
614
+ });
615
+ if (token) {
616
+ process.env.CLAUDE_CODE_OAUTH_TOKEN = token;
617
+ }
618
+ } catch {}
619
+ }
620
+ if (!process.env.CLAUDE_CODE_OAUTH_TOKEN) {
621
+ try {
622
+ const raw = await readFile3(join4(home, ".claude.json"), "utf-8");
623
+ const creds = JSON.parse(raw);
624
+ const accessToken = creds?.claudeAiOauth?.accessToken;
625
+ if (typeof accessToken === "string" && accessToken.length > 0) {
626
+ process.env.CLAUDE_CODE_OAUTH_TOKEN = accessToken;
627
+ }
628
+ } catch {}
629
+ }
630
+ if (process.env.CLAUDE_CODE_OAUTH_TOKEN) {
631
+ delete process.env.ANTHROPIC_API_KEY;
632
+ }
633
+ }
634
+ async function isClaudeAvailable() {
635
+ return new Promise((resolve2) => {
636
+ const proc = spawn3("which", ["claude"], {
637
+ stdio: ["ignore", "pipe", "pipe"]
638
+ });
639
+ proc.on("close", (code) => resolve2(code === 0));
640
+ proc.on("error", () => resolve2(false));
641
+ });
642
+ }
643
+ async function runClaudePrompt(prompt2) {
644
+ await resolveCredentials();
645
+ return new Promise((resolve2) => {
646
+ const proc = spawn3("claude", ["-p", prompt2, "--no-session-persistence"], {
647
+ stdio: ["ignore", "pipe", "pipe"],
648
+ cwd: "/tmp"
649
+ });
650
+ let output = "";
651
+ let stderr = "";
652
+ proc.stdout?.on("data", (data) => {
653
+ output += data.toString();
654
+ });
655
+ proc.stderr?.on("data", (data) => {
656
+ stderr += data.toString();
657
+ });
658
+ proc.on("close", (code) => {
659
+ if (code === 0 && output.trim()) {
660
+ resolve2(output.trim());
661
+ } else {
662
+ debug(`claude CLI exited with code ${code}`);
663
+ if (stderr.trim()) {
664
+ debug(`claude stderr: ${stderr.trim()}`);
665
+ }
666
+ if (!output.trim() && code === 0) {
667
+ debug("claude CLI returned empty output");
668
+ }
669
+ resolve2(null);
670
+ }
671
+ });
672
+ proc.on("error", (err) => {
673
+ debug(`Failed to spawn claude CLI: ${err.message}`);
674
+ resolve2(null);
675
+ });
676
+ });
677
+ }
678
+
679
+ // src/changelog.ts
680
+ var GH_COMMAND = process.env.PUBZ_GH_COMMAND ?? "gh";
574
681
  function parseGitRemoteUrl(remoteUrl) {
575
682
  const sshMatch = remoteUrl.match(/^git@([^:]+):(.+?)(?:\.git)?$/);
576
683
  if (sshMatch) {
@@ -584,7 +691,7 @@ function parseGitRemoteUrl(remoteUrl) {
584
691
  }
585
692
  function runSilent(command, args, cwd) {
586
693
  return new Promise((resolve2) => {
587
- const proc = spawn3(command, args, {
694
+ const proc = spawn4(command, args, {
588
695
  cwd,
589
696
  stdio: ["ignore", "pipe", "pipe"]
590
697
  });
@@ -667,10 +774,6 @@ async function generateChangelog(cwd) {
667
774
  const markdown = formatChangelogMarkdown(commits, repoUrl);
668
775
  return { commits, terminal, markdown, previousTag, repoUrl };
669
776
  }
670
- async function isClaudeAvailable() {
671
- const result = await runSilent("which", ["claude"], process.cwd());
672
- return result.code === 0;
673
- }
674
777
  async function generateAIReleaseNotes(commits, version) {
675
778
  const filtered = commits.filter((c) => !isReleaseCommit(c.message));
676
779
  if (filtered.length === 0)
@@ -683,37 +786,7 @@ Here are the commits included in this release:
683
786
  ${commitList}
684
787
 
685
788
  Write concise, user-friendly release notes in markdown. Group related changes under headings if appropriate (e.g. Features, Bug Fixes, Improvements). Focus on what changed and why it matters to users — not implementation details. Do not include a title or version header. Output only the markdown body.`;
686
- return new Promise((resolve2) => {
687
- const proc = spawn3("claude", ["-p", prompt2], {
688
- stdio: ["ignore", "pipe", "pipe"]
689
- });
690
- let output = "";
691
- let stderr = "";
692
- proc.stdout?.on("data", (data) => {
693
- output += data.toString();
694
- });
695
- proc.stderr?.on("data", (data) => {
696
- stderr += data.toString();
697
- });
698
- proc.on("close", (code) => {
699
- if (code === 0 && output.trim()) {
700
- resolve2(output.trim());
701
- } else {
702
- debug(`claude CLI exited with code ${code}`);
703
- if (stderr.trim()) {
704
- debug(`claude stderr: ${stderr.trim()}`);
705
- }
706
- if (!output.trim() && code === 0) {
707
- debug("claude CLI returned empty output");
708
- }
709
- resolve2(null);
710
- }
711
- });
712
- proc.on("error", (err) => {
713
- debug(`Failed to spawn claude CLI: ${err.message}`);
714
- resolve2(null);
715
- });
716
- });
789
+ return runClaudePrompt(prompt2);
717
790
  }
718
791
  async function createGitHubRelease(version, body, cwd, dryRun) {
719
792
  const tagName = `v${version}`;
@@ -721,7 +794,7 @@ async function createGitHubRelease(version, body, cwd, dryRun) {
721
794
  console.log(`[DRY RUN] Would create GitHub release for ${tagName}`);
722
795
  return { success: true };
723
796
  }
724
- 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);
725
798
  if (result.code !== 0) {
726
799
  return {
727
800
  success: false,
@@ -733,12 +806,12 @@ async function createGitHubRelease(version, body, cwd, dryRun) {
733
806
  }
734
807
 
735
808
  // src/version.ts
736
- import { readFile as readFile3, writeFile } from "node:fs/promises";
809
+ import { readFile as readFile4, writeFile } from "node:fs/promises";
737
810
  async function transformWorkspaceProtocolForPublish(packages, newVersion, dryRun) {
738
811
  const packageNames = new Set(packages.map((p) => p.name));
739
812
  const transforms = [];
740
813
  for (const pkg of packages) {
741
- const content = await readFile3(pkg.packageJsonPath, "utf-8");
814
+ const content = await readFile4(pkg.packageJsonPath, "utf-8");
742
815
  const packageJson = JSON.parse(content);
743
816
  let modified = false;
744
817
  for (const depType of [
@@ -755,9 +828,7 @@ async function transformWorkspaceProtocolForPublish(packages, newVersion, dryRun
755
828
  if (oldVersion.startsWith("workspace:")) {
756
829
  const modifier = oldVersion.replace("workspace:", "");
757
830
  const newVersionSpec = modifier === "*" || modifier === "" ? newVersion : `${modifier}${newVersion}`;
758
- if (dryRun) {
759
- console.log(` [DRY RUN] Would temporarily transform ${pkg.name} ${depType}.${depName}: ${oldVersion} -> ${newVersionSpec}`);
760
- } else {
831
+ if (!dryRun) {
761
832
  transforms.push({
762
833
  packageJsonPath: pkg.packageJsonPath,
763
834
  depType,
@@ -774,7 +845,6 @@ async function transformWorkspaceProtocolForPublish(packages, newVersion, dryRun
774
845
  if (modified && !dryRun) {
775
846
  await writeFile(pkg.packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
776
847
  `);
777
- console.log(` Transformed workspace references in ${pkg.name}`);
778
848
  }
779
849
  }
780
850
  return transforms;
@@ -787,7 +857,7 @@ async function restoreWorkspaceProtocol(transforms) {
787
857
  byPath.set(transform.packageJsonPath, existing);
788
858
  }
789
859
  for (const [packageJsonPath, pathTransforms] of byPath) {
790
- const content = await readFile3(packageJsonPath, "utf-8");
860
+ const content = await readFile4(packageJsonPath, "utf-8");
791
861
  const packageJson = JSON.parse(content);
792
862
  for (const transform of pathTransforms) {
793
863
  const deps = packageJson[transform.depType];
@@ -798,9 +868,6 @@ async function restoreWorkspaceProtocol(transforms) {
798
868
  await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
799
869
  `);
800
870
  }
801
- if (transforms.length > 0) {
802
- console.log(` Restored workspace references in ${byPath.size} package(s)`);
803
- }
804
871
  }
805
872
  function isValidVersion(version) {
806
873
  return /^\d+\.\d+\.\d+(-.+)?$/.test(version);
@@ -823,21 +890,19 @@ function previewBump(version, type) {
823
890
  return `${version} -> ${newVersion}`;
824
891
  }
825
892
  async function updatePackageVersion(pkg, newVersion, dryRun) {
826
- const content = await readFile3(pkg.packageJsonPath, "utf-8");
893
+ const content = await readFile4(pkg.packageJsonPath, "utf-8");
827
894
  const packageJson = JSON.parse(content);
828
895
  packageJson.version = newVersion;
829
896
  if (dryRun) {
830
- console.log(` [DRY RUN] Would update ${pkg.name}: ${pkg.version} -> ${newVersion}`);
831
897
  return;
832
898
  }
833
899
  await writeFile(pkg.packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
834
900
  `);
835
- console.log(` Updated ${pkg.name}: ${pkg.version} -> ${newVersion}`);
836
901
  }
837
902
  async function updateLocalDependencyVersions(packages, newVersion, dryRun) {
838
903
  const packageNames = new Set(packages.map((p) => p.name));
839
904
  for (const pkg of packages) {
840
- const content = await readFile3(pkg.packageJsonPath, "utf-8");
905
+ const content = await readFile4(pkg.packageJsonPath, "utf-8");
841
906
  const packageJson = JSON.parse(content);
842
907
  let modified = false;
843
908
  for (const depType of [
@@ -855,13 +920,9 @@ async function updateLocalDependencyVersions(packages, newVersion, dryRun) {
855
920
  continue;
856
921
  }
857
922
  const newVersionSpec = oldVersion.startsWith("^") ? `^${newVersion}` : oldVersion.startsWith("~") ? `~${newVersion}` : newVersion;
858
- if (deps[depName] !== newVersionSpec) {
859
- if (dryRun) {
860
- console.log(` [DRY RUN] Would update ${pkg.name} ${depType}.${depName}: ${oldVersion} -> ${newVersionSpec}`);
861
- } else {
862
- deps[depName] = newVersionSpec;
863
- modified = true;
864
- }
923
+ if (deps[depName] !== newVersionSpec && !dryRun) {
924
+ deps[depName] = newVersionSpec;
925
+ modified = true;
865
926
  }
866
927
  }
867
928
  }
@@ -869,7 +930,6 @@ async function updateLocalDependencyVersions(packages, newVersion, dryRun) {
869
930
  if (modified && !dryRun) {
870
931
  await writeFile(pkg.packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
871
932
  `);
872
- console.log(` Updated local dependency versions in ${pkg.name}`);
873
933
  }
874
934
  }
875
935
  }
@@ -881,13 +941,12 @@ var REGISTRIES = {
881
941
  };
882
942
  function getVersion() {
883
943
  const __dirname2 = dirname(fileURLToPath(import.meta.url));
884
- const pkgPath = join4(__dirname2, "..", "package.json");
944
+ const pkgPath = join5(__dirname2, "..", "package.json");
885
945
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
886
946
  return pkg.version;
887
947
  }
888
948
  function printUsage() {
889
- console.log(`
890
- pubz - Interactive npm package publisher
949
+ console.log(`pubz - Interactive npm package publisher
891
950
 
892
951
  Usage: pubz [command] [options]
893
952
 
@@ -986,15 +1045,14 @@ async function main() {
986
1045
  const skipAllPrompts = options.ci;
987
1046
  const cwd = process.cwd();
988
1047
  if (options.dryRun) {
989
- 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"));
990
1049
  console.log("");
991
1050
  }
992
- console.log(bold("pubz") + dim(" - npm package publisher"));
993
- console.log(dim("═".repeat(30)));
1051
+ console.log("\uD83D\uDCE6 " + bold("pubz") + dim(" npm package publisher"));
994
1052
  console.log("");
995
1053
  const uncommitted = await hasUncommittedChanges(cwd);
996
1054
  if (uncommitted.hasChanges && !options.dryRun) {
997
- console.log(red(bold("Error:")) + " You have uncommitted changes:");
1055
+ console.error(red(bold("Error:")) + " You have uncommitted changes:");
998
1056
  console.log("");
999
1057
  for (const file of uncommitted.files.slice(0, 10)) {
1000
1058
  console.log(` ${yellow(file)}`);
@@ -1007,8 +1065,6 @@ async function main() {
1007
1065
  closePrompt();
1008
1066
  process.exit(1);
1009
1067
  }
1010
- console.log(cyan("Discovering packages..."));
1011
- console.log("");
1012
1068
  let packages = await discoverPackages(cwd);
1013
1069
  const publishablePackages = packages.filter((p) => !p.isPrivate);
1014
1070
  if (publishablePackages.length === 0) {
@@ -1021,12 +1077,12 @@ async function main() {
1021
1077
  process.exit(1);
1022
1078
  }
1023
1079
  packages = sortByDependencyOrder(publishablePackages);
1024
- console.log(`Found ${green(bold(String(packages.length)))} publishable package(s):`);
1025
- console.log("");
1080
+ frameHeader("Packages");
1026
1081
  for (const pkg of packages) {
1027
1082
  const deps = pkg.localDependencies.length > 0 ? dim(` (depends on: ${pkg.localDependencies.join(", ")})`) : "";
1028
- console.log(` ${dim("•")} ${cyan(pkg.name)}${dim("@")}${yellow(pkg.version)}${deps}`);
1083
+ frameLine(`${dim("•")} ${cyan(pkg.name)}${dim("@")}${yellow(pkg.version)}${deps}`);
1029
1084
  }
1085
+ frameFooter();
1030
1086
  console.log("");
1031
1087
  if (packages.length > 1 && !skipAllPrompts) {
1032
1088
  const selectedPackages = await multiSelect("Select packages to publish:", packages.map((pkg) => ({
@@ -1042,18 +1098,14 @@ async function main() {
1042
1098
  console.log("");
1043
1099
  }
1044
1100
  const currentVersion = packages[0].version;
1045
- console.log(bold(cyan("Step 1:")) + " Version Management");
1046
- console.log(dim("─".repeat(30)));
1047
- console.log("");
1048
- console.log(`Current version: ${yellow(currentVersion)}`);
1049
- console.log("");
1050
1101
  let newVersion = currentVersion;
1102
+ let didBump = false;
1051
1103
  if (options.version) {
1052
1104
  const bumpTypes = ["patch", "minor", "major"];
1053
1105
  const isBumpType = bumpTypes.includes(options.version);
1054
1106
  if (isBumpType) {
1055
1107
  newVersion = bumpVersion(currentVersion, options.version);
1056
- console.log(`Bumping version (${options.version}): ${yellow(currentVersion)} → ${green(newVersion)}`);
1108
+ didBump = true;
1057
1109
  } else {
1058
1110
  const cleaned = options.version.startsWith("v") ? options.version.slice(1) : options.version;
1059
1111
  if (!isValidVersion(cleaned)) {
@@ -1062,45 +1114,18 @@ async function main() {
1062
1114
  process.exit(1);
1063
1115
  }
1064
1116
  newVersion = cleaned;
1065
- console.log(`Using explicit version: ${green(newVersion)}`);
1066
- }
1067
- console.log("");
1068
- console.log(`Updating version to ${green(newVersion)} in all packages...`);
1069
- console.log("");
1070
- for (const pkg of packages) {
1071
- await updatePackageVersion(pkg, newVersion, options.dryRun);
1072
- }
1073
- await updateLocalDependencyVersions(packages, newVersion, options.dryRun);
1074
- for (const pkg of packages) {
1075
- pkg.version = newVersion;
1076
- }
1077
- const commitResult = await commitVersionBump(newVersion, cwd, options.dryRun);
1078
- if (!commitResult.success) {
1079
- console.error(red(bold("Failed to commit version bump:")) + ` ${commitResult.error}`);
1080
- closePrompt();
1081
- process.exit(1);
1117
+ didBump = true;
1082
1118
  }
1083
- console.log("");
1084
1119
  } else if (!skipAllPrompts) {
1120
+ console.log(`Current version: ${yellow(currentVersion)}`);
1121
+ console.log("");
1085
1122
  const shouldBump = skipConfirms || await confirm("Bump version before publishing?");
1086
1123
  if (shouldBump) {
1087
1124
  const bumpChoice = await select("Select version bump type:", [
1088
- {
1089
- label: `patch (${previewBump(currentVersion, "patch")})`,
1090
- value: "patch"
1091
- },
1092
- {
1093
- label: `minor (${previewBump(currentVersion, "minor")})`,
1094
- value: "minor"
1095
- },
1096
- {
1097
- label: `major (${previewBump(currentVersion, "major")})`,
1098
- value: "major"
1099
- },
1100
- {
1101
- label: "custom version",
1102
- value: "custom"
1103
- }
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" }
1104
1129
  ]);
1105
1130
  if (bumpChoice === "custom") {
1106
1131
  let customVersion = "";
@@ -1117,24 +1142,34 @@ async function main() {
1117
1142
  } else {
1118
1143
  newVersion = bumpVersion(currentVersion, bumpChoice);
1119
1144
  }
1120
- console.log("");
1121
- console.log(`Updating version to ${green(newVersion)} in all packages...`);
1122
- console.log("");
1123
- for (const pkg of packages) {
1124
- await updatePackageVersion(pkg, newVersion, options.dryRun);
1125
- }
1126
- await updateLocalDependencyVersions(packages, newVersion, options.dryRun);
1127
- for (const pkg of packages) {
1128
- pkg.version = newVersion;
1129
- }
1130
- const commitResult = await commitVersionBump(newVersion, cwd, options.dryRun);
1131
- if (!commitResult.success) {
1132
- console.error(red(bold("Failed to commit version bump:")) + ` ${commitResult.error}`);
1133
- closePrompt();
1134
- process.exit(1);
1135
- }
1136
- console.log("");
1145
+ didBump = true;
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)}`);
1137
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("");
1138
1173
  }
1139
1174
  let registry = options.registry;
1140
1175
  if (!registry && !skipAllPrompts) {
@@ -1148,62 +1183,31 @@ async function main() {
1148
1183
  value: REGISTRIES.github
1149
1184
  }
1150
1185
  ]);
1151
- }
1152
- registry = registry || REGISTRIES.npm;
1153
- console.log("");
1154
- console.log(`Publishing to: ${cyan(registry)}`);
1155
- console.log("");
1156
- if (!options.dryRun && !options.ci) {
1157
- console.log(cyan("Verifying npm authentication..."));
1158
- const authResult = await checkNpmAuth(registry);
1159
- if (!authResult.authenticated) {
1160
- console.log("");
1161
- console.log(yellow("Not logged in to npm.") + " Starting login...");
1162
- console.log("");
1163
- pausePrompt();
1164
- const loginResult = await npmLogin(registry);
1165
- resetPrompt();
1166
- if (!loginResult.success) {
1167
- console.error(red(bold("Login failed:")) + ` ${loginResult.error}`);
1168
- closePrompt();
1169
- process.exit(1);
1170
- }
1171
- const verifyAuth = await checkNpmAuth(registry);
1172
- if (!verifyAuth.authenticated) {
1173
- console.error(red(bold("Error:")) + " Login did not complete successfully.");
1174
- closePrompt();
1175
- process.exit(1);
1176
- }
1177
- console.log("");
1178
- console.log(green("Logged in as") + ` ${cyan(verifyAuth.username ?? "unknown")}`);
1179
- } else {
1180
- console.log(green("Authenticated as") + ` ${cyan(authResult.username ?? "unknown")}`);
1181
- }
1182
1186
  console.log("");
1183
1187
  }
1188
+ registry = registry || REGISTRIES.npm;
1184
1189
  if (!options.skipBuild) {
1185
- console.log(bold(cyan("Step 2:")) + " Building Packages");
1186
- console.log(dim("".repeat(30)));
1187
- console.log("");
1190
+ frameHeader("\uD83C\uDFD7️ Build");
1191
+ frameLine(dim("Running bun run build..."));
1192
+ frameLine();
1188
1193
  const buildResult = await runBuild(cwd, options.dryRun);
1189
1194
  if (!buildResult.success) {
1195
+ frameFooter();
1190
1196
  console.error(red(bold("Build failed:")) + ` ${buildResult.error}`);
1191
1197
  closePrompt();
1192
1198
  process.exit(1);
1193
1199
  }
1194
- console.log("");
1195
- console.log(cyan("Verifying builds..."));
1196
- console.log("");
1197
1200
  let allBuildsVerified = true;
1198
1201
  for (const pkg of packages) {
1199
1202
  const result = await verifyBuild(pkg);
1200
1203
  if (result.success) {
1201
- console.log(` ${green("✓")} ${pkg.name} build verified`);
1204
+ frameLine(` ${green("✓")} ${pkg.name}`);
1202
1205
  } else {
1203
- console.error(` ${red("✗")} ${pkg.name}: ${result.error}`);
1206
+ frameLine(` ${red("✗")} ${pkg.name}: ${result.error}`);
1204
1207
  allBuildsVerified = false;
1205
1208
  }
1206
1209
  }
1210
+ frameFooter();
1207
1211
  console.log("");
1208
1212
  if (!allBuildsVerified) {
1209
1213
  console.error(red("Build verification failed.") + muted(" Please fix the issues and try again."));
@@ -1211,21 +1215,16 @@ async function main() {
1211
1215
  process.exit(1);
1212
1216
  }
1213
1217
  }
1214
- console.log(bold(cyan("Step 3:")) + " Publishing to npm");
1215
- console.log(dim("─".repeat(30)));
1216
- console.log("");
1217
1218
  if (options.dryRun) {
1218
- console.log(yellow("[DRY RUN]") + ` Would publish the following packages to ${cyan(registry)}:`);
1219
+ console.log(yellow("[DRY RUN]") + ` Would publish to ${cyan(registry)}:`);
1219
1220
  } else {
1220
- console.log("About to publish the following packages:");
1221
+ console.log(`Publishing to ${cyan(registry)}:`);
1221
1222
  }
1222
1223
  console.log("");
1223
1224
  for (const pkg of packages) {
1224
1225
  console.log(` ${dim("•")} ${cyan(pkg.name)}${dim("@")}${yellow(newVersion)}`);
1225
1226
  }
1226
1227
  console.log("");
1227
- console.log(`Registry: ${cyan(registry)}`);
1228
- console.log("");
1229
1228
  if (!options.dryRun && !skipConfirms) {
1230
1229
  const shouldContinue = await confirm("Continue?");
1231
1230
  if (!shouldContinue) {
@@ -1235,14 +1234,38 @@ async function main() {
1235
1234
  }
1236
1235
  console.log("");
1237
1236
  }
1238
- console.log(cyan("Preparing packages for publish..."));
1239
- console.log("");
1240
- const workspaceTransforms = await transformWorkspaceProtocolForPublish(packages, newVersion, options.dryRun);
1241
- if (workspaceTransforms.length > 0 || options.dryRun) {
1242
- 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
+ }
1243
1266
  }
1244
- console.log(cyan("Publishing packages..."));
1245
- console.log("");
1267
+ frameLine(dim("Preparing packages..."));
1268
+ const workspaceTransforms = await transformWorkspaceProtocolForPublish(packages, newVersion, options.dryRun);
1246
1269
  const publishContext = {
1247
1270
  otp: options.otp,
1248
1271
  useBrowserAuth: !options.ci,
@@ -1254,6 +1277,11 @@ async function main() {
1254
1277
  let failedError = "";
1255
1278
  try {
1256
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
+ }
1257
1285
  const result = await publishPackage(pkg, registry, publishContext, options.dryRun);
1258
1286
  if (!result.success) {
1259
1287
  publishFailed = true;
@@ -1261,107 +1289,114 @@ async function main() {
1261
1289
  failedError = result.error ?? "Unknown error";
1262
1290
  break;
1263
1291
  }
1292
+ if (!options.dryRun) {
1293
+ frameLine(` ${green("✓")} ${cyan(pkg.name)}${dim("@")}${yellow(newVersion)}`);
1294
+ }
1264
1295
  }
1265
1296
  } finally {
1266
1297
  if (workspaceTransforms.length > 0) {
1267
- console.log("");
1268
1298
  await restoreWorkspaceProtocol(workspaceTransforms);
1269
1299
  }
1270
1300
  }
1271
1301
  if (publishFailed) {
1302
+ frameFooter();
1272
1303
  console.error(red(bold("Failed to publish")) + ` ${cyan(failedPackageName)}: ${failedError}`);
1273
1304
  console.log("");
1274
- console.log(red("Stopping publish process."));
1305
+ console.error(red("Stopping publish process."));
1275
1306
  closePrompt();
1276
1307
  process.exit(1);
1277
1308
  }
1309
+ frameFooter();
1310
+ console.log("");
1278
1311
  if (options.dryRun) {
1279
- console.log("");
1280
1312
  console.log(muted("Run without --dry-run to actually publish."));
1313
+ console.log("");
1281
1314
  }
1282
- console.log("");
1283
- console.log(dim("═".repeat(30)));
1284
- console.log(green(bold("Publishing complete!")));
1285
- console.log("");
1286
- console.log(`Published version: ${green(bold(newVersion))}`);
1315
+ console.log("" + green(bold(`Published v${newVersion}!`)));
1287
1316
  console.log("");
1288
1317
  const changelog = await generateChangelog(cwd);
1289
1318
  if (changelog.terminal) {
1290
- console.log(bold("Changes since ") + cyan(changelog.previousTag ?? "initial") + bold(":"));
1291
- 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();
1292
1326
  console.log("");
1293
1327
  }
1294
1328
  let releaseNotes = changelog.markdown;
1295
- if (!options.ci && changelog.commits.length > 0) {
1329
+ if (changelog.commits.length > 0) {
1296
1330
  const claudeAvailable = await isClaudeAvailable();
1297
1331
  if (claudeAvailable) {
1298
- const useAI = await confirm("Generate release notes with AI (claude)?");
1332
+ const useAI = skipConfirms || await confirm("Generate release notes with AI (claude)?");
1299
1333
  if (useAI) {
1300
- console.log(cyan("Generating AI release notes..."));
1334
+ console.log("");
1335
+ frameHeader("✨ AI Release Notes");
1336
+ frameLine(dim("Generating..."));
1301
1337
  const aiNotes = await generateAIReleaseNotes(changelog.commits, newVersion);
1302
1338
  if (aiNotes) {
1303
1339
  releaseNotes = aiNotes;
1304
- console.log("");
1305
- console.log(bold("AI-generated release notes:"));
1306
- console.log(aiNotes);
1307
- console.log("");
1340
+ frameLine();
1341
+ for (const line of aiNotes.split(`
1342
+ `)) {
1343
+ frameLine(line);
1344
+ }
1308
1345
  } else {
1309
- 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)"));
1310
1347
  }
1348
+ frameFooter();
1349
+ console.log("");
1311
1350
  }
1312
1351
  }
1313
1352
  }
1314
1353
  if (!options.dryRun) {
1354
+ let shouldTag;
1355
+ let shouldPush = false;
1356
+ let shouldRelease = false;
1315
1357
  if (options.ci) {
1316
- console.log(cyan("Creating git tag..."));
1317
- const tagResult = await createGitTag(newVersion, cwd, options.dryRun);
1318
- if (tagResult.success) {
1319
- console.log(cyan("Pushing tag to origin..."));
1320
- await pushGitTag(newVersion, cwd, options.dryRun);
1321
- if (releaseNotes) {
1322
- console.log(cyan("Creating GitHub release..."));
1323
- const releaseResult = await createGitHubRelease(newVersion, releaseNotes, cwd, options.dryRun);
1324
- if (releaseResult.success && releaseResult.url) {
1325
- console.log(` Release created: ${cyan(releaseResult.url)}`);
1326
- } else if (!releaseResult.success) {
1327
- console.error(yellow(releaseResult.error ?? "Failed to create GitHub release"));
1328
- }
1329
- }
1330
- } else {
1331
- console.error(red(tagResult.error ?? "Failed to create git tag"));
1332
- }
1333
- console.log("");
1358
+ shouldTag = true;
1359
+ shouldPush = true;
1360
+ shouldRelease = !!releaseNotes;
1334
1361
  } else {
1335
- 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}`)}?`);
1336
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)
1337
1370
  console.log("");
1338
- const tagResult = await createGitTag(newVersion, cwd, options.dryRun);
1339
- if (tagResult.success) {
1340
- const shouldPush = skipConfirms || await confirm("Push tag to origin?");
1341
- if (shouldPush) {
1342
- await pushGitTag(newVersion, cwd, options.dryRun);
1343
- if (releaseNotes) {
1344
- const shouldRelease = skipConfirms || await confirm("Create a GitHub release?");
1345
- if (shouldRelease) {
1346
- const releaseResult = await createGitHubRelease(newVersion, releaseNotes, cwd, options.dryRun);
1347
- if (releaseResult.success && releaseResult.url) {
1348
- console.log(` Release created: ${cyan(releaseResult.url)}`);
1349
- } else if (!releaseResult.success) {
1350
- console.error(yellow(releaseResult.error ?? "Failed to create GitHub release"));
1351
- }
1352
- }
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"));
1353
1387
  }
1354
- } else {
1355
- console.log(`Tag created locally. Push manually with: ${dim(`git push origin v${newVersion}`)}`);
1356
1388
  }
1357
1389
  } else {
1358
- console.error(red(tagResult.error ?? "Failed to create git tag"));
1390
+ frameLine(`Push manually: ${dim(`git push origin v${newVersion}`)}`);
1359
1391
  }
1360
- console.log("");
1392
+ } else {
1393
+ frameLine(red(tagResult.error ?? "Failed to create git tag"));
1361
1394
  }
1395
+ frameFooter();
1396
+ console.log("");
1362
1397
  }
1363
1398
  }
1364
- console.log(green(bold("Done!")));
1399
+ console.log("\uD83C\uDF89 " + green(bold("Done!")));
1365
1400
  closePrompt();
1366
1401
  }
1367
1402
  main().catch((error) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pubz",
3
- "version": "0.5.2",
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/"