pubm 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1975,7 +1975,7 @@ function resolveOptions(options) {
1975
1975
 
1976
1976
  // src/tasks/runner.ts
1977
1977
  var import_node_process8 = __toESM(require("process"), 1);
1978
- var import_promise_spawn = __toESM(require("@npmcli/promise-spawn"), 1);
1978
+ var import_promise_spawn2 = __toESM(require("@npmcli/promise-spawn"), 1);
1979
1979
 
1980
1980
  // node_modules/.pnpm/eventemitter3@5.0.1/node_modules/eventemitter3/index.mjs
1981
1981
  var import_index = __toESM(require_eventemitter3(), 1);
@@ -1996,15 +1996,15 @@ var isCompatibleTerminal = tty && tty.isatty && tty.isatty(1) && env.TERM && !is
1996
1996
  var isCI = "CI" in env && ("GITHUB_ACTIONS" in env || "GITLAB_CI" in env || "CIRCLECI" in env);
1997
1997
  var isColorSupported = !isDisabled && (isForced || isWindows && !isDumbTerminal || isCompatibleTerminal || isCI);
1998
1998
  var replaceClose = (index, string, close, replace, head = string.substring(0, index) + replace, tail = string.substring(index + close.length), next = tail.indexOf(close)) => head + (next < 0 ? tail : replaceClose(next, tail, close, replace));
1999
- var clearBleed = (index, string, open2, close, replace) => index < 0 ? open2 + string + close : open2 + replaceClose(index, string, close, replace) + close;
2000
- var filterEmpty = (open2, close, replace = open2, at = open2.length + 1) => (string) => string || !(string === "" || string === void 0) ? clearBleed(
1999
+ var clearBleed = (index, string, open3, close, replace) => index < 0 ? open3 + string + close : open3 + replaceClose(index, string, close, replace) + close;
2000
+ var filterEmpty = (open3, close, replace = open3, at = open3.length + 1) => (string) => string || !(string === "" || string === void 0) ? clearBleed(
2001
2001
  ("" + string).indexOf(close, at),
2002
2002
  string,
2003
- open2,
2003
+ open3,
2004
2004
  close,
2005
2005
  replace
2006
2006
  ) : "";
2007
- var init = (open2, close, replace) => filterEmpty(`\x1B[${open2}m`, `\x1B[${close}m`, replace);
2007
+ var init = (open3, close, replace) => filterEmpty(`\x1B[${open3}m`, `\x1B[${close}m`, replace);
2008
2008
  var colors = {
2009
2009
  reset: init(0, 0),
2010
2010
  bold: init(1, 22, "\x1B[22m\x1B[1m"),
@@ -4484,7 +4484,7 @@ var Git = class {
4484
4484
  try {
4485
4485
  return (await this.git(["tag", "-l"])).trim().split("\n").sort(import_semver.default.compareIdentifiers);
4486
4486
  } catch (error) {
4487
- throw new GitError("Failed to run `git config --get user.name`", {
4487
+ throw new GitError("Failed to run `git tag -l`", {
4488
4488
  cause: error
4489
4489
  });
4490
4490
  }
@@ -4747,8 +4747,24 @@ async function rollback() {
4747
4747
  called = true;
4748
4748
  if (rollbacks.length <= 0) return void 0;
4749
4749
  console.log("Rollback...");
4750
- await Promise.all(rollbacks.map(({ fn, ctx }) => fn(ctx)));
4751
- console.log("Rollback completed");
4750
+ const results = await Promise.allSettled(
4751
+ rollbacks.map(({ fn, ctx }) => fn(ctx))
4752
+ );
4753
+ const failures = results.filter(
4754
+ (r) => r.status === "rejected"
4755
+ );
4756
+ if (failures.length > 0) {
4757
+ for (const failure of failures) {
4758
+ console.error(
4759
+ `Rollback operation failed: ${failure.reason instanceof Error ? failure.reason.message : failure.reason}`
4760
+ );
4761
+ }
4762
+ console.log(
4763
+ "Rollback completed with errors. Some operations may require manual recovery."
4764
+ );
4765
+ } else {
4766
+ console.log("Rollback completed");
4767
+ }
4752
4768
  }
4753
4769
 
4754
4770
  // src/utils/listr.ts
@@ -4915,20 +4931,34 @@ async function replaceVersion(version2) {
4915
4931
  const packageJsonPath = await findOutFile("package.json");
4916
4932
  if (!packageJsonPath) return void 0;
4917
4933
  const packageJson = (await (0, import_promises.readFile)(packageJsonPath)).toString();
4918
- await (0, import_promises.writeFile)(
4919
- packageJsonPath,
4920
- packageJson.replace(versionRegex, `$1${version2}$2`)
4921
- );
4934
+ try {
4935
+ await (0, import_promises.writeFile)(
4936
+ packageJsonPath,
4937
+ packageJson.replace(versionRegex, `$1${version2}$2`)
4938
+ );
4939
+ } catch (error) {
4940
+ throw new AbstractError(
4941
+ `Failed to write version to package.json: ${error instanceof Error ? error.message : error}`,
4942
+ { cause: error }
4943
+ );
4944
+ }
4922
4945
  return "package.json";
4923
4946
  })(),
4924
4947
  (async () => {
4925
4948
  const jsrJsonPath = await findOutFile("jsr.json");
4926
4949
  if (!jsrJsonPath) return void 0;
4927
4950
  const jsrJson = (await (0, import_promises.readFile)(jsrJsonPath)).toString();
4928
- await (0, import_promises.writeFile)(
4929
- jsrJsonPath,
4930
- jsrJson.replace(versionRegex, `$1${version2}$2`)
4931
- );
4951
+ try {
4952
+ await (0, import_promises.writeFile)(
4953
+ jsrJsonPath,
4954
+ jsrJson.replace(versionRegex, `$1${version2}$2`)
4955
+ );
4956
+ } catch (error) {
4957
+ throw new AbstractError(
4958
+ `Failed to write version to jsr.json: ${error instanceof Error ? error.message : error}`,
4959
+ { cause: error }
4960
+ );
4961
+ }
4932
4962
  return "jsr.json";
4933
4963
  })()
4934
4964
  ]);
@@ -4947,6 +4977,7 @@ async function getPackageManager() {
4947
4977
  if (await findOutFile(lockFile2)) return packageManager;
4948
4978
  }
4949
4979
  }
4980
+ console.warn("No lock file found, defaulting to npm.");
4950
4981
  return "npm";
4951
4982
  }
4952
4983
 
@@ -5065,13 +5096,21 @@ var CratesRegistry = class extends Registry {
5065
5096
  { headers: this.headers }
5066
5097
  );
5067
5098
  if (!response.ok) {
5068
- throw new Error(`Crate '${this.packageName}' not found`);
5099
+ if (response.status === 404) {
5100
+ throw new CratesError(
5101
+ `Crate '${this.packageName}' not found on crates.io`
5102
+ );
5103
+ }
5104
+ throw new CratesError(
5105
+ `crates.io API error (HTTP ${response.status}) for crate '${this.packageName}'`
5106
+ );
5069
5107
  }
5070
5108
  const data = await response.json();
5071
5109
  return data.crate.max_version;
5072
5110
  } catch (error) {
5111
+ if (error instanceof CratesError) throw error;
5073
5112
  throw new CratesError(
5074
- `Failed to fetch version for crate '${this.packageName}'`,
5113
+ `Cannot reach crates.io to fetch version for '${this.packageName}'`,
5075
5114
  { cause: error }
5076
5115
  );
5077
5116
  }
