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/bin/cli.js CHANGED
@@ -2416,15 +2416,15 @@ var isCompatibleTerminal = tty && tty.isatty && tty.isatty(1) && env.TERM && !is
2416
2416
  var isCI = "CI" in env && ("GITHUB_ACTIONS" in env || "GITLAB_CI" in env || "CIRCLECI" in env);
2417
2417
  var isColorSupported = !isDisabled && (isForced || isWindows && !isDumbTerminal || isCompatibleTerminal || isCI);
2418
2418
  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));
2419
- var clearBleed = (index, string, open2, close, replace) => index < 0 ? open2 + string + close : open2 + replaceClose(index, string, close, replace) + close;
2420
- var filterEmpty = (open2, close, replace = open2, at = open2.length + 1) => (string) => string || !(string === "" || string === void 0) ? clearBleed(
2419
+ var clearBleed = (index, string, open3, close, replace) => index < 0 ? open3 + string + close : open3 + replaceClose(index, string, close, replace) + close;
2420
+ var filterEmpty = (open3, close, replace = open3, at = open3.length + 1) => (string) => string || !(string === "" || string === void 0) ? clearBleed(
2421
2421
  ("" + string).indexOf(close, at),
2422
2422
  string,
2423
- open2,
2423
+ open3,
2424
2424
  close,
2425
2425
  replace
2426
2426
  ) : "";
2427
- var init = (open2, close, replace) => filterEmpty(`\x1B[${open2}m`, `\x1B[${close}m`, replace);
2427
+ var init = (open3, close, replace) => filterEmpty(`\x1B[${open3}m`, `\x1B[${close}m`, replace);
2428
2428
  var colors = {
2429
2429
  reset: init(0, 0),
2430
2430
  bold: init(1, 22, "\x1B[22m\x1B[1m"),
@@ -4899,7 +4899,7 @@ var Git = class {
4899
4899
  try {
4900
4900
  return (await this.git(["tag", "-l"])).trim().split("\n").sort(semver.compareIdentifiers);
4901
4901
  } catch (error) {
4902
- throw new GitError("Failed to run `git config --get user.name`", {
4902
+ throw new GitError("Failed to run `git tag -l`", {
4903
4903
  cause: error
4904
4904
  });
4905
4905
  }
@@ -5160,7 +5160,7 @@ function resolveOptions(options) {
5160
5160
 
5161
5161
  // src/tasks/runner.ts
5162
5162
  import process14 from "node:process";
5163
- import npmCli from "@npmcli/promise-spawn";
5163
+ import npmCli2 from "@npmcli/promise-spawn";
5164
5164
  import SemVer from "semver";
5165
5165
  import { isCI as isCI2 } from "std-env";
5166
5166
  import { exec as exec7 } from "tinyexec";
@@ -5182,8 +5182,24 @@ async function rollback() {
5182
5182
  called = true;
5183
5183
  if (rollbacks.length <= 0) return void 0;
5184
5184
  console.log("Rollback...");
5185
- await Promise.all(rollbacks.map(({ fn, ctx }) => fn(ctx)));
5186
- console.log("Rollback completed");
5185
+ const results = await Promise.allSettled(
5186
+ rollbacks.map(({ fn, ctx }) => fn(ctx))
5187
+ );
5188
+ const failures = results.filter(
5189
+ (r) => r.status === "rejected"
5190
+ );
5191
+ if (failures.length > 0) {
5192
+ for (const failure of failures) {
5193
+ console.error(
5194
+ `Rollback operation failed: ${failure.reason instanceof Error ? failure.reason.message : failure.reason}`
5195
+ );
5196
+ }
5197
+ console.log(
5198
+ "Rollback completed with errors. Some operations may require manual recovery."
5199
+ );
5200
+ } else {
5201
+ console.log("Rollback completed");
5202
+ }
5187
5203
  }
5188
5204
 
5189
5205
  // src/utils/listr.ts
@@ -5350,20 +5366,34 @@ async function replaceVersion(version2) {
5350
5366
  const packageJsonPath = await findOutFile("package.json");
5351
5367
  if (!packageJsonPath) return void 0;
5352
5368
  const packageJson = (await readFile(packageJsonPath)).toString();
5353
- await writeFile(
5354
- packageJsonPath,
5355
- packageJson.replace(versionRegex, `$1${version2}$2`)
5356
- );
5369
+ try {
5370
+ await writeFile(
5371
+ packageJsonPath,
5372
+ packageJson.replace(versionRegex, `$1${version2}$2`)
5373
+ );
5374
+ } catch (error) {
5375
+ throw new AbstractError(
5376
+ `Failed to write version to package.json: ${error instanceof Error ? error.message : error}`,
5377
+ { cause: error }
5378
+ );
5379
+ }
5357
5380
  return "package.json";
5358
5381
  })(),
5359
5382
  (async () => {
5360
5383
  const jsrJsonPath = await findOutFile("jsr.json");
5361
5384
  if (!jsrJsonPath) return void 0;
5362
5385
  const jsrJson = (await readFile(jsrJsonPath)).toString();
5363
- await writeFile(
5364
- jsrJsonPath,
5365
- jsrJson.replace(versionRegex, `$1${version2}$2`)
5366
- );
5386
+ try {
5387
+ await writeFile(
5388
+ jsrJsonPath,
5389
+ jsrJson.replace(versionRegex, `$1${version2}$2`)
5390
+ );
5391
+ } catch (error) {
5392
+ throw new AbstractError(
5393
+ `Failed to write version to jsr.json: ${error instanceof Error ? error.message : error}`,
5394
+ { cause: error }
5395
+ );
5396
+ }
5367
5397
  return "jsr.json";
5368
5398
  })()
5369
5399
  ]);
@@ -5382,6 +5412,7 @@ async function getPackageManager() {
5382
5412
  if (await findOutFile(lockFile2)) return packageManager;
5383
5413
  }
5384
5414
  }
5415
+ console.warn("No lock file found, defaulting to npm.");
5385
5416
  return "npm";
5386
5417
  }
5387
5418
 
@@ -5500,13 +5531,21 @@ var CratesRegistry = class extends Registry {
5500
5531
  { headers: this.headers }
5501
5532
  );
5502
5533
  if (!response.ok) {
5503
- throw new Error(`Crate '${this.packageName}' not found`);
5534
+ if (response.status === 404) {
5535
+ throw new CratesError(
5536
+ `Crate '${this.packageName}' not found on crates.io`
5537
+ );
5538
+ }
5539
+ throw new CratesError(
5540
+ `crates.io API error (HTTP ${response.status}) for crate '${this.packageName}'`
5541
+ );
5504
5542
  }
5505
5543
  const data = await response.json();
5506
5544
  return data.crate.max_version;
5507
5545
  } catch (error) {
5546
+ if (error instanceof CratesError) throw error;
5508
5547
  throw new CratesError(
5509
- `Failed to fetch version for crate '${this.packageName}'`,
5548
+ `Cannot reach crates.io to fetch version for '${this.packageName}'`,
5510
5549
  { cause: error }
5511
5550
  );
5512
5551
  }
