rush-ai 0.13.0 → 0.14.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.
package/dist/index.js CHANGED
@@ -5,9 +5,10 @@ import {
5
5
  import {
6
6
  AtomicJsonConflictError,
7
7
  pathExists,
8
+ promptCredentials,
8
9
  readJsonFile,
9
10
  writeJsonFile
10
- } from "./chunk-V7P2TZZ4.js";
11
+ } from "./chunk-GDSJUMK4.js";
11
12
  import {
12
13
  ApiError,
13
14
  AuthError,
@@ -403,7 +404,7 @@ function getApiBaseUrl() {
403
404
  async function loginViaBrowser(jsonMode) {
404
405
  const baseUrl = getApiBaseUrl();
405
406
  const state = randomBytes(16).toString("hex");
406
- return new Promise((resolve21, reject) => {
407
+ return new Promise((resolve23, reject) => {
407
408
  let authSaved = false;
408
409
  const rejectLogin = (error) => {
409
410
  clearAuthConfig();
@@ -506,7 +507,7 @@ async function loginViaBrowser(jsonMode) {
506
507
  );
507
508
  }
508
509
  }
509
- resolve21();
510
+ resolve23();
510
511
  } catch (err) {
511
512
  server.close();
512
513
  const authError = err instanceof AuthError ? err : new AuthError(
@@ -943,9 +944,30 @@ function gitAddAndCommit(projectPath, message) {
943
944
  }
944
945
  });
945
946
  }
947
+ function getRemoteDefaultBranch(url) {
948
+ try {
949
+ const out = execFileSync("git", ["ls-remote", "--symref", url, "HEAD"], {
950
+ stdio: ["ignore", "pipe", "ignore"],
951
+ encoding: "utf-8",
952
+ timeout: 3e4,
953
+ env: {
954
+ ...process.env,
955
+ GIT_TERMINAL_PROMPT: "0",
956
+ GIT_ASKPASS: "true",
957
+ SSH_ASKPASS: "true"
958
+ }
959
+ });
960
+ const m = out.match(/^ref:\s+refs\/heads\/(\S+)\s+HEAD/m);
961
+ return m?.[1] ?? null;
962
+ } catch {
963
+ return null;
964
+ }
965
+ }
946
966
  function gitPushUrl(projectPath, url) {
967
+ const remoteDefault = getRemoteDefaultBranch(url);
968
+ const refspec = remoteDefault ? `HEAD:${remoteDefault}` : "HEAD";
947
969
  try {
948
- execFileSync("git", ["push", url, "HEAD", "--force"], {
970
+ execFileSync("git", ["push", url, refspec, "--force"], {
949
971
  cwd: projectPath,
950
972
  stdio: "pipe",
951
973
  timeout: 3e5,
@@ -2350,19 +2372,19 @@ function registerDoctorCommand(program) {
2350
2372
  }
2351
2373
 
2352
2374
  // src/marketplaces/cache.ts
2353
- import { randomUUID } from "crypto";
2375
+ import { randomUUID as randomUUID2 } from "crypto";
2354
2376
  import { constants as fsConstants3 } from "fs";
2355
2377
  import {
2356
2378
  access as access3,
2357
- mkdir as mkdir2,
2379
+ mkdir as mkdir3,
2358
2380
  readdir,
2359
2381
  readFile as readFile3,
2360
- rename,
2361
- rm as rm2,
2362
- writeFile as writeFile2
2382
+ rename as rename2,
2383
+ rm as rm3,
2384
+ writeFile as writeFile3
2363
2385
  } from "fs/promises";
2364
2386
  import { homedir as homedir3 } from "os";
2365
- import { dirname as dirname2, resolve as resolve6 } from "path";
2387
+ import { dirname as dirname2, resolve as resolve7 } from "path";
2366
2388
 
2367
2389
  // src/marketplaces/directory.ts
2368
2390
  import { stat as fsStat } from "fs/promises";
@@ -2818,6 +2840,204 @@ async function detectCacheState(cacheDir) {
2818
2840
  }
2819
2841
  }
2820
2842
 
2843
+ // src/marketplaces/rush.ts
2844
+ import { execFileSync as execFileSync4 } from "child_process";
2845
+ import { randomUUID } from "crypto";
2846
+ import { mkdir as mkdir2, rename, rm as rm2, stat, writeFile as writeFile2 } from "fs/promises";
2847
+ import { resolve as resolve6 } from "path";
2848
+ async function fetchRushMarketplace(source, opts = {}) {
2849
+ const fetchFn = opts.fetchFn ?? fetch;
2850
+ const url = `${inferProtocol(source.host)}${source.host}/api/marketplace`;
2851
+ const headers = {
2852
+ Accept: "application/json"
2853
+ };
2854
+ if (opts.token) {
2855
+ headers.Authorization = `Bearer ${opts.token}`;
2856
+ }
2857
+ const response = await fetchFn(url, { headers });
2858
+ if (!response.ok) {
2859
+ throw new Error(
2860
+ `Failed to fetch rush marketplace from ${url}: ${response.status} ${response.statusText}`
2861
+ );
2862
+ }
2863
+ const data = await response.json();
2864
+ if (!data.plugins || !Array.isArray(data.plugins)) {
2865
+ throw new Error(
2866
+ `Invalid marketplace response from ${url}: missing 'plugins' array`
2867
+ );
2868
+ }
2869
+ return data;
2870
+ }
2871
+ async function fetchRushPlugin(source, pluginSlug, opts = {}) {
2872
+ const fetchFn = opts.fetchFn ?? fetch;
2873
+ const url = `${inferProtocol(source.host)}${source.host}/api/marketplace/${encodeURIComponent(pluginSlug)}`;
2874
+ const headers = {
2875
+ Accept: "application/json"
2876
+ };
2877
+ if (opts.token) {
2878
+ headers.Authorization = `Bearer ${opts.token}`;
2879
+ }
2880
+ const response = await fetchFn(url, { headers });
2881
+ if (response.status === 401) {
2882
+ throw new Error(
2883
+ `Plugin '${pluginSlug}' requires authentication. Run 'rush-ai login' first.`
2884
+ );
2885
+ }
2886
+ if (response.status === 404) {
2887
+ throw new Error(
2888
+ `Plugin '${pluginSlug}' not found in rush marketplace at ${source.host}`
2889
+ );
2890
+ }
2891
+ if (!response.ok) {
2892
+ throw new Error(
2893
+ `Failed to fetch plugin '${pluginSlug}' from ${url}: ${response.status} ${response.statusText}`
2894
+ );
2895
+ }
2896
+ return await response.json();
2897
+ }
2898
+ async function materializeRushPlugin(source, pluginSlug, targetDir, opts = {}) {
2899
+ validateSlug(pluginSlug, "plugin slug");
2900
+ const manifest = await fetchRushPlugin(source, pluginSlug, opts);
2901
+ let mcpServers = {};
2902
+ if (manifest.mcpServers && Object.keys(manifest.mcpServers).length > 0) {
2903
+ mcpServers = { ...manifest.mcpServers };
2904
+ if (opts.secrets && Object.keys(opts.secrets).length > 0) {
2905
+ mcpServers = substituteMcpSecrets(mcpServers, opts.secrets);
2906
+ }
2907
+ }
2908
+ const pluginJson = {
2909
+ name: manifest.name,
2910
+ version: manifest.version || "1.0.0",
2911
+ description: manifest.description,
2912
+ ...Object.keys(mcpServers).length > 0 ? { mcpServers } : {}
2913
+ };
2914
+ const tmpDir = `${targetDir}.${randomUUID()}.tmp`;
2915
+ try {
2916
+ const pluginJsonDir = resolve6(tmpDir, ".claude-plugin");
2917
+ await mkdir2(pluginJsonDir, { recursive: true });
2918
+ await writeFile2(
2919
+ resolve6(pluginJsonDir, "plugin.json"),
2920
+ `${JSON.stringify(pluginJson, null, 2)}
2921
+ `,
2922
+ "utf8"
2923
+ );
2924
+ if (manifest.skills && manifest.skills.length > 0) {
2925
+ await writeFile2(
2926
+ resolve6(tmpDir, "skills.json"),
2927
+ '{"skills":{}}\n',
2928
+ "utf8"
2929
+ );
2930
+ const registryUrl = `${inferProtocol(source.host)}${source.host}`;
2931
+ for (const skill of manifest.skills) {
2932
+ try {
2933
+ const args = [
2934
+ "-y",
2935
+ "reskill@latest",
2936
+ "install",
2937
+ skill.name,
2938
+ "--no-save",
2939
+ "--skip-manifest",
2940
+ "-y",
2941
+ "-f",
2942
+ "-r",
2943
+ registryUrl,
2944
+ ...opts.token ? ["-t", opts.token] : []
2945
+ ];
2946
+ execFileSync4("npx", args, {
2947
+ cwd: tmpDir,
2948
+ timeout: 6e4,
2949
+ stdio: "pipe"
2950
+ });
2951
+ } catch (err) {
2952
+ const stderr = err && typeof err === "object" && "stderr" in err ? err.stderr?.toString() ?? "" : "";
2953
+ if (stderr.includes("401") || stderr.includes("403") || stderr.includes("Unauthorized") || stderr.includes("Forbidden")) {
2954
+ throw new SkillAuthError(skill.name, 401);
2955
+ }
2956
+ output.warn(
2957
+ ` Warning: failed to install skill '${skill.name}': ${err instanceof Error ? err.message : String(err)}`
2958
+ );
2959
+ }
2960
+ }
2961
+ }
2962
+ const dotSkillsDir = resolve6(tmpDir, ".skills");
2963
+ const skillsDir = resolve6(tmpDir, "skills");
2964
+ if (await stat(dotSkillsDir).then((s) => s.isDirectory()).catch(() => false)) {
2965
+ if (!await stat(skillsDir).then((s) => s.isDirectory()).catch(() => false)) {
2966
+ await rename(dotSkillsDir, skillsDir);
2967
+ }
2968
+ }
2969
+ await rm2(resolve6(tmpDir, "skills.json"), { force: true });
2970
+ await rm2(resolve6(tmpDir, ".cursor"), { recursive: true, force: true });
2971
+ await rm2(resolve6(tmpDir, ".claude"), { recursive: true, force: true });
2972
+ await rm2(resolve6(tmpDir, ".codex"), { recursive: true, force: true });
2973
+ await rm2(resolve6(tmpDir, ".github"), { recursive: true, force: true });
2974
+ await rm2(resolve6(tmpDir, ".opencode"), { recursive: true, force: true });
2975
+ await rm2(targetDir, { recursive: true, force: true });
2976
+ await mkdir2(resolve6(targetDir, ".."), { recursive: true });
2977
+ await rename(tmpDir, targetDir);
2978
+ } catch (err) {
2979
+ await rm2(tmpDir, { recursive: true, force: true }).catch(() => {
2980
+ });
2981
+ throw err;
2982
+ }
2983
+ return manifest;
2984
+ }
2985
+ var SkillAuthError = class extends Error {
2986
+ constructor(skillName, status) {
2987
+ super(
2988
+ `Skill '${skillName}' requires authentication (HTTP ${status}). Run 'rush-ai auth login' first.`
2989
+ );
2990
+ this.name = "SkillAuthError";
2991
+ }
2992
+ };
2993
+ function substituteMcpSecrets(mcpServers, secrets) {
2994
+ const result = {};
2995
+ for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
2996
+ if (!serverConfig || typeof serverConfig !== "object") {
2997
+ result[serverName] = serverConfig;
2998
+ continue;
2999
+ }
3000
+ const cfg = { ...serverConfig };
3001
+ if (cfg.env && typeof cfg.env === "object") {
3002
+ const env = {};
3003
+ for (const [k, v] of Object.entries(cfg.env)) {
3004
+ env[k] = substituteValue(v, secrets);
3005
+ }
3006
+ cfg.env = env;
3007
+ }
3008
+ if (cfg.headers && typeof cfg.headers === "object") {
3009
+ const headers = {};
3010
+ for (const [k, v] of Object.entries(
3011
+ cfg.headers
3012
+ )) {
3013
+ headers[k] = substituteValue(v, secrets);
3014
+ }
3015
+ cfg.headers = headers;
3016
+ }
3017
+ result[serverName] = cfg;
3018
+ }
3019
+ return result;
3020
+ }
3021
+ function substituteValue(value, secrets) {
3022
+ return value.replace(/\$\{([^}]+)\}/g, (match, key) => {
3023
+ return key in secrets ? secrets[key] : match;
3024
+ });
3025
+ }
3026
+ function validateSlug(value, label) {
3027
+ if (!value || value.includes("..") || value.startsWith("/") || value.includes("\0")) {
3028
+ throw new Error(
3029
+ `Invalid ${label} '${value}': must not be empty, contain '..', start with '/', or contain null bytes.`
3030
+ );
3031
+ }
3032
+ }
3033
+ function inferProtocol(host) {
3034
+ const hostname = host.split(":")[0];
3035
+ if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0") {
3036
+ return "http://";
3037
+ }
3038
+ return "https://";
3039
+ }
3040
+
2821
3041
  // src/marketplaces/cache.ts
2822
3042
  var MARKETPLACE_CACHE_RELATIVE_PATH = ".rush/marketplaces";
2823
3043
  var CACHE_META_FILENAME = ".rush-marketplace-source.json";
@@ -2844,10 +3064,10 @@ var MarketplaceCache = class {
2844
3064
  gitRunner;
2845
3065
  constructor(opts = {}) {
2846
3066
  if (opts.cacheBaseDir) {
2847
- this.cacheBaseDir = resolve6(opts.cacheBaseDir);
3067
+ this.cacheBaseDir = resolve7(opts.cacheBaseDir);
2848
3068
  } else {
2849
3069
  const home = opts.home ?? homedir3();
2850
- this.cacheBaseDir = resolve6(home, MARKETPLACE_CACHE_RELATIVE_PATH);
3070
+ this.cacheBaseDir = resolve7(home, MARKETPLACE_CACHE_RELATIVE_PATH);
2851
3071
  }
2852
3072
  if (opts.gitRunner) {
2853
3073
  this.gitRunner = opts.gitRunner;
@@ -2860,7 +3080,7 @@ var MarketplaceCache = class {
2860
3080
  `Invalid marketplace name '${name}'. Names must be non-empty and cannot contain '/' or '..'.`
2861
3081
  );
2862
3082
  }
2863
- return resolve6(this.cacheBaseDir, name);
3083
+ return resolve7(this.cacheBaseDir, name);
2864
3084
  }
2865
3085
  /**
2866
3086
  * 添加一个 marketplace 到本地 cache。
@@ -2900,7 +3120,7 @@ var MarketplaceCache = class {
2900
3120
  return resolved;
2901
3121
  }
2902
3122
  case "github": {
2903
- await mkdir2(dirname2(targetDir), { recursive: true });
3123
+ await mkdir3(dirname2(targetDir), { recursive: true });
2904
3124
  const resolved = await cloneGithubMarketplace(
2905
3125
  source,
2906
3126
  targetDir,
@@ -2910,8 +3130,12 @@ var MarketplaceCache = class {
2910
3130
  await this.writeMeta(name, source);
2911
3131
  return resolved;
2912
3132
  }
3133
+ case "rush": {
3134
+ const resolved = await this.resolveRushMarketplace(source, name);
3135
+ await this.writeMeta(name, source);
3136
+ return resolved;
3137
+ }
2913
3138
  case "git":
2914
- case "rush":
2915
3139
  case "npm":
2916
3140
  throw new NotImplementedError(source.kind, source.raw);
2917
3141
  }
@@ -2928,7 +3152,7 @@ var MarketplaceCache = class {
2928
3152
  if (!await pathExists2(target)) {
2929
3153
  return;
2930
3154
  }
2931
- await rm2(target, { recursive: true, force: true });
3155
+ await rm3(target, { recursive: true, force: true });
2932
3156
  }
2933
3157
  /**
2934
3158
  * 重新 fetch 远端 source(仅对 github: / git: / rush:// / npm:)。
@@ -2957,8 +3181,12 @@ var MarketplaceCache = class {
2957
3181
  await this.writeMeta(name, meta.source);
2958
3182
  return resolved;
2959
3183
  }
3184
+ case "rush": {
3185
+ const resolved = await this.resolveRushMarketplace(meta.source, name);
3186
+ await this.writeMeta(name, meta.source);
3187
+ return resolved;
3188
+ }
2960
3189
  case "git":
2961
- case "rush":
2962
3190
  case "npm":
2963
3191
  throw new NotImplementedError(meta.source.kind, meta.source.raw);
2964
3192
  }
@@ -2983,7 +3211,7 @@ var MarketplaceCache = class {
2983
3211
  if (!meta) continue;
2984
3212
  result.push({
2985
3213
  name: entry.name,
2986
- path: resolve6(this.cacheBaseDir, entry.name),
3214
+ path: resolve7(this.cacheBaseDir, entry.name),
2987
3215
  source: meta.source,
2988
3216
  cachedAt: meta.cachedAt
2989
3217
  });
@@ -3026,14 +3254,43 @@ var MarketplaceCache = class {
3026
3254
  const manifest = await readMarketplaceJson(cacheDir);
3027
3255
  return { name, rootDir: cacheDir, source, manifest };
3028
3256
  }
3257
+ case "rush": {
3258
+ const cacheDir = this.pathFor(name);
3259
+ const manifest = await readMarketplaceJson(cacheDir);
3260
+ return { name, rootDir: cacheDir, source, manifest };
3261
+ }
3029
3262
  case "git":
3030
- case "rush":
3031
3263
  case "npm":
3032
3264
  throw new NotImplementedError(source.kind, source.raw);
3033
3265
  }
3034
3266
  }
3267
+ /**
3268
+ * Fetch rush:// marketplace from API and write local marketplace.json.
3269
+ *
3270
+ * Called by `add()` and `update()` — writes/overwrites the local cache so
3271
+ * that `resolveExisting()` (used by `get()`) can read purely from disk.
3272
+ */
3273
+ async resolveRushMarketplace(source, name) {
3274
+ const token = getAuthToken();
3275
+ const data = await fetchRushMarketplace(source, { token });
3276
+ const manifest = {
3277
+ name: data.name || "rush",
3278
+ plugins: data.plugins.map((p) => ({
3279
+ name: p.name,
3280
+ version: p.version,
3281
+ description: p.description,
3282
+ source: `./plugins/${p.name}`
3283
+ }))
3284
+ };
3285
+ const resolvedName = name ?? defaultNameFromSource(source);
3286
+ const rootDir = this.pathFor(resolvedName);
3287
+ const manifestDir = resolve7(rootDir, ".claude-plugin");
3288
+ await mkdir3(manifestDir, { recursive: true });
3289
+ await atomicWriteJson(resolve7(manifestDir, "marketplace.json"), manifest);
3290
+ return { name: resolvedName, rootDir, source, manifest };
3291
+ }
3035
3292
  metaPathFor(name) {
3036
- return resolve6(this.pathFor(name), CACHE_META_FILENAME);
3293
+ return resolve7(this.pathFor(name), CACHE_META_FILENAME);
3037
3294
  }
3038
3295
  async readMeta(name) {
3039
3296
  const metaPath = this.metaPathFor(name);
@@ -3070,7 +3327,7 @@ var MarketplaceCache = class {
3070
3327
  }
3071
3328
  async writeMeta(name, source) {
3072
3329
  const metaPath = this.metaPathFor(name);
3073
- await mkdir2(dirname2(metaPath), { recursive: true });
3330
+ await mkdir3(dirname2(metaPath), { recursive: true });
3074
3331
  const payload = {
3075
3332
  sourceRaw: source.raw,
3076
3333
  cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -3091,12 +3348,12 @@ async function pathExists2(p) {
3091
3348
  async function atomicWriteJson(filePath, payload) {
3092
3349
  const content = `${JSON.stringify(payload, null, 2)}
3093
3350
  `;
3094
- const tmp = `${filePath}.${randomUUID()}.tmp`;
3351
+ const tmp = `${filePath}.${randomUUID2()}.tmp`;
3095
3352
  try {
3096
- await writeFile2(tmp, content, { encoding: "utf8" });
3097
- await rename(tmp, filePath);
3353
+ await writeFile3(tmp, content, { encoding: "utf8" });
3354
+ await rename2(tmp, filePath);
3098
3355
  } catch (err) {
3099
- await rm2(tmp, { force: true }).catch(() => {
3356
+ await rm3(tmp, { force: true }).catch(() => {
3100
3357
  });
3101
3358
  throw err;
3102
3359
  }
@@ -3204,19 +3461,19 @@ function registerAddCommand(group, _root) {
3204
3461
  }
3205
3462
 
3206
3463
  // src/installers/registry.ts
3207
- import { randomUUID as randomUUID2 } from "crypto";
3464
+ import { randomUUID as randomUUID3 } from "crypto";
3208
3465
  import { constants as fsConstants4 } from "fs";
3209
3466
  import {
3210
3467
  access as access4,
3211
- mkdir as mkdir3,
3468
+ mkdir as mkdir4,
3212
3469
  readFile as readFile4,
3213
- rename as rename2,
3214
- rm as rm3,
3215
- stat,
3216
- writeFile as writeFile3
3470
+ rename as rename3,
3471
+ rm as rm4,
3472
+ stat as stat2,
3473
+ writeFile as writeFile4
3217
3474
  } from "fs/promises";
3218
3475
  import { homedir as homedir4 } from "os";
3219
- import { dirname as dirname3, resolve as resolve7 } from "path";
3476
+ import { dirname as dirname3, resolve as resolve8 } from "path";
3220
3477
  var REGISTRY_RELATIVE_PATH = ".rush/plugins/registry.json";
3221
3478
  var REGISTRY_SCHEMA_VERSION = 1;
3222
3479
  var RushRegistryError = class extends Error {
@@ -3305,13 +3562,13 @@ async function pathExists3(p) {
3305
3562
  }
3306
3563
  }
3307
3564
  async function atomicWrite(filePath, content) {
3308
- await mkdir3(dirname3(filePath), { recursive: true });
3309
- const tmp = `${filePath}.${randomUUID2()}.tmp`;
3565
+ await mkdir4(dirname3(filePath), { recursive: true });
3566
+ const tmp = `${filePath}.${randomUUID3()}.tmp`;
3310
3567
  try {
3311
- await writeFile3(tmp, content, { encoding: "utf8", flag: "w" });
3312
- await rename2(tmp, filePath);
3568
+ await writeFile4(tmp, content, { encoding: "utf8", flag: "w" });
3569
+ await rename3(tmp, filePath);
3313
3570
  } catch (err) {
3314
- await rm3(tmp, { force: true }).catch(() => {
3571
+ await rm4(tmp, { force: true }).catch(() => {
3315
3572
  });
3316
3573
  throw err;
3317
3574
  }
@@ -3323,7 +3580,7 @@ async function loadFromPath(filePath) {
3323
3580
  mtimeMs: null
3324
3581
  };
3325
3582
  }
3326
- const stats = await stat(filePath);
3583
+ const stats = await stat2(filePath);
3327
3584
  const raw = await readFile4(filePath, "utf8");
3328
3585
  let parsed;
3329
3586
  try {
@@ -3373,7 +3630,7 @@ var RushRegistryStore = class _RushRegistryStore {
3373
3630
  */
3374
3631
  static resolvePath(opts) {
3375
3632
  const home = opts?.home ?? homedir4();
3376
- return resolve7(home, REGISTRY_RELATIVE_PATH);
3633
+ return resolve8(home, REGISTRY_RELATIVE_PATH);
3377
3634
  }
3378
3635
  /**
3379
3636
  * 读取 registry 文件。
@@ -3432,12 +3689,12 @@ var RushRegistryStore = class _RushRegistryStore {
3432
3689
  throw new RushRegistryConflictError(this.filePath);
3433
3690
  }
3434
3691
  await atomicWrite(this.filePath, this.serialize());
3435
- const stats2 = await stat(this.filePath);
3692
+ const stats2 = await stat2(this.filePath);
3436
3693
  this.loadedMtimeMs = stats2.mtimeMs;
3437
3694
  this.deletedPluginKeys.clear();
3438
3695
  return;
3439
3696
  }
3440
- const stats = await stat(this.filePath).catch(() => null);
3697
+ const stats = await stat2(this.filePath).catch(() => null);
3441
3698
  if (stats === null) {
3442
3699
  if (attempt === 0) {
3443
3700
  await this.reloadAndMerge();
@@ -3453,7 +3710,7 @@ var RushRegistryStore = class _RushRegistryStore {
3453
3710
  throw new RushRegistryConflictError(this.filePath);
3454
3711
  }
3455
3712
  await atomicWrite(this.filePath, this.serialize());
3456
- const afterStats = await stat(this.filePath);
3713
+ const afterStats = await stat2(this.filePath);
3457
3714
  this.loadedMtimeMs = afterStats.mtimeMs;
3458
3715
  this.deletedPluginKeys.clear();
3459
3716
  }
@@ -3940,7 +4197,7 @@ function registerMcpCommand(program) {
3940
4197
  "Set credential values (e.g. --set TOKEN=xxx KEY=yyy)"
3941
4198
  ).action(async (mcpId, opts) => {
3942
4199
  const format = resolveFormat(program.opts());
3943
- const { runMcpInstall, printMcpInstallSummary } = await import("./install-RTV2VWCC.js");
4200
+ const { runMcpInstall, printMcpInstallSummary } = await import("./install-KY7BF54H.js");
3944
4201
  let setValues;
3945
4202
  if (opts.set) {
3946
4203
  setValues = {};
@@ -4001,7 +4258,7 @@ function registerMcpCommand(program) {
4001
4258
  "Comma-separated targets: claude-desktop,claude-code (default: both)"
4002
4259
  ).action(async (mcpId, opts) => {
4003
4260
  const format = resolveFormat(program.opts());
4004
- const { runMcpUninstall, printMcpUninstallSummary } = await import("./install-RTV2VWCC.js");
4261
+ const { runMcpUninstall, printMcpUninstallSummary } = await import("./install-KY7BF54H.js");
4005
4262
  try {
4006
4263
  const result = await runMcpUninstall({
4007
4264
  mcpId,
@@ -4033,26 +4290,29 @@ function registerMcpCommand(program) {
4033
4290
  });
4034
4291
  }
4035
4292
 
4293
+ // src/commands/plugin/install.ts
4294
+ import { resolve as resolve20 } from "path";
4295
+
4036
4296
  // src/installers/claude-code/installer.ts
4037
- import { randomUUID as randomUUID3 } from "crypto";
4297
+ import { randomUUID as randomUUID4 } from "crypto";
4038
4298
  import {
4039
4299
  copyFile,
4040
4300
  lstat,
4041
- mkdir as mkdir4,
4301
+ mkdir as mkdir5,
4042
4302
  readdir as readdir2,
4043
4303
  readFile as readFile5,
4044
4304
  readlink,
4045
- rename as rename3,
4046
- rm as rm4,
4047
- stat as stat2,
4305
+ rename as rename4,
4306
+ rm as rm5,
4307
+ stat as stat3,
4048
4308
  symlink,
4049
4309
  unlink
4050
4310
  } from "fs/promises";
4051
4311
  import { homedir as homedir5 } from "os";
4052
- import { dirname as dirname4, join as join9, resolve as resolve9 } from "path";
4312
+ import { dirname as dirname4, join as join9, resolve as resolve10 } from "path";
4053
4313
 
4054
4314
  // src/installers/claude-code/mcp.ts
4055
- import { execFileSync as execFileSync4 } from "child_process";
4315
+ import { execFileSync as execFileSync5 } from "child_process";
4056
4316
  import { isAbsolute as isAbsolute2 } from "path";
4057
4317
  var RUSH_AI_PLUGIN_NAME = "rush";
4058
4318
  var RUSH_AI_MARKETPLACE_NAME = "rush-marketplace";
@@ -4088,7 +4348,7 @@ function normalizeClaudeMcpServers(ref, manifest, resolver = defaultRushBinaryRe
4088
4348
  }
4089
4349
  function defaultRushBinaryResolver() {
4090
4350
  try {
4091
- const result = execFileSync4("which", ["rush-ai"], {
4351
+ const result = execFileSync5("which", ["rush-ai"], {
4092
4352
  encoding: "utf8",
4093
4353
  stdio: ["ignore", "pipe", "ignore"]
4094
4354
  }).trim();
@@ -4101,7 +4361,7 @@ function defaultRushBinaryResolver() {
4101
4361
  }
4102
4362
 
4103
4363
  // src/installers/claude-code/paths.ts
4104
- import { resolve as resolve8 } from "path";
4364
+ import { resolve as resolve9 } from "path";
4105
4365
  var CLAUDE_DIR = ".claude";
4106
4366
  var PLUGINS_SUBDIR = "plugins";
4107
4367
  var CACHE_SUBDIR = "cache";
@@ -4119,27 +4379,27 @@ var ClaudeCodePaths = class {
4119
4379
  }
4120
4380
  /** `<home>/.claude/` */
4121
4381
  get claudeDir() {
4122
- return resolve8(this.home, CLAUDE_DIR);
4382
+ return resolve9(this.home, CLAUDE_DIR);
4123
4383
  }
4124
4384
  /** `<home>/.claude/settings.json` */
4125
4385
  get settingsJson() {
4126
- return resolve8(this.claudeDir, "settings.json");
4386
+ return resolve9(this.claudeDir, "settings.json");
4127
4387
  }
4128
4388
  /** `<home>/.claude/plugins/` */
4129
4389
  get pluginsDir() {
4130
- return resolve8(this.claudeDir, PLUGINS_SUBDIR);
4390
+ return resolve9(this.claudeDir, PLUGINS_SUBDIR);
4131
4391
  }
4132
4392
  /** `<home>/.claude/plugins/known_marketplaces.json` */
4133
4393
  get knownMarketplacesJson() {
4134
- return resolve8(this.pluginsDir, "known_marketplaces.json");
4394
+ return resolve9(this.pluginsDir, "known_marketplaces.json");
4135
4395
  }
4136
4396
  /** `<home>/.claude/plugins/installed_plugins.json` */
4137
4397
  get installedPluginsJson() {
4138
- return resolve8(this.pluginsDir, "installed_plugins.json");
4398
+ return resolve9(this.pluginsDir, "installed_plugins.json");
4139
4399
  }
4140
4400
  /** `<home>/.claude/plugins/cache/` */
4141
4401
  get cacheDir() {
4142
- return resolve8(this.pluginsDir, CACHE_SUBDIR);
4402
+ return resolve9(this.pluginsDir, CACHE_SUBDIR);
4143
4403
  }
4144
4404
  /**
4145
4405
  * `<home>/.claude/plugins/marketplaces/`。
@@ -4149,34 +4409,34 @@ var ClaudeCodePaths = class {
4149
4409
  * Claude Code 会识别不到 plugin 条目(regression fix,bug #4)。
4150
4410
  */
4151
4411
  get marketplacesRootDir() {
4152
- return resolve8(this.pluginsDir, "marketplaces");
4412
+ return resolve9(this.pluginsDir, "marketplaces");
4153
4413
  }
4154
4414
  /** `<home>/.claude/plugins/marketplaces/<mkt>/` */
4155
4415
  marketplaceInstallDir(marketplace) {
4156
- return resolve8(this.marketplacesRootDir, marketplace);
4416
+ return resolve9(this.marketplacesRootDir, marketplace);
4157
4417
  }
4158
4418
  /** `<home>/.claude/plugins/cache/<mkt>/` */
4159
4419
  marketplaceCacheDir(marketplace) {
4160
- return resolve8(this.cacheDir, marketplace);
4420
+ return resolve9(this.cacheDir, marketplace);
4161
4421
  }
4162
4422
  /** `<home>/.claude/plugins/cache/<mkt>/<plugin>/` */
4163
4423
  pluginCacheDir(ref) {
4164
- return resolve8(this.marketplaceCacheDir(ref.marketplace), ref.name);
4424
+ return resolve9(this.marketplaceCacheDir(ref.marketplace), ref.name);
4165
4425
  }
4166
4426
  /** `<home>/.claude/plugins/cache/<mkt>/<plugin>/<version>/` */
4167
4427
  pluginVersionDir(ref, version) {
4168
- return resolve8(this.pluginCacheDir(ref), version);
4428
+ return resolve9(this.pluginCacheDir(ref), version);
4169
4429
  }
4170
4430
  /** `<home>/.claude/plugins/cache/<mkt>/<plugin>/<version>/.claude-plugin/plugin.json` */
4171
4431
  pluginManifestPath(ref, version) {
4172
- return resolve8(
4432
+ return resolve9(
4173
4433
  this.pluginVersionDir(ref, version),
4174
4434
  PLUGIN_MANIFEST_RELATIVE
4175
4435
  );
4176
4436
  }
4177
4437
  /** `<home>/.claude/plugins/cache/<mkt>/<plugin>/<version>/<capability>/` */
4178
4438
  capabilityDir(ref, version, capability) {
4179
- return resolve8(this.pluginVersionDir(ref, version), capability);
4439
+ return resolve9(this.pluginVersionDir(ref, version), capability);
4180
4440
  }
4181
4441
  };
4182
4442
  function pluginKey(ref) {
@@ -4290,13 +4550,13 @@ var ClaudeCodeInstaller = class {
4290
4550
  }
4291
4551
  try {
4292
4552
  const writtenFiles = [];
4293
- await mkdir4(pluginVersionDir, { recursive: true });
4553
+ await mkdir5(pluginVersionDir, { recursive: true });
4294
4554
  writtenFiles.push(pluginVersionDir);
4295
4555
  for (const cap of CAPABILITY_DIRS) {
4296
- const srcDir = resolve9(plugin.sourceDir, cap);
4556
+ const srcDir = resolve10(plugin.sourceDir, cap);
4297
4557
  if (!await dirExists(srcDir)) continue;
4298
4558
  const dstDir = this.paths.capabilityDir(ref, version, cap);
4299
- await mkdir4(dstDir, { recursive: true });
4559
+ await mkdir5(dstDir, { recursive: true });
4300
4560
  writtenFiles.push(dstDir);
4301
4561
  const copied = await copyDirTracked(srcDir, dstDir);
4302
4562
  writtenFiles.push(...copied);
@@ -4432,7 +4692,7 @@ var ClaudeCodeInstaller = class {
4432
4692
  files.push(mktDir);
4433
4693
  } else if (kind === "dir") {
4434
4694
  if (await pathExists(join9(mktDir, ".rush-marketplace-source.json"))) {
4435
- await rm4(mktDir, { recursive: true, force: true });
4695
+ await rm5(mktDir, { recursive: true, force: true });
4436
4696
  files.push(mktDir);
4437
4697
  }
4438
4698
  }
@@ -4503,12 +4763,12 @@ var ClaudeCodeInstaller = class {
4503
4763
  return { written: false, path: "" };
4504
4764
  }
4505
4765
  const mktDir = this.paths.marketplaceInstallDir(marketplaceName);
4506
- await mkdir4(this.paths.marketplacesRootDir, { recursive: true });
4766
+ await mkdir5(this.paths.marketplacesRootDir, { recursive: true });
4507
4767
  const kind = await inodeKind(mktDir);
4508
4768
  if (kind === "symlink") {
4509
4769
  const target = await readlink(mktDir).catch(() => null);
4510
- const resolvedTarget = target !== null ? resolve9(dirname4(mktDir), target) : null;
4511
- if (resolvedTarget && resolvedTarget === resolve9(src.rootDir)) {
4770
+ const resolvedTarget = target !== null ? resolve10(dirname4(mktDir), target) : null;
4771
+ if (resolvedTarget && resolvedTarget === resolve10(src.rootDir)) {
4512
4772
  return { written: false, path: mktDir };
4513
4773
  }
4514
4774
  throw new Error(
@@ -4541,7 +4801,7 @@ var ClaudeCodeInstaller = class {
4541
4801
  return { written: true, path: mktDir };
4542
4802
  }
4543
4803
  await copyDirTracked(src.rootDir, mktDir).catch(async (err) => {
4544
- await rm4(mktDir, { recursive: true, force: true }).catch(() => {
4804
+ await rm5(mktDir, { recursive: true, force: true }).catch(() => {
4545
4805
  });
4546
4806
  throw err;
4547
4807
  });
@@ -4577,7 +4837,7 @@ var ClaudeCodeInstaller = class {
4577
4837
  const pluginVersionDir = this.paths.pluginVersionDir(ref, version);
4578
4838
  const dryFiles = [pluginVersionDir];
4579
4839
  for (const cap of CAPABILITY_DIRS) {
4580
- const srcDir = resolve9(plugin.sourceDir, cap);
4840
+ const srcDir = resolve10(plugin.sourceDir, cap);
4581
4841
  if (!await dirExists(srcDir)) continue;
4582
4842
  const dstDir = this.paths.capabilityDir(ref, version, cap);
4583
4843
  dryFiles.push(dstDir);
@@ -4697,8 +4957,8 @@ var ClaudeCodeInstaller = class {
4697
4957
  const settings = await this.readRawJsonForRollback(this.paths.settingsJson);
4698
4958
  let backupVersionDir = null;
4699
4959
  if (preexistedVersion === "dir") {
4700
- backupVersionDir = `${pluginVersionDir}.rollback-${randomUUID3()}`;
4701
- await rename3(pluginVersionDir, backupVersionDir);
4960
+ backupVersionDir = `${pluginVersionDir}.rollback-${randomUUID4()}`;
4961
+ await rename4(pluginVersionDir, backupVersionDir);
4702
4962
  }
4703
4963
  return {
4704
4964
  ref,
@@ -4719,7 +4979,7 @@ var ClaudeCodeInstaller = class {
4719
4979
  */
4720
4980
  async finalizeRollback(snap) {
4721
4981
  if (snap.backupVersionDir) {
4722
- await rm4(snap.backupVersionDir, { recursive: true, force: true });
4982
+ await rm5(snap.backupVersionDir, { recursive: true, force: true });
4723
4983
  }
4724
4984
  }
4725
4985
  /**
@@ -4732,19 +4992,19 @@ var ClaudeCodeInstaller = class {
4732
4992
  */
4733
4993
  async applyRollback(snap) {
4734
4994
  if (snap.preexistedVersion === "dir" && snap.backupVersionDir) {
4735
- await rm4(snap.pluginVersionDir, { recursive: true, force: true });
4736
- await rename3(snap.backupVersionDir, snap.pluginVersionDir);
4995
+ await rm5(snap.pluginVersionDir, { recursive: true, force: true });
4996
+ await rename4(snap.backupVersionDir, snap.pluginVersionDir);
4737
4997
  } else if (snap.preexistedVersion === "missing") {
4738
- await rm4(snap.pluginVersionDir, { recursive: true, force: true });
4998
+ await rm5(snap.pluginVersionDir, { recursive: true, force: true });
4739
4999
  }
4740
5000
  if (snap.preexistedPlugin === "missing") {
4741
- await rm4(this.paths.pluginCacheDir(snap.ref), {
5001
+ await rm5(this.paths.pluginCacheDir(snap.ref), {
4742
5002
  recursive: true,
4743
5003
  force: true
4744
5004
  });
4745
5005
  }
4746
5006
  if (snap.preexistedMarketplace === "missing") {
4747
- await rm4(this.paths.marketplaceCacheDir(snap.ref.marketplace), {
5007
+ await rm5(this.paths.marketplaceCacheDir(snap.ref.marketplace), {
4748
5008
  recursive: true,
4749
5009
  force: true
4750
5010
  });
@@ -4758,7 +5018,7 @@ var ClaudeCodeInstaller = class {
4758
5018
  await unlink(mktInstallDir).catch(() => {
4759
5019
  });
4760
5020
  } else if (currentKind !== "missing") {
4761
- await rm4(mktInstallDir, { recursive: true, force: true }).catch(
5021
+ await rm5(mktInstallDir, { recursive: true, force: true }).catch(
4762
5022
  () => {
4763
5023
  }
4764
5024
  );
@@ -4781,7 +5041,7 @@ var ClaudeCodeInstaller = class {
4781
5041
  async restoreRawJson(path4, state) {
4782
5042
  if (!state.existed) {
4783
5043
  if (await pathExists(path4)) {
4784
- await rm4(path4, { force: true });
5044
+ await rm5(path4, { force: true });
4785
5045
  }
4786
5046
  return;
4787
5047
  }
@@ -5116,7 +5376,7 @@ async function defaultSymlinkRunner(target, linkPath) {
5116
5376
  }
5117
5377
  async function dirExists(p) {
5118
5378
  try {
5119
- const s = await stat2(p);
5379
+ const s = await stat3(p);
5120
5380
  return s.isDirectory();
5121
5381
  } catch {
5122
5382
  return false;
@@ -5156,12 +5416,12 @@ async function copyDirTracked(srcDir, dstDir) {
5156
5416
  const srcPath = join9(srcDir, entry.name);
5157
5417
  const dstPath = join9(dstDir, entry.name);
5158
5418
  if (entry.isDirectory()) {
5159
- await mkdir4(dstPath, { recursive: true });
5419
+ await mkdir5(dstPath, { recursive: true });
5160
5420
  written.push(dstPath);
5161
5421
  const subWritten = await copyDirTracked(srcPath, dstPath);
5162
5422
  written.push(...subWritten);
5163
5423
  } else if (entry.isFile()) {
5164
- await mkdir4(dirname4(dstPath), { recursive: true });
5424
+ await mkdir5(dirname4(dstPath), { recursive: true });
5165
5425
  await copyFile(srcPath, dstPath);
5166
5426
  written.push(dstPath);
5167
5427
  }
@@ -5172,7 +5432,7 @@ async function writeAtomicWithMtimeCheck(filePath, data, expectedMtimeMs) {
5172
5432
  if (expectedMtimeMs !== null) {
5173
5433
  let currentMtime = null;
5174
5434
  try {
5175
- const s = await stat2(filePath);
5435
+ const s = await stat3(filePath);
5176
5436
  currentMtime = s.mtimeMs;
5177
5437
  } catch {
5178
5438
  currentMtime = null;
@@ -5199,14 +5459,14 @@ import { constants as fsConstants6 } from "fs";
5199
5459
  import {
5200
5460
  access as access6,
5201
5461
  cp,
5202
- mkdir as mkdir6,
5462
+ mkdir as mkdir7,
5203
5463
  mkdtemp,
5204
5464
  readdir as readdir3,
5205
5465
  readFile as readFile7,
5206
- rename as rename5,
5207
- rm as rm6,
5208
- stat as stat4,
5209
- writeFile as writeFile5
5466
+ rename as rename6,
5467
+ rm as rm7,
5468
+ stat as stat5,
5469
+ writeFile as writeFile6
5210
5470
  } from "fs/promises";
5211
5471
  import { homedir as homedir6 } from "os";
5212
5472
  import {
@@ -5214,7 +5474,7 @@ import {
5214
5474
  dirname as dirname6,
5215
5475
  extname,
5216
5476
  relative as pathRelative,
5217
- resolve as resolve10
5477
+ resolve as resolve11
5218
5478
  } from "path";
5219
5479
 
5220
5480
  // src/installers/codex/mcp.ts
@@ -5318,17 +5578,17 @@ function pluginSectionKey(ref) {
5318
5578
  }
5319
5579
 
5320
5580
  // src/installers/codex/toml.ts
5321
- import { randomUUID as randomUUID4 } from "crypto";
5581
+ import { randomUUID as randomUUID5 } from "crypto";
5322
5582
  import { constants as fsConstants5 } from "fs";
5323
5583
  import {
5324
5584
  access as access5,
5325
5585
  copyFile as copyFile2,
5326
- mkdir as mkdir5,
5586
+ mkdir as mkdir6,
5327
5587
  readFile as readFile6,
5328
- rename as rename4,
5329
- rm as rm5,
5330
- stat as stat3,
5331
- writeFile as writeFile4
5588
+ rename as rename5,
5589
+ rm as rm6,
5590
+ stat as stat4,
5591
+ writeFile as writeFile5
5332
5592
  } from "fs/promises";
5333
5593
  import { dirname as dirname5 } from "path";
5334
5594
  import tomlModule from "@iarna/toml";
@@ -5364,7 +5624,7 @@ async function readCodexConfig(filePath) {
5364
5624
  if (!await pathExists4(filePath)) {
5365
5625
  return { data: {}, mtimeMs: null };
5366
5626
  }
5367
- const stats = await stat3(filePath);
5627
+ const stats = await stat4(filePath);
5368
5628
  const raw = await readFile6(filePath, "utf8");
5369
5629
  try {
5370
5630
  const parsed = tomlParse(raw);
@@ -5379,7 +5639,7 @@ async function backupCodexConfig(filePath, backupPath) {
5379
5639
  }
5380
5640
  let finalBackup = backupPath;
5381
5641
  if (await pathExists4(finalBackup)) {
5382
- finalBackup = `${backupPath}.${randomUUID4().slice(0, 8)}`;
5642
+ finalBackup = `${backupPath}.${randomUUID5().slice(0, 8)}`;
5383
5643
  }
5384
5644
  await copyFile2(filePath, finalBackup);
5385
5645
  return finalBackup;
@@ -5388,19 +5648,19 @@ async function writeCodexConfig(filePath, data, expectedMtimeMs) {
5388
5648
  await assertNoMtimeDrift(filePath, expectedMtimeMs);
5389
5649
  const serialized = tomlStringify(data);
5390
5650
  await atomicWrite2(filePath, serialized);
5391
- const afterStats = await stat3(filePath);
5651
+ const afterStats = await stat4(filePath);
5392
5652
  return { mtimeMs: afterStats.mtimeMs };
5393
5653
  }
5394
5654
  async function restoreCodexConfigFromBackup(filePath, backupPath) {
5395
5655
  if (!backupPath || !await pathExists4(backupPath)) {
5396
5656
  if (await pathExists4(filePath)) {
5397
- await rm5(filePath, { force: true });
5657
+ await rm6(filePath, { force: true });
5398
5658
  }
5399
5659
  return;
5400
5660
  }
5401
5661
  const raw = await readFile6(backupPath, "utf8");
5402
5662
  await atomicWrite2(filePath, raw);
5403
- await rm5(backupPath, { force: true }).catch(() => {
5663
+ await rm6(backupPath, { force: true }).catch(() => {
5404
5664
  });
5405
5665
  }
5406
5666
  function setMarketplaceSection(config, name, entry) {
@@ -5446,13 +5706,13 @@ async function pathExists4(p) {
5446
5706
  }
5447
5707
  }
5448
5708
  async function atomicWrite2(filePath, content) {
5449
- await mkdir5(dirname5(filePath), { recursive: true });
5450
- const tmp = `${filePath}.${randomUUID4()}.tmp`;
5709
+ await mkdir6(dirname5(filePath), { recursive: true });
5710
+ const tmp = `${filePath}.${randomUUID5()}.tmp`;
5451
5711
  try {
5452
- await writeFile4(tmp, content, { encoding: "utf8", flag: "w" });
5453
- await rename4(tmp, filePath);
5712
+ await writeFile5(tmp, content, { encoding: "utf8", flag: "w" });
5713
+ await rename5(tmp, filePath);
5454
5714
  } catch (err) {
5455
- await rm5(tmp, { force: true }).catch(() => {
5715
+ await rm6(tmp, { force: true }).catch(() => {
5456
5716
  });
5457
5717
  throw err;
5458
5718
  }
@@ -5464,7 +5724,7 @@ async function assertNoMtimeDrift(filePath, expectedMtimeMs) {
5464
5724
  }
5465
5725
  return;
5466
5726
  }
5467
- const current = await stat3(filePath).catch(() => null);
5727
+ const current = await stat4(filePath).catch(() => null);
5468
5728
  if (current === null) {
5469
5729
  throw new CodexConfigTomlConflictError(filePath);
5470
5730
  }
@@ -5718,9 +5978,9 @@ var CodexInstaller = class {
5718
5978
  const cfgPath = codexConfigTomlPath(this.home);
5719
5979
  const preExisted = await pathExists5(versionDir);
5720
5980
  if (preExisted) {
5721
- await rm6(versionDir, { recursive: true, force: true });
5981
+ await rm7(versionDir, { recursive: true, force: true });
5722
5982
  }
5723
- await mkdir6(versionDir, { recursive: true });
5983
+ await mkdir7(versionDir, { recursive: true });
5724
5984
  rollback.createdVersionDir = versionDir;
5725
5985
  const dstSkills = codexPluginSkillsDir(versionDir);
5726
5986
  const writtenFiles = [versionDir];
@@ -5855,10 +6115,10 @@ var CodexInstaller = class {
5855
6115
  const srcMcp = plugin.manifest.mcpServers;
5856
6116
  if (srcMcp !== void 0 && srcMcp !== null) {
5857
6117
  if (typeof srcMcp === "string") {
5858
- const destPath = resolve10(versionDir, srcMcp);
6118
+ const destPath = resolve11(versionDir, srcMcp);
5859
6119
  files.push(destPath);
5860
- const srcPath = resolve10(plugin.sourceDir, srcMcp);
5861
- const rel = pathRelative(resolve10(plugin.sourceDir), srcPath);
6120
+ const srcPath = resolve11(plugin.sourceDir, srcMcp);
6121
+ const rel = pathRelative(resolve11(plugin.sourceDir), srcPath);
5862
6122
  const traversal = rel === ".." || rel.startsWith("..") || rel.startsWith("/");
5863
6123
  const exists = await pathExists5(srcPath);
5864
6124
  if (traversal || !exists) {
@@ -5954,18 +6214,18 @@ async function rollbackInstall(home, rollback) {
5954
6214
  }
5955
6215
  );
5956
6216
  } else if (rollback.preExistingConfig === false) {
5957
- await rm6(cfgPath, { force: true }).catch(() => {
6217
+ await rm7(cfgPath, { force: true }).catch(() => {
5958
6218
  });
5959
6219
  }
5960
6220
  if (rollback.createdVersionDir) {
5961
- await rm6(rollback.createdVersionDir, {
6221
+ await rm7(rollback.createdVersionDir, {
5962
6222
  recursive: true,
5963
6223
  force: true
5964
6224
  }).catch(() => {
5965
6225
  });
5966
6226
  }
5967
6227
  if (rollback.createdMarketplacePluginDir) {
5968
- await rm6(rollback.createdMarketplacePluginDir, {
6228
+ await rm7(rollback.createdMarketplacePluginDir, {
5969
6229
  recursive: true,
5970
6230
  force: true
5971
6231
  }).catch(() => {
@@ -6003,14 +6263,14 @@ function assertSafePathComponents(ref, version) {
6003
6263
  }
6004
6264
  async function copyAuthorProvidedMcp(sourceDir, versionDir, relativeRef) {
6005
6265
  if (typeof relativeRef !== "string" || relativeRef.length === 0) return null;
6006
- const srcPath = resolve10(sourceDir, relativeRef);
6007
- const rel = pathRelative(resolve10(sourceDir), srcPath);
6266
+ const srcPath = resolve11(sourceDir, relativeRef);
6267
+ const rel = pathRelative(resolve11(sourceDir), srcPath);
6008
6268
  if (rel === ".." || rel.startsWith("..") || rel.startsWith("/")) {
6009
6269
  return null;
6010
6270
  }
6011
6271
  if (!await pathExists5(srcPath)) return null;
6012
- const destPath = resolve10(versionDir, relativeRef);
6013
- await mkdir6(dirname6(destPath), { recursive: true });
6272
+ const destPath = resolve11(versionDir, relativeRef);
6273
+ await mkdir7(dirname6(destPath), { recursive: true });
6014
6274
  const raw = await readFile7(srcPath, "utf8");
6015
6275
  await writeFileAtomic(destPath, raw);
6016
6276
  let mcpKeys = [];
@@ -6027,18 +6287,18 @@ async function copyAuthorProvidedMcp(sourceDir, versionDir, relativeRef) {
6027
6287
  async function writeCodexMarketplaceMirror(input) {
6028
6288
  const pluginParent = dirname6(input.pluginDir);
6029
6289
  const pluginBase = basename2(input.pluginDir);
6030
- await mkdir6(pluginParent, { recursive: true });
6290
+ await mkdir7(pluginParent, { recursive: true });
6031
6291
  const tmpPluginDir = await mkdtemp(
6032
- resolve10(pluginParent, `.${pluginBase}.tmp-`)
6292
+ resolve11(pluginParent, `.${pluginBase}.tmp-`)
6033
6293
  );
6034
6294
  const backupPluginDir = await mkdtemp(
6035
- resolve10(pluginParent, `.${pluginBase}.bak-`)
6295
+ resolve11(pluginParent, `.${pluginBase}.bak-`)
6036
6296
  );
6037
6297
  let hadExistingPluginDir = false;
6038
6298
  let swappedPluginDir = false;
6039
6299
  try {
6040
- await rm6(tmpPluginDir, { recursive: true, force: true });
6041
- await rm6(backupPluginDir, { recursive: true, force: true }).catch(() => {
6300
+ await rm7(tmpPluginDir, { recursive: true, force: true });
6301
+ await rm7(backupPluginDir, { recursive: true, force: true }).catch(() => {
6042
6302
  });
6043
6303
  await cp(input.versionDir, tmpPluginDir, {
6044
6304
  recursive: true,
@@ -6048,16 +6308,16 @@ async function writeCodexMarketplaceMirror(input) {
6048
6308
  });
6049
6309
  hadExistingPluginDir = await pathExists5(input.pluginDir);
6050
6310
  if (hadExistingPluginDir) {
6051
- await rename5(input.pluginDir, backupPluginDir);
6311
+ await rename6(input.pluginDir, backupPluginDir);
6052
6312
  }
6053
- await rename5(tmpPluginDir, input.pluginDir);
6313
+ await rename6(tmpPluginDir, input.pluginDir);
6054
6314
  swappedPluginDir = true;
6055
6315
  await upsertCodexMarketplaceManifest(input.marketplaceDir, input.plugin);
6056
6316
  if (hadExistingPluginDir) {
6057
- await rm6(backupPluginDir, { recursive: true, force: true });
6317
+ await rm7(backupPluginDir, { recursive: true, force: true });
6058
6318
  }
6059
6319
  } catch (err) {
6060
- await rm6(tmpPluginDir, { recursive: true, force: true }).catch(() => {
6320
+ await rm7(tmpPluginDir, { recursive: true, force: true }).catch(() => {
6061
6321
  });
6062
6322
  let restoredBackup = false;
6063
6323
  if (hadExistingPluginDir && await pathExists5(backupPluginDir)) {
@@ -6065,33 +6325,33 @@ async function writeCodexMarketplaceMirror(input) {
6065
6325
  try {
6066
6326
  if (await pathExists5(input.pluginDir)) {
6067
6327
  displacedPluginDir = await mkdtemp(
6068
- resolve10(pluginParent, `.${pluginBase}.failed-`)
6328
+ resolve11(pluginParent, `.${pluginBase}.failed-`)
6069
6329
  );
6070
- await rm6(displacedPluginDir, { recursive: true, force: true });
6071
- await rename5(input.pluginDir, displacedPluginDir);
6330
+ await rm7(displacedPluginDir, { recursive: true, force: true });
6331
+ await rename6(input.pluginDir, displacedPluginDir);
6072
6332
  }
6073
- await rename5(backupPluginDir, input.pluginDir);
6333
+ await rename6(backupPluginDir, input.pluginDir);
6074
6334
  restoredBackup = true;
6075
6335
  if (displacedPluginDir) {
6076
- await rm6(displacedPluginDir, { recursive: true, force: true }).catch(
6336
+ await rm7(displacedPluginDir, { recursive: true, force: true }).catch(
6077
6337
  () => {
6078
6338
  }
6079
6339
  );
6080
6340
  }
6081
6341
  } catch {
6082
6342
  if (displacedPluginDir && !await pathExists5(input.pluginDir) && await pathExists5(displacedPluginDir)) {
6083
- await rename5(displacedPluginDir, input.pluginDir).catch(() => {
6343
+ await rename6(displacedPluginDir, input.pluginDir).catch(() => {
6084
6344
  });
6085
6345
  }
6086
6346
  }
6087
6347
  } else if (swappedPluginDir) {
6088
- await rm6(input.pluginDir, { recursive: true, force: true }).catch(
6348
+ await rm7(input.pluginDir, { recursive: true, force: true }).catch(
6089
6349
  () => {
6090
6350
  }
6091
6351
  );
6092
6352
  }
6093
6353
  if (restoredBackup || !hadExistingPluginDir) {
6094
- await rm6(backupPluginDir, { recursive: true, force: true }).catch(
6354
+ await rm7(backupPluginDir, { recursive: true, force: true }).catch(
6095
6355
  () => {
6096
6356
  }
6097
6357
  );
@@ -6152,7 +6412,7 @@ async function planCodexSkills(plugin) {
6152
6412
  const usedNames = /* @__PURE__ */ new Set();
6153
6413
  const coveredAliases = /* @__PURE__ */ new Set();
6154
6414
  const commandFiles = await listMarkdownFiles(
6155
- resolve10(plugin.sourceDir, "commands"),
6415
+ resolve11(plugin.sourceDir, "commands"),
6156
6416
  {
6157
6417
  recursive: false
6158
6418
  }
@@ -6162,19 +6422,19 @@ async function planCodexSkills(plugin) {
6162
6422
  commandFiles.map((file2) => markdownSkillAlias(plugin.manifest.name, file2))
6163
6423
  )
6164
6424
  );
6165
- const nativeSkillsDir = resolve10(plugin.sourceDir, "skills");
6425
+ const nativeSkillsDir = resolve11(plugin.sourceDir, "skills");
6166
6426
  if (await hasCodexSkillDir(nativeSkillsDir)) {
6167
6427
  for (const name of await listCodexSkillNames(nativeSkillsDir)) {
6168
6428
  usedNames.add(name);
6169
6429
  coveredAliases.add(skillAlias(plugin.manifest.name, name));
6170
6430
  sources.push({
6171
6431
  kind: "copy-skill",
6172
- sourceDir: resolve10(nativeSkillsDir, name),
6432
+ sourceDir: resolve11(nativeSkillsDir, name),
6173
6433
  skillName: name
6174
6434
  });
6175
6435
  }
6176
6436
  } else {
6177
- const dotSkillsDir = resolve10(plugin.sourceDir, ".skills");
6437
+ const dotSkillsDir = resolve11(plugin.sourceDir, ".skills");
6178
6438
  const claudeSkills = await listMarkdownFiles(dotSkillsDir);
6179
6439
  const claudeAliases = /* @__PURE__ */ new Map();
6180
6440
  for (const file2 of claudeSkills) {
@@ -6213,7 +6473,7 @@ async function planCodexSkills(plugin) {
6213
6473
  async function materializeCodexSkills(plan, dstSkills) {
6214
6474
  for (const source of plan.sources) {
6215
6475
  if (source.kind === "copy-skill") {
6216
- await cp(source.sourceDir, resolve10(dstSkills, source.skillName), {
6476
+ await cp(source.sourceDir, resolve11(dstSkills, source.skillName), {
6217
6477
  recursive: true,
6218
6478
  dereference: false,
6219
6479
  preserveTimestamps: true,
@@ -6224,7 +6484,7 @@ async function materializeCodexSkills(plan, dstSkills) {
6224
6484
  const raw = await readFile7(source.sourceFile, "utf8");
6225
6485
  const normalized = normalizeSkillMarkdown(raw, source.skillName);
6226
6486
  await writeFileAtomic(
6227
- resolve10(dstSkills, source.skillName, "SKILL.md"),
6487
+ resolve11(dstSkills, source.skillName, "SKILL.md"),
6228
6488
  normalized
6229
6489
  );
6230
6490
  }
@@ -6310,7 +6570,7 @@ async function listCodexSkillNames(skillsDir) {
6310
6570
  const names = [];
6311
6571
  for (const entry of entries) {
6312
6572
  if (!entry.isDirectory()) continue;
6313
- if (await pathExists5(resolve10(skillsDir, entry.name, "SKILL.md"))) {
6573
+ if (await pathExists5(resolve11(skillsDir, entry.name, "SKILL.md"))) {
6314
6574
  names.push(entry.name);
6315
6575
  }
6316
6576
  }
@@ -6328,7 +6588,7 @@ async function listMarkdownFiles(dir, opts = {}) {
6328
6588
  return;
6329
6589
  }
6330
6590
  for (const entry of entries) {
6331
- const abs = resolve10(current, entry.name);
6591
+ const abs = resolve11(current, entry.name);
6332
6592
  if (entry.isDirectory()) {
6333
6593
  if (recursive) await walk2(abs);
6334
6594
  continue;
@@ -6383,14 +6643,14 @@ function slugify(value) {
6383
6643
  return slug.length > 0 ? slug : "skill";
6384
6644
  }
6385
6645
  async function writeFileAtomic(filePath, content) {
6386
- await mkdir6(dirname6(filePath), { recursive: true });
6646
+ await mkdir7(dirname6(filePath), { recursive: true });
6387
6647
  const tmp = `${filePath}.${Math.random().toString(36).slice(2)}.tmp`;
6388
6648
  try {
6389
- await writeFile5(tmp, content, { encoding: "utf8", flag: "w" });
6390
- const { rename: rename8 } = await import("fs/promises");
6391
- await rename8(tmp, filePath);
6649
+ await writeFile6(tmp, content, { encoding: "utf8", flag: "w" });
6650
+ const { rename: rename9 } = await import("fs/promises");
6651
+ await rename9(tmp, filePath);
6392
6652
  } catch (err) {
6393
- await rm6(tmp, { force: true }).catch(() => {
6653
+ await rm7(tmp, { force: true }).catch(() => {
6394
6654
  });
6395
6655
  throw err;
6396
6656
  }
@@ -6405,7 +6665,7 @@ async function pathExists5(p) {
6405
6665
  }
6406
6666
  async function isDir(p) {
6407
6667
  try {
6408
- const s = await stat4(p);
6668
+ const s = await stat5(p);
6409
6669
  return s.isDirectory();
6410
6670
  } catch {
6411
6671
  return false;
@@ -6420,7 +6680,7 @@ function parsePluginKey2(key) {
6420
6680
  return { name: key.slice(0, at), marketplace: key.slice(at + 1) };
6421
6681
  }
6422
6682
  async function detectInstalledVersion(home, ref) {
6423
- const baseDir = resolve10(
6683
+ const baseDir = resolve11(
6424
6684
  codexHomeDir(home),
6425
6685
  "plugins",
6426
6686
  "cache",
@@ -6436,14 +6696,14 @@ async function detectInstalledVersion(home, ref) {
6436
6696
  }
6437
6697
  let best = null;
6438
6698
  for (const entry of entries) {
6439
- const versionDir = resolve10(baseDir, entry);
6440
- const manifestPath = resolve10(versionDir, ".codex-plugin", "plugin.json");
6699
+ const versionDir = resolve11(baseDir, entry);
6700
+ const manifestPath = resolve11(versionDir, ".codex-plugin", "plugin.json");
6441
6701
  if (!await pathExists5(manifestPath)) continue;
6442
6702
  try {
6443
6703
  const raw = await readFile7(manifestPath, "utf8");
6444
6704
  const obj = JSON.parse(raw);
6445
6705
  const version = typeof obj.version === "string" && obj.version.length > 0 ? obj.version : entry;
6446
- const s = await stat4(versionDir);
6706
+ const s = await stat5(versionDir);
6447
6707
  if (!best || s.mtimeMs > best.mtimeMs) {
6448
6708
  best = { version, mtimeMs: s.mtimeMs };
6449
6709
  }
@@ -6465,20 +6725,20 @@ function defaultRushAiBinaryResolver() {
6465
6725
  }
6466
6726
 
6467
6727
  // src/installers/cursor/installer.ts
6468
- import { randomUUID as randomUUID6 } from "crypto";
6728
+ import { randomUUID as randomUUID7 } from "crypto";
6469
6729
  import { constants as fsConstants8 } from "fs";
6470
6730
  import {
6471
6731
  access as access8,
6472
6732
  cp as cp2,
6473
- mkdir as mkdir8,
6733
+ mkdir as mkdir9,
6474
6734
  readFile as readFile10,
6475
- rename as rename7,
6476
- rm as rm8,
6477
- stat as stat6,
6478
- writeFile as writeFile7
6735
+ rename as rename8,
6736
+ rm as rm9,
6737
+ stat as stat7,
6738
+ writeFile as writeFile8
6479
6739
  } from "fs/promises";
6480
6740
  import { homedir as homedir7 } from "os";
6481
- import { dirname as dirname8, relative, resolve as resolve13 } from "path";
6741
+ import { dirname as dirname8, relative, resolve as resolve14 } from "path";
6482
6742
 
6483
6743
  // src/installers/cursor/marker.ts
6484
6744
  var RUSH_AI_MARKER = "<!-- rush-ai:auto-generated -->";
@@ -6487,16 +6747,16 @@ function hasRushAiMarker(fileContent) {
6487
6747
  }
6488
6748
 
6489
6749
  // src/installers/cursor/mcp.ts
6490
- import { randomUUID as randomUUID5 } from "crypto";
6750
+ import { randomUUID as randomUUID6 } from "crypto";
6491
6751
  import { constants as fsConstants7 } from "fs";
6492
6752
  import {
6493
6753
  access as access7,
6494
- mkdir as mkdir7,
6754
+ mkdir as mkdir8,
6495
6755
  readFile as readFile8,
6496
- rename as rename6,
6497
- rm as rm7,
6498
- stat as stat5,
6499
- writeFile as writeFile6
6756
+ rename as rename7,
6757
+ rm as rm8,
6758
+ stat as stat6,
6759
+ writeFile as writeFile7
6500
6760
  } from "fs/promises";
6501
6761
  import { dirname as dirname7 } from "path";
6502
6762
  async function readCursorMcpJson(filePath) {
@@ -6506,7 +6766,7 @@ async function readCursorMcpJsonWithMtime(filePath) {
6506
6766
  if (!await pathExists6(filePath)) {
6507
6767
  return { data: {}, mtimeMs: null };
6508
6768
  }
6509
- const stats = await stat5(filePath);
6769
+ const stats = await stat6(filePath);
6510
6770
  const raw = await readFile8(filePath, "utf8");
6511
6771
  let parsed;
6512
6772
  try {
@@ -6574,15 +6834,15 @@ function removeMcpServers(current, keysToRemove) {
6574
6834
  return cloned;
6575
6835
  }
6576
6836
  async function writeCursorMcpJson(filePath, data) {
6577
- await mkdir7(dirname7(filePath), { recursive: true });
6837
+ await mkdir8(dirname7(filePath), { recursive: true });
6578
6838
  const content = `${JSON.stringify(data, null, 2)}
6579
6839
  `;
6580
- const tmp = `${filePath}.${randomUUID5()}.tmp`;
6840
+ const tmp = `${filePath}.${randomUUID6()}.tmp`;
6581
6841
  try {
6582
- await writeFile6(tmp, content, { encoding: "utf8", flag: "w" });
6583
- await rename6(tmp, filePath);
6842
+ await writeFile7(tmp, content, { encoding: "utf8", flag: "w" });
6843
+ await rename7(tmp, filePath);
6584
6844
  } catch (err) {
6585
- await rm7(tmp, { force: true }).catch(() => {
6845
+ await rm8(tmp, { force: true }).catch(() => {
6586
6846
  });
6587
6847
  throw err;
6588
6848
  }
@@ -6597,25 +6857,25 @@ async function pathExists6(p) {
6597
6857
  }
6598
6858
 
6599
6859
  // src/installers/cursor/paths.ts
6600
- import { resolve as resolve11 } from "path";
6860
+ import { resolve as resolve12 } from "path";
6601
6861
  var CURSOR_RELATIVE_DIR = ".cursor";
6602
6862
  function cursorDir(home) {
6603
- return resolve11(home, CURSOR_RELATIVE_DIR);
6863
+ return resolve12(home, CURSOR_RELATIVE_DIR);
6604
6864
  }
6605
6865
  function cursorMcpJsonPath(home) {
6606
- return resolve11(cursorDir(home), "mcp.json");
6866
+ return resolve12(cursorDir(home), "mcp.json");
6607
6867
  }
6608
6868
  function cursorRulesDir(home) {
6609
- return resolve11(cursorDir(home), "rules");
6869
+ return resolve12(cursorDir(home), "rules");
6610
6870
  }
6611
6871
  function cursorRuleMdcPath(home, ruleName) {
6612
- return resolve11(cursorRulesDir(home), `${ruleName}.mdc`);
6872
+ return resolve12(cursorRulesDir(home), `${ruleName}.mdc`);
6613
6873
  }
6614
6874
  function cursorSkillsDir(home) {
6615
- return resolve11(cursorDir(home), "skills");
6875
+ return resolve12(cursorDir(home), "skills");
6616
6876
  }
6617
6877
  function cursorSkillDir(home, skillName) {
6618
- return resolve11(cursorSkillsDir(home), skillName);
6878
+ return resolve12(cursorSkillsDir(home), skillName);
6619
6879
  }
6620
6880
  function bridgeSkillFileReference(skillName) {
6621
6881
  return `.cursor/skills/${skillName}/SKILL.md`;
@@ -6726,9 +6986,9 @@ function quoteIfNeeded(value) {
6726
6986
 
6727
6987
  // src/installers/cursor/skills.ts
6728
6988
  import { readFile as readFile9 } from "fs/promises";
6729
- import { resolve as resolve12 } from "path";
6989
+ import { resolve as resolve13 } from "path";
6730
6990
  async function readSkillDescription(skillSourceDir) {
6731
- const skillMdPath = resolve12(skillSourceDir, "SKILL.md");
6991
+ const skillMdPath = resolve13(skillSourceDir, "SKILL.md");
6732
6992
  let raw;
6733
6993
  try {
6734
6994
  raw = await readFile9(skillMdPath, "utf8");
@@ -6761,11 +7021,11 @@ async function executeRollback(ledger) {
6761
7021
  if (entry.kind === "restore-file") {
6762
7022
  await atomicWriteFile(entry.path, entry.originalContent);
6763
7023
  } else if (entry.kind === "remove-file") {
6764
- await rm8(entry.path, { force: true });
7024
+ await rm9(entry.path, { force: true });
6765
7025
  } else if (entry.kind === "remove-dir") {
6766
- await rm8(entry.path, { recursive: true, force: true });
7026
+ await rm9(entry.path, { recursive: true, force: true });
6767
7027
  } else {
6768
- await rm8(entry.path, { recursive: true, force: true });
7028
+ await rm9(entry.path, { recursive: true, force: true });
6769
7029
  await safeRename(entry.backupPath, entry.path);
6770
7030
  }
6771
7031
  } catch (err) {
@@ -6777,20 +7037,20 @@ async function executeRollback(ledger) {
6777
7037
  return errors;
6778
7038
  }
6779
7039
  async function atomicWriteFile(filePath, content) {
6780
- await mkdir8(dirname8(filePath), { recursive: true });
6781
- const tmp = `${filePath}.${randomUUID6()}.tmp`;
7040
+ await mkdir9(dirname8(filePath), { recursive: true });
7041
+ const tmp = `${filePath}.${randomUUID7()}.tmp`;
6782
7042
  try {
6783
- await writeFile7(tmp, content, { encoding: "utf8", flag: "w" });
6784
- await rename7(tmp, filePath);
7043
+ await writeFile8(tmp, content, { encoding: "utf8", flag: "w" });
7044
+ await rename8(tmp, filePath);
6785
7045
  } catch (err) {
6786
- await rm8(tmp, { force: true }).catch(() => {
7046
+ await rm9(tmp, { force: true }).catch(() => {
6787
7047
  });
6788
7048
  throw err;
6789
7049
  }
6790
7050
  }
6791
7051
  async function getMcpMtimeMs(filePath) {
6792
7052
  try {
6793
- const s = await stat6(filePath);
7053
+ const s = await stat7(filePath);
6794
7054
  return s.mtimeMs;
6795
7055
  } catch {
6796
7056
  return null;
@@ -7023,7 +7283,7 @@ var CursorInstaller = class {
7023
7283
  if (info === "missing") continue;
7024
7284
  if (info === "skill-dir") {
7025
7285
  if (!dryRun) {
7026
- await rm8(filePath, { recursive: true, force: true });
7286
+ await rm9(filePath, { recursive: true, force: true });
7027
7287
  }
7028
7288
  removedFiles.push(filePath);
7029
7289
  continue;
@@ -7037,13 +7297,13 @@ var CursorInstaller = class {
7037
7297
  continue;
7038
7298
  }
7039
7299
  if (!dryRun) {
7040
- await rm8(filePath, { force: true });
7300
+ await rm9(filePath, { force: true });
7041
7301
  }
7042
7302
  removedFiles.push(filePath);
7043
7303
  continue;
7044
7304
  }
7045
7305
  if (!dryRun) {
7046
- await rm8(filePath, { force: true });
7306
+ await rm9(filePath, { force: true });
7047
7307
  }
7048
7308
  removedFiles.push(filePath);
7049
7309
  }
@@ -7091,10 +7351,10 @@ var CursorInstaller = class {
7091
7351
  const prevEntry = registryStore.get(plugin.ref);
7092
7352
  const prevFiles = new Set(prevEntry?.targets?.cursor?.files ?? []);
7093
7353
  if (plugin.capabilities.includes("skills")) {
7094
- const skillsSourceDir = resolve13(plugin.sourceDir, "skills");
7354
+ const skillsSourceDir = resolve14(plugin.sourceDir, "skills");
7095
7355
  const skillDirs = await listSkillDirs(skillsSourceDir);
7096
7356
  for (const skillName of skillDirs) {
7097
- const srcDir = resolve13(skillsSourceDir, skillName);
7357
+ const srcDir = resolve14(skillsSourceDir, skillName);
7098
7358
  const destDir = cursorSkillDir(this.home, skillName);
7099
7359
  const bridgeRulePath = cursorRuleMdcPath(this.home, skillName);
7100
7360
  if (await dirExists2(destDir)) {
@@ -7126,10 +7386,10 @@ var CursorInstaller = class {
7126
7386
  }
7127
7387
  }
7128
7388
  if (plugin.capabilities.includes("rules")) {
7129
- const rulesSourceDir = resolve13(plugin.sourceDir, "rules");
7389
+ const rulesSourceDir = resolve14(plugin.sourceDir, "rules");
7130
7390
  const rulesFiles = await listRuleMdFiles(rulesSourceDir);
7131
7391
  for (const ruleFile of rulesFiles) {
7132
- const srcPath = resolve13(rulesSourceDir, ruleFile);
7392
+ const srcPath = resolve14(rulesSourceDir, ruleFile);
7133
7393
  const ruleName = ruleFile.replace(/\.md$/i, "");
7134
7394
  const destPath = cursorRuleMdcPath(this.home, ruleName);
7135
7395
  await assertMdcWritable(destPath, args.force);
@@ -7166,7 +7426,7 @@ var CursorInstaller = class {
7166
7426
  // -------------------------------------------------------------------------
7167
7427
  async writeSkillDir(args) {
7168
7428
  const preExisted = await dirExists2(args.destDir);
7169
- await mkdir8(dirname8(args.destDir), { recursive: true });
7429
+ await mkdir9(dirname8(args.destDir), { recursive: true });
7170
7430
  if (preExisted) {
7171
7431
  const backup = `${args.destDir}.${process.pid}.${Date.now()}.bak`;
7172
7432
  await safeRename(args.destDir, backup);
@@ -7315,7 +7575,7 @@ async function listRuleMdFiles(rulesDir) {
7315
7575
  }
7316
7576
  async function dirExists2(p) {
7317
7577
  try {
7318
- const s = await stat6(p);
7578
+ const s = await stat7(p);
7319
7579
  return s.isDirectory();
7320
7580
  } catch {
7321
7581
  return false;
@@ -7324,20 +7584,20 @@ async function dirExists2(p) {
7324
7584
  async function fileExists(p) {
7325
7585
  try {
7326
7586
  await access8(p, fsConstants8.F_OK);
7327
- const s = await stat6(p);
7587
+ const s = await stat7(p);
7328
7588
  return s.isFile();
7329
7589
  } catch {
7330
7590
  return false;
7331
7591
  }
7332
7592
  }
7333
7593
  async function safeRename(from, to) {
7334
- const { rename: rename8 } = await import("fs/promises");
7335
- await rename8(from, to);
7594
+ const { rename: rename9 } = await import("fs/promises");
7595
+ await rename9(from, to);
7336
7596
  }
7337
7597
  async function classifyArtifactPath(p) {
7338
7598
  let s;
7339
7599
  try {
7340
- s = await stat6(p);
7600
+ s = await stat7(p);
7341
7601
  } catch {
7342
7602
  return "missing";
7343
7603
  }
@@ -7350,14 +7610,14 @@ async function classifyArtifactPath(p) {
7350
7610
  }
7351
7611
 
7352
7612
  // src/migration/cleanup.ts
7353
- import { lstat as lstat3, rm as rm9, unlink as unlink2 } from "fs/promises";
7613
+ import { lstat as lstat3, rm as rm10, unlink as unlink2 } from "fs/promises";
7354
7614
  import { homedir as homedir9 } from "os";
7355
- import { resolve as resolve15 } from "path";
7615
+ import { resolve as resolve16 } from "path";
7356
7616
 
7357
7617
  // src/migration/detect.ts
7358
- import { access as access9, lstat as lstat2, readFile as readFile11, readlink as readlink2, stat as stat7 } from "fs/promises";
7618
+ import { access as access9, lstat as lstat2, readFile as readFile11, readlink as readlink2, stat as stat8 } from "fs/promises";
7359
7619
  import { homedir as homedir8 } from "os";
7360
- import { isAbsolute as isAbsolute4, resolve as resolve14 } from "path";
7620
+ import { isAbsolute as isAbsolute4, resolve as resolve15 } from "path";
7361
7621
  var LEGACY_ASSET_MANIFEST_RELATIVE = ".rush/plugins/claude-code/asset-manifest.json";
7362
7622
  var LEGACY_ASSETS_DIR_RELATIVE = ".rush/plugins/claude-code/assets";
7363
7623
  var LEGACY_CLAUDE_CODE_DIR_RELATIVE = ".rush/plugins/claude-code";
@@ -7376,7 +7636,7 @@ async function isSymlinkPointingInto(linkPath, expectedTarget) {
7376
7636
  const lst = await lstat2(linkPath);
7377
7637
  if (!lst.isSymbolicLink()) return false;
7378
7638
  const rawTarget = await readlink2(linkPath);
7379
- const resolvedTarget = isAbsolute4(rawTarget) ? rawTarget : resolve14(linkPath, "..", rawTarget);
7639
+ const resolvedTarget = isAbsolute4(rawTarget) ? rawTarget : resolve15(linkPath, "..", rawTarget);
7380
7640
  return resolvedTarget === expectedTarget || resolvedTarget.startsWith(`${expectedTarget}/`);
7381
7641
  } catch {
7382
7642
  return false;
@@ -7413,10 +7673,10 @@ async function hasLegacyMcpWithoutEnabled(settingsJsonPath) {
7413
7673
  }
7414
7674
  async function detectLegacyInstall(opts = {}) {
7415
7675
  const home = opts.home ?? homedir8();
7416
- const assetManifestPath = resolve14(home, LEGACY_ASSET_MANIFEST_RELATIVE);
7417
- const legacyAssetsDir = resolve14(home, LEGACY_ASSETS_DIR_RELATIVE);
7418
- const skillSymlinkPath = resolve14(home, LEGACY_SKILL_SYMLINK_RELATIVE);
7419
- const settingsJsonPath = resolve14(home, CLAUDE_SETTINGS_JSON_RELATIVE);
7676
+ const assetManifestPath = resolve15(home, LEGACY_ASSET_MANIFEST_RELATIVE);
7677
+ const legacyAssetsDir = resolve15(home, LEGACY_ASSETS_DIR_RELATIVE);
7678
+ const skillSymlinkPath = resolve15(home, LEGACY_SKILL_SYMLINK_RELATIVE);
7679
+ const settingsJsonPath = resolve15(home, CLAUDE_SETTINGS_JSON_RELATIVE);
7420
7680
  const [hasAssetManifest, hasLegacySkillSymlink, legacyMcpWithoutEnabled] = await Promise.all([
7421
7681
  pathExists7(assetManifestPath),
7422
7682
  isSymlinkPointingInto(skillSymlinkPath, legacyAssetsDir),
@@ -7431,9 +7691,9 @@ async function detectLegacyInstall(opts = {}) {
7431
7691
  }
7432
7692
  async function detectLegacyVersion(opts = {}) {
7433
7693
  const home = opts.home ?? homedir8();
7434
- const manifestPath = resolve14(home, LEGACY_ASSET_MANIFEST_RELATIVE);
7694
+ const manifestPath = resolve15(home, LEGACY_ASSET_MANIFEST_RELATIVE);
7435
7695
  try {
7436
- const lst = await stat7(manifestPath);
7696
+ const lst = await stat8(manifestPath);
7437
7697
  if (!lst.isFile()) return "0.7.x";
7438
7698
  const raw = await readFile11(manifestPath, "utf8");
7439
7699
  const parsed = JSON.parse(raw);
@@ -7449,9 +7709,9 @@ async function detectLegacyVersion(opts = {}) {
7449
7709
 
7450
7710
  // src/migration/cleanup.ts
7451
7711
  async function cleanupLegacyDir(home) {
7452
- const dir = resolve15(home, LEGACY_CLAUDE_CODE_DIR_RELATIVE);
7712
+ const dir = resolve16(home, LEGACY_CLAUDE_CODE_DIR_RELATIVE);
7453
7713
  try {
7454
- await rm9(dir, { recursive: true, force: true });
7714
+ await rm10(dir, { recursive: true, force: true });
7455
7715
  return { ok: true };
7456
7716
  } catch (err) {
7457
7717
  return {
@@ -7461,7 +7721,7 @@ async function cleanupLegacyDir(home) {
7461
7721
  }
7462
7722
  }
7463
7723
  async function cleanupLegacySymlink(home) {
7464
- const path4 = resolve15(home, LEGACY_SKILL_SYMLINK_RELATIVE);
7724
+ const path4 = resolve16(home, LEGACY_SKILL_SYMLINK_RELATIVE);
7465
7725
  try {
7466
7726
  let lst;
7467
7727
  try {
@@ -7483,7 +7743,7 @@ async function cleanupLegacySymlink(home) {
7483
7743
  }
7484
7744
  }
7485
7745
  async function cleanupLegacyMcp(home) {
7486
- const path4 = resolve15(home, CLAUDE_SETTINGS_JSON_RELATIVE);
7746
+ const path4 = resolve16(home, CLAUDE_SETTINGS_JSON_RELATIVE);
7487
7747
  try {
7488
7748
  const { data, existed } = await readJsonFile(
7489
7749
  path4,
@@ -7539,13 +7799,13 @@ function errorMessage(err) {
7539
7799
  }
7540
7800
 
7541
7801
  // src/migration/log.ts
7542
- import { appendFile as appendFile2, mkdir as mkdir9 } from "fs/promises";
7802
+ import { appendFile as appendFile2, mkdir as mkdir10 } from "fs/promises";
7543
7803
  import { homedir as homedir10 } from "os";
7544
- import { dirname as dirname9, resolve as resolve16 } from "path";
7804
+ import { dirname as dirname9, resolve as resolve17 } from "path";
7545
7805
  var MIGRATION_LOG_RELATIVE_PATH = ".rush/plugins/migration-failed.log";
7546
7806
  function resolveMigrationLogPath(opts = {}) {
7547
7807
  const home = opts.home ?? homedir10();
7548
- return resolve16(home, MIGRATION_LOG_RELATIVE_PATH);
7808
+ return resolve17(home, MIGRATION_LOG_RELATIVE_PATH);
7549
7809
  }
7550
7810
  async function appendMigrationFailure(reason, opts = {}) {
7551
7811
  const now = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
@@ -7562,7 +7822,7 @@ async function appendMigrationFailure(reason, opts = {}) {
7562
7822
  const payload = `${lines.join("\n")}
7563
7823
  `;
7564
7824
  try {
7565
- await mkdir9(dirname9(logPath), { recursive: true });
7825
+ await mkdir10(dirname9(logPath), { recursive: true });
7566
7826
  await appendFile2(logPath, payload, { encoding: "utf8" });
7567
7827
  } catch {
7568
7828
  }
@@ -7582,8 +7842,8 @@ import {
7582
7842
 
7583
7843
  // src/plugins/capabilities.ts
7584
7844
  import { constants as fsConstants9 } from "fs";
7585
- import { access as access10, readdir as readdir4, stat as stat8 } from "fs/promises";
7586
- import { extname as extname2, resolve as resolve17 } from "path";
7845
+ import { access as access10, readdir as readdir4, stat as stat9 } from "fs/promises";
7846
+ import { extname as extname2, resolve as resolve18 } from "path";
7587
7847
  var CAPABILITY_ORDER = [
7588
7848
  "commands",
7589
7849
  "skills",
@@ -7612,10 +7872,10 @@ async function scanCapabilities(sourceDir, manifest) {
7612
7872
  return CAPABILITY_ORDER.filter((cap) => found.has(cap));
7613
7873
  }
7614
7874
  async function hasCommands(sourceDir) {
7615
- return dirHasFileWithExt(resolve17(sourceDir, "commands"), ".md");
7875
+ return dirHasFileWithExt(resolve18(sourceDir, "commands"), ".md");
7616
7876
  }
7617
7877
  async function hasSkills(sourceDir) {
7618
- const skillsDir = resolve17(sourceDir, "skills");
7878
+ const skillsDir = resolve18(sourceDir, "skills");
7619
7879
  if (await dirExists3(skillsDir)) {
7620
7880
  let entries;
7621
7881
  try {
@@ -7625,7 +7885,7 @@ async function hasSkills(sourceDir) {
7625
7885
  }
7626
7886
  for (const entry of entries) {
7627
7887
  if (!entry.isDirectory()) continue;
7628
- const skillMdPath = resolve17(skillsDir, entry.name, "SKILL.md");
7888
+ const skillMdPath = resolve18(skillsDir, entry.name, "SKILL.md");
7629
7889
  if (await fileExists2(skillMdPath)) {
7630
7890
  return true;
7631
7891
  }
@@ -7634,10 +7894,10 @@ async function hasSkills(sourceDir) {
7634
7894
  return hasClaudeStyleSkills(sourceDir);
7635
7895
  }
7636
7896
  async function hasRules(sourceDir) {
7637
- return dirHasFileWithExt(resolve17(sourceDir, "rules"), ".md");
7897
+ return dirHasFileWithExt(resolve18(sourceDir, "rules"), ".md");
7638
7898
  }
7639
7899
  async function hasHooks(sourceDir) {
7640
- const hooksDir = resolve17(sourceDir, "hooks");
7900
+ const hooksDir = resolve18(sourceDir, "hooks");
7641
7901
  if (!await dirExists3(hooksDir)) {
7642
7902
  return false;
7643
7903
  }
@@ -7679,7 +7939,7 @@ async function dirHasFileWithExt(dirPath, ext) {
7679
7939
  );
7680
7940
  }
7681
7941
  async function hasClaudeStyleSkills(sourceDir) {
7682
- const dotSkillsDir = resolve17(sourceDir, ".skills");
7942
+ const dotSkillsDir = resolve18(sourceDir, ".skills");
7683
7943
  if (!await dirExists3(dotSkillsDir)) {
7684
7944
  return false;
7685
7945
  }
@@ -7691,7 +7951,7 @@ async function hasClaudeStyleSkills(sourceDir) {
7691
7951
  return false;
7692
7952
  }
7693
7953
  for (const entry of entries) {
7694
- const abs = resolve17(dirPath, entry.name);
7954
+ const abs = resolve18(dirPath, entry.name);
7695
7955
  if (entry.isDirectory()) {
7696
7956
  if (await walk2(abs)) return true;
7697
7957
  continue;
@@ -7706,7 +7966,7 @@ async function hasClaudeStyleSkills(sourceDir) {
7706
7966
  }
7707
7967
  async function dirExists3(p) {
7708
7968
  try {
7709
- const s = await stat8(p);
7969
+ const s = await stat9(p);
7710
7970
  return s.isDirectory();
7711
7971
  } catch {
7712
7972
  return false;
@@ -7715,7 +7975,7 @@ async function dirExists3(p) {
7715
7975
  async function fileExists2(p) {
7716
7976
  try {
7717
7977
  await access10(p, fsConstants9.R_OK);
7718
- const s = await stat8(p);
7978
+ const s = await stat9(p);
7719
7979
  return s.isFile();
7720
7980
  } catch {
7721
7981
  return false;
@@ -7786,10 +8046,10 @@ var InvalidPluginVersionError = class extends PluginResolverError {
7786
8046
  // src/plugins/manifest.ts
7787
8047
  import { constants as fsConstants10 } from "fs";
7788
8048
  import { access as access11, readFile as readFile12 } from "fs/promises";
7789
- import { resolve as resolve18 } from "path";
8049
+ import { resolve as resolve19 } from "path";
7790
8050
  var PLUGIN_MANIFEST_RELATIVE_PATH = ".claude-plugin/plugin.json";
7791
8051
  async function readPluginManifest(pluginName, sourceDir) {
7792
- const manifestPath = resolve18(sourceDir, PLUGIN_MANIFEST_RELATIVE_PATH);
8052
+ const manifestPath = resolve19(sourceDir, PLUGIN_MANIFEST_RELATIVE_PATH);
7793
8053
  try {
7794
8054
  await access11(manifestPath, fsConstants10.R_OK);
7795
8055
  } catch {
@@ -8458,6 +8718,11 @@ function claudeMarketplaceSourceFrom(marketplace) {
8458
8718
  rootDir: marketplace.rootDir,
8459
8719
  descriptor: { kind: "git", url: src.url }
8460
8720
  };
8721
+ case "rush":
8722
+ return {
8723
+ rootDir: marketplace.rootDir,
8724
+ descriptor: { kind: "directory", path: marketplace.rootDir }
8725
+ };
8461
8726
  default:
8462
8727
  return void 0;
8463
8728
  }
@@ -8534,45 +8799,151 @@ async function runInstall(input) {
8534
8799
  marketplace = await cache.get(ref.marketplace);
8535
8800
  } catch (err) {
8536
8801
  if (err instanceof MarketplaceNotFoundError) {
8802
+ if (ref.marketplace === "rush" || ref.marketplace === "rush-marketplace") {
8803
+ const apiHost = getGlobalConfig().api.replace(/^https?:\/\//, "");
8804
+ const rushSource = parseSource(`rush://${apiHost}`);
8805
+ await cache.add(rushSource, { as: ref.marketplace });
8806
+ marketplace = await cache.get(ref.marketplace);
8807
+ } else {
8808
+ throw new RushError(
8809
+ `Marketplace '${ref.marketplace}' is not in the local cache. Run 'rush-ai marketplace add <source>' first.`,
8810
+ { marketplaceName: ref.marketplace },
8811
+ "MARKETPLACE_NOT_FOUND",
8812
+ 2
8813
+ );
8814
+ }
8815
+ } else {
8816
+ throw err;
8817
+ }
8818
+ }
8819
+ if (marketplace.source.kind === "rush") {
8820
+ const TWENTY_FOUR_HOURS = 24 * 60 * 60 * 1e3;
8821
+ const entryMissing = !marketplace.manifest.plugins.some(
8822
+ (p) => p.name === ref.name
8823
+ );
8824
+ const cacheList = await cache.list();
8825
+ const cacheEntry = cacheList.find((m) => m.name === ref.marketplace);
8826
+ const isStale = cacheEntry?.cachedAt ? Date.now() - new Date(cacheEntry.cachedAt).getTime() > TWENTY_FOUR_HOURS : false;
8827
+ if (entryMissing || isStale) {
8828
+ marketplace = await cache.update(ref.marketplace);
8829
+ }
8830
+ if (!marketplace.manifest.plugins.some((p) => p.name === ref.name)) {
8537
8831
  throw new RushError(
8538
- `Marketplace '${ref.marketplace}' is not in the local cache. Run 'rush-ai marketplace add <source>' first.`,
8539
- { marketplaceName: ref.marketplace },
8540
- "MARKETPLACE_NOT_FOUND",
8832
+ `Plugin '${ref.name}' not found in rush marketplace. Verify the plugin exists on the Web and is public.`,
8833
+ { pluginName: ref.name, marketplace: ref.marketplace },
8834
+ "PLUGIN_NOT_FOUND_IN_MARKETPLACE",
8541
8835
  2
8542
8836
  );
8543
8837
  }
8544
- throw err;
8838
+ }
8839
+ if (marketplace.source.kind === "rush") {
8840
+ const pluginDir = resolve20(marketplace.rootDir, "plugins", ref.name);
8841
+ const manifestPath = resolve20(pluginDir, ".claude-plugin/plugin.json");
8842
+ const alreadyMaterialized = await pathExists2(manifestPath);
8843
+ const hasNewSecrets = input.secrets && Object.keys(input.secrets).length > 0;
8844
+ const shouldMaterialize = !alreadyMaterialized || force || hasNewSecrets;
8845
+ if (shouldMaterialize && dryRun && !alreadyMaterialized) {
8846
+ throw new RushError(
8847
+ `Plugin '${ref.name}' has not been installed yet. Run without --dry-run first to fetch and cache the plugin manifest.`,
8848
+ { pluginName: ref.name },
8849
+ "PLUGIN_NOT_MATERIALIZED",
8850
+ 2
8851
+ );
8852
+ }
8853
+ if (shouldMaterialize && !dryRun) {
8854
+ const rushSource = marketplace.source;
8855
+ const token = getAuthToken();
8856
+ let apiManifest;
8857
+ try {
8858
+ apiManifest = await fetchRushPlugin(rushSource, ref.name, { token });
8859
+ } catch (err) {
8860
+ const msg = err instanceof Error ? err.message : String(err);
8861
+ throw new RushError(
8862
+ `Failed to fetch plugin '${ref.name}' from rush marketplace: ${msg}`,
8863
+ { pluginName: ref.name, marketplace: ref.marketplace },
8864
+ "PLUGIN_FETCH_FAILED",
8865
+ 2
8866
+ );
8867
+ }
8868
+ let secrets = {};
8869
+ if (apiManifest.requiredSecrets && apiManifest.requiredSecrets.length > 0) {
8870
+ const presetSecrets = input.secrets ?? {};
8871
+ const missingMeta = {};
8872
+ for (const s of apiManifest.requiredSecrets) {
8873
+ if (!(s.key in presetSecrets)) {
8874
+ const isSecret = s.type === "secret" || s.type === "password";
8875
+ missingMeta[s.key] = {
8876
+ type: isSecret ? "secret" : "text",
8877
+ required: true,
8878
+ helpUrl: s.helpUrl
8879
+ };
8880
+ }
8881
+ }
8882
+ const prompted = Object.keys(missingMeta).length > 0 ? await promptCredentials(missingMeta) : {};
8883
+ secrets = { ...prompted, ...presetSecrets };
8884
+ }
8885
+ try {
8886
+ await materializeRushPlugin(rushSource, ref.name, pluginDir, {
8887
+ token,
8888
+ secrets
8889
+ });
8890
+ } catch (err) {
8891
+ if (err instanceof SkillAuthError) {
8892
+ throw new RushError(
8893
+ err.message,
8894
+ { pluginName: ref.name, marketplace: ref.marketplace },
8895
+ "AUTH_REQUIRED",
8896
+ 2
8897
+ );
8898
+ }
8899
+ throw err;
8900
+ }
8901
+ }
8545
8902
  }
8546
8903
  const resolveFn = input.resolvePluginFn ?? resolvePlugin;
8547
8904
  let plugin;
8548
8905
  try {
8549
8906
  plugin = await resolveFn(ref, marketplace);
8550
8907
  } catch (err) {
8551
- if (err instanceof PluginNotFoundInMarketplaceError) {
8908
+ if (err instanceof PluginNotFoundInMarketplaceError && marketplace.source.kind === "rush") {
8909
+ marketplace = await cache.update(ref.marketplace);
8910
+ try {
8911
+ plugin = await resolveFn(ref, marketplace);
8912
+ } catch (retryErr) {
8913
+ if (retryErr instanceof PluginNotFoundInMarketplaceError) {
8914
+ throw new RushError(
8915
+ retryErr.message,
8916
+ { pluginName: ref.name, marketplace: ref.marketplace },
8917
+ "PLUGIN_NOT_FOUND_IN_MARKETPLACE",
8918
+ 2
8919
+ );
8920
+ }
8921
+ throw retryErr;
8922
+ }
8923
+ } else if (err instanceof PluginNotFoundInMarketplaceError) {
8552
8924
  throw new RushError(
8553
8925
  err.message,
8554
8926
  { pluginName: ref.name, marketplace: ref.marketplace },
8555
8927
  "PLUGIN_NOT_FOUND_IN_MARKETPLACE",
8556
8928
  2
8557
8929
  );
8558
- }
8559
- if (err instanceof PluginManifestNotFoundError) {
8930
+ } else if (err instanceof PluginManifestNotFoundError) {
8560
8931
  throw new RushError(
8561
8932
  err.message,
8562
8933
  { pluginName: ref.name, marketplace: ref.marketplace },
8563
8934
  "PLUGIN_MANIFEST_NOT_FOUND",
8564
8935
  2
8565
8936
  );
8566
- }
8567
- if (err instanceof PluginResolverError) {
8937
+ } else if (err instanceof PluginResolverError) {
8568
8938
  throw new RushError(
8569
8939
  err.message,
8570
8940
  { pluginName: ref.name, marketplace: ref.marketplace },
8571
8941
  "PLUGIN_RESOLVE_FAILED",
8572
8942
  2
8573
8943
  );
8944
+ } else {
8945
+ throw err;
8574
8946
  }
8575
- throw err;
8576
8947
  }
8577
8948
  let migrationOutcome;
8578
8949
  if (!dryRun) {
@@ -8683,14 +9054,38 @@ function registerInstallCommand(group, _root) {
8683
9054
  ).argument("<ref>", "plugin reference: <name> or <name>@<marketplace>").option(
8684
9055
  "--target <list>",
8685
9056
  `comma-separated targets (default: ${[...DEFAULT_TARGETS].join(",")})`
8686
- ).option("--force", "reinstall even if same version is already installed").option("--dry-run", "don't touch disk; print the plan").action(
9057
+ ).option("--force", "reinstall even if same version is already installed").option("--dry-run", "don't touch disk; print the plan").option(
9058
+ "--secret <key=value>",
9059
+ "pre-set MCP secret values (repeatable)",
9060
+ (val, acc) => {
9061
+ acc.push(val);
9062
+ return acc;
9063
+ },
9064
+ []
9065
+ ).action(
8687
9066
  async (ref, opts) => {
9067
+ const secrets = {};
9068
+ if (opts.secret && opts.secret.length > 0) {
9069
+ for (const pair of opts.secret) {
9070
+ const eqIdx = pair.indexOf("=");
9071
+ if (eqIdx <= 0) {
9072
+ throw new RushError(
9073
+ `Invalid --secret format '${pair}'. Expected KEY=VALUE.`,
9074
+ { raw: pair },
9075
+ "INVALID_SECRET_FORMAT",
9076
+ 2
9077
+ );
9078
+ }
9079
+ secrets[pair.slice(0, eqIdx)] = pair.slice(eqIdx + 1);
9080
+ }
9081
+ }
8688
9082
  const result = await runInstall({
8689
9083
  ref,
8690
9084
  ...opts.target !== void 0 ? { targetRaw: opts.target } : {},
8691
9085
  targetExplicit: opts.target !== void 0,
8692
9086
  ...opts.force ? { force: true } : {},
8693
9087
  ...opts.dryRun ? { dryRun: true } : {},
9088
+ ...Object.keys(secrets).length > 0 ? { secrets } : {},
8694
9089
  migrationReporter: {
8695
9090
  info: (line) => output.dim(line),
8696
9091
  warn: (line) => output.warn(line)
@@ -9313,7 +9708,7 @@ function registerPluginCommand(program) {
9313
9708
 
9314
9709
  // src/commands/skill/index.ts
9315
9710
  import { existsSync as existsSync11, readdirSync, readFileSync as readFileSync7 } from "fs";
9316
- import { basename as basename3, resolve as resolve19 } from "path";
9711
+ import { basename as basename3, resolve as resolve21 } from "path";
9317
9712
  var SKILL_DESCRIPTION = "Print agent usage skills (hand-off, agent-shelf, ...) as raw markdown.";
9318
9713
  var SKILL_HELP_AFTER = `
9319
9714
  Examples:
@@ -9330,11 +9725,11 @@ function resolveSkillsDir() {
9330
9725
  const baseDir = import.meta.dirname ?? __dirname;
9331
9726
  if (!baseDir) return null;
9332
9727
  const candidates = [
9333
- resolve19(baseDir, "skills"),
9334
- resolve19(baseDir, "..", "skills"),
9335
- resolve19(baseDir, "..", "..", "skills"),
9336
- resolve19(baseDir, "..", "..", "..", "skills"),
9337
- resolve19(baseDir, "..", "..", "..", "..", "skills")
9728
+ resolve21(baseDir, "skills"),
9729
+ resolve21(baseDir, "..", "skills"),
9730
+ resolve21(baseDir, "..", "..", "skills"),
9731
+ resolve21(baseDir, "..", "..", "..", "skills"),
9732
+ resolve21(baseDir, "..", "..", "..", "..", "skills")
9338
9733
  ];
9339
9734
  for (const p of candidates) {
9340
9735
  if (existsSync11(p)) return p;
@@ -9360,7 +9755,7 @@ function registerSkillCommand(program) {
9360
9755
  return;
9361
9756
  }
9362
9757
  const target = name ?? "README";
9363
- const file2 = resolve19(dir, `${target}.md`);
9758
+ const file2 = resolve21(dir, `${target}.md`);
9364
9759
  if (!existsSync11(file2)) {
9365
9760
  output.error(`Unknown skill "${target}".`);
9366
9761
  output.dim(`Available: ${available.join(", ") || "(none)"}`);
@@ -9373,7 +9768,7 @@ function registerSkillCommand(program) {
9373
9768
 
9374
9769
  // src/commands/task/index.ts
9375
9770
  import { createWriteStream } from "fs";
9376
- import { mkdir as mkdir10, readFile as readFile14, stat as stat9 } from "fs/promises";
9771
+ import { mkdir as mkdir11, readFile as readFile14, stat as stat10 } from "fs/promises";
9377
9772
  import path3 from "path";
9378
9773
  import { Readable } from "stream";
9379
9774
  import { pipeline } from "stream/promises";
@@ -9399,13 +9794,13 @@ async function readStdinIfPiped() {
9399
9794
  if (process.stdin.isTTY) {
9400
9795
  return null;
9401
9796
  }
9402
- return new Promise((resolve21, reject) => {
9797
+ return new Promise((resolve23, reject) => {
9403
9798
  const chunks = [];
9404
9799
  process.stdin.on("data", (chunk) => {
9405
9800
  chunks.push(chunk);
9406
9801
  });
9407
9802
  process.stdin.on("end", () => {
9408
- resolve21(Buffer.concat(chunks).toString("utf-8").trim());
9803
+ resolve23(Buffer.concat(chunks).toString("utf-8").trim());
9409
9804
  });
9410
9805
  process.stdin.on("error", reject);
9411
9806
  });
@@ -9606,7 +10001,7 @@ function buildDeployUrl(prefix, env, apiBaseUrl) {
9606
10001
  }
9607
10002
 
9608
10003
  // src/commands/task/push.ts
9609
- import { resolve as resolve20 } from "path";
10004
+ import { resolve as resolve22 } from "path";
9610
10005
  import chalk5 from "chalk";
9611
10006
 
9612
10007
  // src/util/env-file.ts
@@ -9750,7 +10145,7 @@ function registerPushSubcommand(task, program) {
9750
10145
  requireAuth();
9751
10146
  const format = resolveFormat(program.opts());
9752
10147
  const client = createClient();
9753
- const projectPath = resolve20(opts.path);
10148
+ const projectPath = resolve22(opts.path);
9754
10149
  if (format !== "json") {
9755
10150
  output.info("Checking project readiness...");
9756
10151
  }
@@ -9927,6 +10322,9 @@ function pushWithRouting(projectPath, source, envGitRemote) {
9927
10322
 
9928
10323
  // src/commands/task/deploy.ts
9929
10324
  var DOMAIN_PREFIX_REGEX = /^[a-z0-9][a-z0-9-]{0,28}[a-z0-9]$|^[a-z0-9]$/;
10325
+ function getApiBaseUrl2() {
10326
+ return process.env.RUSH_API_URL ?? getGlobalConfig().api;
10327
+ }
9930
10328
  function validateDomainPrefix(prefix) {
9931
10329
  if (!DOMAIN_PREFIX_REGEX.test(prefix)) {
9932
10330
  throw new RushError(
@@ -10178,7 +10576,7 @@ async function confirmPublish(args) {
10178
10576
  return answer.trim().toLowerCase().startsWith("y");
10179
10577
  }
10180
10578
  function readOneLine() {
10181
- return new Promise((resolve21) => {
10579
+ return new Promise((resolve23) => {
10182
10580
  let acc = "";
10183
10581
  const onData = (chunk) => {
10184
10582
  acc += chunk.toString("utf-8");
@@ -10186,7 +10584,7 @@ function readOneLine() {
10186
10584
  if (nlIdx !== -1) {
10187
10585
  process.stdin.removeListener("data", onData);
10188
10586
  process.stdin.pause();
10189
- resolve21(acc.slice(0, nlIdx));
10587
+ resolve23(acc.slice(0, nlIdx));
10190
10588
  }
10191
10589
  };
10192
10590
  process.stdin.resume();
@@ -10206,7 +10604,7 @@ async function publishNextjs(client, projectId, commitHash, domain, format) {
10206
10604
  }
10207
10605
  });
10208
10606
  if (domain !== void 0) {
10209
- const { api: apiBase } = getGlobalConfig();
10607
+ const apiBase = getApiBaseUrl2();
10210
10608
  return {
10211
10609
  url: buildDeployUrl(domain, "production", apiBase),
10212
10610
  domain: buildDeployDomain(domain, "production", apiBase)
@@ -10247,7 +10645,7 @@ async function publishStatic(client, projectId, commitHash, env, domain) {
10247
10645
  { taskId: projectId, reason: "publish_failed" }
10248
10646
  );
10249
10647
  }
10250
- const { api: apiBase } = getGlobalConfig();
10648
+ const apiBase = getApiBaseUrl2();
10251
10649
  const resolvedDomain = domain !== void 0 ? buildDeployDomain(domain, env, apiBase) : publishResp.data.data?.domain;
10252
10650
  const resolvedUrl = domain !== void 0 ? buildDeployUrl(domain, env, apiBase) : publishResp.data.data?.url;
10253
10651
  const versionId = commitHash;
@@ -10355,7 +10753,7 @@ function registerDomainSubcommand(task, program) {
10355
10753
  return;
10356
10754
  }
10357
10755
  if (data.available) {
10358
- const { api } = getGlobalConfig();
10756
+ const api = process.env.RUSH_API_URL ?? getGlobalConfig().api;
10359
10757
  const url = buildDeployUrl(prefix, "production", api);
10360
10758
  output.success(`Prefix available: ${url}`);
10361
10759
  } else {
@@ -10943,7 +11341,7 @@ async function downloadFile(file2, destPath, client) {
10943
11341
  if (!response.body) {
10944
11342
  throw new Error("No response body");
10945
11343
  }
10946
- await mkdir10(path3.dirname(destPath), { recursive: true });
11344
+ await mkdir11(path3.dirname(destPath), { recursive: true });
10947
11345
  const nodeStream = Readable.fromWeb(
10948
11346
  response.body
10949
11347
  );
@@ -11483,7 +11881,7 @@ async function uploadFileForTask(client, localPath) {
11483
11881
  const resolved = path3.resolve(localPath);
11484
11882
  let fileStat;
11485
11883
  try {
11486
- fileStat = await stat9(resolved);
11884
+ fileStat = await stat10(resolved);
11487
11885
  } catch {
11488
11886
  throw new RushError(`File not found: ${localPath}`);
11489
11887
  }
@@ -11549,7 +11947,7 @@ function registerCommands(program) {
11549
11947
  }
11550
11948
 
11551
11949
  // src/util/update-check.ts
11552
- import { mkdir as mkdir11, readFile as readFile15, writeFile as writeFile8 } from "fs/promises";
11950
+ import { mkdir as mkdir12, readFile as readFile15, writeFile as writeFile9 } from "fs/promises";
11553
11951
  import { homedir as homedir12 } from "os";
11554
11952
  import { dirname as dirname10, join as join10 } from "path";
11555
11953
  var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
@@ -11574,8 +11972,8 @@ function isNewerVersion(current, latest) {
11574
11972
  }
11575
11973
  async function writeLastCheck(checkFile) {
11576
11974
  try {
11577
- await mkdir11(dirname10(checkFile), { recursive: true });
11578
- await writeFile8(checkFile, JSON.stringify({ lastCheck: Date.now() }));
11975
+ await mkdir12(dirname10(checkFile), { recursive: true });
11976
+ await writeFile9(checkFile, JSON.stringify({ lastCheck: Date.now() }));
11579
11977
  } catch {
11580
11978
  }
11581
11979
  }