@@ -5101,6 +5140,12 @@ var CratesRegistry = class extends Registry {
5101
5140
  if (process.env.CARGO_REGISTRY_TOKEN) return true;
5102
5141
  return this.isInstalled();
5103
5142
  }
5143
+ getRequirements() {
5144
+ return {
5145
+ needsPackageScripts: false,
5146
+ requiredManifest: "Cargo.toml"
5147
+ };
5148
+ }
5104
5149
  async isPackageNameAvaliable() {
5105
5150
  try {
5106
5151
  const response = await fetch(
@@ -5108,8 +5153,11 @@ var CratesRegistry = class extends Registry {
5108
5153
  { headers: this.headers }
5109
5154
  );
5110
5155
  return !response.ok;
5111
- } catch {
5112
- return true;
5156
+ } catch (error) {
5157
+ throw new CratesError(
5158
+ `Failed to check package name availability on crates.io`,
5159
+ { cause: error }
5160
+ );
5113
5161
  }
5114
5162
  }
5115
5163
  };
@@ -5187,32 +5235,50 @@ var Db = class {
5187
5235
  (0, import_node_fs.mkdirSync)(this.path);
5188
5236
  }
5189
5237
  } catch {
5190
- (0, import_node_fs.mkdirSync)(this.path);
5238
+ try {
5239
+ (0, import_node_fs.mkdirSync)(this.path);
5240
+ } catch (error) {
5241
+ throw new Error(
5242
+ `Failed to create token storage directory at '${this.path}': ${error instanceof Error ? error.message : error}`
5243
+ );
5244
+ }
5191
5245
  }
5192
5246
  }
5193
5247
  set(field, value) {
5194
- (0, import_node_fs.writeFileSync)(
5195
- import_node_path3.default.resolve(this.path, Buffer.from(e(field, field)).toString("base64")),
5196
- Buffer.from(e(`${value}`, field)),
5197
- { encoding: "binary" }
5198
- );
5248
+ try {
5249
+ (0, import_node_fs.writeFileSync)(
5250
+ import_node_path3.default.resolve(
5251
+ this.path,
5252
+ Buffer.from(e(field, field)).toString("base64")
5253
+ ),
5254
+ Buffer.from(e(`${value}`, field)),
5255
+ { encoding: "binary" }
5256
+ );
5257
+ } catch (error) {
5258
+ throw new Error(
5259
+ `Failed to save token for '${field}': ${error instanceof Error ? error.message : error}`
5260
+ );
5261
+ }
5199
5262
  }
5200
5263
  get(field) {
5264
+ const filePath = import_node_path3.default.resolve(
5265
+ this.path,
5266
+ Buffer.from(e(field, field)).toString("base64")
5267
+ );
5268
+ let raw;
5201
5269
  try {
5202
- return d(
5203
- Buffer.from(
5204
- (0, import_node_fs.readFileSync)(
5205
- import_node_path3.default.resolve(
5206
- this.path,
5207
- Buffer.from(e(field, field)).toString("base64")
5208
- )
5209
- )
5210
- ).toString(),
5211
- field
5212
- );
5270
+ raw = (0, import_node_fs.readFileSync)(filePath);
5213
5271
  } catch {
5214
5272
  return null;
5215
5273
  }
5274
+ try {
5275
+ return d(Buffer.from(raw).toString(), field);
5276
+ } catch {
5277
+ console.warn(
5278
+ `Stored token for '${field}' appears corrupted. It will be re-requested.`
5279
+ );
5280
+ return null;
5281
+ }
5216
5282
  }
5217
5283
  };
5218
5284
 
@@ -5226,9 +5292,12 @@ function getScope(packageName) {
5226
5292
  }
5227
5293
  function getScopeAndName(packageName) {
5228
5294
  const matches = packageName.match(/^@([a-zA-Z0-9]+)\/([a-zA-Z0-9]+)$/);
5229
- const scope = matches?.[1];
5230
- const name = matches?.[2];
5231
- return [`${scope}`, `${name}`];
5295
+ if (!matches) {
5296
+ throw new Error(
5297
+ `Invalid scoped package name: '${packageName}'. Expected format: @scope/name`
5298
+ );
5299
+ }
5300
+ return [matches[1], matches[2]];
5232
5301
  }