@@ -5536,6 +5575,12 @@ var CratesRegistry = class extends Registry {
5536
5575
  if (process.env.CARGO_REGISTRY_TOKEN) return true;
5537
5576
  return this.isInstalled();
5538
5577
  }
5578
+ getRequirements() {
5579
+ return {
5580
+ needsPackageScripts: false,
5581
+ requiredManifest: "Cargo.toml"
5582
+ };
5583
+ }
5539
5584
  async isPackageNameAvaliable() {
5540
5585
  try {
5541
5586
  const response = await fetch(
@@ -5543,8 +5588,11 @@ var CratesRegistry = class extends Registry {
5543
5588
  { headers: this.headers }
5544
5589
  );
5545
5590
  return !response.ok;
5546
- } catch {
5547
- return true;
5591
+ } catch (error) {
5592
+ throw new CratesError(
5593
+ `Failed to check package name availability on crates.io`,
5594
+ { cause: error }
5595
+ );
5548
5596
  }
5549
5597
  }
5550
5598
  };
@@ -5621,30 +5669,48 @@ var Db = class {
5621
5669
  mkdirSync5(this.path);
5622
5670
  }
5623
5671
  } catch {
5624
- mkdirSync5(this.path);
5672
+ try {
5673
+ mkdirSync5(this.path);
5674
+ } catch (error) {
5675
+ throw new Error(
5676
+ `Failed to create token storage directory at '${this.path}': ${error instanceof Error ? error.message : error}`
5677
+ );
5678
+ }
5625
5679
  }
5626
5680
  }
5627
5681
  set(field, value) {
5628
- writeFileSync4(
5629
- path8.resolve(this.path, Buffer.from(e(field, field)).toString("base64")),
5630
- Buffer.from(e(`${value}`, field)),
5631
- { encoding: "binary" }
5632
- );
5682
+ try {
5683
+ writeFileSync4(
5684
+ path8.resolve(
5685
+ this.path,
5686
+ Buffer.from(e(field, field)).toString("base64")
5687
+ ),
5688
+ Buffer.from(e(`${value}`, field)),
5689
+ { encoding: "binary" }
5690
+ );
5691
+ } catch (error) {
5692
+ throw new Error(
5693
+ `Failed to save token for '${field}': ${error instanceof Error ? error.message : error}`
5694
+ );
5695
+ }
5633
5696
  }
