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.js CHANGED
@@ -1942,7 +1942,7 @@ function resolveOptions(options) {
1942
1942
 
1943
1943
  // src/tasks/runner.ts
1944
1944
  import process10 from "node:process";
1945
- import npmCli from "@npmcli/promise-spawn";
1945
+ import npmCli2 from "@npmcli/promise-spawn";
1946
1946
 
1947
1947
  // node_modules/.pnpm/eventemitter3@5.0.1/node_modules/eventemitter3/index.mjs
1948
1948
  var import_index = __toESM(require_eventemitter3(), 1);
@@ -1963,15 +1963,15 @@ var isCompatibleTerminal = tty && tty.isatty && tty.isatty(1) && env.TERM && !is
1963
1963
  var isCI = "CI" in env && ("GITHUB_ACTIONS" in env || "GITLAB_CI" in env || "CIRCLECI" in env);
1964
1964
  var isColorSupported = !isDisabled && (isForced || isWindows && !isDumbTerminal || isCompatibleTerminal || isCI);
1965
1965
  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));
1966
- var clearBleed = (index, string, open2, close, replace) => index < 0 ? open2 + string + close : open2 + replaceClose(index, string, close, replace) + close;
1967
- var filterEmpty = (open2, close, replace = open2, at = open2.length + 1) => (string) => string || !(string === "" || string === void 0) ? clearBleed(
1966
+ var clearBleed = (index, string, open3, close, replace) => index < 0 ? open3 + string + close : open3 + replaceClose(index, string, close, replace) + close;
1967
+ var filterEmpty = (open3, close, replace = open3, at = open3.length + 1) => (string) => string || !(string === "" || string === void 0) ? clearBleed(
1968
1968
  ("" + string).indexOf(close, at),
1969
1969
  string,
1970
- open2,
1970
+ open3,
1971
1971
  close,
1972
1972
  replace
1973
1973
  ) : "";
1974
- var init = (open2, close, replace) => filterEmpty(`\x1B[${open2}m`, `\x1B[${close}m`, replace);
1974
+ var init = (open3, close, replace) => filterEmpty(`\x1B[${open3}m`, `\x1B[${close}m`, replace);
1975
1975
  var colors = {
1976
1976
  reset: init(0, 0),
1977
1977
  bold: init(1, 22, "\x1B[22m\x1B[1m"),
@@ -4451,7 +4451,7 @@ var Git = class {
4451
4451
  try {
4452
4452
  return (await this.git(["tag", "-l"])).trim().split("\n").sort(semver.compareIdentifiers);
4453
4453
  } catch (error) {
4454
- throw new GitError("Failed to run `git config --get user.name`", {
4454
+ throw new GitError("Failed to run `git tag -l`", {
4455
4455
  cause: error
4456
4456
  });
4457
4457
  }
@@ -4714,8 +4714,24 @@ async function rollback() {
4714
4714
  called = true;
4715
4715
  if (rollbacks.length <= 0) return void 0;
4716
4716
  console.log("Rollback...");
4717
- await Promise.all(rollbacks.map(({ fn, ctx }) => fn(ctx)));
4718
- console.log("Rollback completed");
4717
+ const results = await Promise.allSettled(
4718
+ rollbacks.map(({ fn, ctx }) => fn(ctx))
4719
+ );
4720
+ const failures = results.filter(
4721
+ (r) => r.status === "rejected"
4722
+ );
4723
+ if (failures.length > 0) {
4724
+ for (const failure of failures) {
4725
+ console.error(
4726
+ `Rollback operation failed: ${failure.reason instanceof Error ? failure.reason.message : failure.reason}`
4727
+ );
4728
+ }
4729
+ console.log(
4730
+ "Rollback completed with errors. Some operations may require manual recovery."
4731
+ );
4732
+ } else {
4733
+ console.log("Rollback completed");
4734
+ }
4719
4735
  }
4720
4736
 
4721
4737
  // src/utils/listr.ts
@@ -4882,20 +4898,34 @@ async function replaceVersion(version2) {
4882
4898
  const packageJsonPath = await findOutFile("package.json");
4883
4899
  if (!packageJsonPath) return void 0;
4884
4900
  const packageJson = (await readFile(packageJsonPath)).toString();
4885
- await writeFile(
4886
- packageJsonPath,
4887
- packageJson.replace(versionRegex, `$1${version2}$2`)
4888
- );
4901
+ try {
4902
+ await writeFile(
4903
+ packageJsonPath,
4904
+ packageJson.replace(versionRegex, `$1${version2}$2`)
4905
+ );
4906
+ } catch (error) {
4907
+ throw new AbstractError(
4908
+ `Failed to write version to package.json: ${error instanceof Error ? error.message : error}`,
4909
+ { cause: error }
4910
+ );
4911
+ }
4889
4912
  return "package.json";
4890
4913
  })(),
4891
4914
  (async () => {
4892
4915
  const jsrJsonPath = await findOutFile("jsr.json");
4893
4916
  if (!jsrJsonPath) return void 0;
4894
4917
  const jsrJson = (await readFile(jsrJsonPath)).toString();
4895
- await writeFile(
4896
- jsrJsonPath,
4897
- jsrJson.replace(versionRegex, `$1${version2}$2`)
4898
- );
4918
+ try {
4919
+ await writeFile(
4920
+ jsrJsonPath,
4921
+ jsrJson.replace(versionRegex, `$1${version2}$2`)
4922
+ );
4923
+ } catch (error) {
4924
+ throw new AbstractError(
4925
+ `Failed to write version to jsr.json: ${error instanceof Error ? error.message : error}`,
4926
+ { cause: error }
4927
+ );
4928
+ }
4899
4929
  return "jsr.json";
4900
4930
  })()
4901
4931
  ]);
@@ -4914,6 +4944,7 @@ async function getPackageManager() {
4914
4944
  if (await findOutFile(lockFile2)) return packageManager;
4915
4945
  }
4916
4946
  }
4947
+ console.warn("No lock file found, defaulting to npm.");
4917
4948
  return "npm";
4918
4949
  }
