pubz 0.3.0 → 0.4.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 +67 -53
  2. package/dist/cli.js +208 -10
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # `pubz`
2
2
 
3
+ <img width="1024" height="1024" alt="image" src="https://github.com/user-attachments/assets/11ffa33c-e895-4a7d-b2c3-dfadde8dd124" />
4
+
5
+ ---
6
+
3
7
  ```bash
4
8
  bunx pubz
5
9
  ```
@@ -14,8 +18,10 @@ bunx pubz
14
18
  6. Commits version changes
15
19
  7. Prompts you for where you want to publish (e.g. `npm` or private registry)
16
20
  8. Builds packages
17
- 9. Publishes to npm
18
- 10. Prompts you to create a `git tag` and push it
21
+ 9. Transforms `workspace:` definitions to hard version numbers (so `npm` can be used for publishing with OIDC support).
22
+ 10. Publishes to npm
23
+ 11. Prompts you to create a `git tag` and push it
24
+ 12. Generates a changelog and creates a GitHub Release
19
25
 
20
26
  ## Options
21
27
 
@@ -181,49 +187,35 @@ Discovering packages...
181
187
 
182
188
  Found 1 publishable package(s):
183
189
 
184
- • pubz@0.2.2
190
+ • pubz@0.4.0
185
191
 
186
192
  Step 1: Version Management
187
193
  ──────────────────────────────
188
194
 
189
- Current version: 0.2.2
190
-
191
- ? Bump version before publishing? [Y/n]
192
- ? Select version bump type:
193
-
194
- > 1) patch (0.2.2 -> 0.2.3)
195
- 2) minor (0.2.2 -> 0.3.0)
196
- 3) major (0.2.2 -> 1.0.0)
197
-
198
- Enter choice [1-3] (default: 1): 1
199
-
200
- Updating version to 0.2.3 in all packages...
201
-
202
- Updated pubz: 0.2.2 -> 0.2.3
203
- M package.json
204
- Committing version bump...
205
- [main 945e1a3] chore: release v0.2.3
206
- 1 file changed, 1 insertion(+), 1 deletion(-)
207
- Changes committed
195
+ Current version: 0.4.0
208
196
 
197
+ ? Bump version before publishing? [Y/n] n
209
198
  ? Select publish target:
210
199
 