5634
5697
  get(field) {
5698
+ const filePath = path8.resolve(
5699
+ this.path,
5700
+ Buffer.from(e(field, field)).toString("base64")
5701
+ );
5702
+ let raw;
5635
5703
  try {
5636
- return d(
5637
- Buffer.from(
5638
- readFileSync3(
5639
- path8.resolve(
5640
- this.path,
5641
- Buffer.from(e(field, field)).toString("base64")
5642
- )
5643
- )
5644
- ).toString(),
5645
- field
5646
- );
5704
+ raw = readFileSync3(filePath);
5705
+ } catch {
5706
+ return null;
5707
+ }
5708
+ try {
5709
+ return d(Buffer.from(raw).toString(), field);
5647
5710
  } catch {
5711
+ console.warn(
5712
+ `Stored token for '${field}' appears corrupted. It will be re-requested.`
5713
+ );
5648
5714
  return null;
5649
5715
  }
5650
5716
  }
@@ -5660,9 +5726,12 @@ function getScope(packageName) {
5660
5726
  }
5661
5727
  function getScopeAndName(packageName) {
5662
5728
  const matches = packageName.match(/^@([a-zA-Z0-9]+)\/([a-zA-Z0-9]+)$/);
5663
- const scope = matches?.[1];
5664
- const name = matches?.[2];
5665
- return [`${scope}`, `${name}`];
5729
+ if (!matches) {
5730
+ throw new Error(
5731
+ `Invalid scoped package name: '${packageName}'. Expected format: @scope/name`
5732
+ );
5733
+ }
5734
+ return [matches[1], matches[2]];
5666
5735
  }
5667
5736
  var scopedPackagePattern = /^(?:@([^/]+?)[/])?([^/]+?)$/;
5668
5737
  var blacklist = ["node_modules", "favicon.ico"];
@@ -5781,6 +5850,12 @@ ${stderr}` : ""}`,
5781
5850
  async isPackageNameAvaliable() {
5782
5851
  return isValidPackageName(this.packageName);
5783
5852
  }
5853
+ getRequirements() {
5854
+ return {
5855
+ needsPackageScripts: false,
5856
+ requiredManifest: "jsr.json"
5857
+ };
5858
+ }
5784
5859
  };