4919
4950
 
@@ -5032,13 +5063,21 @@ var CratesRegistry = class extends Registry {
5032
5063
  { headers: this.headers }
5033
5064
  );
5034
5065
  if (!response.ok) {
5035
- throw new Error(`Crate '${this.packageName}' not found`);
5066
+ if (response.status === 404) {
5067
+ throw new CratesError(
5068
+ `Crate '${this.packageName}' not found on crates.io`
5069
+ );
5070
+ }
5071
+ throw new CratesError(
5072
+ `crates.io API error (HTTP ${response.status}) for crate '${this.packageName}'`
5073
+ );
5036
5074
  }
5037
5075
  const data = await response.json();
5038
5076
  return data.crate.max_version;
5039
5077
  } catch (error) {
5078
+ if (error instanceof CratesError) throw error;
5040
5079
  throw new CratesError(
5041
- `Failed to fetch version for crate '${this.packageName}'`,
5080
+ `Cannot reach crates.io to fetch version for '${this.packageName}'`,
5042
5081
  { cause: error }
5043
5082
  );
5044
5083
  }
@@ -5068,6 +5107,12 @@ var CratesRegistry = class extends Registry {
5068
5107
  if (process.env.CARGO_REGISTRY_TOKEN) return true;
5069
5108
  return this.isInstalled();
5070
5109
  }
5110
+ getRequirements() {
5111
+ return {
5112
+ needsPackageScripts: false,
5113
+ requiredManifest: "Cargo.toml"
5114
+ };
5115
+ }
5071
5116
  async isPackageNameAvaliable() {
5072
5117
  try {
5073
5118
  const response = await fetch(
@@ -5075,8 +5120,11 @@ var CratesRegistry = class extends Registry {
5075
5120
  { headers: this.headers }
5076
5121
  );
5077
5122
  return !response.ok;
5078
- } catch {
5079
- return true;
5123
+ } catch (error) {
5124
+ throw new CratesError(
5125
+ `Failed to check package name availability on crates.io`,
5126
+ { cause: error }
5127
+ );
5080
5128
  }
5081
5129
  }
5082
5130
  };
@@ -5153,32 +5201,50 @@ var Db = class {
5153
5201
  mkdirSync(this.path);
5154
5202
  }
5155
5203
  } catch {
5156
- mkdirSync(this.path);
5204
+ try {
5205
+ mkdirSync(this.path);
5206
+ } catch (error) {
5207
+ throw new Error(
5208
+ `Failed to create token storage directory at '${this.path}': ${error instanceof Error ? error.message : error}`
5209
+ );
5210
+ }
5157
5211
  }
5158
5212
  }
5159
5213
  set(field, value) {
5160
- writeFileSync(
5161
- path3.resolve(this.path, Buffer.from(e(field, field)).toString("base64")),
5162
- Buffer.from(e(`${value}`, field)),
5163
- { encoding: "binary" }
5164
- );
5214
+ try {
5215
+ writeFileSync(
5216
+ path3.resolve(
5217
+ this.path,
5218
+ Buffer.from(e(field, field)).toString("base64")
5219
+ ),
5220
+ Buffer.from(e(`${value}`, field)),
5221
+ { encoding: "binary" }
5222
+ );
5223
+ } catch (error) {
5224
+ throw new Error(
5225
+ `Failed to save token for '${field}': ${error instanceof Error ? error.message : error}`
5226
+ );
5227
+ }
5165
5228
  }
5166
5229
  get(field) {
5230
+ const filePath = path3.resolve(
5231
+ this.path,
5232
+ Buffer.from(e(field, field)).toString("base64")
5233
+ );
5234
+ let raw;
5167
5235
  try {
5168
- return d(
5169
- Buffer.from(
5170
- readFileSync(
5171
- path3.resolve(
5172
- this.path,
5173
- Buffer.from(e(field, field)).toString("base64")
5174
- )
5175
- )
5176
- ).toString(),
5177
- field
5178
- );
5236
+ raw = readFileSync(filePath);
5179
5237
  } catch {
5180
5238
  return null;
5181
5239
  }
5240
+ try {
5241
+ return d(Buffer.from(raw).toString(), field);
5242
+ } catch {
5243
+ console.warn(
5244
+ `Stored token for '${field}' appears corrupted. It will be re-requested.`
5245
+ );
5246
+ return null;
5247
+ }
5182
5248
  }
5183
5249
  };
5184
5250
 
@@ -5192,9 +5258,12 @@ function getScope(packageName) {
5192
5258
  }
5193
5259
  function getScopeAndName(packageName) {
5194
5260
  const matches = packageName.match(/^@([a-zA-Z0-9]+)\/([a-zA-Z0-9]+)$/);
5195
- const scope = matches?.[1];
5196
- const name = matches?.[2];
5197
- return [`${scope}`, `${name}`];
5261
+ if (!matches) {
5262
+ throw new Error(
5263
+ `Invalid scoped package name: '${packageName}'. Expected format: @scope/name`
5264
+ );
5265
+ }
5266
+ return [matches[1], matches[2]];
5198
5267
  }