211
200
  > 1) Public npm registry (https://registry.npmjs.org)
212
201
  2) GitHub Packages (https://npm.pkg.github.com)
213
202
 
214
- Enter choice [1-2] (default: 1):
203
+ Enter choice [1-2] (default: 1):
215
204
 
216
205
  Publishing to: https://registry.npmjs.org
217
206
 
207
+ Verifying npm authentication...
208
+ Authenticated as zdavison
209
+
218
210
  Step 2: Building Packages
219
211
  ──────────────────────────────
220
212
 
221
213
  Running build...
222
214
 
223
215
  $ bun build src/cli.ts --outdir dist --target node
224
- Bundled 7 modules in 7ms
216
+ Bundled 10 modules in 5ms
225
217
 
226
- cli.js 28.65 KB (entry point)
218
+ cli.js 41.27 KB (entry point)
227
219
 
228
220
 
229
221
  Build completed successfully
@@ -237,46 +229,68 @@ Step 3: Publishing to npm
237
229
 
238
230
  About to publish the following packages:
239
231
 
240
- • pubz@0.2.3
232
+ • pubz@0.4.0
241
233
 
242
234
  Registry: https://registry.npmjs.org
243
235
 
244
- ? Continue? [Y/n]
236
+ ? Continue? [Y/n]
237
+
238
+ Preparing packages for publish...
245
239
 
246
240
  Publishing packages...
247
241
 
248
- Publishing pubz@0.2.3...
249
- npm notice
250
- npm notice 📦 pubz@0.2.3
251
- npm notice Tarball Contents
252
- npm notice 717B package.json
253
- npm notice 2.3kB README.md
254
- npm notice 28.7kB dist/cli.js
255
- npm notice Tarball Details
256
- npm notice name: pubz
257
- npm notice version: 0.2.3
258
- npm notice filename: pubz-0.2.3.tgz
259
- npm notice package size: 8.3 kB
260
- npm notice unpacked size: 31.6 kB
261
- npm notice shasum: b8cd25d62b05d5cd6a4ecc8ff6ef6e522e7b2aa5
262
- npm notice integrity: sha512-jihTMvUxMeXNX[...]2+gtHJexETkWA==
263
- npm notice total files: 3
264
- npm notice
265
- + pubz@0.2.3
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
266
265
  pubz published successfully
267
266
 
268
267
  ══════════════════════════════
269
268
  Publishing complete!
270
269
 
271
- Published version: 0.2.3
272
-
273
- ? Create a git tag for v0.2.3? [Y/n]
274
-
275
- Tag v0.2.3 created
276
- ? Push tag to origin? [Y/n]
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
277
289
  To github.com:mm-zacharydavison/pubz.git
278
- * [new tag] v0.2.3 -> v0.2.3
279
- Tag v0.2.3 pushed to origin
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
280
294
 
281
295
  Done!
282
296
  ```
package/dist/cli.js CHANGED
@@ -195,6 +195,9 @@ function prompt(question) {
195
195
  function closePrompt() {
196
196
  rl.close();
197
197
  }
198
+ function pausePrompt() {
199
+ rl.close();
200
+ }
198
201
  function resetPrompt() {
199
202
  rl.close();
200
203
  rl = readline.createInterface({
@@ -317,10 +320,25 @@ async function multiSelect(message, options, allSelectedByDefault = true) {
317
320
 
318
321
  // src/auth.ts
319
322
  import { spawn } from "node:child_process";
323
+ import { homedir } from "node:os";
324
+
325
+ // src/log.ts
326
+ var verboseEnabled = false;
327
+ function setVerbose(enabled) {
328
+ verboseEnabled = enabled;
329
+ }
330
+ function debug(...args) {
331
+ if (verboseEnabled) {
332
+ console.error("[debug]", ...args);
333
+ }
334
+ }
335
+
336
+ // src/auth.ts
320
337
  async function checkNpmAuth(registry) {
321
338
  return new Promise((resolve2) => {
322
339
  const proc = spawn("npm", ["whoami", "--registry", registry], {
323
- stdio: ["inherit", "pipe", "pipe"]
340
+ stdio: ["ignore", "pipe", "pipe"],
341
+ cwd: homedir()
324
342
  });
325
343
  let stdout = "";
326
344
  let stderr = "";
@@ -334,6 +352,7 @@ async function checkNpmAuth(registry) {
334
352
  if (code === 0 && stdout.trim()) {
335
353
  resolve2({ authenticated: true, username: stdout.trim() });
336
354
  } else {
355
+ debug(`npm whoami failed: code=${code}, stdout=${JSON.stringify(stdout)}, stderr=${JSON.stringify(stderr)}`);
337
356
  resolve2({ authenticated: false });
338
357
  }
339
358
  });
@@ -341,10 +360,13 @@ async function checkNpmAuth(registry) {
341
360
  }
342
361
  async function npmLogin(registry) {
343
362
  return new Promise((resolve2) => {
363
+ debug(`spawning: npm login --registry ${registry}`);
344
364
  const proc = spawn("npm", ["login", "--registry", registry], {
345
- stdio: "inherit"
365
+ stdio: "inherit",
366
+ cwd: homedir()
346
367
  });
347
368
  proc.on("close", (code) => {
369
+ debug(`npm login exited: code=${code}`);
348
370
  if (code === 0) {
349
371
  resolve2({ success: true });
350
372
  } else {
@@ -357,6 +379,7 @@ async function npmLogin(registry) {
357
379
  // src/publish.ts
358
380
  import { spawn as spawn2 } from "node:child_process";
359
381
  import { readFile as readFile2, stat as stat3 } from "node:fs/promises";
382
+ import { homedir as homedir2 } from "node:os";
360
383
  import { join as join3 } from "node:path";
361
384
  function run(command, args, cwd) {
362
385
  return new Promise((resolve2) => {
@@ -455,7 +478,9 @@ async function publishPackage(pkg, registry, context, dryRun) {
455
478
  let result;
456
479
  if (context.useBrowserAuth) {
457
480
  args.push("--auth-type", "web");
458
- const interactiveResult = await runInteractive(NPM_COMMAND, args, pkg.path);
481
+ args.push(pkg.path);
482
+ context.onInteractiveStart?.();
483
+ const interactiveResult = await runInteractive(NPM_COMMAND, args, homedir2());
459
484
  result = { code: interactiveResult.code, output: "" };
460
485
  context.onInteractiveComplete?.();
461
486
  } else {
@@ -535,6 +560,118 @@ async function pushGitTag(version, cwd, dryRun) {
535
560
  return { success: true };
536
561
  }
537
562
 
563
+ // src/changelog.ts
564
+ import { spawn as spawn3 } from "node:child_process";
565
+ function parseGitRemoteUrl(remoteUrl) {
566
+ const sshMatch = remoteUrl.match(/^git@([^:]+):(.+?)(?:\.git)?$/);
567
+ if (sshMatch) {
568
+ return `https://${sshMatch[1]}/${sshMatch[2]}`;
569
+ }
570
+ const httpsMatch = remoteUrl.match(/^https?:\/\/([^/]+)\/(.+?)(?:\.git)?$/);
571
+ if (httpsMatch) {
572
+ return `https://${httpsMatch[1]}/${httpsMatch[2]}`;
573
+ }
574
+ return null;
575
+ }
576
+ function runSilent(command, args, cwd) {
577
+ return new Promise((resolve2) => {
578
+ const proc = spawn3(command, args, {
579
+ cwd,
580
+ stdio: ["ignore", "pipe", "pipe"]
581
+ });
582
+ let output = "";
583
+ proc.stdout?.on("data", (data) => {
584
+ output += data.toString();
585
+ });
586
+ proc.stderr?.on("data", (data) => {
587
+ output += data.toString();
588
+ });
589
+ proc.on("close", (code) => {
590
+ resolve2({ code: code ?? 1, output });
591
+ });
592
+ });
593
+ }
594
+ async function getPreviousTag(cwd) {
595
+ const result = await runSilent("git", ["tag", "--sort=-version:refname"], cwd);
596
+ if (result.code !== 0)
597
+ return null;
598
+ const tags = result.output.trim().split(`
599
+ `).filter((t) => t.length > 0);
600
+ return tags[0] ?? null;
601
+ }
602
+ async function getRepoUrl(cwd) {
603
+ const result = await runSilent("git", ["remote", "get-url", "origin"], cwd);
604
+ if (result.code !== 0)
605
+ return null;
606
+ return parseGitRemoteUrl(result.output.trim());
607
+ }
608
+ async function getCommitsSince(ref, cwd) {
609
+ const result = await runSilent("git", ["log", `${ref}..HEAD`, "--oneline", "--no-decorate"], cwd);
610
+ if (result.code !== 0)
611
+ return [];
612
+ return result.output.trim().split(`
613
+ `).filter((line) => line.length > 0).map((line) => {
614
+ const spaceIdx = line.indexOf(" ");
615
+ return {
616
+ sha: line.slice(0, spaceIdx),
617
+ message: line.slice(spaceIdx + 1)
618
+ };
619
+ });
620
+ }
621
+ function isReleaseCommit(message) {
622
+ return /^chore: release v/.test(message);
623
+ }
624
+ function formatChangelogTerminal(commits) {
625
+ const filtered = commits.filter((c) => !isReleaseCommit(c.message));
626
+ if (filtered.length === 0)
627
+ return "";
628
+ return filtered.map((c) => ` ${dim(c.sha)} ${c.message}`).join(`
629
+ `);
630
+ }
631
+ function formatChangelogMarkdown(commits, repoUrl) {
632
+ const filtered = commits.filter((c) => !isReleaseCommit(c.message));
633
+ if (filtered.length === 0)
634
+ return "";
635
+ return filtered.map((c) => {
636
+ const shaRef = repoUrl ? `[\`${c.sha}\`](${repoUrl}/commit/${c.sha})` : `\`${c.sha}\``;
637
+ return `- ${shaRef} ${c.message}`;
638
+ }).join(`
639
+ `);
640
+ }
641
+ async function fetchTags(cwd) {
642
+ await runSilent("git", ["fetch", "--tags"], cwd);
643
+ }
644
+ async function generateChangelog(cwd) {
645
+ await fetchTags(cwd);
646
+ const [previousTag, repoUrl] = await Promise.all([
647
+ getPreviousTag(cwd),
648
+ getRepoUrl(cwd)
649
+ ]);
650
+ if (!previousTag) {
651
+ return { commits: [], terminal: "", markdown: "", previousTag: null, repoUrl };
652
+ }
653
+ const commits = await getCommitsSince(previousTag, cwd);
654
+ const terminal = formatChangelogTerminal(commits);
655
+ const markdown = formatChangelogMarkdown(commits, repoUrl);
656
+ return { commits, terminal, markdown, previousTag, repoUrl };
657
+ }
658
+ async function createGitHubRelease(version, body, cwd, dryRun) {
659
+ const tagName = `v${version}`;
660
+ if (dryRun) {
661
+ console.log(`[DRY RUN] Would create GitHub release for ${tagName}`);
662
+ return { success: true };
663
+ }
664
+ const result = await runSilent("gh", ["release", "create", tagName, "--title", tagName, "--notes", body], cwd);
665
+ if (result.code !== 0) {
666
+ return {
667
+ success: false,
668
+ error: result.output.trim() || `Failed to create GitHub release for ${tagName}`
669
+ };
670
+ }
671
+ const url = result.output.trim();
672
+ return { success: true, url };
673
+ }
674
+
538
675
  // src/version.ts
