@freecodecamp/universe-cli 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.cjs +141 -17
  2. package/dist/index.js +146 -21
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -23566,6 +23566,16 @@ function createProxyClient(cfg) {
23566
23566
  (raw) => repoRowSchema.parse(raw)
23567
23567
  );
23568
23568
  },
23569
+ async deleteRepoRequest(req) {
23570
+ const url2 = `${base}/api/repo/${encodeURIComponent(req.id)}`;
23571
+ return call(url2, {
23572
+ method: "DELETE",
23573
+ headers: {
23574
+ Authorization: await userBearer(),
23575
+ Accept: "application/json"
23576
+ }
23577
+ });
23578
+ },
23569
23579
  async listRepoTemplates() {
23570
23580
  const res = await call(
23571
23581
  `${base}/api/repo/templates`,
@@ -25295,7 +25305,9 @@ async function create(options, deps = {}) {
25295
25305
  }
25296
25306
  } catch (err) {
25297
25307
  const { code, message, kind, requestId } = wrapProxyError(command, err);
25298
- outputError({ json: options.json, command }, code, message, {
25308
+ const display = kind === "already_exists" && !options.json ? `${message}
25309
+ \u2192 run \`universe repo ls --status all\` to find the existing request (it may be active or failed)` : message;
25310
+ outputError({ json: options.json, command }, code, display, {
25299
25311
  logError: error48,
25300
25312
  kind,
25301
25313
  requestId,
@@ -25314,19 +25326,20 @@ async function ls3(options, deps = {}) {
25314
25326
  const exit = deps.exit ?? exitWithCode;
25315
25327
  let identitySource;
25316
25328
  try {
25317
- if (options.status !== void 0 && !LS_STATUSES.includes(options.status)) {
25329
+ const requestedStatus = options.all ? "all" : options.status;
25330
+ if (requestedStatus !== void 0 && !LS_STATUSES.includes(requestedStatus)) {
25318
25331
  throw new UsageError(
25319
- `invalid --status "${options.status}": must be one of ${LS_STATUSES.join(", ")}`
25332
+ `invalid --status "${requestedStatus}": must be one of ${LS_STATUSES.join(", ")}`
25320
25333
  );
25321
25334
  }
25322
25335
  const setup = await setupClient2(deps);
25323
25336
  const client = setup.client;
25324
25337
  identitySource = setup.identitySource;
25325
25338
  const rows = await client.listRepoRequests({
25326
- status: options.status,
25339
+ status: requestedStatus,
25327
25340
  mine: options.mine ?? false
25328
25341
  });
25329
- const status2 = options.status ?? "pending";
25342
+ const status2 = requestedStatus ?? "pending";
25330
25343
  if (options.json) {
25331
25344
  emitJson9(
25332
25345
  buildEnvelope(command, true, {
@@ -25425,6 +25438,62 @@ async function reject(options, deps = {}) {
25425
25438
  }
25426
25439
  }
25427
25440
 
25441
+ // src/commands/repo/rm.ts
25442
+ async function rm3(options, deps = {}) {
25443
+ const command = "repo rm";
25444
+ const success2 = deps.logSuccess ?? ((s) => O2.success(s));
25445
+ const error48 = deps.logError ?? ((s) => O2.error(s));
25446
+ const exit = deps.exit ?? exitWithCode;
25447
+ const prompts = deps.prompts ?? defaultRepoPrompts;
25448
+ const isTTY = deps.isTTY ?? Boolean(process.stdout.isTTY);
25449
+ let identitySource;
25450
+ try {
25451
+ if (!options.id || options.id.trim().length === 0) {
25452
+ throw new UsageError("request id is required (positional argument)");
25453
+ }
25454
+ const setup = await setupClient2(deps);
25455
+ const client = setup.client;
25456
+ identitySource = setup.identitySource;
25457
+ if (!options.json && !options.yes) {
25458
+ if (!isTTY) {
25459
+ throw new UsageError(
25460
+ "non-interactive session: pass --yes to delete without confirmation"
25461
+ );
25462
+ }
25463
+ const cur = await client.getRepoRequest(options.id);
25464
+ const ok = await prompts.confirm({
25465
+ message: `Delete the ${cur.status} request for "${cur.name}" (${cur.id})? This frees the repo name.`
25466
+ });
25467
+ if (prompts.isCancel(ok) || ok === false) {
25468
+ throw new ConfirmError("repo rm cancelled");
25469
+ }
25470
+ }
25471
+ await client.deleteRepoRequest({ id: options.id });
25472
+ if (options.json) {
25473
+ emitJson9(
25474
+ buildEnvelope(command, true, {
25475
+ id: options.id,
25476
+ deleted: true,
25477
+ identitySource
25478
+ })
25479
+ );
25480
+ } else {
25481
+ success2(
25482
+ `Deleted request ${options.id} \u2014 the repo name is free to request again`
25483
+ );
25484
+ }
25485
+ } catch (err) {
25486
+ const { code, message, kind, requestId } = wrapProxyError(command, err);
25487
+ outputError({ json: options.json, command }, code, message, {
25488
+ logError: error48,
25489
+ kind,
25490
+ requestId,
25491
+ extras: identitySource ? { identitySource } : void 0
25492
+ });
25493
+ exit(code);
25494
+ }
25495
+ }
25496
+
25428
25497
  // src/commands/repo/status.ts
25429
25498
  function humanRow(row) {
25430
25499
  const lines = [
@@ -25481,6 +25550,7 @@ async function status(options, deps = {}) {
25481
25550
  }
25482
25551
 
25483
25552
  // src/lib/update-notifier.ts
25553
+ var import_node_child_process4 = require("child_process");
25484
25554
  var import_node_fs3 = require("fs");
25485
25555
  var import_promises8 = require("fs/promises");
25486
25556
  var import_node_os2 = require("os");
@@ -25489,8 +25559,21 @@ var APP_DIR2 = "universe-cli";
25489
25559
  var CACHE_FILE = "update-check.json";
25490
25560
  var PKG_NAME = "@freecodecamp/universe-cli";
25491
25561
  var NPM_LATEST_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
25492
- var TTL_MS = 6 * 60 * 60 * 1e3;
25562
+ var DEFAULT_TTL_MS = 60 * 60 * 1e3;
25493
25563
  var FETCH_TIMEOUT_MS = 3e3;
25564
+ var REFRESH_ENV = "UNIVERSE_REFRESH_WORKER";
25565
+ function ttlMs() {
25566
+ const raw = process.env["UNIVERSE_UPDATE_TTL_MS"];
25567
+ if (raw !== void 0) {
25568
+ const n = Number.parseInt(raw, 10);
25569
+ if (Number.isFinite(n) && n >= 0) return n;
25570
+ }
25571
+ return DEFAULT_TTL_MS;
25572
+ }
25573
+ function latestUrl() {
25574
+ const override = process.env["UNIVERSE_UPDATE_URL"];
25575
+ return override && override.length > 0 ? override : NPM_LATEST_URL;
25576
+ }
25494
25577
  function configBase2() {
25495
25578
  const xdg = process.env["XDG_CONFIG_HOME"];
25496
25579
  if (xdg && xdg.length > 0) return xdg;
@@ -25544,7 +25627,7 @@ async function fetchLatest() {
25544
25627
  const ctl = new AbortController();
25545
25628
  const timer = setTimeout(() => ctl.abort(), FETCH_TIMEOUT_MS);
25546
25629
  try {
25547
- const res = await fetch(NPM_LATEST_URL, {
25630
+ const res = await fetch(latestUrl(), {
25548
25631
  signal: ctl.signal,
25549
25632
  headers: { accept: "application/json" }
25550
25633
  });
@@ -25581,7 +25664,7 @@ async function refreshIfStale(now = Date.now(), options = {}) {
25581
25664
  if (isDisabled()) return;
25582
25665
  if (!options.force) {
25583
25666
  const cache = await readCache();
25584
- if (cache !== null && now - cache.lastCheck < TTL_MS) return;
25667
+ if (cache !== null && now - cache.lastCheck < ttlMs()) return;
25585
25668
  }
25586
25669
  const latest = await fetchLatest();
25587
25670
  if (latest === null) return;
@@ -25590,6 +25673,25 @@ async function refreshIfStale(now = Date.now(), options = {}) {
25590
25673
  } catch {
25591
25674
  }
25592
25675
  }
25676
+ function spawnRefresh(now = Date.now()) {
25677
+ if (isDisabled()) return;
25678
+ const cache = readCacheSync();
25679
+ if (cache !== null && now - cache.lastCheck < ttlMs()) return;
25680
+ try {
25681
+ const entry = process.argv[1];
25682
+ const args = entry ? [entry] : [];
25683
+ const child = (0, import_node_child_process4.spawn)(process.execPath, args, {
25684
+ detached: true,
25685
+ stdio: "ignore",
25686
+ env: { ...process.env, [REFRESH_ENV]: "1" }
25687
+ });
25688
+ child.unref();
25689
+ } catch {
25690
+ }
25691
+ }
25692
+ async function runRefreshWorker() {
25693
+ await refreshIfStale(Date.now(), { force: true });
25694
+ }
25593
25695
  function getNoticeSync(current) {
25594
25696
  if (isDisabled()) return null;
25595
25697
  const cache = readCacheSync();
@@ -25630,14 +25732,17 @@ function installExitNotice(current) {
25630
25732
  printed = true;
25631
25733
  const n = getNoticeSync(current);
25632
25734
  if (n === null) return;
25633
- process.stderr.write(formatNotice(n));
25735
+ try {
25736
+ (0, import_node_fs3.writeSync)(2, formatNotice(n));
25737
+ } catch {
25738
+ }
25634
25739
  };
25635
25740
  process.on("beforeExit", emit);
25636
25741
  process.on("exit", emit);
25637
25742
  }
25638
25743
 
25639
25744
  // src/cli.ts
25640
- var version2 = true ? "0.8.1" : "0.0.0";
25745
+ var version2 = true ? "0.9.0" : "0.0.0";
25641
25746
  function handleActionError(command, json2, err) {
25642
25747
  const ctx = { json: json2, command };
25643
25748
  const message = err instanceof Error ? err.message : "unknown error";
@@ -25660,8 +25765,7 @@ async function run(argv = process.argv) {
25660
25765
  const args = argv.slice(2);
25661
25766
  const versionRequested = isVersionRequest(args);
25662
25767
  if (!versionRequested) {
25663
- void refreshIfStale().catch(() => {
25664
- });
25768
+ spawnRefresh();
25665
25769
  }
25666
25770
  const firstPosIdx = findFirstPositional(args);
25667
25771
  const namespace = firstPosIdx >= 0 ? args[firstPosIdx] : void 0;
@@ -25765,13 +25869,14 @@ async function run(argv = process.argv) {
25765
25869
  repoCli.command("ls", "List repo requests (default: pending)").option("--json", "Output as JSON").option(
25766
25870
  "--status <status>",
25767
25871
  "pending | approved | active | rejected | failed | all"
25768
- ).option("--mine", "Only requests you submitted").action(
25872
+ ).option("--mine", "Only requests you submitted").option("--all", "Show every state (shorthand for --status all)").action(
25769
25873
  async (flags) => {
25770
25874
  try {
25771
25875
  await ls3({
25772
25876
  json: flags.json ?? false,
25773
25877
  status: flags.status,
25774
- mine: flags.mine ?? false
25878
+ mine: flags.mine ?? false,
25879
+ all: flags.all ?? false
25775
25880
  });
25776
25881
  } catch (err) {
25777
25882
  handleActionError("repo ls", flags.json ?? false, err);
@@ -25813,6 +25918,20 @@ async function run(argv = process.argv) {
25813
25918
  handleActionError("repo status", flags.json ?? false, err);
25814
25919
  }
25815
25920
  });
25921
+ repoCli.command(
25922
+ "rm <id>",
25923
+ "Delete a request, freeing its repo name (admin only)"
25924
+ ).option("--json", "Output as JSON").option("--yes", "Skip confirmation prompts (required for non-TTY/CI)").action(async (id, flags) => {
25925
+ try {
25926
+ await rm3({
25927
+ json: flags.json ?? false,
25928
+ id,
25929
+ yes: flags.yes ?? false
25930
+ });
25931
+ } catch (err) {
25932
+ handleActionError("repo rm", flags.json ?? false, err);
25933
+ }
25934
+ });
25816
25935
  repoCli.help();
25817
25936
  repoCli.version(version2);
25818
25937
  const knownRepoSubs = /* @__PURE__ */ new Set([
@@ -25820,7 +25939,8 @@ async function run(argv = process.argv) {
25820
25939
  "ls",
25821
25940
  "approve",
25822
25941
  "reject",
25823
- "status"
25942
+ "status",
25943
+ "rm"
25824
25944
  ]);
25825
25945
  const repoValueFlags = /* @__PURE__ */ new Set([
25826
25946
  "--visibility",
@@ -25975,5 +26095,9 @@ function installFatalHandlers(onFatal = defaultOnFatal) {
25975
26095
  }
25976
26096
 
25977
26097
  // src/index.ts
25978
- installFatalHandlers();
25979
- void run();
26098
+ if (process.env[REFRESH_ENV] === "1") {
26099
+ void runRefreshWorker();
26100
+ } else {
26101
+ installFatalHandlers();
26102
+ void run();
26103
+ }
package/dist/index.js CHANGED
@@ -889,6 +889,16 @@ function createProxyClient(cfg) {
889
889
  (raw) => repoRowSchema.parse(raw)
890
890
  );
891
891
  },
892
+ async deleteRepoRequest(req) {
893
+ const url = `${base}/api/repo/${encodeURIComponent(req.id)}`;
894
+ return call(url, {
895
+ method: "DELETE",
896
+ headers: {
897
+ Authorization: await userBearer(),
898
+ Accept: "application/json"
899
+ }
900
+ });
901
+ },
892
902
  async listRepoTemplates() {
893
903
  const res = await call(
894
904
  `${base}/api/repo/templates`,
@@ -2645,7 +2655,9 @@ async function create(options, deps = {}) {
2645
2655
  }
2646
2656
  } catch (err) {
2647
2657
  const { code, message, kind, requestId } = wrapProxyError(command, err);
2648
- outputError({ json: options.json, command }, code, message, {
2658
+ const display = kind === "already_exists" && !options.json ? `${message}
2659
+ \u2192 run \`universe repo ls --status all\` to find the existing request (it may be active or failed)` : message;
2660
+ outputError({ json: options.json, command }, code, display, {
2649
2661
  logError: error,
2650
2662
  kind,
2651
2663
  requestId,
@@ -2665,19 +2677,20 @@ async function ls3(options, deps = {}) {
2665
2677
  const exit = deps.exit ?? exitWithCode;
2666
2678
  let identitySource;
2667
2679
  try {
2668
- if (options.status !== void 0 && !LS_STATUSES.includes(options.status)) {
2680
+ const requestedStatus = options.all ? "all" : options.status;
2681
+ if (requestedStatus !== void 0 && !LS_STATUSES.includes(requestedStatus)) {
2669
2682
  throw new UsageError(
2670
- `invalid --status "${options.status}": must be one of ${LS_STATUSES.join(", ")}`
2683
+ `invalid --status "${requestedStatus}": must be one of ${LS_STATUSES.join(", ")}`
2671
2684
  );
2672
2685
  }
2673
2686
  const setup = await setupClient2(deps);
2674
2687
  const client = setup.client;
2675
2688
  identitySource = setup.identitySource;
2676
2689
  const rows = await client.listRepoRequests({
2677
- status: options.status,
2690
+ status: requestedStatus,
2678
2691
  mine: options.mine ?? false
2679
2692
  });
2680
- const status2 = options.status ?? "pending";
2693
+ const status2 = requestedStatus ?? "pending";
2681
2694
  if (options.json) {
2682
2695
  emitJson9(
2683
2696
  buildEnvelope(command, true, {
@@ -2777,8 +2790,65 @@ async function reject(options, deps = {}) {
2777
2790
  }
2778
2791
  }
2779
2792
 
2780
- // src/commands/repo/status.ts
2793
+ // src/commands/repo/rm.ts
2781
2794
  import { log as log17 } from "@clack/prompts";
2795
+ async function rm3(options, deps = {}) {
2796
+ const command = "repo rm";
2797
+ const success = deps.logSuccess ?? ((s) => log17.success(s));
2798
+ const error = deps.logError ?? ((s) => log17.error(s));
2799
+ const exit = deps.exit ?? exitWithCode;
2800
+ const prompts = deps.prompts ?? defaultRepoPrompts;
2801
+ const isTTY = deps.isTTY ?? Boolean(process.stdout.isTTY);
2802
+ let identitySource;
2803
+ try {
2804
+ if (!options.id || options.id.trim().length === 0) {
2805
+ throw new UsageError("request id is required (positional argument)");
2806
+ }
2807
+ const setup = await setupClient2(deps);
2808
+ const client = setup.client;
2809
+ identitySource = setup.identitySource;
2810
+ if (!options.json && !options.yes) {
2811
+ if (!isTTY) {
2812
+ throw new UsageError(
2813
+ "non-interactive session: pass --yes to delete without confirmation"
2814
+ );
2815
+ }
2816
+ const cur = await client.getRepoRequest(options.id);
2817
+ const ok = await prompts.confirm({
2818
+ message: `Delete the ${cur.status} request for "${cur.name}" (${cur.id})? This frees the repo name.`
2819
+ });
2820
+ if (prompts.isCancel(ok) || ok === false) {
2821
+ throw new ConfirmError("repo rm cancelled");
2822
+ }
2823
+ }
2824
+ await client.deleteRepoRequest({ id: options.id });
2825
+ if (options.json) {
2826
+ emitJson9(
2827
+ buildEnvelope(command, true, {
2828
+ id: options.id,
2829
+ deleted: true,
2830
+ identitySource
2831
+ })
2832
+ );
2833
+ } else {
2834
+ success(
2835
+ `Deleted request ${options.id} \u2014 the repo name is free to request again`
2836
+ );
2837
+ }
2838
+ } catch (err) {
2839
+ const { code, message, kind, requestId } = wrapProxyError(command, err);
2840
+ outputError({ json: options.json, command }, code, message, {
2841
+ logError: error,
2842
+ kind,
2843
+ requestId,
2844
+ extras: identitySource ? { identitySource } : void 0
2845
+ });
2846
+ exit(code);
2847
+ }
2848
+ }
2849
+
2850
+ // src/commands/repo/status.ts
2851
+ import { log as log18 } from "@clack/prompts";
2782
2852
  function humanRow(row) {
2783
2853
  const lines = [
2784
2854
  `Request ${row.id}`,
@@ -2799,8 +2869,8 @@ function humanRow(row) {
2799
2869
  }
2800
2870
  async function status(options, deps = {}) {
2801
2871
  const command = "repo status";
2802
- const message = deps.logMessage ?? ((s) => log17.message(s));
2803
- const error = deps.logError ?? ((s) => log17.error(s));
2872
+ const message = deps.logMessage ?? ((s) => log18.message(s));
2873
+ const error = deps.logError ?? ((s) => log18.error(s));
2804
2874
  const exit = deps.exit ?? exitWithCode;
2805
2875
  let identitySource;
2806
2876
  try {
@@ -2834,7 +2904,8 @@ async function status(options, deps = {}) {
2834
2904
  }
2835
2905
 
2836
2906
  // src/lib/update-notifier.ts
2837
- import { readFileSync } from "fs";
2907
+ import { spawn as spawn2 } from "child_process";
2908
+ import { readFileSync, writeSync } from "fs";
2838
2909
  import { mkdir as mkdir2, readFile as readFile6, writeFile as writeFile2 } from "fs/promises";
2839
2910
  import { homedir as homedir2 } from "os";
2840
2911
  import { dirname as dirname2, join as join3 } from "path";
@@ -2842,8 +2913,21 @@ var APP_DIR2 = "universe-cli";
2842
2913
  var CACHE_FILE = "update-check.json";
2843
2914
  var PKG_NAME = "@freecodecamp/universe-cli";
2844
2915
  var NPM_LATEST_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
2845
- var TTL_MS = 6 * 60 * 60 * 1e3;
2916
+ var DEFAULT_TTL_MS = 60 * 60 * 1e3;
2846
2917
  var FETCH_TIMEOUT_MS = 3e3;
2918
+ var REFRESH_ENV = "UNIVERSE_REFRESH_WORKER";
2919
+ function ttlMs() {
2920
+ const raw = process.env["UNIVERSE_UPDATE_TTL_MS"];
2921
+ if (raw !== void 0) {
2922
+ const n = Number.parseInt(raw, 10);
2923
+ if (Number.isFinite(n) && n >= 0) return n;
2924
+ }
2925
+ return DEFAULT_TTL_MS;
2926
+ }
2927
+ function latestUrl() {
2928
+ const override = process.env["UNIVERSE_UPDATE_URL"];
2929
+ return override && override.length > 0 ? override : NPM_LATEST_URL;
2930
+ }
2847
2931
  function configBase2() {
2848
2932
  const xdg = process.env["XDG_CONFIG_HOME"];
2849
2933
  if (xdg && xdg.length > 0) return xdg;
@@ -2897,7 +2981,7 @@ async function fetchLatest() {
2897
2981
  const ctl = new AbortController();
2898
2982
  const timer = setTimeout(() => ctl.abort(), FETCH_TIMEOUT_MS);
2899
2983
  try {
2900
- const res = await fetch(NPM_LATEST_URL, {
2984
+ const res = await fetch(latestUrl(), {
2901
2985
  signal: ctl.signal,
2902
2986
  headers: { accept: "application/json" }
2903
2987
  });
@@ -2934,7 +3018,7 @@ async function refreshIfStale(now = Date.now(), options = {}) {
2934
3018
  if (isDisabled()) return;
2935
3019
  if (!options.force) {
2936
3020
  const cache = await readCache();
2937
- if (cache !== null && now - cache.lastCheck < TTL_MS) return;
3021
+ if (cache !== null && now - cache.lastCheck < ttlMs()) return;
2938
3022
  }
2939
3023
  const latest = await fetchLatest();
2940
3024
  if (latest === null) return;
@@ -2943,6 +3027,25 @@ async function refreshIfStale(now = Date.now(), options = {}) {
2943
3027
  } catch {
2944
3028
  }
2945
3029
  }
3030
+ function spawnRefresh(now = Date.now()) {
3031
+ if (isDisabled()) return;
3032
+ const cache = readCacheSync();
3033
+ if (cache !== null && now - cache.lastCheck < ttlMs()) return;
3034
+ try {
3035
+ const entry = process.argv[1];
3036
+ const args = entry ? [entry] : [];
3037
+ const child = spawn2(process.execPath, args, {
3038
+ detached: true,
3039
+ stdio: "ignore",
3040
+ env: { ...process.env, [REFRESH_ENV]: "1" }
3041
+ });
3042
+ child.unref();
3043
+ } catch {
3044
+ }
3045
+ }
3046
+ async function runRefreshWorker() {
3047
+ await refreshIfStale(Date.now(), { force: true });
3048
+ }
2946
3049
  function getNoticeSync(current) {
2947
3050
  if (isDisabled()) return null;
2948
3051
  const cache = readCacheSync();
@@ -2983,14 +3086,17 @@ function installExitNotice(current) {
2983
3086
  printed = true;
2984
3087
  const n = getNoticeSync(current);
2985
3088
  if (n === null) return;
2986
- process.stderr.write(formatNotice(n));
3089
+ try {
3090
+ writeSync(2, formatNotice(n));
3091
+ } catch {
3092
+ }
2987
3093
  };
2988
3094
  process.on("beforeExit", emit);
2989
3095
  process.on("exit", emit);
2990
3096
  }
2991
3097
 
2992
3098
  // src/cli.ts
2993
- var version = true ? "0.8.1" : "0.0.0";
3099
+ var version = true ? "0.9.0" : "0.0.0";
2994
3100
  function handleActionError(command, json, err) {
2995
3101
  const ctx = { json, command };
2996
3102
  const message = err instanceof Error ? err.message : "unknown error";
@@ -3013,8 +3119,7 @@ async function run(argv = process.argv) {
3013
3119
  const args = argv.slice(2);
3014
3120
  const versionRequested = isVersionRequest(args);
3015
3121
  if (!versionRequested) {
3016
- void refreshIfStale().catch(() => {
3017
- });
3122
+ spawnRefresh();
3018
3123
  }
3019
3124
  const firstPosIdx = findFirstPositional(args);
3020
3125
  const namespace = firstPosIdx >= 0 ? args[firstPosIdx] : void 0;
@@ -3118,13 +3223,14 @@ async function run(argv = process.argv) {
3118
3223
  repoCli.command("ls", "List repo requests (default: pending)").option("--json", "Output as JSON").option(
3119
3224
  "--status <status>",
3120
3225
  "pending | approved | active | rejected | failed | all"
3121
- ).option("--mine", "Only requests you submitted").action(
3226
+ ).option("--mine", "Only requests you submitted").option("--all", "Show every state (shorthand for --status all)").action(
3122
3227
  async (flags) => {
3123
3228
  try {
3124
3229
  await ls3({
3125
3230
  json: flags.json ?? false,
3126
3231
  status: flags.status,
3127
- mine: flags.mine ?? false
3232
+ mine: flags.mine ?? false,
3233
+ all: flags.all ?? false
3128
3234
  });
3129
3235
  } catch (err) {
3130
3236
  handleActionError("repo ls", flags.json ?? false, err);
@@ -3166,6 +3272,20 @@ async function run(argv = process.argv) {
3166
3272
  handleActionError("repo status", flags.json ?? false, err);
3167
3273
  }
3168
3274
  });
3275
+ repoCli.command(
3276
+ "rm <id>",
3277
+ "Delete a request, freeing its repo name (admin only)"
3278
+ ).option("--json", "Output as JSON").option("--yes", "Skip confirmation prompts (required for non-TTY/CI)").action(async (id, flags) => {
3279
+ try {
3280
+ await rm3({
3281
+ json: flags.json ?? false,
3282
+ id,
3283
+ yes: flags.yes ?? false
3284
+ });
3285
+ } catch (err) {
3286
+ handleActionError("repo rm", flags.json ?? false, err);
3287
+ }
3288
+ });
3169
3289
  repoCli.help();
3170
3290
  repoCli.version(version);
3171
3291
  const knownRepoSubs = /* @__PURE__ */ new Set([
@@ -3173,7 +3293,8 @@ async function run(argv = process.argv) {
3173
3293
  "ls",
3174
3294
  "approve",
3175
3295
  "reject",
3176
- "status"
3296
+ "status",
3297
+ "rm"
3177
3298
  ]);
3178
3299
  const repoValueFlags = /* @__PURE__ */ new Set([
3179
3300
  "--visibility",
@@ -3328,5 +3449,9 @@ function installFatalHandlers(onFatal = defaultOnFatal) {
3328
3449
  }
3329
3450
 
3330
3451
  // src/index.ts
3331
- installFatalHandlers();
3332
- void run();
3452
+ if (process.env[REFRESH_ENV] === "1") {
3453
+ void runRefreshWorker();
3454
+ } else {
3455
+ installFatalHandlers();
3456
+ void run();
3457
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@freecodecamp/universe-cli",
3
- "version": "0.8.1",
3
+ "version": "0.9.0",
4
4
  "main": "dist/index.js",
5
5
  "scripts": {
6
6
  "test": "vitest run",