5785
5860
  var _JsrClient = class _JsrClient {
5786
5861
  constructor(apiEndpoint) {
@@ -5802,9 +5877,7 @@ var _JsrClient = class _JsrClient {
5802
5877
  const response = await this.fetch("/user");
5803
5878
  if (response.status === 401) return null;
5804
5879
  if (!response.ok) {
5805
- throw new Error(
5806
- `HTTP ${response.status}: ${response.statusText}`
5807
- );
5880
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
5808
5881
  }
5809
5882
  return await response.json();
5810
5883
  } catch (error) {
@@ -5818,9 +5891,7 @@ var _JsrClient = class _JsrClient {
5818
5891
  const response = await this.fetch(`/user/member/${scope}`);
5819
5892
  if (response.status === 401) return null;
5820
5893
  if (!response.ok) {
5821
- throw new Error(
5822
- `HTTP ${response.status}: ${response.statusText}`
5823
- );
5894
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
5824
5895
  }
5825
5896
  return await response.json();
5826
5897
  } catch (error) {
@@ -5837,15 +5908,11 @@ var _JsrClient = class _JsrClient {
5837
5908
  const response = await this.fetch("/user/scopes");
5838
5909
  if (response.status === 401) return [];
5839
5910
  if (!response.ok) {
5840
- throw new Error(
5841
- `HTTP ${response.status}: ${response.statusText}`
5842
- );
5911
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
5843
5912
  }
5844
5913
  const body = await response.json();
5845
5914
  if (!Array.isArray(body)) {
5846
- throw new Error(
5847
- `Expected array response but got ${typeof body}`
5848
- );
5915
+ throw new Error(`Expected array response but got ${typeof body}`);
5849
5916
  }
5850
5917
  return body.map(({ scope }) => scope);
5851
5918
  } catch (error) {
@@ -5861,9 +5928,15 @@ var _JsrClient = class _JsrClient {
5861
5928
  const [scope, name] = getScopeAndName(packageName);
5862
5929
  try {
5863
5930
  const response = await this.fetch(`/scopes/${scope}/packages/${name}`);
5864
- if (!response.ok) return null;
5931
+ if (response.status === 404) return null;
5932
+ if (!response.ok) {
5933
+ throw new JsrError(
5934
+ `JSR API error (HTTP ${response.status}) for package '${packageName}'`
5935
+ );
5936
+ }
5865
5937
  return await response.json();
5866
5938
  } catch (error) {
5939
+ if (error instanceof JsrError) throw error;
5867
5940
  throw new JsrError(
5868
5941
  `Failed to fetch \`${this.apiEndpoint}/scopes/${scope}/packages/${name}\``,
5869
5942
  {
@@ -5878,8 +5951,18 @@ var _JsrClient = class _JsrClient {
5878
5951
  method: "POST",
5879
5952
  body: JSON.stringify({ scope })
5880
5953
  });
5881
- return response.status === 200 || response.status === 201;
5954
+ if (response.status === 200 || response.status === 201) return true;
5955
+ let detail = "";
5956
+ try {
5957
+ const body = await response.json();
5958
+ detail = body.message || body.error || JSON.stringify(body);
5959
+ } catch {
5960
+ }
5961
+ throw new JsrError(
5962
+ `Failed to create scope '${scope}': HTTP ${response.status}${detail ? ` \u2014 ${detail}` : ""}`
5963
+ );
5882
5964
  } catch (error) {
5965
+ if (error instanceof JsrError) throw error;
5883
5966
  throw new JsrError(`Failed to fetch \`${this.apiEndpoint}/scopes\``, {
5884
5967
  cause: error
5885
5968
  });
@@ -5890,8 +5973,18 @@ var _JsrClient = class _JsrClient {
5890
5973
  const response = await this.fetch(`/scopes/${scope}`, {
5891
5974
  method: "DELETE"
5892
5975
  });
5893
- return response.status === 200 || response.status === 204;
5976
+ if (response.status === 200 || response.status === 204) return true;
5977
+ let detail = "";
5978
+ try {
5979
+ const body = await response.json();
5980
+ detail = body.message || body.error || JSON.stringify(body);
5981
+ } catch {
5982
+ }
5983
+ throw new JsrError(
5984
+ `Failed to delete scope '${scope}': HTTP ${response.status}${detail ? ` \u2014 ${detail}` : ""}`
5985
+ );
5894
5986
  } catch (error) {
5987
+ if (error instanceof JsrError) throw error;
5895
5988
  throw new JsrError(
5896
5989
  `Failed to fetch \`${this.apiEndpoint}/scopes/${scope}\``,
5897
5990
  {
@@ -5907,8 +6000,18 @@ var _JsrClient = class _JsrClient {
5907
6000
  method: "POST",
5908
6001
  body: JSON.stringify({ package: name })
5909
6002
  });
5910
- return response.status === 200 || response.status === 201;
6003
+ if (response.status === 200 || response.status === 201) return true;
6004
+ let detail = "";
6005
+ try {
6006
+ const body = await response.json();
6007
+ detail = body.message || body.error || JSON.stringify(body);
6008
+ } catch {
6009
+ }
6010
+ throw new JsrError(
6011
+ `Failed to create package '${packageName}': HTTP ${response.status}${detail ? ` \u2014 ${detail}` : ""}`
6012
+ );
5911
6013
  } catch (error) {
6014
+ if (error instanceof JsrError) throw error;
5912
6015
  throw new JsrError(
5913
6016
  `Failed to fetch \`${this.apiEndpoint}/scopes/${scope}/packages\``,
5914
6017
  {
@@ -5923,8 +6026,18 @@ var _JsrClient = class _JsrClient {
5923
6026
  const response = await this.fetch(`/scopes/${scope}/packages/${name}`, {
5924
6027
  method: "DELETE"
5925
6028
  });
5926
- return response.status === 200 || response.status === 204;
6029
+ if (response.status === 200 || response.status === 204) return true;
6030
+ let detail = "";
6031
+ try {
6032
+ const body = await response.json();
6033
+ detail = body.message || body.error || JSON.stringify(body);
6034
+ } catch {
6035
+ }
6036
+ throw new JsrError(
6037
+ `Failed to delete package '${packageName}': HTTP ${response.status}${detail ? ` \u2014 ${detail}` : ""}`
6038
+ );
5927
6039
  } catch (error) {
6040
+ if (error instanceof JsrError) throw error;
5928
6041
  throw new JsrError(
5929
6042
  `Failed to fetch \`${this.apiEndpoint}/scopes/${scope}/packages/${name}\``,
5930
6043
  {
@@ -5937,9 +6050,7 @@ var _JsrClient = class _JsrClient {
5937
6050
  try {
5938
6051
  const response = await this.fetch(`/packages?query=${query}`);
5939
6052
  if (!response.ok) {
5940
- throw new Error(
5941
- `HTTP ${response.status}: ${response.statusText}`
5942
- );
6053
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
5943
6054
  }
5944
6055
  return await response.json();
5945
6056
  } catch (error) {
@@ -6017,7 +6128,7 @@ var NpmRegistry = class extends Registry {
6017
6128
  await this.npm(["whoami"]);
6018
6129
  return true;
6019
6130
  } catch (error) {
6020
- if (error instanceof NonZeroExitError2 && error.output?.stderr.includes("ENEEDAUTH")) {
6131
+ if (error instanceof NonZeroExitError2) {
6021
6132
  return false;
6022
6133
  }
6023
6134
  throw new NpmError("Failed to run `npm whoami`", { cause: error });
@@ -6025,16 +6136,22 @@ var NpmRegistry = class extends Registry {
6025
6136
  }
6026
6137
  async collaborators() {
6027
6138
  try {
6028
- return JSON.parse(
6029
- await this.npm([
6030
- "access",
6031
- "list",
6032
- "collaborators",
6033
- this.packageName,
6034
- "--json"
6035
- ])
6036
- );
6139
+ const output = await this.npm([
6140
+ "access",
6141
+ "list",
6142
+ "collaborators",
6143
+ this.packageName,
6144
+ "--json"
6145
+ ]);
6146
+ try {
6147
+ return JSON.parse(output);
6148
+ } catch {
6149
+ throw new NpmError(
6150
+ `Unexpected response from npm registry for collaborators of '${this.packageName}'`
6151
+ );
6152
+ }
6037
6153
  } catch (error) {
6154
+ if (error instanceof NpmError) throw error;
6038
6155
  throw new NpmError(
6039
6156
  `Failed to run \`npm access list collaborators ${this.packageName} --json\``,
6040
6157
  { cause: error }
@@ -6048,12 +6165,21 @@ var NpmRegistry = class extends Registry {
6048
6165
  }
6049
6166
  async distTags() {
6050
6167
  try {
6051
- return Object.keys(
6052
- JSON.parse(
6053
- await this.npm(["view", this.packageName, "dist-tags", "--json"])
6054
- )
6055
- );
6168
+ const output = await this.npm([
6169
+ "view",
6170
+ this.packageName,
6171
+ "dist-tags",
6172
+ "--json"
6173
+ ]);
6174
+ try {
6175
+ return Object.keys(JSON.parse(output));
6176
+ } catch {
6177
+ throw new NpmError(
6178
+ `Unexpected response from npm registry for dist-tags of '${this.packageName}'`
6179
+ );
6180
+ }
6056
6181
  } catch (error) {
6182
+ if (error instanceof NpmError) throw error;
6057
6183
  throw new NpmError(
6058
6184
  `Failed to run \`npm view ${this.packageName} dist-tags --json\``,
6059
6185
  { cause: error }
@@ -6083,12 +6209,7 @@ var NpmRegistry = class extends Registry {
6083
6209
  if (error instanceof NonZeroExitError2 && error.output?.stderr.includes("EOTP")) {
6084
6210
  return false;
6085
6211
  }
6086
- throw new NpmError(
6087
- "Failed to run `npm publish --provenance --access public`",
6088
- {
6089
- cause: error
6090
- }
6091
- );
6212
+ throw this.classifyPublishError(error);
6092
6213
  }
6093
6214
  }
6094
6215
  async publish(otp) {
@@ -6100,14 +6221,39 @@ var NpmRegistry = class extends Registry {
6100
6221
  if (error instanceof NonZeroExitError2 && error.output?.stderr.includes("EOTP")) {
6101
6222
  return false;
6102
6223
  }
6103
- throw new NpmError(`Failed to run \`npm ${args.join(" ")}\``, {
6104
- cause: error
6105
- });
6224
+ throw this.classifyPublishError(error);
6106
6225
  }
6107
6226
  }
6108
6227
  async isPackageNameAvaliable() {
6109
6228
  return isValidPackageName(this.packageName);
6110
6229
  }
6230
+ getRequirements() {
6231
+ return {
6232
+ needsPackageScripts: true,
6233
+ requiredManifest: "package.json"
6234
+ };
6235
+ }
6236
+ classifyPublishError(error) {
6237
+ if (error instanceof NonZeroExitError2) {
6238
+ const stderr = error.output?.stderr ?? "";
6239
+ if (stderr.includes("EOTP")) {
6240
+ return new NpmError("OTP required for publishing", { cause: error });
6241
+ }
6242
+ if (stderr.includes("403") || stderr.includes("Forbidden")) {
6243
+ return new NpmError(
6244
+ "Permission denied (403 Forbidden). Check your npm access token permissions.",
6245
+ { cause: error }
6246
+ );
6247
+ }
6248
+ if (stderr.includes("429") || stderr.includes("Too Many Requests")) {
6249
+ return new NpmError(
6250
+ "Rate limited by npm registry. Please wait and try again.",
6251
+ { cause: error }
6252
+ );
6253
+ }
6254
+ }
6255
+ return new NpmError("Failed to publish to npm", { cause: error });
6256
+ }
6111
6257
  };
6112
6258
  async function npmRegistry() {
6113
6259
  const packageJson = await getPackageJson();
@@ -6139,17 +6285,34 @@ var jsrAvailableCheckTasks = {
6139
6285
  if (!JsrClient.token) {
6140
6286
  task.output = "Retrieving jsr API token";
6141
6287
  if (ctx.promptEnabled) {
6142
- while (true) {
6288
+ const maxAttempts = 3;
6289
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
6143
6290
  JsrClient.token = await task.prompt(ListrEnquirerPromptAdapter).run({
6144
6291
  type: "password",
6145
- message: `Please enter the jsr ${color.bold("API token")}`,
6292
+ message: `Please enter the jsr ${color.bold("API token")}${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`,
6146
6293
  footer: `
6147
6294
  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'")}.`
6148
6295
  });
6149
6296
  try {
6150
6297
  if (await jsr.client.user()) break;
6151
- task.output = "The jsr API token is invalid. Please re-enter a valid token.";
6152
- } catch {
6298
+ if (attempt < maxAttempts) {
6299
+ task.output = "The jsr API token is invalid. Please re-enter a valid token.";
6300
+ }
6301
+ } catch (error) {
6302
+ if (error instanceof Error && (error.message.includes("fetch") || error.message.includes("network") || error.message.includes("ENOTFOUND"))) {
6303
+ throw new JsrAvailableError(
6304
+ "JSR API is unreachable. Check your network connection.",
6305
+ { cause: error }
6306
+ );
6307
+ }
6308
+ if (attempt < maxAttempts) {
6309
+ task.output = "The jsr API token is invalid. Please re-enter a valid token.";
6310
+ }
6311
+ }
6312
+ if (attempt === maxAttempts) {
6313
+ throw new JsrAvailableError(
6314
+ "JSR token verification failed after 3 attempts."
6315
+ );
6153
6316
  }
6154
6317
  }
6155
6318
  } else {
@@ -6283,8 +6446,11 @@ var jsrPublishTasks = {
6283
6446
  };
6284
6447
 
6285
6448
  // src/tasks/npm.ts
6449
+ import { spawn } from "node:child_process";
6286
6450
  import process13 from "node:process";
6287
6451
  import { ListrEnquirerPromptAdapter as ListrEnquirerPromptAdapter2 } from "@listr2/prompt-adapter-enquirer";
6452
+ import npmCli from "@npmcli/promise-spawn";
6453
+ var { open } = npmCli;
6288
6454
  var NpmAvailableError = class extends AbstractError {
6289
6455
  constructor(message, { cause } = {}) {
6290
6456
  super(message, { cause });
@@ -6295,12 +6461,55 @@ var NpmAvailableError = class extends AbstractError {
6295
6461
  var npmAvailableCheckTasks = {
6296
6462
  title: "Checking npm avaliable for publising",
6297
6463
  skip: (ctx) => !!ctx.preview,
6298
- task: async () => {
6464
+ task: async (ctx, task) => {
6299
6465
  const npm = await npmRegistry();
6300
6466
  if (!await npm.isLoggedIn()) {
6301
- throw new NpmAvailableError(
6302
- "You are not logged in. Please log in first using `npm login`."
6303
- );
6467
+ if (ctx.promptEnabled) {
6468
+ try {
6469
+ task.output = "Launching npm login...";
6470
+ await new Promise((resolve, reject) => {
6471
+ const child = spawn("npm", ["login"], {
6472
+ stdio: ["pipe", "pipe", "pipe"]
6473
+ });
6474
+ let opened = false;
6475
+ const onData = (data) => {
6476
+ const text = data.toString();
6477
+ const urlMatch = text.match(
6478
+ /https:\/\/www\.npmjs\.com\/login[^\s]*/
6479
+ );
6480
+ if (urlMatch && !opened) {
6481
+ opened = true;
6482
+ task.output = `Login at: ${color.cyan(urlMatch[0])}`;
6483
+ open(urlMatch[0]);
6484
+ child.stdin?.write("\n");
6485
+ }
6486
+ };
6487
+ child.stdout?.on("data", onData);
6488
+ child.stderr?.on("data", onData);
6489
+ child.on(
6490
+ "close",
6491
+ (code) => code === 0 ? resolve() : reject(
6492
+ new Error(`npm login exited with code ${code}`)
6493
+ )
6494
+ );
6495
+ child.on("error", reject);
6496
+ });
6497
+ } catch (error) {
6498
+ throw new NpmAvailableError(
6499
+ "npm login failed. Please run `npm login` manually and try again.",
6500
+ { cause: error }
6501
+ );
6502
+ }
6503
+ if (!await npm.isLoggedIn()) {
6504
+ throw new NpmAvailableError(
6505
+ "Still not logged in after npm login. Please verify your credentials."
6506
+ );
6507
+ }
6508
+ } else {
6509
+ throw new NpmAvailableError(
6510
+ "Not logged in to npm. Set NODE_AUTH_TOKEN in your CI environment. For GitHub Actions, add it as a repository secret."
6511
+ );
6512
+ }
6304
6513
  }
6305
6514
  if (await npm.isPublished()) {
6306
6515
  if (!await npm.hasPermission()) {
@@ -6328,24 +6537,31 @@ var npmPublishTasks = {
6328
6537
  let result = await npm.publish();
6329
6538
  if (!result) {
6330
6539
  task.title = "Running npm publish (OTP code needed)";
6331
- while (!result) {
6540
+ const maxAttempts = 3;
6541
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
6332
6542
  result = await npm.publish(
6333
6543
  await task.prompt(ListrEnquirerPromptAdapter2).run({
6334
6544
  type: "password",
6335
- message: "npm OTP code"
6545
+ message: `npm OTP code${attempt > 1 ? ` (attempt ${attempt}/${maxAttempts})` : ""}`
6336
6546
  })
6337
6547
  );
6338
- if (!result) {
6339
- task.output = "2FA failed";
6548
+ if (result) break;
6549
+ if (attempt < maxAttempts) {
6550
+ task.output = "2FA failed. Please try again.";
6340
6551
  }
6341
6552
  }
6553
+ if (!result) {
6554
+ throw new NpmAvailableError(
6555
+ "OTP verification failed after 3 attempts."
6556
+ );
6557
+ }
6342
6558
  task.title = "Running npm publish (2FA passed)";
6343
6559
  }
6344
6560
  } else {
6345
6561
  const npmTokenEnv = process13.env.NODE_AUTH_TOKEN;
6346
6562
  if (!npmTokenEnv) {
6347
6563
  throw new NpmAvailableError(
6348
- "NODE_AUTH_TOKEN not found in the environment variables. Please set the token and try again."
6564
+ "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"
6349
6565
  );
6350
6566
  }
6351
6567
  const result = await npm.publishProvenance();
@@ -6451,6 +6667,7 @@ var prerequisitesCheckTask = (options) => {
6451
6667
  );
6452
6668
  }
6453
6669
  ctx.cleanWorkingTree = false;
6670
+ return;
6454
6671
  }
6455
6672
  ctx.cleanWorkingTree = true;
6456
6673
  }
@@ -6551,6 +6768,16 @@ async function validateEngineVersion(engine, version2) {
6551
6768
  }
6552
6769
 
6553
6770
  // src/tasks/required-conditions-check.ts
6771
+ var registryRequirementsMap = {
6772
+ npm: { needsPackageScripts: true },
6773
+ jsr: { needsPackageScripts: false },
6774
+ crates: { needsPackageScripts: false }
6775
+ };
6776
+ function needsPackageScripts(registries) {
6777
+ return registries.some(
6778
+ (r) => registryRequirementsMap[r]?.needsPackageScripts ?? true
6779
+ );
6780
+ }
6554
6781
  var RequiredConditionCheckError = class extends AbstractError {
6555
6782
  constructor(message, { cause } = {}) {
6556
6783
  super(message, { cause });
@@ -6626,7 +6853,7 @@ var requiredConditionsCheckTask = (options) => createListr({
6626
6853
  },
6627
6854
  {
6628
6855
  title: "Checking if test and build scripts exist",
6629
- skip: (ctx) => ctx.jsrOnly,
6856
+ skip: (ctx) => !needsPackageScripts(ctx.registries),
6630
6857
  task: async (ctx) => {
6631
6858
  const { scripts } = await getPackageJson();
6632
6859
  const errors = [];
@@ -6680,14 +6907,12 @@ var requiredConditionsCheckTask = (options) => createListr({
6680
6907
  });
6681
6908
 
6682
6909
  // src/tasks/runner.ts
6683
- var { open } = npmCli;
6910
+ var { open: open2 } = npmCli2;
6684
6911
  var { prerelease } = SemVer;
6685
6912
  async function run(options) {
6686
6913
  const ctx = {
6687
6914
  ...options,
6688
- promptEnabled: !isCI2 && process14.stdin.isTTY,
6689
- npmOnly: options.registries.every((registry) => registry !== "jsr"),
6690
- jsrOnly: options.registries.every((registry) => registry === "jsr")
6915
+ promptEnabled: !isCI2 && process14.stdin.isTTY
6691
6916
  };
6692
6917
  try {
6693
6918
  if (options.contents) process14.chdir(options.contents);
@@ -6723,9 +6948,16 @@ async function run(options) {
6723
6948
  title: "Running tests",
6724
6949
  task: async (ctx2) => {
6725
6950
  const packageManager = await getPackageManager();
6726
- await exec7(packageManager, ["run", ctx2.testScript], {
6727
- throwOnError: true
6728
- });
6951
+ try {
6952
+ await exec7(packageManager, ["run", ctx2.testScript], {
6953
+ throwOnError: true
6954
+ });
6955
+ } catch (error) {
6956
+ throw new AbstractError(
6957
+ `Test script '${ctx2.testScript}' failed. Run \`${packageManager} run ${ctx2.testScript}\` locally to see full output.`,
6958
+ { cause: error }
6959
+ );
6960
+ }
6729
6961
  }
6730
6962
  },
6731
6963
  {
@@ -6739,7 +6971,7 @@ async function run(options) {
6739
6971
  });
6740
6972
  } catch (error) {
6741
6973
  throw new AbstractError(
6742
- `Failed to run \`${packageManager} run ${ctx2.buildScript}\``,
6974
+ `Build script '${ctx2.buildScript}' failed. Run \`${packageManager} run ${ctx2.buildScript}\` locally to see full output.`,
6743
6975
  { cause: error }
6744
6976
  );
6745
6977
  }
@@ -6754,15 +6986,27 @@ async function run(options) {
6754
6986
  let commited = false;
6755
6987
  addRollback(async () => {
6756
6988
  if (tagCreated) {
6757
- console.log("Deleting tag...");
6758
- await git.deleteTag(`${await git.latestTag()}`);
6989
+ try {
6990
+ console.log("Deleting tag...");
6991
+ await git.deleteTag(`${await git.latestTag()}`);
6992
+ } catch (error) {
6993
+ console.error(
6994
+ `Failed to delete tag: ${error instanceof Error ? error.message : error}`
6995
+ );
6996
+ }
6759
6997
  }
6760
6998
  if (commited) {
6761
- console.log("Reset commits...");
6762
- await git.reset();
6763
- await git.stash();
6764
- await git.reset("HEAD^", "--hard");
6765
- await git.popStash();
6999
+ try {
7000
+ console.log("Reset commits...");
7001
+ await git.reset();
7002
+ await git.stash();
7003
+ await git.reset("HEAD^", "--hard");
7004
+ await git.popStash();
7005
+ } catch (error) {
7006
+ console.error(
7007
+ `Failed to reset commits: ${error instanceof Error ? error.message : error}`
7008
+ );
7009
+ }
6766
7010
  }
6767
7011
  }, ctx2);
6768
7012
  await git.reset();
@@ -6835,7 +7079,7 @@ ${repositoryUrl}/compare/${lastRev}...${latestTag}`;
6835
7079
  );
6836
7080
  const linkUrl = link2("Link", releaseDraftUrl.toString());
6837
7081
  task.title += ` ${linkUrl}`;
6838
- await open(releaseDraftUrl.toString());
7082
+ await open2(releaseDraftUrl.toString());
6839
7083
  }
6840
7084
  }
6841
7085
  ]
@@ -6863,7 +7107,9 @@ import { inc } from "semver";
6863
7107
  import { stat as stat3 } from "node:fs/promises";
6864
7108
  import path9 from "node:path";
6865
7109
 
6866
- // src/monorepo/groups.ts
7110
+ // src/monorepo/discover.ts
7111
+ import { existsSync as existsSync6, readdirSync as readdirSync3, statSync as statSync2 } from "node:fs";
7112
+ import path10 from "node:path";
6867
7113
  import micromatch from "micromatch";
6868
7114
 
6869
7115
  // src/monorepo/workspace.ts
@@ -6871,12 +7117,15 @@ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "node:f
6871
7117
  import { join } from "node:path";
6872
7118
  import { parse as parse2 } from "yaml";
6873
7119
 
7120
+ // src/monorepo/groups.ts
7121
+ import micromatch2 from "micromatch";
7122
+
6874
7123
  // src/validate/entry-points.ts
6875
- import { existsSync as existsSync6 } from "node:fs";
6876
- import path10 from "node:path";
7124
+ import { existsSync as existsSync7 } from "node:fs";
7125
+ import path11 from "node:path";
6877
7126
 
6878
7127
  // src/validate/extraneous-files.ts
6879
- import micromatch2 from "micromatch";
7128
+ import micromatch3 from "micromatch";
6880
7129
 
6881
7130
  // src/index.ts
6882
7131
  async function pubm(options) {
@@ -7121,6 +7370,7 @@ defaultCmd.action(
7121
7370
  );
7122
7371
  } catch (e2) {
7123
7372
  consoleError(e2);
7373
+ process.exitCode = 1;
7124
7374
  }
7125
7375
  }
7126
7376
  );