5199
5268
  var scopedPackagePattern = /^(?:@([^/]+?)[/])?([^/]+?)$/;
5200
5269
  var blacklist = ["node_modules", "favicon.ico"];
@@ -5313,6 +5382,12 @@ ${stderr}` : ""}`,
5313
5382
  async isPackageNameAvaliable() {
5314
5383
  return isValidPackageName(this.packageName);
5315
5384
  }
5385
+ getRequirements() {
5386
+ return {
5387
+ needsPackageScripts: false,
5388
+ requiredManifest: "jsr.json"
5389
+ };
5390
+ }
5316
5391
  };
5317
5392
  var _JsrClient = class _JsrClient {
5318
5393
  constructor(apiEndpoint) {
@@ -5334,9 +5409,7 @@ var _JsrClient = class _JsrClient {
5334
5409
  const response = await this.fetch("/user");
5335
5410
  if (response.status === 401) return null;
5336
5411
  if (!response.ok) {
5337
- throw new Error(
5338
- `HTTP ${response.status}: ${response.statusText}`
5339
- );
5412
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
5340
5413
  }
5341
5414
  return await response.json();
5342
5415
  } catch (error) {
@@ -5350,9 +5423,7 @@ var _JsrClient = class _JsrClient {
5350
5423
  const response = await this.fetch(`/user/member/${scope}`);
5351
5424
  if (response.status === 401) return null;
5352
5425
  if (!response.ok) {
5353
- throw new Error(
5354
- `HTTP ${response.status}: ${response.statusText}`
5355
- );
5426
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
5356
5427
  }
5357
5428
  return await response.json();
5358
5429
  } catch (error) {
@@ -5369,15 +5440,11 @@ var _JsrClient = class _JsrClient {
5369
5440
  const response = await this.fetch("/user/scopes");
5370
5441
  if (response.status === 401) return [];
5371
5442
  if (!response.ok) {
5372
- throw new Error(
5373
- `HTTP ${response.status}: ${response.statusText}`
5374
- );
5443
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
5375
5444
  }
5376
5445
  const body = await response.json();
5377
5446
  if (!Array.isArray(body)) {
5378
- throw new Error(
5379
- `Expected array response but got ${typeof body}`
5380
- );
5447
+ throw new Error(`Expected array response but got ${typeof body}`);
5381
5448
  }
5382
5449
  return body.map(({ scope }) => scope);
5383
5450
  } catch (error) {
@@ -5393,9 +5460,15 @@ var _JsrClient = class _JsrClient {
5393
5460
  const [scope, name] = getScopeAndName(packageName);
5394
5461
  try {
5395
5462
  const response = await this.fetch(`/scopes/${scope}/packages/${name}`);
5396
- if (!response.ok) return null;
5463
+ if (response.status === 404) return null;
5464
+ if (!response.ok) {
5465
+ throw new JsrError(
5466
+ `JSR API error (HTTP ${response.status}) for package '${packageName}'`
5467
+ );
5468
+ }
5397
5469
  return await response.json();
5398
5470
  } catch (error) {
5471
+ if (error instanceof JsrError) throw error;
5399
5472
  throw new JsrError(
5400
5473
  `Failed to fetch \`${this.apiEndpoint}/scopes/${scope}/packages/${name}\``,
5401
5474
  {
@@ -5410,8 +5483,18 @@ var _JsrClient = class _JsrClient {
5410
5483
  method: "POST",
5411
5484
  body: JSON.stringify({ scope })
5412
5485
  });
5413
- return response.status === 200 || response.status === 201;
5486
+ if (response.status === 200 || response.status === 201) return true;
5487
+ let detail = "";
5488
+ try {
5489
+ const body = await response.json();
5490
+ detail = body.message || body.error || JSON.stringify(body);
5491
+ } catch {
5492
+ }
5493
+ throw new JsrError(
5494
+ `Failed to create scope '${scope}': HTTP ${response.status}${detail ? ` \u2014 ${detail}` : ""}`
5495
+ );
5414
5496
  } catch (error) {
5497
+ if (error instanceof JsrError) throw error;
5415
5498
  throw new JsrError(`Failed to fetch \`${this.apiEndpoint}/scopes\``, {
5416
5499
  cause: error
5417
5500
  });
@@ -5422,8 +5505,18 @@ var _JsrClient = class _JsrClient {
5422
5505
  const response = await this.fetch(`/scopes/${scope}`, {
5423
5506
  method: "DELETE"
5424
5507
  });
5425
- return response.status === 200 || response.status === 204;
5508
+ if (response.status === 200 || response.status === 204) return true;
5509
+ let detail = "";
5510
+ try {
5511
+ const body = await response.json();
5512
+ detail = body.message || body.error || JSON.stringify(body);
5513
+ } catch {
5514
+ }
5515
+ throw new JsrError(
5516
+ `Failed to delete scope '${scope}': HTTP ${response.status}${detail ? ` \u2014 ${detail}` : ""}`
5517
+ );
5426
5518
  } catch (error) {
5519
+ if (error instanceof JsrError) throw error;
5427
5520
  throw new JsrError(
5428
5521
  `Failed to fetch \`${this.apiEndpoint}/scopes/${scope}\``,
5429
5522
  {
@@ -5439,8 +5532,18 @@ var _JsrClient = class _JsrClient {
5439
5532
  method: "POST",
5440
5533
  body: JSON.stringify({ package: name })
5441
5534
  });
5442
- return response.status === 200 || response.status === 201;
5535
+ if (response.status === 200 || response.status === 201) return true;
5536
+ let detail = "";
5537
+ try {
5538
+ const body = await response.json();
5539
+ detail = body.message || body.error || JSON.stringify(body);
5540
+ } catch {
5541
+ }
5542
+ throw new JsrError(
5543
+ `Failed to create package '${packageName}': HTTP ${response.status}${detail ? ` \u2014 ${detail}` : ""}`
5544
+ );
5443
5545
  } catch (error) {
5546
+ if (error instanceof JsrError) throw error;
5444
5547
  throw new JsrError(
5445
5548
  `Failed to fetch \`${this.apiEndpoint}/scopes/${scope}/packages\``,
5446
5549
  {
@@ -5455,8 +5558,18 @@ var _JsrClient = class _JsrClient {
5455
5558
  const response = await this.fetch(`/scopes/${scope}/packages/${name}`, {
5456
5559
  method: "DELETE"
5457
5560
  });
5458
- return response.status === 200 || response.status === 204;
5561
+ if (response.status === 200 || response.status === 204) return true;
5562
+ let detail = "";
5563
+ try {
5564
+ const body = await response.json();
5565
+ detail = body.message || body.error || JSON.stringify(body);
5566
+ } catch {
5567
+ }
5568
+ throw new JsrError(
5569
+ `Failed to delete package '${packageName}': HTTP ${response.status}${detail ? ` \u2014 ${detail}` : ""}`
5570
+ );
5459
5571
  } catch (error) {
5572
+ if (error instanceof JsrError) throw error;
5460
5573
  throw new JsrError(
5461
5574
  `Failed to fetch \`${this.apiEndpoint}/scopes/${scope}/packages/${name}\``,
5462
5575
  {
@@ -5469,9 +5582,7 @@ var _JsrClient = class _JsrClient {
5469
5582
  try {
5470
5583
  const response = await this.fetch(`/packages?query=${query}`);
5471
5584
  if (!response.ok) {
5472
- throw new Error(
5473
- `HTTP ${response.status}: ${response.statusText}`
5474
- );
5585
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
5475
5586
  }
5476
5587
  return await response.json();
5477
5588
  } catch (error) {
@@ -5549,7 +5660,7 @@ var NpmRegistry = class extends Registry {
5549
5660
  await this.npm(["whoami"]);
5550
5661
  return true;
5551
5662
  } catch (error) {
5552
- if (error instanceof NonZeroExitError2 && error.output?.stderr.includes("ENEEDAUTH")) {
5663
+ if (error instanceof NonZeroExitError2) {
5553
5664
  return false;
5554
5665
  }
5555
5666
  throw new NpmError("Failed to run `npm whoami`", { cause: error });
@@ -5557,16 +5668,22 @@ var NpmRegistry = class extends Registry {
5557
5668
  }
5558
5669
  async collaborators() {
5559
5670
  try {
5560
- return JSON.parse(
5561
- await this.npm([
5562
- "access",
5563
- "list",
5564
- "collaborators",
5565
- this.packageName,
5566
- "--json"
5567
- ])
5568
- );
5671
+ const output = await this.npm([
5672
+ "access",
5673
+ "list",
5674
+ "collaborators",
5675
+ this.packageName,
5676
+ "--json"
5677
+ ]);
5678
+ try {
5679
+ return JSON.parse(output);
5680
+ } catch {
5681
+ throw new NpmError(
5682
+ `Unexpected response from npm registry for collaborators of '${this.packageName}'`
5683
+ );
5684
+ }
5569
5685
  } catch (error) {
5686
+ if (error instanceof NpmError) throw error;
5570
5687
  throw new NpmError(
5571
5688
  `Failed to run \`npm access list collaborators ${this.packageName} --json\``,
5572
5689
  { cause: error }
@@ -5580,12 +5697,21 @@ var NpmRegistry = class extends Registry {
5580
5697
  }
5581
5698
  async distTags() {
5582
5699
  try {
5583
- return Object.keys(
5584
- JSON.parse(
5585
- await this.npm(["view", this.packageName, "dist-tags", "--json"])
5586
- )
5587
- );
5700
+ const output = await this.npm([
5701
+ "view",
5702
+ this.packageName,
5703
+ "dist-tags",
5704
+ "--json"
5705
+ ]);
5706
+ try {
5707
+ return Object.keys(JSON.parse(output));
5708
+ } catch {
5709
+ throw new NpmError(
5710
+ `Unexpected response from npm registry for dist-tags of '${this.packageName}'`
5711
+ );
5712
+ }
5588
5713
  } catch (error) {
5714
+ if (error instanceof NpmError) throw error;
5589
5715
  throw new NpmError(
5590
5716
  `Failed to run \`npm view ${this.packageName} dist-tags --json\``,
5591
5717
  { cause: error }
@@ -5615,12 +5741,7 @@ var NpmRegistry = class extends Registry {
5615
5741
  if (error instanceof NonZeroExitError2 && error.output?.stderr.includes("EOTP")) {
5616
5742
  return false;
5617
5743
  }
5618
- throw new NpmError(
5619
- "Failed to run `npm publish --provenance --access public`",
5620
- {
5621
- cause: error
5622
- }
5623
- );
5744
+ throw this.classifyPublishError(error);
5624
5745
  }
5625
5746
  }
5626
5747
  async publish(otp) {
@@ -5632,14 +5753,39 @@ var NpmRegistry = class extends Registry {
5632
5753
  if (error instanceof NonZeroExitError2 && error.output?.stderr.includes("EOTP")) {
5633
5754
  return false;
5634
5755
  }
5635
- throw new NpmError(`Failed to run \`npm ${args.join(" ")}\``, {
5636
- cause: error
5637
- });
5756
+ throw this.classifyPublishError(error);
5638
5757
  }
5639
5758
  }
5640
5759
  async isPackageNameAvaliable() {
5641
5760
  return isValidPackageName(this.packageName);
5642
5761
  }
5762
+ getRequirements() {
5763
+ return {
5764
+ needsPackageScripts: true,
5765
+ requiredManifest: "package.json"
5766
+ };
5767
+ }
5768
+ classifyPublishError(error) {
5769
+ if (error instanceof NonZeroExitError2) {
5770
+ const stderr = error.output?.stderr ?? "";
5771
+ if (stderr.includes("EOTP")) {
5772
+ return new NpmError("OTP required for publishing", { cause: error });
5773
+ }
5774
+ if (stderr.includes("403") || stderr.includes("Forbidden")) {
5775
+ return new NpmError(
5776
+ "Permission denied (403 Forbidden). Check your npm access token permissions.",
5777
+ { cause: error }
5778
+ );
5779
+ }
5780
+ if (stderr.includes("429") || stderr.includes("Too Many Requests")) {
5781
+ return new NpmError(
5782
+ "Rate limited by npm registry. Please wait and try again.",
5783
+ { cause: error }
5784
+ );
5785
+ }
5786
+ }
5787
+ return new NpmError("Failed to publish to npm", { cause: error });
5788
+ }
5643
5789
  };
5644
5790
  async function npmRegistry() {
5645
5791
  const packageJson = await getPackageJson();
@@ -5671,17 +5817,34 @@ var jsrAvailableCheckTasks = {
5671
5817
  if (!JsrClient.token) {
5672
5818
  task.output = "Retrieving jsr API token";
5673
5819
  if (ctx.promptEnabled) {
5674
- while (true) {
5820
+ const maxAttempts = 3;
5821
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
5675
5822
  JsrClient.token = await task.prompt(ListrEnquirerPromptAdapter).run({
5676
5823
  type: "password",
5677
- message: `Please enter the jsr ${color.bold("API token")}`,
5824
+ message: `Please enter the jsr ${color.bold("API token")}${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`,
5678
5825
  footer: `
5679
5826
  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'")}.`
5680
5827
  });
5681
5828
  try {
5682
5829
  if (await jsr.client.user()) break;
5683
- task.output = "The jsr API token is invalid. Please re-enter a valid token.";
5684
- } catch {
5830
+ if (attempt < maxAttempts) {
5831
+ task.output = "The jsr API token is invalid. Please re-enter a valid token.";
5832
+ }
5833
+ } catch (error) {
5834
+ if (error instanceof Error && (error.message.includes("fetch") || error.message.includes("network") || error.message.includes("ENOTFOUND"))) {
5835
+ throw new JsrAvailableError(
5836
+ "JSR API is unreachable. Check your network connection.",
5837
+ { cause: error }
5838
+ );
5839
+ }
5840
+ if (attempt < maxAttempts) {
5841
+ task.output = "The jsr API token is invalid. Please re-enter a valid token.";
5842
+ }
5843
+ }
5844
+ if (attempt === maxAttempts) {
5845
+ throw new JsrAvailableError(
5846
+ "JSR token verification failed after 3 attempts."
5847
+ );
5685
5848
  }
5686
5849
  }
5687
5850
  } else {
@@ -5815,8 +5978,11 @@ var jsrPublishTasks = {
5815
5978
  };
5816
5979
 
5817
5980
  // src/tasks/npm.ts
5981
+ import { spawn } from "node:child_process";
5818
5982
  import process9 from "node:process";
5819
5983
  import { ListrEnquirerPromptAdapter as ListrEnquirerPromptAdapter2 } from "@listr2/prompt-adapter-enquirer";
5984
+ import npmCli from "@npmcli/promise-spawn";
5985
+ var { open } = npmCli;
5820
5986
  var NpmAvailableError = class extends AbstractError {
5821
5987
  constructor(message, { cause } = {}) {
5822
5988
  super(message, { cause });
@@ -5827,12 +5993,55 @@ var NpmAvailableError = class extends AbstractError {
5827
5993
  var npmAvailableCheckTasks = {
5828
5994
  title: "Checking npm avaliable for publising",
5829
5995
  skip: (ctx) => !!ctx.preview,
5830
- task: async () => {
5996
+ task: async (ctx, task) => {
5831
5997
  const npm = await npmRegistry();
5832
5998
  if (!await npm.isLoggedIn()) {
5833
- throw new NpmAvailableError(
5834
- "You are not logged in. Please log in first using `npm login`."
5835
- );
5999
+ if (ctx.promptEnabled) {
6000
+ try {
6001
+ task.output = "Launching npm login...";
6002
+ await new Promise((resolve, reject) => {
6003
+ const child = spawn("npm", ["login"], {
6004
+ stdio: ["pipe", "pipe", "pipe"]
6005
+ });
6006
+ let opened = false;
6007
+ const onData = (data) => {
6008
+ const text = data.toString();
6009
+ const urlMatch = text.match(
6010
+ /https:\/\/www\.npmjs\.com\/login[^\s]*/
6011
+ );
6012
+ if (urlMatch && !opened) {
6013
+ opened = true;
6014
+ task.output = `Login at: ${color.cyan(urlMatch[0])}`;
6015
+ open(urlMatch[0]);
6016
+ child.stdin?.write("\n");
6017
+ }
6018
+ };
6019
+ child.stdout?.on("data", onData);
6020
+ child.stderr?.on("data", onData);
6021
+ child.on(
6022
+ "close",
6023
+ (code) => code === 0 ? resolve() : reject(
6024
+ new Error(`npm login exited with code ${code}`)
6025
+ )
6026
+ );
6027
+ child.on("error", reject);
6028
+ });
6029
+ } catch (error) {
6030
+ throw new NpmAvailableError(
6031
+ "npm login failed. Please run `npm login` manually and try again.",
6032
+ { cause: error }
6033
+ );
6034
+ }
6035
+ if (!await npm.isLoggedIn()) {
6036
+ throw new NpmAvailableError(
6037
+ "Still not logged in after npm login. Please verify your credentials."
6038
+ );
6039
+ }
6040
+ } else {
6041
+ throw new NpmAvailableError(
6042
+ "Not logged in to npm. Set NODE_AUTH_TOKEN in your CI environment. For GitHub Actions, add it as a repository secret."
6043
+ );
6044
+ }
5836
6045
  }
5837
6046
  if (await npm.isPublished()) {
5838
6047
  if (!await npm.hasPermission()) {
@@ -5860,24 +6069,31 @@ var npmPublishTasks = {
5860
6069
  let result = await npm.publish();
5861
6070
  if (!result) {
5862
6071
  task.title = "Running npm publish (OTP code needed)";
5863
- while (!result) {
6072
+ const maxAttempts = 3;
6073
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
5864
6074
  result = await npm.publish(
5865
6075
  await task.prompt(ListrEnquirerPromptAdapter2).run({
5866
6076
  type: "password",
5867
- message: "npm OTP code"
6077
+ message: `npm OTP code${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`
5868
6078
  })
5869
6079
  );
5870
- if (!result) {
5871
- task.output = "2FA failed";
6080
+ if (result) break;
6081
+ if (attempt < maxAttempts) {
6082
+ task.output = "2FA failed. Please try again.";
5872
6083
  }
5873
6084
  }
6085
+ if (!result) {
6086
+ throw new NpmAvailableError(
6087
+ "OTP verification failed after 3 attempts."
6088
+ );
6089
+ }
5874
6090
  task.title = "Running npm publish (2FA passed)";
5875
6091
  }
5876
6092
  } else {
5877
6093
  const npmTokenEnv = process9.env.NODE_AUTH_TOKEN;
5878
6094
  if (!npmTokenEnv) {
5879
6095
  throw new NpmAvailableError(
5880
- "NODE_AUTH_TOKEN not found in the environment variables. Please set the token and try again."
6096
+ "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"
5881
6097
  );
5882
6098
  }
5883
6099
  const result = await npm.publishProvenance();
@@ -5983,6 +6199,7 @@ var prerequisitesCheckTask = (options) => {
5983
6199
  );
5984
6200
  }
5985
6201
  ctx.cleanWorkingTree = false;
6202
+ return;
5986
6203
  }
5987
6204
  ctx.cleanWorkingTree = true;
5988
6205
  }
@@ -6083,6 +6300,16 @@ async function validateEngineVersion(engine, version2) {
6083
6300
  }
6084
6301
 
6085
6302
  // src/tasks/required-conditions-check.ts
6303
+ var registryRequirementsMap = {
6304
+ npm: { needsPackageScripts: true },
6305
+ jsr: { needsPackageScripts: false },
6306
+ crates: { needsPackageScripts: false }
6307
+ };
6308
+ function needsPackageScripts(registries) {
6309
+ return registries.some(
6310
+ (r) => registryRequirementsMap[r]?.needsPackageScripts ?? true
6311
+ );
6312
+ }
6086
6313
  var RequiredConditionCheckError = class extends AbstractError {
6087
6314
  constructor(message, { cause } = {}) {
6088
6315
  super(message, { cause });
@@ -6158,7 +6385,7 @@ var requiredConditionsCheckTask = (options) => createListr({
6158
6385
  },
6159
6386
  {
6160
6387
  title: "Checking if test and build scripts exist",
6161
- skip: (ctx) => ctx.jsrOnly,
6388
+ skip: (ctx) => !needsPackageScripts(ctx.registries),
6162
6389
  task: async (ctx) => {
6163
6390
  const { scripts } = await getPackageJson();
6164
6391
  const errors = [];
@@ -6212,14 +6439,12 @@ var requiredConditionsCheckTask = (options) => createListr({
6212
6439
  });
6213
6440
 
6214
6441
  // src/tasks/runner.ts
6215
- var { open } = npmCli;
6442
+ var { open: open2 } = npmCli2;
6216
6443
  var { prerelease } = SemVer;
6217
6444
  async function run(options) {
6218
6445
  const ctx = {
6219
6446
  ...options,
6220
- promptEnabled: !isCI2 && process10.stdin.isTTY,
6221
- npmOnly: options.registries.every((registry) => registry !== "jsr"),
6222
- jsrOnly: options.registries.every((registry) => registry === "jsr")
6447
+ promptEnabled: !isCI2 && process10.stdin.isTTY
6223
6448
  };
6224
6449
  try {
6225
6450
  if (options.contents) process10.chdir(options.contents);
@@ -6255,9 +6480,16 @@ async function run(options) {
6255
6480
  title: "Running tests",
6256
6481
  task: async (ctx2) => {
6257
6482
  const packageManager = await getPackageManager();
6258
- await exec7(packageManager, ["run", ctx2.testScript], {
6259
- throwOnError: true
6260
- });
6483
+ try {
6484
+ await exec7(packageManager, ["run", ctx2.testScript], {
6485
+ throwOnError: true
6486
+ });
6487
+ } catch (error) {
6488
+ throw new AbstractError(
6489
+ `Test script '${ctx2.testScript}' failed. Run \`${packageManager} run ${ctx2.testScript}\` locally to see full output.`,
6490
+ { cause: error }
6491
+ );
6492
+ }
6261
6493
  }
6262
6494
  },
6263
6495
  {
@@ -6271,7 +6503,7 @@ async function run(options) {
6271
6503
  });
6272
6504
  } catch (error) {
6273
6505
  throw new AbstractError(
6274
- `Failed to run \`${packageManager} run ${ctx2.buildScript}\``,
6506
+ `Build script '${ctx2.buildScript}' failed. Run \`${packageManager} run ${ctx2.buildScript}\` locally to see full output.`,
6275
6507
  { cause: error }
6276
6508
  );
6277
6509
  }
@@ -6286,15 +6518,27 @@ async function run(options) {
6286
6518
  let commited = false;
6287
6519
  addRollback(async () => {
6288
6520
  if (tagCreated) {
6289
- console.log("Deleting tag...");
6290
- await git.deleteTag(`${await git.latestTag()}`);
6521
+ try {
6522
+ console.log("Deleting tag...");
6523
+ await git.deleteTag(`${await git.latestTag()}`);
6524
+ } catch (error) {
6525
+ console.error(
6526
+ `Failed to delete tag: ${error instanceof Error ? error.message : error}`
6527
+ );
6528
+ }
6291
6529
  }
6292
6530
  if (commited) {
6293
- console.log("Reset commits...");
6294
- await git.reset();
6295
- await git.stash();
6296
- await git.reset("HEAD^", "--hard");
6297
- await git.popStash();
6531
+ try {
6532
+ console.log("Reset commits...");
6533
+ await git.reset();
6534
+ await git.stash();
6535
+ await git.reset("HEAD^", "--hard");
6536
+ await git.popStash();
6537
+ } catch (error) {
6538
+ console.error(
6539
+ `Failed to reset commits: ${error instanceof Error ? error.message : error}`
6540
+ );
6541
+ }
6298
6542
  }
6299
6543
  }, ctx2);
6300
6544
  await git.reset();
@@ -6367,7 +6611,7 @@ ${repositoryUrl}/compare/${lastRev}...${latestTag}`;
6367
6611
  );
6368
6612
  const linkUrl = link2("Link", releaseDraftUrl.toString());
6369
6613
  task.title += ` ${linkUrl}`;
6370
- await open(releaseDraftUrl.toString());
6614
+ await open2(releaseDraftUrl.toString());
6371
6615
  }
6372
6616
  }
6373
6617
  ]
@@ -6825,13 +7069,47 @@ function topologicalSort(graph) {
6825
7069
  return sorted.reverse();
6826
7070
  }
6827
7071
 
6828
- // src/monorepo/groups.ts
7072
+ // src/monorepo/discover.ts
7073
+ import { existsSync as existsSync4, readdirSync as readdirSync3, statSync as statSync2 } from "node:fs";
7074
+ import path8 from "node:path";
6829
7075
  import micromatch from "micromatch";
7076
+
7077
+ // src/monorepo/workspace.ts
7078
+ import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
7079
+ import { join } from "node:path";
7080
+ import { parse as parse2 } from "yaml";
7081
+ function detectWorkspace(cwd) {
7082
+ const root = cwd ?? process.cwd();
7083
+ const pnpmWorkspacePath = join(root, "pnpm-workspace.yaml");
7084
+ if (existsSync3(pnpmWorkspacePath)) {
7085
+ const content = readFileSync3(pnpmWorkspacePath, "utf-8");
7086
+ const parsed = parse2(content);
7087
+ const packages = parsed?.packages ?? [];
7088
+ return { type: "pnpm", patterns: packages };
7089
+ }
7090
+ const packageJsonPath = join(root, "package.json");
7091
+ if (existsSync3(packageJsonPath)) {
7092
+ const content = readFileSync3(packageJsonPath, "utf-8");
7093
+ const pkg = JSON.parse(content);
7094
+ if (pkg.workspaces) {
7095
+ if (Array.isArray(pkg.workspaces)) {
7096
+ return { type: "npm", patterns: pkg.workspaces };
7097
+ }
7098
+ if (typeof pkg.workspaces === "object" && Array.isArray(pkg.workspaces.packages)) {
7099
+ return { type: "yarn", patterns: pkg.workspaces.packages };
7100
+ }
7101
+ }
7102
+ }
7103
+ return null;
7104
+ }
7105
+
7106
+ // src/monorepo/groups.ts
7107
+ import micromatch2 from "micromatch";
6830
7108
  function resolveGroups(groups, allPackages) {
6831
7109
  return groups.map((group) => {
6832
7110
  const resolved = /* @__PURE__ */ new Set();
6833
7111
  for (const pattern of group) {
6834
- const matches = micromatch(allPackages, pattern);
7112
+ const matches = micromatch2(allPackages, pattern);
6835
7113
  for (const match of matches) {
6836
7114
  resolved.add(match);
6837
7115
  }
@@ -6868,50 +7146,21 @@ function applyLinkedGroup(bumps, group) {
6868
7146
  }
6869
7147
  }
6870
7148
 
6871
- // src/monorepo/workspace.ts
6872
- import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
6873
- import { join } from "node:path";
6874
- import { parse as parse2 } from "yaml";
6875
- function detectWorkspace(cwd) {
6876
- const root = cwd ?? process.cwd();
6877
- const pnpmWorkspacePath = join(root, "pnpm-workspace.yaml");
6878
- if (existsSync3(pnpmWorkspacePath)) {
6879
- const content = readFileSync3(pnpmWorkspacePath, "utf-8");
6880
- const parsed = parse2(content);
6881
- const packages = parsed?.packages ?? [];
6882
- return { type: "pnpm", patterns: packages };
6883
- }
6884
- const packageJsonPath = join(root, "package.json");
6885
- if (existsSync3(packageJsonPath)) {
6886
- const content = readFileSync3(packageJsonPath, "utf-8");
6887
- const pkg = JSON.parse(content);
6888
- if (pkg.workspaces) {
6889
- if (Array.isArray(pkg.workspaces)) {
6890
- return { type: "npm", patterns: pkg.workspaces };
6891
- }
6892
- if (typeof pkg.workspaces === "object" && Array.isArray(pkg.workspaces.packages)) {
6893
- return { type: "yarn", patterns: pkg.workspaces.packages };
6894
- }
6895
- }
6896
- }
6897
- return null;
6898
- }
6899
-
6900
7149
  // src/prerelease/pre.ts
6901
7150
  import {
6902
- existsSync as existsSync4,
7151
+ existsSync as existsSync5,
6903
7152
  mkdirSync as mkdirSync4,
6904
7153
  readFileSync as readFileSync4,
6905
7154
  rmSync,
6906
7155
  writeFileSync as writeFileSync3
6907
7156
  } from "node:fs";
6908
- import path8 from "node:path";
7157
+ import path9 from "node:path";
6909
7158
  function getPreStatePath(cwd) {
6910
- return path8.resolve(cwd ?? process.cwd(), ".pubm", "pre.json");
7159
+ return path9.resolve(cwd ?? process.cwd(), ".pubm", "pre.json");
6911
7160
  }
6912
7161
  function readPreState(cwd) {
6913
7162
  const filePath = getPreStatePath(cwd);
6914
- if (!existsSync4(filePath)) {
7163
+ if (!existsSync5(filePath)) {
6915
7164
  return null;
6916
7165
  }
6917
7166
  const content = readFileSync4(filePath, "utf-8");
@@ -6919,13 +7168,13 @@ function readPreState(cwd) {
6919
7168
  }
6920
7169
  function enterPreMode(tag, cwd) {
6921
7170
  const filePath = getPreStatePath(cwd);
6922
- if (existsSync4(filePath)) {
7171
+ if (existsSync5(filePath)) {
6923
7172
  throw new Error(
6924
7173
  "Already in pre mode. Exit pre mode first before entering a new one."
6925
7174
  );
6926
7175
  }
6927
- const dir = path8.dirname(filePath);
6928
- if (!existsSync4(dir)) {
7176
+ const dir = path9.dirname(filePath);
7177
+ if (!existsSync5(dir)) {
6929
7178
  mkdirSync4(dir, { recursive: true });
6930
7179
  }
6931
7180
  const state = {
@@ -6937,7 +7186,7 @@ function enterPreMode(tag, cwd) {
6937
7186
  }
6938
7187
  function exitPreMode(cwd) {
6939
7188
  const filePath = getPreStatePath(cwd);
6940
- if (!existsSync4(filePath)) {
7189
+ if (!existsSync5(filePath)) {
6941
7190
  throw new Error("Not in pre mode. Enter pre mode first before exiting.");
6942
7191
  }
6943
7192
  rmSync(filePath);
@@ -6965,11 +7214,11 @@ function generateSnapshotVersion(options) {
6965
7214
  }
6966
7215
 
6967
7216
  // src/validate/entry-points.ts
6968
- import { existsSync as existsSync5 } from "node:fs";
6969
- import path9 from "node:path";
7217
+ import { existsSync as existsSync6 } from "node:fs";
7218
+ import path10 from "node:path";
6970
7219
  var SIMPLE_FIELDS = ["main", "module", "types", "typings"];
6971
7220
  function checkPath(filePath, cwd) {
6972
- return existsSync5(path9.resolve(cwd, filePath));
7221
+ return existsSync6(path10.resolve(cwd, filePath));
6973
7222
  }
6974
7223
  function validateExports(exports, cwd, prefix = "exports") {
6975
7224
  const errors = [];
@@ -7022,7 +7271,7 @@ function validateEntryPoints(pkg, cwd) {
7022
7271
  }
7023
7272
 
7024
7273
  // src/validate/extraneous-files.ts
7025
- import micromatch2 from "micromatch";
7274
+ import micromatch3 from "micromatch";
7026
7275
  var PATTERNS = [
7027
7276
  {
7028
7277
  pattern: [".env", ".env.*"],
@@ -7060,7 +7309,7 @@ function detectExtraneousFiles(files) {
7060
7309
  const seen = /* @__PURE__ */ new Set();
7061
7310
  for (const { pattern, reason, basename } of PATTERNS) {
7062
7311
  const options = basename ? { basename: true } : {};
7063
- const matched = micromatch2(files, pattern, options);
7312
+ const matched = micromatch3(files, pattern, options);
7064
7313
  for (const file of matched) {
7065
7314
  if (!seen.has(file)) {
7066
7315
  seen.add(file);