5233
5302
  var scopedPackagePattern = /^(?:@([^/]+?)[/])?([^/]+?)$/;
5234
5303
  var blacklist = ["node_modules", "favicon.ico"];
@@ -5348,6 +5417,12 @@ ${stderr}` : ""}`,
5348
5417
  async isPackageNameAvaliable() {
5349
5418
  return isValidPackageName(this.packageName);
5350
5419
  }
5420
+ getRequirements() {
5421
+ return {
5422
+ needsPackageScripts: false,
5423
+ requiredManifest: "jsr.json"
5424
+ };
5425
+ }
5351
5426
  };
5352
5427
  var _JsrClient = class _JsrClient {
5353
5428
  constructor(apiEndpoint) {
@@ -5369,9 +5444,7 @@ var _JsrClient = class _JsrClient {
5369
5444
  const response = await this.fetch("/user");
5370
5445
  if (response.status === 401) return null;
5371
5446
  if (!response.ok) {
5372
- throw new Error(
5373
- `HTTP ${response.status}: ${response.statusText}`
5374
- );
5447
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
5375
5448
  }
5376
5449
  return await response.json();
5377
5450
  } catch (error) {
@@ -5385,9 +5458,7 @@ var _JsrClient = class _JsrClient {
5385
5458
  const response = await this.fetch(`/user/member/${scope}`);
5386
5459
  if (response.status === 401) return null;
5387
5460
  if (!response.ok) {
5388
- throw new Error(
5389
- `HTTP ${response.status}: ${response.statusText}`
5390
- );
5461
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
5391
5462
  }
5392
5463
  return await response.json();
5393
5464
  } catch (error) {
@@ -5404,15 +5475,11 @@ var _JsrClient = class _JsrClient {
5404
5475
  const response = await this.fetch("/user/scopes");
5405
5476
  if (response.status === 401) return [];
5406
5477
  if (!response.ok) {
5407
- throw new Error(
5408
- `HTTP ${response.status}: ${response.statusText}`
5409
- );
5478
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
5410
5479
  }
5411
5480
  const body = await response.json();
5412
5481
  if (!Array.isArray(body)) {
5413
- throw new Error(
5414
- `Expected array response but got ${typeof body}`
5415
- );
5482
+ throw new Error(`Expected array response but got ${typeof body}`);
5416
5483
  }
5417
5484
  return body.map(({ scope }) => scope);
5418
5485
  } catch (error) {
@@ -5428,9 +5495,15 @@ var _JsrClient = class _JsrClient {
5428
5495
  const [scope, name] = getScopeAndName(packageName);
5429
5496
  try {
5430
5497
  const response = await this.fetch(`/scopes/${scope}/packages/${name}`);
5431
- if (!response.ok) return null;
5498
+ if (response.status === 404) return null;
5499
+ if (!response.ok) {
5500
+ throw new JsrError(
5501
+ `JSR API error (HTTP ${response.status}) for package '${packageName}'`
5502
+ );
5503
+ }
5432
5504
  return await response.json();
5433
5505
  } catch (error) {
5506
+ if (error instanceof JsrError) throw error;
5434
5507
  throw new JsrError(
5435
5508
  `Failed to fetch \`${this.apiEndpoint}/scopes/${scope}/packages/${name}\``,
5436
5509
  {
@@ -5445,8 +5518,18 @@ var _JsrClient = class _JsrClient {
5445
5518
  method: "POST",
5446
5519
  body: JSON.stringify({ scope })
5447
5520
  });
5448
- return response.status === 200 || response.status === 201;
5521
+ if (response.status === 200 || response.status === 201) return true;
5522
+ let detail = "";
5523
+ try {
5524
+ const body = await response.json();
5525
+ detail = body.message || body.error || JSON.stringify(body);
5526
+ } catch {
5527
+ }
5528
+ throw new JsrError(
5529
+ `Failed to create scope '${scope}': HTTP ${response.status}${detail ? ` \u2014 ${detail}` : ""}`
5530
+ );
5449
5531
  } catch (error) {
5532
+ if (error instanceof JsrError) throw error;
5450
5533
  throw new JsrError(`Failed to fetch \`${this.apiEndpoint}/scopes\``, {
5451
5534
  cause: error
5452
5535
  });
@@ -5457,8 +5540,18 @@ var _JsrClient = class _JsrClient {
5457
5540
  const response = await this.fetch(`/scopes/${scope}`, {
5458
5541
  method: "DELETE"
5459
5542
  });
5460
- return response.status === 200 || response.status === 204;
5543
+ if (response.status === 200 || response.status === 204) return true;
5544
+ let detail = "";
5545
+ try {
5546
+ const body = await response.json();
5547
+ detail = body.message || body.error || JSON.stringify(body);
5548
+ } catch {
5549
+ }
5550
+ throw new JsrError(
5551
+ `Failed to delete scope '${scope}': HTTP ${response.status}${detail ? ` \u2014 ${detail}` : ""}`
5552
+ );
5461
5553
  } catch (error) {
5554
+ if (error instanceof JsrError) throw error;
5462
5555
  throw new JsrError(
5463
5556
  `Failed to fetch \`${this.apiEndpoint}/scopes/${scope}\``,
5464
5557
  {
@@ -5474,8 +5567,18 @@ var _JsrClient = class _JsrClient {
5474
5567
  method: "POST",
5475
5568
  body: JSON.stringify({ package: name })
5476
5569
  });
5477
- return response.status === 200 || response.status === 201;
5570
+ if (response.status === 200 || response.status === 201) return true;
5571
+ let detail = "";
5572
+ try {
5573
+ const body = await response.json();
5574
+ detail = body.message || body.error || JSON.stringify(body);
5575
+ } catch {
5576
+ }
5577
+ throw new JsrError(
5578
+ `Failed to create package '${packageName}': HTTP ${response.status}${detail ? ` \u2014 ${detail}` : ""}`
5579
+ );
5478
5580
  } catch (error) {
5581
+ if (error instanceof JsrError) throw error;
5479
5582
  throw new JsrError(
5480
5583
  `Failed to fetch \`${this.apiEndpoint}/scopes/${scope}/packages\``,
5481
5584
  {
@@ -5490,8 +5593,18 @@ var _JsrClient = class _JsrClient {
5490
5593
  const response = await this.fetch(`/scopes/${scope}/packages/${name}`, {
5491
5594
  method: "DELETE"
5492
5595
  });
5493
- return response.status === 200 || response.status === 204;
5596
+ if (response.status === 200 || response.status === 204) return true;
5597
+ let detail = "";
5598
+ try {
5599
+ const body = await response.json();
5600
+ detail = body.message || body.error || JSON.stringify(body);
5601
+ } catch {
5602
+ }
5603
+ throw new JsrError(
5604
+ `Failed to delete package '${packageName}': HTTP ${response.status}${detail ? ` \u2014 ${detail}` : ""}`
5605
+ );
5494
5606
  } catch (error) {
5607
+ if (error instanceof JsrError) throw error;
5495
5608
  throw new JsrError(
5496
5609
  `Failed to fetch \`${this.apiEndpoint}/scopes/${scope}/packages/${name}\``,
5497
5610
  {
@@ -5504,9 +5617,7 @@ var _JsrClient = class _JsrClient {
5504
5617
  try {
5505
5618
  const response = await this.fetch(`/packages?query=${query}`);
5506
5619
  if (!response.ok) {
5507
- throw new Error(
5508
- `HTTP ${response.status}: ${response.statusText}`
5509
- );
5620
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
5510
5621
  }
5511
5622
  return await response.json();
5512
5623
  } catch (error) {
@@ -5584,7 +5695,7 @@ var NpmRegistry = class extends Registry {
5584
5695
  await this.npm(["whoami"]);
5585
5696
  return true;
5586
5697
  } catch (error) {
5587
- if (error instanceof import_tinyexec4.NonZeroExitError && error.output?.stderr.includes("ENEEDAUTH")) {
5698
+ if (error instanceof import_tinyexec4.NonZeroExitError) {
5588
5699
  return false;
5589
5700
  }
5590
5701
  throw new NpmError("Failed to run `npm whoami`", { cause: error });
@@ -5592,16 +5703,22 @@ var NpmRegistry = class extends Registry {
5592
5703
  }
5593
5704
  async collaborators() {
5594
5705
  try {
5595
- return JSON.parse(
5596
- await this.npm([
5597
- "access",
5598
- "list",
5599
- "collaborators",
5600
- this.packageName,
5601
- "--json"
5602
- ])
5603
- );
5706
+ const output = await this.npm([
5707
+ "access",
5708
+ "list",
5709
+ "collaborators",
5710
+ this.packageName,
5711
+ "--json"
5712
+ ]);
5713
+ try {
5714
+ return JSON.parse(output);
5715
+ } catch {
5716
+ throw new NpmError(
5717
+ `Unexpected response from npm registry for collaborators of '${this.packageName}'`
5718
+ );
5719
+ }
5604
5720
  } catch (error) {
5721
+ if (error instanceof NpmError) throw error;
5605
5722
  throw new NpmError(
5606
5723
  `Failed to run \`npm access list collaborators ${this.packageName} --json\``,
5607
5724
  { cause: error }
@@ -5615,12 +5732,21 @@ var NpmRegistry = class extends Registry {
5615
5732
  }
5616
5733
  async distTags() {
5617
5734
  try {
5618
- return Object.keys(
5619
- JSON.parse(
5620
- await this.npm(["view", this.packageName, "dist-tags", "--json"])
5621
- )
5622
- );
5735
+ const output = await this.npm([
5736
+ "view",
5737
+ this.packageName,
5738
+ "dist-tags",
5739
+ "--json"
5740
+ ]);
5741
+ try {
5742
+ return Object.keys(JSON.parse(output));
5743
+ } catch {
5744
+ throw new NpmError(
5745
+ `Unexpected response from npm registry for dist-tags of '${this.packageName}'`
5746
+ );
5747
+ }
5623
5748
  } catch (error) {
5749
+ if (error instanceof NpmError) throw error;
5624
5750
  throw new NpmError(
5625
5751
  `Failed to run \`npm view ${this.packageName} dist-tags --json\``,
5626
5752
  { cause: error }
@@ -5650,12 +5776,7 @@ var NpmRegistry = class extends Registry {
5650
5776
  if (error instanceof import_tinyexec4.NonZeroExitError && error.output?.stderr.includes("EOTP")) {
5651
5777
  return false;
5652
5778
  }
5653
- throw new NpmError(
5654
- "Failed to run `npm publish --provenance --access public`",
5655
- {
5656
- cause: error
5657
- }
5658
- );
5779
+ throw this.classifyPublishError(error);
5659
5780
  }
5660
5781
  }
5661
5782
  async publish(otp) {
@@ -5667,14 +5788,39 @@ var NpmRegistry = class extends Registry {
5667
5788
  if (error instanceof import_tinyexec4.NonZeroExitError && error.output?.stderr.includes("EOTP")) {
5668
5789
  return false;
5669
5790
  }
5670
- throw new NpmError(`Failed to run \`npm ${args.join(" ")}\``, {
5671
- cause: error
5672
- });
5791
+ throw this.classifyPublishError(error);
5673
5792
  }
5674
5793
  }
5675
5794
  async isPackageNameAvaliable() {
5676
5795
  return isValidPackageName(this.packageName);
5677
5796
  }
5797
+ getRequirements() {
5798
+ return {
5799
+ needsPackageScripts: true,
5800
+ requiredManifest: "package.json"
5801
+ };
5802
+ }
5803
+ classifyPublishError(error) {
5804
+ if (error instanceof import_tinyexec4.NonZeroExitError) {
5805
+ const stderr = error.output?.stderr ?? "";
5806
+ if (stderr.includes("EOTP")) {
5807
+ return new NpmError("OTP required for publishing", { cause: error });
5808
+ }
5809
+ if (stderr.includes("403") || stderr.includes("Forbidden")) {
5810
+ return new NpmError(
5811
+ "Permission denied (403 Forbidden). Check your npm access token permissions.",
5812
+ { cause: error }
5813
+ );
5814
+ }
5815
+ if (stderr.includes("429") || stderr.includes("Too Many Requests")) {
5816
+ return new NpmError(
5817
+ "Rate limited by npm registry. Please wait and try again.",
5818
+ { cause: error }
5819
+ );
5820
+ }
5821
+ }
5822
+ return new NpmError("Failed to publish to npm", { cause: error });
5823
+ }
5678
5824
  };
5679
5825
  async function npmRegistry() {
5680
5826
  const packageJson = await getPackageJson();
@@ -5706,17 +5852,34 @@ var jsrAvailableCheckTasks = {
5706
5852
  if (!JsrClient.token) {
5707
5853
  task.output = "Retrieving jsr API token";
5708
5854
  if (ctx.promptEnabled) {
5709
- while (true) {
5855
+ const maxAttempts = 3;
5856
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
5710
5857
  JsrClient.token = await task.prompt(import_prompt_adapter_enquirer.ListrEnquirerPromptAdapter).run({
5711
5858
  type: "password",
5712
- message: `Please enter the jsr ${color.bold("API token")}`,
5859
+ message: `Please enter the jsr ${color.bold("API token")}${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`,
5713
5860
  footer: `
5714
5861
  Generate a token from ${color.bold(link2("jsr.io", "https://jsr.io/account/tokens/create/"))}. ${color.red("You should select")} ${color.bold("'Interact with the JSR API'")}.`
5715
5862
  });
5716
5863
  try {
5717
5864
  if (await jsr.client.user()) break;
5718
- task.output = "The jsr API token is invalid. Please re-enter a valid token.";
5719
- } catch {
5865
+ if (attempt < maxAttempts) {
5866
+ task.output = "The jsr API token is invalid. Please re-enter a valid token.";
5867
+ }
5868
+ } catch (error) {
5869
+ if (error instanceof Error && (error.message.includes("fetch") || error.message.includes("network") || error.message.includes("ENOTFOUND"))) {
5870
+ throw new JsrAvailableError(
5871
+ "JSR API is unreachable. Check your network connection.",
5872
+ { cause: error }
5873
+ );
5874
+ }
5875
+ if (attempt < maxAttempts) {
5876
+ task.output = "The jsr API token is invalid. Please re-enter a valid token.";
5877
+ }
5878
+ }
5879
+ if (attempt === maxAttempts) {
5880
+ throw new JsrAvailableError(
5881
+ "JSR token verification failed after 3 attempts."
5882
+ );
5720
5883
  }
5721
5884
  }
5722
5885
  } else {
@@ -5850,8 +6013,11 @@ var jsrPublishTasks = {
5850
6013
  };
5851
6014
 
5852
6015
  // src/tasks/npm.ts
6016
+ var import_node_child_process = require("child_process");
5853
6017
  var import_node_process7 = __toESM(require("process"), 1);
5854
6018
  var import_prompt_adapter_enquirer2 = require("@listr2/prompt-adapter-enquirer");
6019
+ var import_promise_spawn = __toESM(require("@npmcli/promise-spawn"), 1);
6020
+ var { open } = import_promise_spawn.default;
5855
6021
  var NpmAvailableError = class extends AbstractError {
5856
6022
  constructor(message, { cause } = {}) {
5857
6023
  super(message, { cause });
@@ -5862,12 +6028,55 @@ var NpmAvailableError = class extends AbstractError {
5862
6028
  var npmAvailableCheckTasks = {
5863
6029
  title: "Checking npm avaliable for publising",
5864
6030
  skip: (ctx) => !!ctx.preview,
5865
- task: async () => {
6031
+ task: async (ctx, task) => {
5866
6032
  const npm = await npmRegistry();
5867
6033
  if (!await npm.isLoggedIn()) {
5868
- throw new NpmAvailableError(
5869
- "You are not logged in. Please log in first using `npm login`."
5870
- );
6034
+ if (ctx.promptEnabled) {
6035
+ try {
6036
+ task.output = "Launching npm login...";
6037
+ await new Promise((resolve, reject) => {
6038
+ const child = (0, import_node_child_process.spawn)("npm", ["login"], {
6039
+ stdio: ["pipe", "pipe", "pipe"]
6040
+ });
6041
+ let opened = false;
6042
+ const onData = (data) => {
6043
+ const text = data.toString();
6044
+ const urlMatch = text.match(
6045
+ /https:\/\/www\.npmjs\.com\/login[^\s]*/
6046
+ );
6047
+ if (urlMatch && !opened) {
6048
+ opened = true;
6049
+ task.output = `Login at: ${color.cyan(urlMatch[0])}`;
6050
+ open(urlMatch[0]);
6051
+ child.stdin?.write("\n");
6052
+ }
6053
+ };
6054
+ child.stdout?.on("data", onData);
6055
+ child.stderr?.on("data", onData);
6056
+ child.on(
6057
+ "close",
6058
+ (code) => code === 0 ? resolve() : reject(
6059
+ new Error(`npm login exited with code ${code}`)
6060
+ )
6061
+ );
6062
+ child.on("error", reject);
6063
+ });
6064
+ } catch (error) {
6065
+ throw new NpmAvailableError(
6066
+ "npm login failed. Please run `npm login` manually and try again.",
6067
+ { cause: error }
6068
+ );
6069
+ }
6070
+ if (!await npm.isLoggedIn()) {
6071
+ throw new NpmAvailableError(
6072
+ "Still not logged in after npm login. Please verify your credentials."
6073
+ );
6074
+ }
6075
+ } else {
6076
+ throw new NpmAvailableError(
6077
+ "Not logged in to npm. Set NODE_AUTH_TOKEN in your CI environment. For GitHub Actions, add it as a repository secret."
6078
+ );
6079
+ }
5871
6080
  }
5872
6081
  if (await npm.isPublished()) {
5873
6082
  if (!await npm.hasPermission()) {
@@ -5895,24 +6104,31 @@ var npmPublishTasks = {
5895
6104
  let result = await npm.publish();
5896
6105
  if (!result) {
5897
6106
  task.title = "Running npm publish (OTP code needed)";
5898
- while (!result) {
6107
+ const maxAttempts = 3;
6108
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
5899
6109
  result = await npm.publish(
5900
6110
  await task.prompt(import_prompt_adapter_enquirer2.ListrEnquirerPromptAdapter).run({
5901
6111
  type: "password",
5902
- message: "npm OTP code"
6112
+ message: `npm OTP code${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`
5903
6113
  })
5904
6114
  );
5905
- if (!result) {
5906
- task.output = "2FA failed";
6115
+ if (result) break;
6116
+ if (attempt < maxAttempts) {
6117
+ task.output = "2FA failed. Please try again.";
5907
6118
  }
5908
6119
  }
6120
+ if (!result) {
6121
+ throw new NpmAvailableError(
6122
+ "OTP verification failed after 3 attempts."
6123
+ );
6124
+ }
5909
6125
  task.title = "Running npm publish (2FA passed)";
5910
6126
  }
5911
6127
  } else {
5912
6128
  const npmTokenEnv = import_node_process7.default.env.NODE_AUTH_TOKEN;
5913
6129
  if (!npmTokenEnv) {
5914
6130
  throw new NpmAvailableError(
5915
- "NODE_AUTH_TOKEN not found in the environment variables. Please set the token and try again."
6131
+ "NODE_AUTH_TOKEN not found in environment variables. Set it in your CI configuration:\n GitHub Actions: Add NODE_AUTH_TOKEN as a repository secret\n Other CI: Export NODE_AUTH_TOKEN with your npm access token"
5916
6132
  );
5917
6133
  }
5918
6134
  const result = await npm.publishProvenance();
@@ -6018,6 +6234,7 @@ var prerequisitesCheckTask = (options) => {
6018
6234
  );
6019
6235
  }
6020
6236
  ctx.cleanWorkingTree = false;
6237
+ return;
6021
6238
  }
6022
6239
  ctx.cleanWorkingTree = true;
6023
6240
  }
@@ -6119,6 +6336,16 @@ async function validateEngineVersion(engine, version2) {
6119
6336
  }
6120
6337
 
6121
6338
  // src/tasks/required-conditions-check.ts
6339
+ var registryRequirementsMap = {
6340
+ npm: { needsPackageScripts: true },
6341
+ jsr: { needsPackageScripts: false },
6342
+ crates: { needsPackageScripts: false }
6343
+ };
6344
+ function needsPackageScripts(registries) {
6345
+ return registries.some(
6346
+ (r) => registryRequirementsMap[r]?.needsPackageScripts ?? true
6347
+ );
6348
+ }
6122
6349
  var RequiredConditionCheckError = class extends AbstractError {
6123
6350
  constructor(message, { cause } = {}) {
6124
6351
  super(message, { cause });
@@ -6194,7 +6421,7 @@ var requiredConditionsCheckTask = (options) => createListr({
6194
6421
  },
6195
6422
  {
6196
6423
  title: "Checking if test and build scripts exist",
6197
- skip: (ctx) => ctx.jsrOnly,
6424
+ skip: (ctx) => !needsPackageScripts(ctx.registries),
6198
6425
  task: async (ctx) => {
6199
6426
  const { scripts } = await getPackageJson();
6200
6427
  const errors = [];
@@ -6248,14 +6475,12 @@ var requiredConditionsCheckTask = (options) => createListr({
6248
6475
  });
6249
6476
 
6250
6477
  // src/tasks/runner.ts
6251
- var { open } = import_promise_spawn.default;
6478
+ var { open: open2 } = import_promise_spawn2.default;
6252
6479
  var { prerelease } = import_semver3.default;
6253
6480
  async function run(options) {
6254
6481
  const ctx = {
6255
6482
  ...options,
6256
- promptEnabled: !import_std_env.isCI && import_node_process8.default.stdin.isTTY,
6257
- npmOnly: options.registries.every((registry) => registry !== "jsr"),
6258
- jsrOnly: options.registries.every((registry) => registry === "jsr")
6483
+ promptEnabled: !import_std_env.isCI && import_node_process8.default.stdin.isTTY
6259
6484
  };
6260
6485
  try {
6261
6486
  if (options.contents) import_node_process8.default.chdir(options.contents);
@@ -6291,9 +6516,16 @@ async function run(options) {
6291
6516
  title: "Running tests",
6292
6517
  task: async (ctx2) => {
6293
6518
  const packageManager = await getPackageManager();
6294
- await (0, import_tinyexec6.exec)(packageManager, ["run", ctx2.testScript], {
6295
- throwOnError: true
6296
- });
6519
+ try {
6520
+ await (0, import_tinyexec6.exec)(packageManager, ["run", ctx2.testScript], {
6521
+ throwOnError: true
6522
+ });
6523
+ } catch (error) {
6524
+ throw new AbstractError(
6525
+ `Test script '${ctx2.testScript}' failed. Run \`${packageManager} run ${ctx2.testScript}\` locally to see full output.`,
6526
+ { cause: error }
6527
+ );
6528
+ }
6297
6529
  }
6298
6530
  },
6299
6531
  {
@@ -6307,7 +6539,7 @@ async function run(options) {
6307
6539
  });
6308
6540
  } catch (error) {
6309
6541
  throw new AbstractError(
6310
- `Failed to run \`${packageManager} run ${ctx2.buildScript}\``,
6542
+ `Build script '${ctx2.buildScript}' failed. Run \`${packageManager} run ${ctx2.buildScript}\` locally to see full output.`,
6311
6543
  { cause: error }
6312
6544
  );
6313
6545
  }
@@ -6322,15 +6554,27 @@ async function run(options) {
6322
6554
  let commited = false;
6323
6555
  addRollback(async () => {
6324
6556
  if (tagCreated) {
6325
- console.log("Deleting tag...");
6326
- await git.deleteTag(`${await git.latestTag()}`);
6557
+ try {
6558
+ console.log("Deleting tag...");
6559
+ await git.deleteTag(`${await git.latestTag()}`);
6560
+ } catch (error) {
6561
+ console.error(
6562
+ `Failed to delete tag: ${error instanceof Error ? error.message : error}`
6563
+ );
6564
+ }
6327
6565
  }
6328
6566
  if (commited) {
6329
- console.log("Reset commits...");
6330
- await git.reset();
6331
- await git.stash();
6332
- await git.reset("HEAD^", "--hard");
6333
- await git.popStash();
6567
+ try {
6568
+ console.log("Reset commits...");
6569
+ await git.reset();
6570
+ await git.stash();
6571
+ await git.reset("HEAD^", "--hard");
6572
+ await git.popStash();
6573
+ } catch (error) {
6574
+ console.error(
6575
+ `Failed to reset commits: ${error instanceof Error ? error.message : error}`
6576
+ );
6577
+ }
6334
6578
  }
6335
6579
  }, ctx2);
6336
6580
  await git.reset();
@@ -6403,7 +6647,7 @@ ${repositoryUrl}/compare/${lastRev}...${latestTag}`;
6403
6647
  );
6404
6648
  const linkUrl = link2("Link", releaseDraftUrl.toString());
6405
6649
  task.title += ` ${linkUrl}`;
6406
- await open(releaseDraftUrl.toString());
6650
+ await open2(releaseDraftUrl.toString());
6407
6651
  }
6408
6652
  }
6409
6653
  ]
@@ -6861,13 +7105,47 @@ function topologicalSort(graph) {
6861
7105
  return sorted.reverse();
6862
7106
  }
6863
7107
 
6864
- // src/monorepo/groups.ts
7108
+ // src/monorepo/discover.ts
7109
+ var import_node_fs6 = require("fs");
7110
+ var import_node_path9 = __toESM(require("path"), 1);
6865
7111
  var import_micromatch = __toESM(require("micromatch"), 1);
7112
+
7113
+ // src/monorepo/workspace.ts
7114
+ var import_node_fs5 = require("fs");
7115
+ var import_node_path8 = require("path");
7116
+ var import_yaml3 = require("yaml");
7117
+ function detectWorkspace(cwd) {
7118
+ const root = cwd ?? process.cwd();
7119
+ const pnpmWorkspacePath = (0, import_node_path8.join)(root, "pnpm-workspace.yaml");
7120
+ if ((0, import_node_fs5.existsSync)(pnpmWorkspacePath)) {
7121
+ const content = (0, import_node_fs5.readFileSync)(pnpmWorkspacePath, "utf-8");
7122
+ const parsed = (0, import_yaml3.parse)(content);
7123
+ const packages = parsed?.packages ?? [];
7124
+ return { type: "pnpm", patterns: packages };
7125
+ }
7126
+ const packageJsonPath = (0, import_node_path8.join)(root, "package.json");
7127
+ if ((0, import_node_fs5.existsSync)(packageJsonPath)) {
7128
+ const content = (0, import_node_fs5.readFileSync)(packageJsonPath, "utf-8");
7129
+ const pkg = JSON.parse(content);
7130
+ if (pkg.workspaces) {
7131
+ if (Array.isArray(pkg.workspaces)) {
7132
+ return { type: "npm", patterns: pkg.workspaces };
7133
+ }
7134
+ if (typeof pkg.workspaces === "object" && Array.isArray(pkg.workspaces.packages)) {
7135
+ return { type: "yarn", patterns: pkg.workspaces.packages };
7136
+ }
7137
+ }
7138
+ }
7139
+ return null;
7140
+ }
7141
+
7142
+ // src/monorepo/groups.ts
7143
+ var import_micromatch2 = __toESM(require("micromatch"), 1);
6866
7144
  function resolveGroups(groups, allPackages) {
6867
7145
  return groups.map((group) => {
6868
7146
  const resolved = /* @__PURE__ */ new Set();
6869
7147
  for (const pattern of group) {
6870
- const matches = (0, import_micromatch.default)(allPackages, pattern);
7148
+ const matches = (0, import_micromatch2.default)(allPackages, pattern);
6871
7149
  for (const match of matches) {
6872
7150
  resolved.add(match);
6873
7151
  }
@@ -6904,73 +7182,44 @@ function applyLinkedGroup(bumps, group) {
6904
7182
  }
6905
7183
  }
6906
7184
 
6907
- // src/monorepo/workspace.ts
6908
- var import_node_fs5 = require("fs");
6909
- var import_node_path8 = require("path");
6910
- var import_yaml3 = require("yaml");
6911
- function detectWorkspace(cwd) {
6912
- const root = cwd ?? process.cwd();
6913
- const pnpmWorkspacePath = (0, import_node_path8.join)(root, "pnpm-workspace.yaml");
6914
- if ((0, import_node_fs5.existsSync)(pnpmWorkspacePath)) {
6915
- const content = (0, import_node_fs5.readFileSync)(pnpmWorkspacePath, "utf-8");
6916
- const parsed = (0, import_yaml3.parse)(content);
6917
- const packages = parsed?.packages ?? [];
6918
- return { type: "pnpm", patterns: packages };
6919
- }
6920
- const packageJsonPath = (0, import_node_path8.join)(root, "package.json");
6921
- if ((0, import_node_fs5.existsSync)(packageJsonPath)) {
6922
- const content = (0, import_node_fs5.readFileSync)(packageJsonPath, "utf-8");
6923
- const pkg = JSON.parse(content);
6924
- if (pkg.workspaces) {
6925
- if (Array.isArray(pkg.workspaces)) {
6926
- return { type: "npm", patterns: pkg.workspaces };
6927
- }
6928
- if (typeof pkg.workspaces === "object" && Array.isArray(pkg.workspaces.packages)) {
6929
- return { type: "yarn", patterns: pkg.workspaces.packages };
6930
- }
6931
- }
6932
- }
6933
- return null;
6934
- }
6935
-
6936
7185
  // src/prerelease/pre.ts
6937
- var import_node_fs6 = require("fs");
6938
- var import_node_path9 = __toESM(require("path"), 1);
7186
+ var import_node_fs7 = require("fs");
7187
+ var import_node_path10 = __toESM(require("path"), 1);
6939
7188
  function getPreStatePath(cwd) {
6940
- return import_node_path9.default.resolve(cwd ?? process.cwd(), ".pubm", "pre.json");
7189
+ return import_node_path10.default.resolve(cwd ?? process.cwd(), ".pubm", "pre.json");
6941
7190
  }
6942
7191
  function readPreState(cwd) {
6943
7192
  const filePath = getPreStatePath(cwd);
6944
- if (!(0, import_node_fs6.existsSync)(filePath)) {
7193
+ if (!(0, import_node_fs7.existsSync)(filePath)) {
6945
7194
  return null;
6946
7195
  }
6947
- const content = (0, import_node_fs6.readFileSync)(filePath, "utf-8");
7196
+ const content = (0, import_node_fs7.readFileSync)(filePath, "utf-8");
6948
7197
  return JSON.parse(content);
6949
7198
  }
6950
7199
  function enterPreMode(tag, cwd) {
6951
7200
  const filePath = getPreStatePath(cwd);
6952
- if ((0, import_node_fs6.existsSync)(filePath)) {
7201
+ if ((0, import_node_fs7.existsSync)(filePath)) {
6953
7202
  throw new Error(
6954
7203
  "Already in pre mode. Exit pre mode first before entering a new one."
6955
7204
  );
6956
7205
  }
6957
- const dir = import_node_path9.default.dirname(filePath);
6958
- if (!(0, import_node_fs6.existsSync)(dir)) {
6959
- (0, import_node_fs6.mkdirSync)(dir, { recursive: true });
7206
+ const dir = import_node_path10.default.dirname(filePath);
7207
+ if (!(0, import_node_fs7.existsSync)(dir)) {
7208
+ (0, import_node_fs7.mkdirSync)(dir, { recursive: true });
6960
7209
  }
6961
7210
  const state = {
6962
7211
  mode: "pre",
6963
7212
  tag,
6964
7213
  packages: {}
6965
7214
  };
6966
- (0, import_node_fs6.writeFileSync)(filePath, JSON.stringify(state, null, 2), "utf-8");
7215
+ (0, import_node_fs7.writeFileSync)(filePath, JSON.stringify(state, null, 2), "utf-8");
6967
7216
  }
6968
7217
  function exitPreMode(cwd) {
6969
7218
  const filePath = getPreStatePath(cwd);
6970
- if (!(0, import_node_fs6.existsSync)(filePath)) {
7219
+ if (!(0, import_node_fs7.existsSync)(filePath)) {
6971
7220
  throw new Error("Not in pre mode. Enter pre mode first before exiting.");
6972
7221
  }
6973
- (0, import_node_fs6.rmSync)(filePath);
7222
+ (0, import_node_fs7.rmSync)(filePath);
6974
7223
  }
6975
7224
 
6976
7225
  // src/prerelease/snapshot.ts
@@ -6995,11 +7244,11 @@ function generateSnapshotVersion(options) {
6995
7244
  }
6996
7245
 
6997
7246
  // src/validate/entry-points.ts
6998
- var import_node_fs7 = require("fs");
6999
- var import_node_path10 = __toESM(require("path"), 1);
7247
+ var import_node_fs8 = require("fs");
7248
+ var import_node_path11 = __toESM(require("path"), 1);
7000
7249
  var SIMPLE_FIELDS = ["main", "module", "types", "typings"];
7001
7250
  function checkPath(filePath, cwd) {
7002
- return (0, import_node_fs7.existsSync)(import_node_path10.default.resolve(cwd, filePath));
7251
+ return (0, import_node_fs8.existsSync)(import_node_path11.default.resolve(cwd, filePath));
7003
7252
  }
7004
7253
  function validateExports(exports2, cwd, prefix = "exports") {
7005
7254
  const errors = [];
@@ -7052,7 +7301,7 @@ function validateEntryPoints(pkg, cwd) {
7052
7301
  }
7053
7302
 
7054
7303
  // src/validate/extraneous-files.ts
7055
- var import_micromatch2 = __toESM(require("micromatch"), 1);
7304
+ var import_micromatch3 = __toESM(require("micromatch"), 1);
7056
7305
  var PATTERNS = [
7057
7306
  {
7058
7307
  pattern: [".env", ".env.*"],
@@ -7090,7 +7339,7 @@ function detectExtraneousFiles(files) {
7090
7339
  const seen = /* @__PURE__ */ new Set();
7091
7340
  for (const { pattern, reason, basename } of PATTERNS) {
7092
7341
  const options = basename ? { basename: true } : {};
7093
- const matched = (0, import_micromatch2.default)(files, pattern, options);
7342
+ const matched = (0, import_micromatch3.default)(files, pattern, options);
7094
7343
  for (const file of matched) {
7095
7344
  if (!seen.has(file)) {
7096
7345
  seen.add(file);