539
676
  import { readFile as readFile3, writeFile } from "node:fs/promises";
540
677
  async function transformWorkspaceProtocolForPublish(packages, newVersion, dryRun) {
@@ -605,6 +742,9 @@ async function restoreWorkspaceProtocol(transforms) {
605
742
  console.log(` Restored workspace references in ${byPath.size} package(s)`);
606
743
  }
607
744
  }
745
+ function isValidVersion(version) {
746
+ return /^\d+\.\d+\.\d+(-.+)?$/.test(version);
747
+ }
608
748
  function bumpVersion(version, type) {
609
749
  if (type === "none")
610
750
  return version;
@@ -702,6 +842,7 @@ Options:
702
842
  --yes, -y Skip yes/no confirmation prompts (still asks for choices)
703
843
  --ci CI mode: skip all prompts, auto-accept everything
704
844
  --version <value> Version bump type (patch|minor|major) or explicit version (required with --ci)
845
+ --verbose Show debug logging
705
846
  -h, --help Show this help message
706
847
 
707
848
  Examples:
@@ -721,6 +862,7 @@ function parseArgs(args) {
721
862
  skipConfirms: false,
722
863
  ci: false,
723
864
  version: "",
865
+ verbose: false,
724
866
  help: false
725
867
  };
726
868
  for (let i = 0;i < args.length; i++) {
@@ -748,6 +890,9 @@ function parseArgs(args) {
748
890
  case "--version":
749
891
  options.version = args[++i] || "";
750
892
  break;
893
+ case "--verbose":
894
+ options.verbose = true;
895
+ break;
751
896
  case "-h":
752
897
  case "--help":
753
898
  options.help = true;
@@ -762,6 +907,7 @@ async function main() {
762
907
  process.exit(0);
763
908
  }
764
909
  const options = parseArgs(process.argv.slice(2));
910
+ setVerbose(options.verbose);
765
911
  if (options.help) {
766
912
  printUsage();
767
913
  process.exit(0);
@@ -849,7 +995,13 @@ async function main() {
849
995
  newVersion = bumpVersion(currentVersion, options.version);
850
996
  console.log(`Bumping version (${options.version}): ${yellow(currentVersion)} → ${green(newVersion)}`);
851
997
  } else {
852
- newVersion = options.version;
998
+ const cleaned = options.version.startsWith("v") ? options.version.slice(1) : options.version;
999
+ if (!isValidVersion(cleaned)) {
1000
+ console.error(red(bold("Error:")) + ` Invalid version "${options.version}". Expected format: major.minor.patch (e.g. 1.2.3, 1.2.3-beta)`);
1001
+ closePrompt();
1002
+ process.exit(1);
1003
+ }
1004
+ newVersion = cleaned;
853
1005
  console.log(`Using explicit version: ${green(newVersion)}`);
854
1006
  }
855
1007
  console.log("");
@@ -872,7 +1024,7 @@ async function main() {
872
1024
  } else if (!skipAllPrompts) {
873
1025
  const shouldBump = skipConfirms || await confirm("Bump version before publishing?");
874
1026
  if (shouldBump) {
875
- const bumpType = await select("Select version bump type:", [
1027
+ const bumpChoice = await select("Select version bump type:", [
876
1028
  {
877
1029
  label: `patch (${previewBump(currentVersion, "patch")})`,
878
1030
  value: "patch"
@@ -884,9 +1036,27 @@ async function main() {
884
1036
  {
885
1037
  label: `major (${previewBump(currentVersion, "major")})`,
886
1038
  value: "major"
1039
+ },
1040
+ {
1041
+ label: "custom version",
1042
+ value: "custom"
887
1043
  }
888
1044
  ]);
889
- newVersion = bumpVersion(currentVersion, bumpType);
1045
+ if (bumpChoice === "custom") {
1046
+ let customVersion = "";
1047
+ while (!customVersion) {
1048
+ const input = await prompt(` Enter version: `);
1049
+ const cleaned = input.startsWith("v") ? input.slice(1) : input;
1050
+ if (isValidVersion(cleaned)) {
1051
+ customVersion = cleaned;
1052
+ } else {
1053
+ console.log(yellow(" Invalid version. Expected format: major.minor.patch (e.g. 1.2.3, 1.2.3-beta)"));
1054
+ }
1055
+ }
1056
+ newVersion = customVersion;
1057
+ } else {
1058
+ newVersion = bumpVersion(currentVersion, bumpChoice);
1059
+ }
890
1060
  console.log("");
891
1061
  console.log(`Updating version to ${green(newVersion)} in all packages...`);
892
1062
  console.log("");
@@ -930,7 +1100,9 @@ async function main() {
930
1100
  console.log("");
931
1101
  console.log(yellow("Not logged in to npm.") + " Starting login...");
932
1102
  console.log("");
1103
+ pausePrompt();
933
1104
  const loginResult = await npmLogin(registry);
1105
+ resetPrompt();
934
1106
  if (!loginResult.success) {
935
1107
  console.error(red(bold("Login failed:")) + ` ${loginResult.error}`);
936
1108
  closePrompt();
@@ -1014,6 +1186,7 @@ async function main() {
1014
1186
  const publishContext = {
1015
1187
  otp: options.otp,
1016
1188
  useBrowserAuth: !options.ci,
1189
+ onInteractiveStart: pausePrompt,
1017
1190
  onInteractiveComplete: resetPrompt
1018
1191
  };
1019
1192
  let publishFailed = false;
@@ -1052,27 +1225,52 @@ async function main() {
1052
1225
  console.log("");
1053
1226
  console.log(`Published version: ${green(bold(newVersion))}`);
1054
1227
  console.log("");
1228
+ const changelog = await generateChangelog(cwd);
1229
+ if (changelog.terminal) {
1230
+ console.log(bold("Changes since ") + cyan(changelog.previousTag ?? "initial") + bold(":"));
1231
+ console.log(changelog.terminal);
1232
+ console.log("");
1233
+ }
1055
1234
  if (!options.dryRun) {
1056
1235
  if (options.ci) {
1057
- console.log("");
1058
1236
  console.log(cyan("Creating git tag..."));
1059
1237
  const tagResult = await createGitTag(newVersion, cwd, options.dryRun);
1060
1238
  if (tagResult.success) {
1061
1239
  console.log(cyan("Pushing tag to origin..."));
1062
1240
  await pushGitTag(newVersion, cwd, options.dryRun);
1241
+ if (changelog.markdown) {
1242
+ console.log(cyan("Creating GitHub release..."));
1243
+ const releaseResult = await createGitHubRelease(newVersion, changelog.markdown, cwd, options.dryRun);
1244
+ if (releaseResult.success && releaseResult.url) {
1245
+ console.log(` Release created: ${cyan(releaseResult.url)}`);
1246
+ } else if (!releaseResult.success) {
1247
+ console.error(yellow(releaseResult.error ?? "Failed to create GitHub release"));
1248
+ }
1249
+ }
1063
1250
  } else {
1064
1251
  console.error(red(tagResult.error ?? "Failed to create git tag"));
1065
1252
  }
1066
1253
  console.log("");
1067
- } else if (!skipConfirms) {
1068
- const shouldTag = await confirm(`Create a git tag for ${cyan(`v${newVersion}`)}?`);
1254
+ } else {
1255
+ const shouldTag = skipConfirms || await confirm(`Create a git tag for ${cyan(`v${newVersion}`)}?`);
1069
1256
  if (shouldTag) {
1070
1257
  console.log("");
1071
1258
  const tagResult = await createGitTag(newVersion, cwd, options.dryRun);
1072
1259
  if (tagResult.success) {
1073
- const shouldPush = await confirm("Push tag to origin?");
1260
+ const shouldPush = skipConfirms || await confirm("Push tag to origin?");
1074
1261
  if (shouldPush) {
1075
1262
  await pushGitTag(newVersion, cwd, options.dryRun);
1263
+ if (changelog.markdown) {
1264
+ const shouldRelease = skipConfirms || await confirm("Create a GitHub release?");
1265
+ if (shouldRelease) {
1266
+ const releaseResult = await createGitHubRelease(newVersion, changelog.markdown, cwd, options.dryRun);
1267
+ if (releaseResult.success && releaseResult.url) {
1268
+ console.log(` Release created: ${cyan(releaseResult.url)}`);
1269
+ } else if (!releaseResult.success) {
1270
+ console.error(yellow(releaseResult.error ?? "Failed to create GitHub release"));
1271
+ }
1272
+ }
1273
+ }
1076
1274
  } else {
1077
1275
  console.log(`Tag created locally. Push manually with: ${dim(`git push origin v${newVersion}`)}`);
1078
1276
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pubz",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Interactive CLI for publishing npm packages (single or monorepo)",
5
5
  "type": "module",
6
6
  "bin": {