rush-ai 0.19.0 → 0.21.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
@@ -25,14 +25,14 @@ import {
25
25
  syncCodexMarketplaceMirror,
26
26
  writeCodexConfig,
27
27
  writeCodexMarketplacePluginMirror
28
- } from "./chunk-RLKEUPBP.js";
28
+ } from "./chunk-GPOA7SAG.js";
29
29
  import {
30
30
  SkillAuthError,
31
31
  fetchRushMarketplace,
32
32
  fetchRushPlugin,
33
33
  materializeRushPlugin,
34
34
  pickContentLoader
35
- } from "./chunk-2AICQRQP.js";
35
+ } from "./chunk-C7KJUHEF.js";
36
36
  import {
37
37
  consumeSSEStreamWithReconnect
38
38
  } from "./chunk-MG4HY2PD.js";
@@ -81,7 +81,7 @@ import {
81
81
  defaultRushBinaryResolver,
82
82
  normalizeClaudeMcpServers,
83
83
  readExternalMcpServers
84
- } from "./chunk-X45FKY3L.js";
84
+ } from "./chunk-22YQT6XF.js";
85
85
 
86
86
  // src/index.ts
87
87
  import chalk7 from "chalk";
@@ -446,7 +446,7 @@ function getApiBaseUrl() {
446
446
  async function loginViaBrowser(jsonMode) {
447
447
  const baseUrl = getApiBaseUrl();
448
448
  const state = randomBytes(16).toString("hex");
449
- return new Promise((resolve23, reject) => {
449
+ return new Promise((resolve25, reject) => {
450
450
  let authSaved = false;
451
451
  const rejectLogin = (error) => {
452
452
  clearAuthConfig();
@@ -549,7 +549,7 @@ async function loginViaBrowser(jsonMode) {
549
549
  );
550
550
  }
551
551
  }
552
- resolve23();
552
+ resolve25();
553
553
  } catch (err) {
554
554
  server.close();
555
555
  const authError = err instanceof AuthError ? err : new AuthError(
@@ -3357,8 +3357,8 @@ async function writeFileAtomic(filePath, content) {
3357
3357
  const tmp = `${filePath}.${Math.random().toString(36).slice(2)}.tmp`;
3358
3358
  try {
3359
3359
  await writeFile2(tmp, content, { encoding: "utf8", flag: "w" });
3360
- const { rename: rename7 } = await import("fs/promises");
3361
- await rename7(tmp, filePath);
3360
+ const { rename: rename8 } = await import("fs/promises");
3361
+ await rename8(tmp, filePath);
3362
3362
  } catch (err) {
3363
3363
  await rm(tmp, { force: true }).catch(() => {
3364
3364
  });
@@ -4170,12 +4170,41 @@ var MarketplaceCache = class {
4170
4170
  const data = await fetchRushMarketplace(source, { token });
4171
4171
  const manifest = {
4172
4172
  name: data.name || "rush",
4173
- plugins: data.plugins.map((p) => ({
4174
- name: p.name,
4175
- version: p.version,
4176
- description: p.description,
4177
- source: `./plugins/${p.name}`
4178
- }))
4173
+ plugins: data.plugins.map((p) => {
4174
+ const entry = {
4175
+ name: p.name,
4176
+ version: p.version,
4177
+ description: p.description,
4178
+ source: `./plugins/${p.name}`
4179
+ };
4180
+ const cat = p.category;
4181
+ if (typeof cat === "string" && cat.length > 0) {
4182
+ entry.category = cat;
4183
+ }
4184
+ const apiAuthor = p.author;
4185
+ if (apiAuthor && typeof apiAuthor === "object") {
4186
+ entry.author = { ...apiAuthor };
4187
+ }
4188
+ const apiHomepage = p.homepage;
4189
+ let homepageOut;
4190
+ if (typeof apiHomepage === "string" && apiHomepage.length > 0) {
4191
+ homepageOut = apiHomepage;
4192
+ } else {
4193
+ const apiSource = p.source;
4194
+ if (apiSource && typeof apiSource === "object") {
4195
+ const sUrl = apiSource.url;
4196
+ if (typeof sUrl === "string" && /^https?:\/\//i.test(sUrl)) {
4197
+ homepageOut = sUrl.replace(/\.git$/, "");
4198
+ }
4199
+ } else if (typeof apiSource === "string" && /^https?:\/\//i.test(apiSource)) {
4200
+ homepageOut = apiSource;
4201
+ }
4202
+ }
4203
+ if (homepageOut) {
4204
+ entry.homepage = homepageOut;
4205
+ }
4206
+ return entry;
4207
+ })
4179
4208
  };
4180
4209
  const resolvedName = name ?? defaultNameFromSource(source);
4181
4210
  const rootDir = this.pathFor(resolvedName);
@@ -5448,107 +5477,1113 @@ function registerMcpCommand(program) {
5448
5477
  }
5449
5478
  });
5450
5479
  }
5451
-
5452
- // src/commands/playbook/index.ts
5453
- import { existsSync as existsSync11, readdirSync, readFileSync as readFileSync7 } from "fs";
5454
- import { basename as basename3, resolve as resolve9 } from "path";
5455
- var PLAYBOOK_DESCRIPTION = "Print agent usage playbooks (hand-off, agent-shelf, ...) as raw markdown.";
5456
- var PLAYBOOK_HELP_AFTER = `
5457
- Examples:
5458
- $ npx rush-ai playbook Print the playbook index
5459
- $ npx rush-ai playbook hand-off Print the hand-off playbook
5460
- $ npx rush-ai playbook agent-shelf Print the agent-shelf playbook
5461
- $ npx rush-ai playbook --list List available playbooks
5462
-
5463
- Designed to be consumed by AI agents inside IDEs (Cursor, Claude Code,
5464
- Codex, etc). Output is raw markdown on stdout \u2014 pipe it, grep it, feed it
5465
- to your own context.
5466
- `;
5467
- function resolvePlaybooksDir() {
5468
- const baseDir = import.meta.dirname ?? __dirname;
5469
- if (!baseDir) return null;
5470
- const candidates = [
5471
- resolve9(baseDir, "skills"),
5472
- resolve9(baseDir, "..", "skills"),
5473
- resolve9(baseDir, "..", "..", "skills"),
5474
- resolve9(baseDir, "..", "..", "..", "skills"),
5475
- resolve9(baseDir, "..", "..", "..", "..", "skills")
5476
- ];
5477
- for (const p of candidates) {
5478
- if (existsSync11(resolve9(p, ".rush-playbooks"))) return p;
5480
+
5481
+ // src/commands/playbook/index.ts
5482
+ import { existsSync as existsSync11, readdirSync, readFileSync as readFileSync7 } from "fs";
5483
+ import { basename as basename3, resolve as resolve9 } from "path";
5484
+ var PLAYBOOK_DESCRIPTION = "Print agent usage playbooks (hand-off, agent-shelf, ...) as raw markdown.";
5485
+ var PLAYBOOK_HELP_AFTER = `
5486
+ Examples:
5487
+ $ npx rush-ai playbook Print the playbook index
5488
+ $ npx rush-ai playbook hand-off Print the hand-off playbook
5489
+ $ npx rush-ai playbook agent-shelf Print the agent-shelf playbook
5490
+ $ npx rush-ai playbook --list List available playbooks
5491
+
5492
+ Designed to be consumed by AI agents inside IDEs (Cursor, Claude Code,
5493
+ Codex, etc). Output is raw markdown on stdout \u2014 pipe it, grep it, feed it
5494
+ to your own context.
5495
+ `;
5496
+ function resolvePlaybooksDir() {
5497
+ const baseDir = import.meta.dirname ?? __dirname;
5498
+ if (!baseDir) return null;
5499
+ const candidates = [
5500
+ resolve9(baseDir, "skills"),
5501
+ resolve9(baseDir, "..", "skills"),
5502
+ resolve9(baseDir, "..", "..", "skills"),
5503
+ resolve9(baseDir, "..", "..", "..", "skills"),
5504
+ resolve9(baseDir, "..", "..", "..", "..", "skills")
5505
+ ];
5506
+ for (const p of candidates) {
5507
+ if (existsSync11(resolve9(p, ".rush-playbooks"))) return p;
5508
+ }
5509
+ return null;
5510
+ }
5511
+ function listPlaybooks(dir) {
5512
+ return readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => basename3(f, ".md")).sort();
5513
+ }
5514
+ function getAvailablePlaybooks() {
5515
+ const dir = resolvePlaybooksDir();
5516
+ return dir ? listPlaybooks(dir) : [];
5517
+ }
5518
+ function isPlaybookName(name) {
5519
+ if (!name) return false;
5520
+ return getAvailablePlaybooks().includes(name);
5521
+ }
5522
+ function printPlaybook(name, opts = {}) {
5523
+ const dir = resolvePlaybooksDir();
5524
+ if (!dir) {
5525
+ output.error(
5526
+ "Could not locate the skills/ directory. This is a packaging bug \u2014 please file an issue."
5527
+ );
5528
+ process.exit(2);
5529
+ return;
5530
+ }
5531
+ const available = listPlaybooks(dir);
5532
+ if (opts.list) {
5533
+ for (const s of available) output.log(s);
5534
+ return;
5535
+ }
5536
+ const target = name ?? "README";
5537
+ const file2 = resolve9(dir, `${target}.md`);
5538
+ if (!existsSync11(file2)) {
5539
+ output.error(`Unknown playbook "${target}".`);
5540
+ output.dim(`Available: ${available.join(", ") || "(none)"}`);
5541
+ process.exit(1);
5542
+ return;
5543
+ }
5544
+ process.stdout.write(readFileSync7(file2, "utf-8"));
5545
+ }
5546
+ function registerPlaybookCommand(program) {
5547
+ program.command("playbook [name]").description(PLAYBOOK_DESCRIPTION).addHelpText("after", PLAYBOOK_HELP_AFTER).option("--list", "List available playbook names and exit").action((name, opts) => {
5548
+ printPlaybook(name, opts);
5549
+ });
5550
+ }
5551
+
5552
+ // src/commands/plugin/install.ts
5553
+ import { rm as rm12 } from "fs/promises";
5554
+ import { homedir as homedir18 } from "os";
5555
+ import { resolve as resolve22 } from "path";
5556
+
5557
+ // src/installers/claude-3p/installer.ts
5558
+ import { randomUUID as randomUUID3 } from "crypto";
5559
+ import {
5560
+ cp as cp2,
5561
+ mkdir as mkdir5,
5562
+ readdir as readdir4,
5563
+ readFile as readFile6,
5564
+ rename as rename3,
5565
+ rm as rm6,
5566
+ writeFile as writeFile5
5567
+ } from "fs/promises";
5568
+ import { homedir as homedir10 } from "os";
5569
+ import { dirname as dirname5, join as join9, resolve as resolve11 } from "path";
5570
+
5571
+ // src/installers/claude-3p/paths.ts
5572
+ import { readdir as readdir3, stat as stat3 } from "fs/promises";
5573
+ import { resolve as resolve10 } from "path";
5574
+ var CLAUDE_3P_APP_DIR = "Claude-3p";
5575
+ var LOCAL_AGENT_SESSIONS_DIR = "local-agent-mode-sessions";
5576
+ var COWORK_PLUGINS_DIR = "cowork_plugins";
5577
+ var PERSONAL_ORG_UUID = "00000000-0000-4000-8000-000000000001";
5578
+ var PLUGIN_MANIFEST_RELATIVE = ".claude-plugin/plugin.json";
5579
+ var MARKETPLACE_MANIFEST_RELATIVE = ".claude-plugin/marketplace.json";
5580
+ var UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
5581
+ var ClaudeCpPaths = class {
5582
+ constructor(home) {
5583
+ this.home = home;
5584
+ }
5585
+ /** `<home>/Library/Application Support/Claude-3p/` */
5586
+ get appDir() {
5587
+ return resolve10(
5588
+ this.home,
5589
+ "Library",
5590
+ "Application Support",
5591
+ CLAUDE_3P_APP_DIR
5592
+ );
5593
+ }
5594
+ /** `<appDir>/local-agent-mode-sessions/` */
5595
+ get sessionsDir() {
5596
+ return resolve10(this.appDir, LOCAL_AGENT_SESSIONS_DIR);
5597
+ }
5598
+ /** `<sessionsDir>/<account-uuid>/` */
5599
+ accountDir(accountUuid) {
5600
+ return resolve10(this.sessionsDir, accountUuid);
5601
+ }
5602
+ /** `<sessionsDir>/<account-uuid>/<org-uuid>/` */
5603
+ orgDir(accountUuid, orgUuid) {
5604
+ return resolve10(this.accountDir(accountUuid), orgUuid);
5605
+ }
5606
+ /** `<orgDir>/cowork_account_settings.json` */
5607
+ accountSettingsJson(accountUuid, orgUuid) {
5608
+ return resolve10(
5609
+ this.orgDir(accountUuid, orgUuid),
5610
+ "cowork_account_settings.json"
5611
+ );
5612
+ }
5613
+ /** `<orgDir>/cowork_settings.json` */
5614
+ coworkSettingsJson(accountUuid, orgUuid) {
5615
+ return resolve10(this.orgDir(accountUuid, orgUuid), "cowork_settings.json");
5616
+ }
5617
+ /** `<orgDir>/cowork_plugins/` */
5618
+ coworkPluginsDir(accountUuid, orgUuid) {
5619
+ return resolve10(this.orgDir(accountUuid, orgUuid), COWORK_PLUGINS_DIR);
5620
+ }
5621
+ /** `<cowork_plugins>/installed_plugins.json` */
5622
+ installedPluginsJson(accountUuid, orgUuid) {
5623
+ return resolve10(
5624
+ this.coworkPluginsDir(accountUuid, orgUuid),
5625
+ "installed_plugins.json"
5626
+ );
5627
+ }
5628
+ /** `<cowork_plugins>/known_marketplaces.json` */
5629
+ knownMarketplacesJson(accountUuid, orgUuid) {
5630
+ return resolve10(
5631
+ this.coworkPluginsDir(accountUuid, orgUuid),
5632
+ "known_marketplaces.json"
5633
+ );
5634
+ }
5635
+ /** `<cowork_plugins>/org_uninstalled.json` */
5636
+ orgUninstalledJson(accountUuid, orgUuid) {
5637
+ return resolve10(
5638
+ this.coworkPluginsDir(accountUuid, orgUuid),
5639
+ "org_uninstalled.json"
5640
+ );
5641
+ }
5642
+ /** `<cowork_plugins>/marketplaces/` */
5643
+ marketplacesRootDir(accountUuid, orgUuid) {
5644
+ return resolve10(this.coworkPluginsDir(accountUuid, orgUuid), "marketplaces");
5645
+ }
5646
+ /** `<cowork_plugins>/marketplaces/<mkt>/` */
5647
+ marketplaceDir(accountUuid, orgUuid, marketplace) {
5648
+ return resolve10(this.marketplacesRootDir(accountUuid, orgUuid), marketplace);
5649
+ }
5650
+ /** `<cowork_plugins>/marketplaces/<mkt>/.claude-plugin/marketplace.json` */
5651
+ marketplaceManifestPath(accountUuid, orgUuid, marketplace) {
5652
+ return resolve10(
5653
+ this.marketplaceDir(accountUuid, orgUuid, marketplace),
5654
+ MARKETPLACE_MANIFEST_RELATIVE
5655
+ );
5656
+ }
5657
+ /** `<cowork_plugins>/marketplaces/<mkt>/<plugin>/` */
5658
+ pluginDir(accountUuid, orgUuid, ref) {
5659
+ return resolve10(
5660
+ this.marketplaceDir(accountUuid, orgUuid, ref.marketplace),
5661
+ ref.name
5662
+ );
5663
+ }
5664
+ /** `<pluginDir>/.claude-plugin/plugin.json` */
5665
+ pluginManifestPath(accountUuid, orgUuid, ref) {
5666
+ return resolve10(
5667
+ this.pluginDir(accountUuid, orgUuid, ref),
5668
+ PLUGIN_MANIFEST_RELATIVE
5669
+ );
5670
+ }
5671
+ /** `<pluginDir>/.mcp.json` */
5672
+ pluginMcpJsonPath(accountUuid, orgUuid, ref) {
5673
+ return resolve10(this.pluginDir(accountUuid, orgUuid, ref), ".mcp.json");
5674
+ }
5675
+ /** `<pluginDir>/<capability>/` */
5676
+ capabilityDir(accountUuid, orgUuid, ref, capability) {
5677
+ return resolve10(this.pluginDir(accountUuid, orgUuid, ref), capability);
5678
+ }
5679
+ };
5680
+ function pluginKey(ref) {
5681
+ return `${ref.name}@${ref.marketplace}`;
5682
+ }
5683
+ async function resolveClaudeCpAccount(paths, options = {}) {
5684
+ const orgUuid = options.orgUuid ?? PERSONAL_ORG_UUID;
5685
+ if (options.accountUuid !== void 0) {
5686
+ if (!UUID_V4_RE.test(options.accountUuid)) return null;
5687
+ const settingsPath = paths.accountSettingsJson(
5688
+ options.accountUuid,
5689
+ orgUuid
5690
+ );
5691
+ if (!await pathExists(settingsPath)) return null;
5692
+ return { accountUuid: options.accountUuid, orgUuid, warnings: [] };
5693
+ }
5694
+ let entries;
5695
+ try {
5696
+ entries = await readdir3(paths.sessionsDir, { withFileTypes: true });
5697
+ } catch {
5698
+ return null;
5699
+ }
5700
+ const accountDirs = entries.filter(
5701
+ (entry) => entry.isDirectory() && UUID_V4_RE.test(entry.name)
5702
+ );
5703
+ if (accountDirs.length === 0) return null;
5704
+ const candidates = [];
5705
+ for (const entry of accountDirs) {
5706
+ const settingsPath = paths.accountSettingsJson(entry.name, orgUuid);
5707
+ if (!await pathExists(settingsPath)) continue;
5708
+ const stats = await stat3(paths.accountDir(entry.name)).catch(() => null);
5709
+ candidates.push({
5710
+ accountUuid: entry.name,
5711
+ mtimeMs: stats?.mtimeMs ?? 0
5712
+ });
5713
+ }
5714
+ if (candidates.length === 0) return null;
5715
+ candidates.sort((a, b) => b.mtimeMs - a.mtimeMs);
5716
+ const pick = candidates[0];
5717
+ if (!pick) return null;
5718
+ const warnings = candidates.length > 1 ? [
5719
+ `Multiple Claude-3p accounts found; selected most recent account ${pick.accountUuid}. Pass accountUuid to override.`
5720
+ ] : [];
5721
+ return { accountUuid: pick.accountUuid, orgUuid, warnings };
5722
+ }
5723
+
5724
+ // src/installers/claude-3p/installer.ts
5725
+ var ClaudeCpInstaller = class {
5726
+ target = "claude-3p";
5727
+ paths;
5728
+ accountOptions;
5729
+ rushBinaryResolver;
5730
+ now;
5731
+ marketplaceSource;
5732
+ constructor(opts = {}) {
5733
+ this.paths = new ClaudeCpPaths(opts.home ?? homedir10());
5734
+ this.accountOptions = {
5735
+ ...opts.accountUuid !== void 0 ? { accountUuid: opts.accountUuid } : {},
5736
+ ...opts.orgUuid !== void 0 ? { orgUuid: opts.orgUuid } : {}
5737
+ };
5738
+ this.rushBinaryResolver = opts.rushBinaryResolver ?? defaultRushBinaryResolver;
5739
+ this.now = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
5740
+ if (opts.marketplaceSource !== void 0) {
5741
+ this.marketplaceSource = opts.marketplaceSource;
5742
+ }
5743
+ }
5744
+ async detect() {
5745
+ return await this.resolveAccount() !== null;
5746
+ }
5747
+ async isInstalled(ref) {
5748
+ const account = await this.resolveAccount();
5749
+ if (!account) return false;
5750
+ const data = await this.readInstalledPlugins(account);
5751
+ const entries = data.plugins[pluginKey(ref)];
5752
+ return Array.isArray(entries) && entries.some((e) => e.scope === "user");
5753
+ }
5754
+ async list() {
5755
+ const account = await this.resolveAccount();
5756
+ if (!account) return [];
5757
+ const data = await this.readInstalledPlugins(account);
5758
+ const out = [];
5759
+ for (const [key, entries] of Object.entries(data.plugins)) {
5760
+ if (!Array.isArray(entries) || entries.length === 0) continue;
5761
+ const ref = parsePluginKey2(key);
5762
+ if (!ref) continue;
5763
+ const pick = entries.find((e) => e.scope === "user") ?? entries[0];
5764
+ if (!pick) continue;
5765
+ out.push({
5766
+ ref,
5767
+ version: pick.version,
5768
+ installedAt: pick.installedAt,
5769
+ targets: [this.target]
5770
+ });
5771
+ }
5772
+ out.sort((a, b) => {
5773
+ const ak = pluginKey(a.ref);
5774
+ const bk = pluginKey(b.ref);
5775
+ return ak < bk ? -1 : ak > bk ? 1 : 0;
5776
+ });
5777
+ return out;
5778
+ }
5779
+ async install(plugin, opts = {}) {
5780
+ const account = await this.resolveAccount();
5781
+ if (!account) {
5782
+ return {
5783
+ target: this.target,
5784
+ status: "skipped",
5785
+ included: [],
5786
+ skipped: [],
5787
+ artifacts: { files: [], mcpKeys: [] }
5788
+ };
5789
+ }
5790
+ const guardError = assertSafePathComponents2(plugin.ref, plugin.version);
5791
+ if (guardError) return this.buildFailedResult(guardError);
5792
+ if (!opts.force && !opts.dryRun) {
5793
+ try {
5794
+ if (await this.isAlreadyInstalledAtVersion(account, plugin)) {
5795
+ const files = [];
5796
+ if (await this.upsertKnownMarketplace(account, plugin.ref)) {
5797
+ pushUnique(
5798
+ files,
5799
+ this.paths.knownMarketplacesJson(
5800
+ account.accountUuid,
5801
+ account.orgUuid
5802
+ )
5803
+ );
5804
+ }
5805
+ if (await this.enablePlugin(account, plugin.ref)) {
5806
+ pushUnique(
5807
+ files,
5808
+ this.paths.coworkSettingsJson(
5809
+ account.accountUuid,
5810
+ account.orgUuid
5811
+ )
5812
+ );
5813
+ }
5814
+ return {
5815
+ target: this.target,
5816
+ status: "ok",
5817
+ included: this.computeIncluded(plugin),
5818
+ skipped: this.computeSkipped(plugin),
5819
+ artifacts: { files, mcpKeys: [] },
5820
+ ...account.warnings.length > 0 ? { notes: account.warnings } : {}
5821
+ };
5822
+ }
5823
+ } catch (err) {
5824
+ return this.buildFailedResult(err);
5825
+ }
5826
+ }
5827
+ if (opts.dryRun) {
5828
+ try {
5829
+ const result = await this.computeDryRun(account, plugin);
5830
+ return appendNotes(result, account.warnings);
5831
+ } catch (err) {
5832
+ return this.buildFailedResult(err);
5833
+ }
5834
+ }
5835
+ let rollback;
5836
+ try {
5837
+ rollback = await this.captureRollback(account, plugin.ref);
5838
+ } catch (err) {
5839
+ return this.buildFailedResult(err);
5840
+ }
5841
+ try {
5842
+ const writtenFiles = [];
5843
+ const pluginDir = this.paths.pluginDir(
5844
+ account.accountUuid,
5845
+ account.orgUuid,
5846
+ plugin.ref
5847
+ );
5848
+ await mkdir5(pluginDir, { recursive: true });
5849
+ pushUnique(writtenFiles, pluginDir);
5850
+ const copied = await copyPluginSourceTracked(plugin.sourceDir, pluginDir);
5851
+ for (const file2 of copied) pushUnique(writtenFiles, file2);
5852
+ const mcpServers = await this.resolveMcpServers(plugin);
5853
+ const mcpKeys = mcpServers ? Object.keys(mcpServers) : [];
5854
+ if (mcpServers && mcpKeys.length > 0) {
5855
+ const mcpPath = this.paths.pluginMcpJsonPath(
5856
+ account.accountUuid,
5857
+ account.orgUuid,
5858
+ plugin.ref
5859
+ );
5860
+ await writeJsonFile(mcpPath, { mcpServers });
5861
+ pushUnique(writtenFiles, mcpPath);
5862
+ }
5863
+ const manifestPath = this.paths.pluginManifestPath(
5864
+ account.accountUuid,
5865
+ account.orgUuid,
5866
+ plugin.ref
5867
+ );
5868
+ await writeJsonFile(manifestPath, buildPluginJson(plugin, mcpKeys));
5869
+ pushUnique(writtenFiles, manifestPath);
5870
+ const marketplaceManifestPath = this.paths.marketplaceManifestPath(
5871
+ account.accountUuid,
5872
+ account.orgUuid,
5873
+ plugin.ref.marketplace
5874
+ );
5875
+ await writeJsonFile(
5876
+ marketplaceManifestPath,
5877
+ await this.buildMarketplaceManifest(plugin.ref)
5878
+ );
5879
+ pushUnique(writtenFiles, marketplaceManifestPath);
5880
+ if (await this.upsertKnownMarketplace(account, plugin.ref)) {
5881
+ pushUnique(
5882
+ writtenFiles,
5883
+ this.paths.knownMarketplacesJson(account.accountUuid, account.orgUuid)
5884
+ );
5885
+ }
5886
+ await this.upsertInstalledPlugin(account, plugin);
5887
+ pushUnique(
5888
+ writtenFiles,
5889
+ this.paths.installedPluginsJson(account.accountUuid, account.orgUuid)
5890
+ );
5891
+ if (await this.enablePlugin(account, plugin.ref)) {
5892
+ pushUnique(
5893
+ writtenFiles,
5894
+ this.paths.coworkSettingsJson(account.accountUuid, account.orgUuid)
5895
+ );
5896
+ }
5897
+ await this.finalizeRollback(rollback);
5898
+ return {
5899
+ target: this.target,
5900
+ status: "ok",
5901
+ included: this.computeIncluded(plugin),
5902
+ skipped: this.computeSkipped(plugin),
5903
+ artifacts: { files: writtenFiles, mcpKeys },
5904
+ ...account.warnings.length > 0 ? { notes: account.warnings } : {}
5905
+ };
5906
+ } catch (err) {
5907
+ await this.applyRollback(rollback).catch(() => {
5908
+ });
5909
+ return this.buildFailedResult(err);
5910
+ }
5911
+ }
5912
+ async uninstall(ref, opts = {}) {
5913
+ const account = await this.resolveAccount();
5914
+ if (!account) {
5915
+ return {
5916
+ target: this.target,
5917
+ status: "ok",
5918
+ artifacts: { files: [], mcpKeys: [] }
5919
+ };
5920
+ }
5921
+ const guardError = assertSafePathComponents2(ref, "0.0.0");
5922
+ if (guardError) return this.buildFailedUninstallResult(guardError);
5923
+ try {
5924
+ const mcpKeys = await this.collectMcpKeys(account, ref);
5925
+ const files = await this.computeUninstallFiles(account, ref);
5926
+ if (opts.dryRun) {
5927
+ return {
5928
+ target: this.target,
5929
+ status: "ok",
5930
+ artifacts: { files, mcpKeys }
5931
+ };
5932
+ }
5933
+ const touchedFiles = [];
5934
+ const removedFromRegistry = await this.removeInstalledPlugin(
5935
+ account,
5936
+ ref
5937
+ );
5938
+ if (removedFromRegistry) {
5939
+ pushUnique(
5940
+ touchedFiles,
5941
+ this.paths.installedPluginsJson(account.accountUuid, account.orgUuid)
5942
+ );
5943
+ }
5944
+ if (await this.disablePlugin(account, ref)) {
5945
+ pushUnique(
5946
+ touchedFiles,
5947
+ this.paths.coworkSettingsJson(account.accountUuid, account.orgUuid)
5948
+ );
5949
+ }
5950
+ const pluginDir = this.paths.pluginDir(
5951
+ account.accountUuid,
5952
+ account.orgUuid,
5953
+ ref
5954
+ );
5955
+ if (await pathExists(pluginDir)) {
5956
+ await rm6(pluginDir, { recursive: true, force: true });
5957
+ pushUnique(touchedFiles, pluginDir);
5958
+ }
5959
+ if (removedFromRegistry && !await this.marketplaceStillReferenced(account, ref.marketplace)) {
5960
+ const marketplaceDir = this.paths.marketplaceDir(
5961
+ account.accountUuid,
5962
+ account.orgUuid,
5963
+ ref.marketplace
5964
+ );
5965
+ await rm6(marketplaceDir, { recursive: true, force: true });
5966
+ pushUnique(touchedFiles, marketplaceDir);
5967
+ if (await this.removeKnownMarketplace(account, ref.marketplace)) {
5968
+ pushUnique(
5969
+ touchedFiles,
5970
+ this.paths.knownMarketplacesJson(
5971
+ account.accountUuid,
5972
+ account.orgUuid
5973
+ )
5974
+ );
5975
+ }
5976
+ }
5977
+ return {
5978
+ target: this.target,
5979
+ status: "ok",
5980
+ artifacts: { files: touchedFiles, mcpKeys }
5981
+ };
5982
+ } catch (err) {
5983
+ return this.buildFailedUninstallResult(err);
5984
+ }
5985
+ }
5986
+ async resolveAccount() {
5987
+ return resolveClaudeCpAccount(this.paths, this.accountOptions);
5988
+ }
5989
+ async readInstalledPlugins(account) {
5990
+ const filePath = this.paths.installedPluginsJson(
5991
+ account.accountUuid,
5992
+ account.orgUuid
5993
+ );
5994
+ if (!await pathExists(filePath)) return { version: 2, plugins: {} };
5995
+ const { data } = await readJsonFile(filePath, () => ({
5996
+ version: 2,
5997
+ plugins: {}
5998
+ }));
5999
+ if (data.version !== 2) {
6000
+ throw new Error(
6001
+ `${filePath} has unsupported version ${String(data.version)}; expected 2`
6002
+ );
6003
+ }
6004
+ if (!data.plugins || typeof data.plugins !== "object" || Array.isArray(data.plugins)) {
6005
+ throw new Error(`${filePath} has invalid plugins shape`);
6006
+ }
6007
+ return data;
6008
+ }
6009
+ async readCoworkSettings(account) {
6010
+ const filePath = this.paths.coworkSettingsJson(
6011
+ account.accountUuid,
6012
+ account.orgUuid
6013
+ );
6014
+ if (!await pathExists(filePath)) return {};
6015
+ const { data } = await readJsonFile(
6016
+ filePath,
6017
+ () => ({})
6018
+ );
6019
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
6020
+ throw new Error(`${filePath} has invalid cowork settings shape`);
6021
+ }
6022
+ if (data.enabledPlugins !== void 0 && (!data.enabledPlugins || typeof data.enabledPlugins !== "object" || Array.isArray(data.enabledPlugins))) {
6023
+ throw new Error(`${filePath} has invalid enabledPlugins shape`);
6024
+ }
6025
+ return data;
6026
+ }
6027
+ async enablePlugin(account, ref) {
6028
+ const filePath = this.paths.coworkSettingsJson(
6029
+ account.accountUuid,
6030
+ account.orgUuid
6031
+ );
6032
+ const data = await this.readCoworkSettings(account);
6033
+ const key = pluginKey(ref);
6034
+ if (data.enabledPlugins?.[key] === true) return false;
6035
+ await writeJsonFile(filePath, {
6036
+ ...data,
6037
+ enabledPlugins: {
6038
+ ...data.enabledPlugins ?? {},
6039
+ [key]: true
6040
+ }
6041
+ });
6042
+ return true;
6043
+ }
6044
+ async disablePlugin(account, ref) {
6045
+ const filePath = this.paths.coworkSettingsJson(
6046
+ account.accountUuid,
6047
+ account.orgUuid
6048
+ );
6049
+ if (!await pathExists(filePath)) return false;
6050
+ const data = await this.readCoworkSettings(account);
6051
+ const key = pluginKey(ref);
6052
+ if (data.enabledPlugins?.[key] !== true) return false;
6053
+ const nextEnabledPlugins = { ...data.enabledPlugins };
6054
+ delete nextEnabledPlugins[key];
6055
+ const next = { ...data };
6056
+ if (Object.keys(nextEnabledPlugins).length > 0) {
6057
+ next.enabledPlugins = nextEnabledPlugins;
6058
+ } else {
6059
+ delete next.enabledPlugins;
6060
+ }
6061
+ await writeJsonFile(filePath, next);
6062
+ return true;
6063
+ }
6064
+ async isAlreadyInstalledAtVersion(account, plugin) {
6065
+ const data = await this.readInstalledPlugins(account);
6066
+ const entries = data.plugins[pluginKey(plugin.ref)];
6067
+ if (!Array.isArray(entries)) return false;
6068
+ return entries.some(
6069
+ (entry) => entry.scope === "user" && entry.version === plugin.version
6070
+ );
6071
+ }
6072
+ async upsertInstalledPlugin(account, plugin) {
6073
+ const filePath = this.paths.installedPluginsJson(
6074
+ account.accountUuid,
6075
+ account.orgUuid
6076
+ );
6077
+ const data = await this.readInstalledPlugins(account);
6078
+ const key = pluginKey(plugin.ref);
6079
+ const nowIso = this.now();
6080
+ const installPath = this.paths.pluginDir(
6081
+ account.accountUuid,
6082
+ account.orgUuid,
6083
+ plugin.ref
6084
+ );
6085
+ const entries = data.plugins[key] ?? [];
6086
+ const existingUser = entries.find((entry) => entry.scope === "user");
6087
+ const nextUser = {
6088
+ scope: "user",
6089
+ installPath,
6090
+ version: plugin.version,
6091
+ installedAt: existingUser?.installedAt ?? nowIso,
6092
+ lastUpdated: nowIso
6093
+ };
6094
+ const nextEntries = [
6095
+ nextUser,
6096
+ ...entries.filter((entry) => entry.scope !== "user")
6097
+ ];
6098
+ data.plugins = { ...data.plugins, [key]: nextEntries };
6099
+ await writeJsonFile(filePath, data);
6100
+ }
6101
+ async removeInstalledPlugin(account, ref) {
6102
+ const filePath = this.paths.installedPluginsJson(
6103
+ account.accountUuid,
6104
+ account.orgUuid
6105
+ );
6106
+ if (!await pathExists(filePath)) return false;
6107
+ const data = await this.readInstalledPlugins(account);
6108
+ const key = pluginKey(ref);
6109
+ const entries = data.plugins[key];
6110
+ if (!Array.isArray(entries)) return false;
6111
+ const nextEntries = entries.filter((entry) => entry.scope !== "user");
6112
+ if (nextEntries.length === entries.length) return false;
6113
+ if (nextEntries.length > 0) {
6114
+ data.plugins = { ...data.plugins, [key]: nextEntries };
6115
+ } else {
6116
+ const nextPlugins = { ...data.plugins };
6117
+ delete nextPlugins[key];
6118
+ data.plugins = nextPlugins;
6119
+ }
6120
+ await writeJsonFile(filePath, data);
6121
+ return true;
6122
+ }
6123
+ async readKnownMarketplaces(account) {
6124
+ const filePath = this.paths.knownMarketplacesJson(
6125
+ account.accountUuid,
6126
+ account.orgUuid
6127
+ );
6128
+ if (!await pathExists(filePath)) return {};
6129
+ const { data } = await readJsonFile(
6130
+ filePath,
6131
+ () => ({})
6132
+ );
6133
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
6134
+ throw new Error(`${filePath} has invalid known marketplaces shape`);
6135
+ }
6136
+ return data;
6137
+ }
6138
+ async upsertKnownMarketplace(account, ref) {
6139
+ const filePath = this.paths.knownMarketplacesJson(
6140
+ account.accountUuid,
6141
+ account.orgUuid
6142
+ );
6143
+ const data = await this.readKnownMarketplaces(account);
6144
+ if (Object.hasOwn(data, ref.marketplace)) return false;
6145
+ await writeJsonFile(filePath, {
6146
+ ...data,
6147
+ [ref.marketplace]: this.buildKnownMarketplaceEntry(account, ref)
6148
+ });
6149
+ return true;
6150
+ }
6151
+ async removeKnownMarketplace(account, marketplace) {
6152
+ const filePath = this.paths.knownMarketplacesJson(
6153
+ account.accountUuid,
6154
+ account.orgUuid
6155
+ );
6156
+ if (!await pathExists(filePath)) return false;
6157
+ const data = await this.readKnownMarketplaces(account);
6158
+ if (!Object.hasOwn(data, marketplace)) return false;
6159
+ const next = { ...data };
6160
+ delete next[marketplace];
6161
+ await writeJsonFile(filePath, next);
6162
+ return true;
6163
+ }
6164
+ buildKnownMarketplaceEntry(account, ref) {
6165
+ const installLocation = this.paths.marketplaceDir(
6166
+ account.accountUuid,
6167
+ account.orgUuid,
6168
+ ref.marketplace
6169
+ );
6170
+ return {
6171
+ source: {
6172
+ source: "directory",
6173
+ path: this.marketplaceSource?.rootDir ?? installLocation
6174
+ },
6175
+ installLocation,
6176
+ lastUpdated: this.now(),
6177
+ autoUpdate: false
6178
+ };
6179
+ }
6180
+ async marketplaceStillReferenced(account, marketplace) {
6181
+ const data = await this.readInstalledPlugins(account);
6182
+ const suffix = `@${marketplace}`;
6183
+ return Object.entries(data.plugins).some(
6184
+ ([key, entries]) => key.endsWith(suffix) && Array.isArray(entries) && entries.length > 0
6185
+ );
6186
+ }
6187
+ async computeDryRun(account, plugin) {
6188
+ const files = [];
6189
+ const pluginDir = this.paths.pluginDir(
6190
+ account.accountUuid,
6191
+ account.orgUuid,
6192
+ plugin.ref
6193
+ );
6194
+ pushUnique(files, pluginDir);
6195
+ const planned = await listDirFilesRecursive(plugin.sourceDir, pluginDir, {
6196
+ skipTopLevel: /* @__PURE__ */ new Set(["rules"])
6197
+ });
6198
+ for (const file2 of planned) pushUnique(files, file2);
6199
+ const mcpServers = await this.resolveMcpServers(plugin);
6200
+ const mcpKeys = mcpServers ? Object.keys(mcpServers) : [];
6201
+ if (mcpServers && mcpKeys.length > 0) {
6202
+ pushUnique(
6203
+ files,
6204
+ this.paths.pluginMcpJsonPath(
6205
+ account.accountUuid,
6206
+ account.orgUuid,
6207
+ plugin.ref
6208
+ )
6209
+ );
6210
+ }
6211
+ pushUnique(
6212
+ files,
6213
+ this.paths.pluginManifestPath(
6214
+ account.accountUuid,
6215
+ account.orgUuid,
6216
+ plugin.ref
6217
+ )
6218
+ );
6219
+ pushUnique(
6220
+ files,
6221
+ this.paths.marketplaceManifestPath(
6222
+ account.accountUuid,
6223
+ account.orgUuid,
6224
+ plugin.ref.marketplace
6225
+ )
6226
+ );
6227
+ pushUnique(
6228
+ files,
6229
+ this.paths.knownMarketplacesJson(account.accountUuid, account.orgUuid)
6230
+ );
6231
+ pushUnique(
6232
+ files,
6233
+ this.paths.installedPluginsJson(account.accountUuid, account.orgUuid)
6234
+ );
6235
+ pushUnique(
6236
+ files,
6237
+ this.paths.coworkSettingsJson(account.accountUuid, account.orgUuid)
6238
+ );
6239
+ return {
6240
+ target: this.target,
6241
+ status: "ok",
6242
+ included: this.computeIncluded(plugin),
6243
+ skipped: this.computeSkipped(plugin),
6244
+ artifacts: { files, mcpKeys }
6245
+ };
6246
+ }
6247
+ async computeUninstallFiles(account, ref) {
6248
+ const files = [];
6249
+ const hasInstalledEntry = await this.hasInstalledPluginEntry(account, ref);
6250
+ if (hasInstalledEntry) {
6251
+ pushUnique(
6252
+ files,
6253
+ this.paths.installedPluginsJson(account.accountUuid, account.orgUuid)
6254
+ );
6255
+ }
6256
+ if (await this.hasEnabledPluginEntry(account, ref)) {
6257
+ pushUnique(
6258
+ files,
6259
+ this.paths.coworkSettingsJson(account.accountUuid, account.orgUuid)
6260
+ );
6261
+ }
6262
+ const pluginDir = this.paths.pluginDir(
6263
+ account.accountUuid,
6264
+ account.orgUuid,
6265
+ ref
6266
+ );
6267
+ if (await pathExists(pluginDir)) pushUnique(files, pluginDir);
6268
+ if (hasInstalledEntry && !await this.marketplaceWouldStillBeReferencedAfterRemoval(
6269
+ account,
6270
+ ref.marketplace,
6271
+ pluginKey(ref)
6272
+ )) {
6273
+ pushUnique(
6274
+ files,
6275
+ this.paths.marketplaceDir(
6276
+ account.accountUuid,
6277
+ account.orgUuid,
6278
+ ref.marketplace
6279
+ )
6280
+ );
6281
+ if (await this.hasKnownMarketplaceEntry(account, ref.marketplace)) {
6282
+ pushUnique(
6283
+ files,
6284
+ this.paths.knownMarketplacesJson(account.accountUuid, account.orgUuid)
6285
+ );
6286
+ }
6287
+ }
6288
+ return files;
6289
+ }
6290
+ async hasEnabledPluginEntry(account, ref) {
6291
+ const data = await this.readCoworkSettings(account);
6292
+ return data.enabledPlugins?.[pluginKey(ref)] === true;
6293
+ }
6294
+ async hasInstalledPluginEntry(account, ref) {
6295
+ const data = await this.readInstalledPlugins(account);
6296
+ const entries = data.plugins[pluginKey(ref)];
6297
+ return Array.isArray(entries) && entries.some((entry) => entry.scope === "user");
6298
+ }
6299
+ async hasKnownMarketplaceEntry(account, marketplace) {
6300
+ const data = await this.readKnownMarketplaces(account);
6301
+ return Object.hasOwn(data, marketplace);
6302
+ }
6303
+ async marketplaceWouldStillBeReferencedAfterRemoval(account, marketplace, removedKey) {
6304
+ const data = await this.readInstalledPlugins(account);
6305
+ const suffix = `@${marketplace}`;
6306
+ for (const [key, entries] of Object.entries(data.plugins)) {
6307
+ if (key === removedKey) continue;
6308
+ if (key.endsWith(suffix) && Array.isArray(entries) && entries.length > 0) {
6309
+ return true;
6310
+ }
6311
+ }
6312
+ return false;
6313
+ }
6314
+ async resolveMcpServers(plugin) {
6315
+ if (typeof plugin.manifest.mcpServers === "string") {
6316
+ const external = await readExternalMcpServers(
6317
+ plugin.sourceDir,
6318
+ plugin.manifest.mcpServers
6319
+ );
6320
+ if (!external) return void 0;
6321
+ return normalizeClaudeMcpServers(
6322
+ plugin.ref,
6323
+ { ...plugin.manifest, mcpServers: external },
6324
+ this.rushBinaryResolver
6325
+ );
6326
+ }
6327
+ return normalizeClaudeMcpServers(
6328
+ plugin.ref,
6329
+ plugin.manifest,
6330
+ this.rushBinaryResolver
6331
+ );
6332
+ }
6333
+ computeIncluded(plugin) {
6334
+ return plugin.capabilities.filter((cap) => cap !== "rules");
6335
+ }
6336
+ computeSkipped(plugin) {
6337
+ return plugin.capabilities.includes("rules") ? ["rules"] : [];
6338
+ }
6339
+ async buildMarketplaceManifest(ref) {
6340
+ if (this.marketplaceSource) {
6341
+ const sourceManifest = resolve11(
6342
+ this.marketplaceSource.rootDir,
6343
+ ".claude-plugin",
6344
+ "marketplace.json"
6345
+ );
6346
+ const raw = await readFile6(sourceManifest, "utf8");
6347
+ return JSON.parse(raw);
6348
+ }
6349
+ return {
6350
+ name: ref.marketplace,
6351
+ plugins: [{ name: ref.name, source: `./${ref.name}` }]
6352
+ };
6353
+ }
6354
+ async collectMcpKeys(account, ref) {
6355
+ const mcpPath = this.paths.pluginMcpJsonPath(
6356
+ account.accountUuid,
6357
+ account.orgUuid,
6358
+ ref
6359
+ );
6360
+ if (!await pathExists(mcpPath)) return [];
6361
+ try {
6362
+ const raw = await readFile6(mcpPath, "utf8");
6363
+ const parsed = JSON.parse(raw);
6364
+ if (parsed.mcpServers && typeof parsed.mcpServers === "object") {
6365
+ return Object.keys(parsed.mcpServers);
6366
+ }
6367
+ } catch {
6368
+ return [];
6369
+ }
6370
+ return [];
6371
+ }
6372
+ async captureRollback(account, ref) {
6373
+ const marketplaceDir = this.paths.marketplaceDir(
6374
+ account.accountUuid,
6375
+ account.orgUuid,
6376
+ ref.marketplace
6377
+ );
6378
+ const marketplaceDirExisted = await pathExists(marketplaceDir);
6379
+ const pluginDir = this.paths.pluginDir(
6380
+ account.accountUuid,
6381
+ account.orgUuid,
6382
+ ref
6383
+ );
6384
+ const files = [
6385
+ await snapshotFile(
6386
+ this.paths.marketplaceManifestPath(
6387
+ account.accountUuid,
6388
+ account.orgUuid,
6389
+ ref.marketplace
6390
+ )
6391
+ ),
6392
+ await snapshotFile(
6393
+ this.paths.knownMarketplacesJson(account.accountUuid, account.orgUuid)
6394
+ ),
6395
+ await snapshotFile(
6396
+ this.paths.installedPluginsJson(account.accountUuid, account.orgUuid)
6397
+ ),
6398
+ await snapshotFile(
6399
+ this.paths.coworkSettingsJson(account.accountUuid, account.orgUuid)
6400
+ )
6401
+ ];
6402
+ return {
6403
+ pluginDir: await moveDirAside(pluginDir),
6404
+ marketplaceDir,
6405
+ marketplaceDirExisted,
6406
+ files
6407
+ };
6408
+ }
6409
+ async finalizeRollback(snapshot) {
6410
+ if (snapshot.pluginDir.backupPath) {
6411
+ await rm6(snapshot.pluginDir.backupPath, { recursive: true, force: true });
6412
+ }
6413
+ }
6414
+ async applyRollback(snapshot) {
6415
+ await restoreMovedDir(snapshot.pluginDir);
6416
+ for (const file2 of snapshot.files) {
6417
+ await restoreFile(file2);
6418
+ }
6419
+ if (!snapshot.marketplaceDirExisted) {
6420
+ await rm6(snapshot.marketplaceDir, { recursive: true, force: true });
6421
+ }
6422
+ }
6423
+ buildFailedResult(err) {
6424
+ const message = err instanceof Error ? err.message : String(err);
6425
+ return {
6426
+ target: this.target,
6427
+ status: "failed",
6428
+ included: [],
6429
+ skipped: [],
6430
+ artifacts: { files: [], mcpKeys: [] },
6431
+ errors: [message]
6432
+ };
6433
+ }
6434
+ buildFailedUninstallResult(err) {
6435
+ const message = err instanceof Error ? err.message : String(err);
6436
+ return {
6437
+ target: this.target,
6438
+ status: "failed",
6439
+ artifacts: { files: [], mcpKeys: [] },
6440
+ errors: [message]
6441
+ };
6442
+ }
6443
+ };
6444
+ function buildPluginJson(plugin, mcpKeys) {
6445
+ const { mcpServers: _mcpServers, ...rest } = plugin.manifest;
6446
+ return {
6447
+ ...rest,
6448
+ name: plugin.ref.name,
6449
+ version: plugin.version,
6450
+ ...mcpKeys.length > 0 ? { mcpServers: "./.mcp.json" } : {}
6451
+ };
6452
+ }
6453
+ function appendNotes(result, notes) {
6454
+ if (notes.length === 0) return result;
6455
+ return { ...result, notes: [...result.notes ?? [], ...notes] };
6456
+ }
6457
+ function parsePluginKey2(key) {
6458
+ const at = key.lastIndexOf("@");
6459
+ if (at <= 0 || at === key.length - 1) return null;
6460
+ return { name: key.slice(0, at), marketplace: key.slice(at + 1) };
6461
+ }
6462
+ function assertSafePathComponents2(ref, version) {
6463
+ for (const [label, value] of [
6464
+ ["plugin name", ref.name],
6465
+ ["marketplace", ref.marketplace],
6466
+ ["version", version]
6467
+ ]) {
6468
+ if (value.length === 0 || value === "." || value === ".." || value.includes("/") || value.includes("\\")) {
6469
+ return new Error(`Invalid ${label} '${value}' for Claude-3p path`);
6470
+ }
5479
6471
  }
5480
6472
  return null;
5481
6473
  }
5482
- function listPlaybooks(dir) {
5483
- return readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => basename3(f, ".md")).sort();
6474
+ async function snapshotFile(path4) {
6475
+ if (!await pathExists(path4)) return { path: path4, existed: false, content: null };
6476
+ return { path: path4, existed: true, content: await readFile6(path4, "utf8") };
5484
6477
  }
5485
- function getAvailablePlaybooks() {
5486
- const dir = resolvePlaybooksDir();
5487
- return dir ? listPlaybooks(dir) : [];
6478
+ async function restoreFile(snapshot) {
6479
+ if (snapshot.existed) {
6480
+ await writeTextFileAtomic(snapshot.path, snapshot.content ?? "");
6481
+ return;
6482
+ }
6483
+ await rm6(snapshot.path, { force: true });
6484
+ await pruneEmptyParents(dirname5(snapshot.path), 2);
5488
6485
  }
5489
- function isPlaybookName(name) {
5490
- if (!name) return false;
5491
- return getAvailablePlaybooks().includes(name);
6486
+ async function moveDirAside(path4) {
6487
+ if (!await pathExists(path4)) {
6488
+ return { path: path4, existed: false, backupPath: null };
6489
+ }
6490
+ const backupPath = `${path4}.rush-ai-backup-${randomUUID3()}`;
6491
+ await rename3(path4, backupPath);
6492
+ return { path: path4, existed: true, backupPath };
5492
6493
  }
5493
- function printPlaybook(name, opts = {}) {
5494
- const dir = resolvePlaybooksDir();
5495
- if (!dir) {
5496
- output.error(
5497
- "Could not locate the skills/ directory. This is a packaging bug \u2014 please file an issue."
5498
- );
5499
- process.exit(2);
5500
- return;
6494
+ async function restoreMovedDir(snapshot) {
6495
+ await rm6(snapshot.path, { recursive: true, force: true });
6496
+ if (snapshot.backupPath) {
6497
+ await rename3(snapshot.backupPath, snapshot.path);
5501
6498
  }
5502
- const available = listPlaybooks(dir);
5503
- if (opts.list) {
5504
- for (const s of available) output.log(s);
5505
- return;
6499
+ }
6500
+ async function copyPluginSourceTracked(srcDir, dstDir) {
6501
+ await mkdir5(dstDir, { recursive: true });
6502
+ await cp2(srcDir, dstDir, { recursive: true, force: true });
6503
+ await rm6(join9(dstDir, "rules"), { recursive: true, force: true });
6504
+ return listExistingDirPaths(dstDir);
6505
+ }
6506
+ async function listDirFilesRecursive(srcDir, dstDir, opts = {}) {
6507
+ const out = [dstDir];
6508
+ async function walk2(src, dst, depth) {
6509
+ const entries = await readdir4(src, { withFileTypes: true });
6510
+ for (const entry of entries) {
6511
+ if (depth === 0 && opts.skipTopLevel?.has(entry.name)) continue;
6512
+ const srcPath = join9(src, entry.name);
6513
+ const dstPath = join9(dst, entry.name);
6514
+ out.push(dstPath);
6515
+ if (entry.isDirectory()) await walk2(srcPath, dstPath, depth + 1);
6516
+ }
5506
6517
  }
5507
- const target = name ?? "README";
5508
- const file2 = resolve9(dir, `${target}.md`);
5509
- if (!existsSync11(file2)) {
5510
- output.error(`Unknown playbook "${target}".`);
5511
- output.dim(`Available: ${available.join(", ") || "(none)"}`);
5512
- process.exit(1);
5513
- return;
6518
+ await walk2(srcDir, dstDir, 0);
6519
+ return out;
6520
+ }
6521
+ async function listExistingDirPaths(dir) {
6522
+ const out = [dir];
6523
+ async function walk2(current) {
6524
+ const entries = await readdir4(current, { withFileTypes: true });
6525
+ for (const entry of entries) {
6526
+ const p = join9(current, entry.name);
6527
+ out.push(p);
6528
+ if (entry.isDirectory()) await walk2(p);
6529
+ }
5514
6530
  }
5515
- process.stdout.write(readFileSync7(file2, "utf-8"));
6531
+ await walk2(dir);
6532
+ return out;
5516
6533
  }
5517
- function registerPlaybookCommand(program) {
5518
- program.command("playbook [name]").description(PLAYBOOK_DESCRIPTION).addHelpText("after", PLAYBOOK_HELP_AFTER).option("--list", "List available playbook names and exit").action((name, opts) => {
5519
- printPlaybook(name, opts);
5520
- });
6534
+ async function pruneEmptyParents(startDir, maxDepth) {
6535
+ let current = startDir;
6536
+ for (let i = 0; i < maxDepth; i++) {
6537
+ try {
6538
+ const entries = await readdir4(current);
6539
+ if (entries.length > 0) return;
6540
+ await rm6(current, { recursive: false, force: true });
6541
+ current = dirname5(current);
6542
+ } catch {
6543
+ return;
6544
+ }
6545
+ }
6546
+ }
6547
+ function pushUnique(list, value) {
6548
+ if (!list.includes(value)) list.push(value);
6549
+ }
6550
+ async function writeTextFileAtomic(path4, content) {
6551
+ await mkdir5(dirname5(path4), { recursive: true });
6552
+ const tmp = `${path4}.${randomUUID3()}.tmp`;
6553
+ try {
6554
+ await writeFile5(tmp, content, "utf8");
6555
+ await rename3(tmp, path4);
6556
+ } catch (err) {
6557
+ await rm6(tmp, { force: true }).catch(() => {
6558
+ });
6559
+ throw err;
6560
+ }
5521
6561
  }
5522
-
5523
- // src/commands/plugin/install.ts
5524
- import { rm as rm11 } from "fs/promises";
5525
- import { homedir as homedir17 } from "os";
5526
- import { resolve as resolve20 } from "path";
5527
6562
 
5528
6563
  // src/installers/claude-code/installer.ts
5529
- import { randomUUID as randomUUID3 } from "crypto";
6564
+ import { randomUUID as randomUUID4 } from "crypto";
5530
6565
  import {
5531
6566
  copyFile,
5532
6567
  lstat,
5533
- mkdir as mkdir5,
5534
- readdir as readdir3,
5535
- readFile as readFile6,
6568
+ mkdir as mkdir6,
6569
+ readdir as readdir5,
6570
+ readFile as readFile7,
5536
6571
  readlink,
5537
- rename as rename3,
5538
- rm as rm6,
5539
- stat as stat3,
6572
+ rename as rename4,
6573
+ rm as rm7,
6574
+ stat as stat4,
5540
6575
  symlink,
5541
6576
  unlink
5542
6577
  } from "fs/promises";
5543
- import { homedir as homedir10 } from "os";
5544
- import { dirname as dirname5, join as join9, resolve as resolve11 } from "path";
6578
+ import { homedir as homedir11 } from "os";
6579
+ import { dirname as dirname6, join as join10, resolve as resolve13 } from "path";
5545
6580
 
5546
6581
  // src/installers/claude-code/paths.ts
5547
- import { resolve as resolve10 } from "path";
6582
+ import { resolve as resolve12 } from "path";
5548
6583
  var CLAUDE_DIR = ".claude";
5549
6584
  var PLUGINS_SUBDIR = "plugins";
5550
6585
  var CACHE_SUBDIR = "cache";
5551
- var PLUGIN_MANIFEST_RELATIVE = ".claude-plugin/plugin.json";
6586
+ var PLUGIN_MANIFEST_RELATIVE2 = ".claude-plugin/plugin.json";
5552
6587
  var CAPABILITY_DIRS = [
5553
6588
  "commands",
5554
6589
  "skills",
@@ -5562,27 +6597,27 @@ var ClaudeCodePaths = class {
5562
6597
  }
5563
6598
  /** `<home>/.claude/` */
5564
6599
  get claudeDir() {
5565
- return resolve10(this.home, CLAUDE_DIR);
6600
+ return resolve12(this.home, CLAUDE_DIR);
5566
6601
  }
5567
6602
  /** `<home>/.claude/settings.json` */
5568
6603
  get settingsJson() {
5569
- return resolve10(this.claudeDir, "settings.json");
6604
+ return resolve12(this.claudeDir, "settings.json");
5570
6605
  }
5571
6606
  /** `<home>/.claude/plugins/` */
5572
6607
  get pluginsDir() {
5573
- return resolve10(this.claudeDir, PLUGINS_SUBDIR);
6608
+ return resolve12(this.claudeDir, PLUGINS_SUBDIR);
5574
6609
  }
5575
6610
  /** `<home>/.claude/plugins/known_marketplaces.json` */
5576
6611
  get knownMarketplacesJson() {
5577
- return resolve10(this.pluginsDir, "known_marketplaces.json");
6612
+ return resolve12(this.pluginsDir, "known_marketplaces.json");
5578
6613
  }
5579
6614
  /** `<home>/.claude/plugins/installed_plugins.json` */
5580
6615
  get installedPluginsJson() {
5581
- return resolve10(this.pluginsDir, "installed_plugins.json");
6616
+ return resolve12(this.pluginsDir, "installed_plugins.json");
5582
6617
  }
5583
6618
  /** `<home>/.claude/plugins/cache/` */
5584
6619
  get cacheDir() {
5585
- return resolve10(this.pluginsDir, CACHE_SUBDIR);
6620
+ return resolve12(this.pluginsDir, CACHE_SUBDIR);
5586
6621
  }
5587
6622
  /**
5588
6623
  * `<home>/.claude/plugins/marketplaces/`。
@@ -5592,37 +6627,37 @@ var ClaudeCodePaths = class {
5592
6627
  * Claude Code 会识别不到 plugin 条目(regression fix,bug #4)。
5593
6628
  */
5594
6629
  get marketplacesRootDir() {
5595
- return resolve10(this.pluginsDir, "marketplaces");
6630
+ return resolve12(this.pluginsDir, "marketplaces");
5596
6631
  }
5597
6632
  /** `<home>/.claude/plugins/marketplaces/<mkt>/` */
5598
6633
  marketplaceInstallDir(marketplace) {
5599
- return resolve10(this.marketplacesRootDir, marketplace);
6634
+ return resolve12(this.marketplacesRootDir, marketplace);
5600
6635
  }
5601
6636
  /** `<home>/.claude/plugins/cache/<mkt>/` */
5602
6637
  marketplaceCacheDir(marketplace) {
5603
- return resolve10(this.cacheDir, marketplace);
6638
+ return resolve12(this.cacheDir, marketplace);
5604
6639
  }
5605
6640
  /** `<home>/.claude/plugins/cache/<mkt>/<plugin>/` */
5606
6641
  pluginCacheDir(ref) {
5607
- return resolve10(this.marketplaceCacheDir(ref.marketplace), ref.name);
6642
+ return resolve12(this.marketplaceCacheDir(ref.marketplace), ref.name);
5608
6643
  }
5609
6644
  /** `<home>/.claude/plugins/cache/<mkt>/<plugin>/<version>/` */
5610
6645
  pluginVersionDir(ref, version) {
5611
- return resolve10(this.pluginCacheDir(ref), version);
6646
+ return resolve12(this.pluginCacheDir(ref), version);
5612
6647
  }
5613
6648
  /** `<home>/.claude/plugins/cache/<mkt>/<plugin>/<version>/.claude-plugin/plugin.json` */
5614
6649
  pluginManifestPath(ref, version) {
5615
- return resolve10(
6650
+ return resolve12(
5616
6651
  this.pluginVersionDir(ref, version),
5617
- PLUGIN_MANIFEST_RELATIVE
6652
+ PLUGIN_MANIFEST_RELATIVE2
5618
6653
  );
5619
6654
  }
5620
6655
  /** `<home>/.claude/plugins/cache/<mkt>/<plugin>/<version>/<capability>/` */
5621
6656
  capabilityDir(ref, version, capability) {
5622
- return resolve10(this.pluginVersionDir(ref, version), capability);
6657
+ return resolve12(this.pluginVersionDir(ref, version), capability);
5623
6658
  }
5624
6659
  };
5625
- function pluginKey(ref) {
6660
+ function pluginKey2(ref) {
5626
6661
  return `${ref.name}@${ref.marketplace}`;
5627
6662
  }
5628
6663
 
@@ -5635,7 +6670,7 @@ var ClaudeCodeInstaller = class {
5635
6670
  marketplaceSource;
5636
6671
  symlinkRunner;
5637
6672
  constructor(opts = {}) {
5638
- const home = opts.home ?? homedir10();
6673
+ const home = opts.home ?? homedir11();
5639
6674
  this.paths = new ClaudeCodePaths(home);
5640
6675
  this.rushBinaryResolver = opts.rushBinaryResolver ?? defaultRushBinaryResolver;
5641
6676
  this.now = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
@@ -5658,7 +6693,7 @@ var ClaudeCodeInstaller = class {
5658
6693
  this.paths.installedPluginsJson,
5659
6694
  () => ({ version: 2, plugins: {} })
5660
6695
  );
5661
- const entries = data.plugins?.[pluginKey(ref)];
6696
+ const entries = data.plugins?.[pluginKey2(ref)];
5662
6697
  return Array.isArray(entries) && entries.length > 0;
5663
6698
  }
5664
6699
  async list() {
@@ -5672,7 +6707,7 @@ var ClaudeCodeInstaller = class {
5672
6707
  const out = [];
5673
6708
  for (const [key, scopeEntries] of Object.entries(data.plugins ?? {})) {
5674
6709
  if (!Array.isArray(scopeEntries) || scopeEntries.length === 0) continue;
5675
- const ref = parsePluginKey2(key);
6710
+ const ref = parsePluginKey3(key);
5676
6711
  if (!ref) continue;
5677
6712
  const pick = scopeEntries.find((e) => e.scope === "user") ?? scopeEntries[0];
5678
6713
  if (!pick) continue;
@@ -5700,7 +6735,7 @@ var ClaudeCodeInstaller = class {
5700
6735
  }
5701
6736
  const { ref, version } = plugin;
5702
6737
  const pluginVersionDir = this.paths.pluginVersionDir(ref, version);
5703
- const key = pluginKey(ref);
6738
+ const key = pluginKey2(ref);
5704
6739
  if (!opts.force && version !== "unknown") {
5705
6740
  let already = false;
5706
6741
  try {
@@ -5733,13 +6768,13 @@ var ClaudeCodeInstaller = class {
5733
6768
  }
5734
6769
  try {
5735
6770
  const writtenFiles = [];
5736
- await mkdir5(pluginVersionDir, { recursive: true });
6771
+ await mkdir6(pluginVersionDir, { recursive: true });
5737
6772
  writtenFiles.push(pluginVersionDir);
5738
6773
  for (const cap of CAPABILITY_DIRS) {
5739
- const srcDir = resolve11(plugin.sourceDir, cap);
6774
+ const srcDir = resolve13(plugin.sourceDir, cap);
5740
6775
  if (!await dirExists(srcDir)) continue;
5741
6776
  const dstDir = this.paths.capabilityDir(ref, version, cap);
5742
- await mkdir5(dstDir, { recursive: true });
6777
+ await mkdir6(dstDir, { recursive: true });
5743
6778
  writtenFiles.push(dstDir);
5744
6779
  const copied = await copyDirTracked(srcDir, dstDir);
5745
6780
  writtenFiles.push(...copied);
@@ -5751,11 +6786,11 @@ var ClaudeCodeInstaller = class {
5751
6786
  this.rushBinaryResolver
5752
6787
  );
5753
6788
  if (normalizedMcp && Object.keys(normalizedMcp).length > 0) {
5754
- const mcpJsonPath = resolve11(pluginVersionDir, ".mcp.json");
6789
+ const mcpJsonPath = resolve13(pluginVersionDir, ".mcp.json");
5755
6790
  await writeJsonFile(mcpJsonPath, { mcpServers: normalizedMcp });
5756
6791
  writtenFiles.push(mcpJsonPath);
5757
6792
  }
5758
- const pluginJsonContent = buildPluginJson(plugin, normalizedMcp);
6793
+ const pluginJsonContent = buildPluginJson2(plugin, normalizedMcp);
5759
6794
  await writeJsonFile(manifestPath, pluginJsonContent);
5760
6795
  writtenFiles.push(manifestPath);
5761
6796
  const mcpKeys = normalizedMcp ? Object.keys(normalizedMcp) : [];
@@ -5820,7 +6855,7 @@ var ClaudeCodeInstaller = class {
5820
6855
  artifacts: { files: [], mcpKeys: [] }
5821
6856
  };
5822
6857
  }
5823
- const key = pluginKey(ref);
6858
+ const key = pluginKey2(ref);
5824
6859
  const touchedFiles = [];
5825
6860
  const installedMcpKeys = await this.collectMcpKeysFromInstalled(ref);
5826
6861
  if (opts.dryRun) {
@@ -5879,8 +6914,8 @@ var ClaudeCodeInstaller = class {
5879
6914
  await unlink(mktDir);
5880
6915
  files.push(mktDir);
5881
6916
  } else if (kind === "dir") {
5882
- if (await pathExists(join9(mktDir, ".rush-marketplace-source.json"))) {
5883
- await rm6(mktDir, { recursive: true, force: true });
6917
+ if (await pathExists(join10(mktDir, ".rush-marketplace-source.json"))) {
6918
+ await rm7(mktDir, { recursive: true, force: true });
5884
6919
  files.push(mktDir);
5885
6920
  }
5886
6921
  }
@@ -5951,12 +6986,12 @@ var ClaudeCodeInstaller = class {
5951
6986
  return { written: false, path: "" };
5952
6987
  }
5953
6988
  const mktDir = this.paths.marketplaceInstallDir(marketplaceName);
5954
- await mkdir5(this.paths.marketplacesRootDir, { recursive: true });
6989
+ await mkdir6(this.paths.marketplacesRootDir, { recursive: true });
5955
6990
  const kind = await inodeKind(mktDir);
5956
6991
  if (kind === "symlink") {
5957
6992
  const target = await readlink(mktDir).catch(() => null);
5958
- const resolvedTarget = target !== null ? resolve11(dirname5(mktDir), target) : null;
5959
- if (resolvedTarget && resolvedTarget === resolve11(src.rootDir)) {
6993
+ const resolvedTarget = target !== null ? resolve13(dirname6(mktDir), target) : null;
6994
+ if (resolvedTarget && resolvedTarget === resolve13(src.rootDir)) {
5960
6995
  return { written: false, path: mktDir };
5961
6996
  }
5962
6997
  throw new Error(
@@ -5964,7 +6999,7 @@ var ClaudeCodeInstaller = class {
5964
6999
  );
5965
7000
  }
5966
7001
  if (kind === "dir") {
5967
- const metaPath = join9(mktDir, ".rush-marketplace-source.json");
7002
+ const metaPath = join10(mktDir, ".rush-marketplace-source.json");
5968
7003
  if (await pathExists(metaPath)) {
5969
7004
  const metaSourceRaw = await readMarketplaceCacheSource(metaPath);
5970
7005
  const currentSourceRaw = descriptorToSourceRaw(src.descriptor);
@@ -5989,7 +7024,7 @@ var ClaudeCodeInstaller = class {
5989
7024
  return { written: true, path: mktDir };
5990
7025
  }
5991
7026
  await copyDirTracked(src.rootDir, mktDir).catch(async (err) => {
5992
- await rm6(mktDir, { recursive: true, force: true }).catch(() => {
7027
+ await rm7(mktDir, { recursive: true, force: true }).catch(() => {
5993
7028
  });
5994
7029
  throw err;
5995
7030
  });
@@ -6016,7 +7051,7 @@ var ClaudeCodeInstaller = class {
6016
7051
  this.paths.installedPluginsJson,
6017
7052
  () => ({ version: 2, plugins: {} })
6018
7053
  );
6019
- const entries = data.plugins?.[pluginKey(ref)];
7054
+ const entries = data.plugins?.[pluginKey2(ref)];
6020
7055
  if (!Array.isArray(entries)) return false;
6021
7056
  return entries.some((e) => e.scope === "user" && e.version === version);
6022
7057
  }
@@ -6025,11 +7060,11 @@ var ClaudeCodeInstaller = class {
6025
7060
  const pluginVersionDir = this.paths.pluginVersionDir(ref, version);
6026
7061
  const dryFiles = [pluginVersionDir];
6027
7062
  for (const cap of CAPABILITY_DIRS) {
6028
- const srcDir = resolve11(plugin.sourceDir, cap);
7063
+ const srcDir = resolve13(plugin.sourceDir, cap);
6029
7064
  if (!await dirExists(srcDir)) continue;
6030
7065
  const dstDir = this.paths.capabilityDir(ref, version, cap);
6031
7066
  dryFiles.push(dstDir);
6032
- const plannedFiles = await listDirFilesRecursive(srcDir, dstDir);
7067
+ const plannedFiles = await listDirFilesRecursive2(srcDir, dstDir);
6033
7068
  dryFiles.push(...plannedFiles);
6034
7069
  }
6035
7070
  dryFiles.push(this.paths.pluginManifestPath(ref, version));
@@ -6039,7 +7074,7 @@ var ClaudeCodeInstaller = class {
6039
7074
  this.rushBinaryResolver
6040
7075
  );
6041
7076
  if (normalizedMcpDry && Object.keys(normalizedMcpDry).length > 0) {
6042
- dryFiles.push(resolve11(pluginVersionDir, ".mcp.json"));
7077
+ dryFiles.push(resolve13(pluginVersionDir, ".mcp.json"));
6043
7078
  }
6044
7079
  if (this.marketplaceSource) {
6045
7080
  const mktInstallDir = this.paths.marketplaceInstallDir(ref.marketplace);
@@ -6053,7 +7088,7 @@ var ClaudeCodeInstaller = class {
6053
7088
  if (await this.wouldInstalledPluginsChange(ref, version, pluginVersionDir)) {
6054
7089
  dryFiles.push(this.paths.installedPluginsJson);
6055
7090
  }
6056
- if (await this.wouldSettingsChange(pluginKey(ref))) {
7091
+ if (await this.wouldSettingsChange(pluginKey2(ref))) {
6057
7092
  dryFiles.push(this.paths.settingsJson);
6058
7093
  }
6059
7094
  const normalizedMcp = await resolveClaudeMcpServers(
@@ -6088,7 +7123,7 @@ var ClaudeCodeInstaller = class {
6088
7123
  this.paths.installedPluginsJson,
6089
7124
  () => ({ version: 2, plugins: {} })
6090
7125
  );
6091
- const key = pluginKey(ref);
7126
+ const key = pluginKey2(ref);
6092
7127
  const entries = data.plugins?.[key] ?? [];
6093
7128
  const userEntry = entries.find((e) => e.scope === "user");
6094
7129
  if (!userEntry) return true;
@@ -6153,8 +7188,8 @@ var ClaudeCodeInstaller = class {
6153
7188
  const settings = await this.readRawJsonForRollback(this.paths.settingsJson);
6154
7189
  let backupVersionDir = null;
6155
7190
  if (preexistedVersion === "dir") {
6156
- backupVersionDir = `${pluginVersionDir}.rollback-${randomUUID3()}`;
6157
- await rename3(pluginVersionDir, backupVersionDir);
7191
+ backupVersionDir = `${pluginVersionDir}.rollback-${randomUUID4()}`;
7192
+ await rename4(pluginVersionDir, backupVersionDir);
6158
7193
  }
6159
7194
  return {
6160
7195
  ref,
@@ -6175,7 +7210,7 @@ var ClaudeCodeInstaller = class {
6175
7210
  */
6176
7211
  async finalizeRollback(snap) {
6177
7212
  if (snap.backupVersionDir) {
6178
- await rm6(snap.backupVersionDir, { recursive: true, force: true });
7213
+ await rm7(snap.backupVersionDir, { recursive: true, force: true });
6179
7214
  }
6180
7215
  }
6181
7216
  /**
@@ -6188,19 +7223,19 @@ var ClaudeCodeInstaller = class {
6188
7223
  */
6189
7224
  async applyRollback(snap) {
6190
7225
  if (snap.preexistedVersion === "dir" && snap.backupVersionDir) {
6191
- await rm6(snap.pluginVersionDir, { recursive: true, force: true });
6192
- await rename3(snap.backupVersionDir, snap.pluginVersionDir);
7226
+ await rm7(snap.pluginVersionDir, { recursive: true, force: true });
7227
+ await rename4(snap.backupVersionDir, snap.pluginVersionDir);
6193
7228
  } else if (snap.preexistedVersion === "missing") {
6194
- await rm6(snap.pluginVersionDir, { recursive: true, force: true });
7229
+ await rm7(snap.pluginVersionDir, { recursive: true, force: true });
6195
7230
  }
6196
7231
  if (snap.preexistedPlugin === "missing") {
6197
- await rm6(this.paths.pluginCacheDir(snap.ref), {
7232
+ await rm7(this.paths.pluginCacheDir(snap.ref), {
6198
7233
  recursive: true,
6199
7234
  force: true
6200
7235
  });
6201
7236
  }
6202
7237
  if (snap.preexistedMarketplace === "missing") {
6203
- await rm6(this.paths.marketplaceCacheDir(snap.ref.marketplace), {
7238
+ await rm7(this.paths.marketplaceCacheDir(snap.ref.marketplace), {
6204
7239
  recursive: true,
6205
7240
  force: true
6206
7241
  });
@@ -6214,7 +7249,7 @@ var ClaudeCodeInstaller = class {
6214
7249
  await unlink(mktInstallDir).catch(() => {
6215
7250
  });
6216
7251
  } else if (currentKind !== "missing") {
6217
- await rm6(mktInstallDir, { recursive: true, force: true }).catch(
7252
+ await rm7(mktInstallDir, { recursive: true, force: true }).catch(
6218
7253
  () => {
6219
7254
  }
6220
7255
  );
@@ -6237,7 +7272,7 @@ var ClaudeCodeInstaller = class {
6237
7272
  async restoreRawJson(path4, state) {
6238
7273
  if (!state.existed) {
6239
7274
  if (await pathExists(path4)) {
6240
- await rm6(path4, { force: true });
7275
+ await rm7(path4, { force: true });
6241
7276
  }
6242
7277
  return;
6243
7278
  }
@@ -6332,7 +7367,7 @@ var ClaudeCodeInstaller = class {
6332
7367
  this.paths.installedPluginsJson,
6333
7368
  () => ({ version: 2, plugins: {} })
6334
7369
  );
6335
- const key = pluginKey(ref);
7370
+ const key = pluginKey2(ref);
6336
7371
  const now = this.now();
6337
7372
  const existingEntries = data.plugins?.[key] ?? [];
6338
7373
  const userIdx = existingEntries.findIndex((e) => e.scope === "user");
@@ -6406,7 +7441,7 @@ var ClaudeCodeInstaller = class {
6406
7441
  this.paths.installedPluginsJson,
6407
7442
  () => ({ version: 2, plugins: {} })
6408
7443
  );
6409
- const key = pluginKey(ref);
7444
+ const key = pluginKey2(ref);
6410
7445
  const existingEntries = data.plugins?.[key];
6411
7446
  if (!Array.isArray(existingEntries) || existingEntries.length === 0) {
6412
7447
  return false;
@@ -6461,7 +7496,7 @@ var ClaudeCodeInstaller = class {
6461
7496
  this.paths.installedPluginsJson,
6462
7497
  () => ({ version: 2, plugins: {} })
6463
7498
  );
6464
- const entries = data.plugins?.[pluginKey(ref)];
7499
+ const entries = data.plugins?.[pluginKey2(ref)];
6465
7500
  if (!Array.isArray(entries) || entries.length === 0) return false;
6466
7501
  return entries.some((e) => e.scope === "user");
6467
7502
  }
@@ -6489,7 +7524,7 @@ var ClaudeCodeInstaller = class {
6489
7524
  );
6490
7525
  const servers = data.mcpServers;
6491
7526
  if (typeof servers === "string") {
6492
- const mcpJsonPath = resolve11(dirname5(manifestPath), "..", servers);
7527
+ const mcpJsonPath = resolve13(dirname6(manifestPath), "..", servers);
6493
7528
  if (!await pathExists(mcpJsonPath)) return [];
6494
7529
  const { data: mcpData } = await readJsonFile(
6495
7530
  mcpJsonPath,
@@ -6514,11 +7549,11 @@ var ClaudeCodeInstaller = class {
6514
7549
  this.paths.installedPluginsJson,
6515
7550
  () => ({ version: 2, plugins: {} })
6516
7551
  );
6517
- const entries = data.plugins?.[pluginKey(ref)];
7552
+ const entries = data.plugins?.[pluginKey2(ref)];
6518
7553
  if (!Array.isArray(entries) || entries.length === 0) return null;
6519
7554
  const userEntry = entries.find((e) => e.scope === "user") ?? entries[0];
6520
7555
  if (!userEntry) return null;
6521
- const manifestPath = join9(
7556
+ const manifestPath = join10(
6522
7557
  userEntry.installPath,
6523
7558
  ".claude-plugin",
6524
7559
  "plugin.json"
@@ -6529,7 +7564,7 @@ var ClaudeCodeInstaller = class {
6529
7564
  return null;
6530
7565
  }
6531
7566
  };
6532
- function parsePluginKey2(key) {
7567
+ function parsePluginKey3(key) {
6533
7568
  const at = key.indexOf("@");
6534
7569
  if (at <= 0 || at === key.length - 1) return null;
6535
7570
  return { name: key.slice(0, at), marketplace: key.slice(at + 1) };
@@ -6551,7 +7586,7 @@ async function resolveClaudeMcpServers(ref, plugin, rushBinaryResolver) {
6551
7586
  }
6552
7587
  return void 0;
6553
7588
  }
6554
- function buildPluginJson(plugin, mcpServers) {
7589
+ function buildPluginJson2(plugin, mcpServers) {
6555
7590
  const { manifest } = plugin;
6556
7591
  const {
6557
7592
  mcpServers: _origMcp,
@@ -6567,7 +7602,7 @@ function buildPluginJson(plugin, mcpServers) {
6567
7602
  }
6568
7603
  async function readMarketplaceCacheSource(metaPath) {
6569
7604
  try {
6570
- const raw = await readFile6(metaPath, "utf8");
7605
+ const raw = await readFile7(metaPath, "utf8");
6571
7606
  const parsed = JSON.parse(raw);
6572
7607
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
6573
7608
  const sourceRaw = parsed.sourceRaw;
@@ -6602,7 +7637,7 @@ async function defaultSymlinkRunner(target, linkPath) {
6602
7637
  }
6603
7638
  async function dirExists(p) {
6604
7639
  try {
6605
- const s = await stat3(p);
7640
+ const s = await stat4(p);
6606
7641
  return s.isDirectory();
6607
7642
  } catch {
6608
7643
  return false;
@@ -6619,15 +7654,15 @@ async function inodeKind(p) {
6619
7654
  return "missing";
6620
7655
  }
6621
7656
  }
6622
- async function listDirFilesRecursive(srcDir, dstDir) {
7657
+ async function listDirFilesRecursive2(srcDir, dstDir) {
6623
7658
  const planned = [];
6624
- const entries = await readdir3(srcDir, { withFileTypes: true });
7659
+ const entries = await readdir5(srcDir, { withFileTypes: true });
6625
7660
  for (const entry of entries) {
6626
- const srcPath = join9(srcDir, entry.name);
6627
- const dstPath = join9(dstDir, entry.name);
7661
+ const srcPath = join10(srcDir, entry.name);
7662
+ const dstPath = join10(dstDir, entry.name);
6628
7663
  if (entry.isDirectory()) {
6629
7664
  planned.push(dstPath);
6630
- const sub = await listDirFilesRecursive(srcPath, dstPath);
7665
+ const sub = await listDirFilesRecursive2(srcPath, dstPath);
6631
7666
  planned.push(...sub);
6632
7667
  } else if (entry.isFile()) {
6633
7668
  planned.push(dstPath);
@@ -6637,17 +7672,17 @@ async function listDirFilesRecursive(srcDir, dstDir) {
6637
7672
  }
6638
7673
  async function copyDirTracked(srcDir, dstDir) {
6639
7674
  const written = [];
6640
- const entries = await readdir3(srcDir, { withFileTypes: true });
7675
+ const entries = await readdir5(srcDir, { withFileTypes: true });
6641
7676
  for (const entry of entries) {
6642
- const srcPath = join9(srcDir, entry.name);
6643
- const dstPath = join9(dstDir, entry.name);
7677
+ const srcPath = join10(srcDir, entry.name);
7678
+ const dstPath = join10(dstDir, entry.name);
6644
7679
  if (entry.isDirectory()) {
6645
- await mkdir5(dstPath, { recursive: true });
7680
+ await mkdir6(dstPath, { recursive: true });
6646
7681
  written.push(dstPath);
6647
7682
  const subWritten = await copyDirTracked(srcPath, dstPath);
6648
7683
  written.push(...subWritten);
6649
7684
  } else if (entry.isFile()) {
6650
- await mkdir5(dirname5(dstPath), { recursive: true });
7685
+ await mkdir6(dirname6(dstPath), { recursive: true });
6651
7686
  await copyFile(srcPath, dstPath);
6652
7687
  written.push(dstPath);
6653
7688
  }
@@ -6658,7 +7693,7 @@ async function writeAtomicWithMtimeCheck(filePath, data, expectedMtimeMs) {
6658
7693
  if (expectedMtimeMs !== null) {
6659
7694
  let currentMtime = null;
6660
7695
  try {
6661
- const s = await stat3(filePath);
7696
+ const s = await stat4(filePath);
6662
7697
  currentMtime = s.mtimeMs;
6663
7698
  } catch {
6664
7699
  currentMtime = null;
@@ -6681,20 +7716,20 @@ async function retryOnConflict(fn) {
6681
7716
  }
6682
7717
 
6683
7718
  // src/installers/cursor/installer.ts
6684
- import { randomUUID as randomUUID5 } from "crypto";
7719
+ import { randomUUID as randomUUID6 } from "crypto";
6685
7720
  import { constants as fsConstants7 } from "fs";
6686
7721
  import {
6687
7722
  access as access7,
6688
- cp as cp2,
6689
- mkdir as mkdir7,
6690
- readFile as readFile9,
6691
- rename as rename5,
6692
- rm as rm8,
6693
- stat as stat5,
6694
- writeFile as writeFile6
7723
+ cp as cp3,
7724
+ mkdir as mkdir8,
7725
+ readFile as readFile10,
7726
+ rename as rename6,
7727
+ rm as rm9,
7728
+ stat as stat6,
7729
+ writeFile as writeFile7
6695
7730
  } from "fs/promises";
6696
- import { homedir as homedir11 } from "os";
6697
- import { dirname as dirname7, relative, resolve as resolve14 } from "path";
7731
+ import { homedir as homedir12 } from "os";
7732
+ import { dirname as dirname8, relative, resolve as resolve16 } from "path";
6698
7733
 
6699
7734
  // src/installers/cursor/marker.ts
6700
7735
  var RUSH_AI_MARKER = "<!-- rush-ai:auto-generated -->";
@@ -6703,18 +7738,18 @@ function hasRushAiMarker(fileContent) {
6703
7738
  }
6704
7739
 
6705
7740
  // src/installers/cursor/mcp.ts
6706
- import { randomUUID as randomUUID4 } from "crypto";
7741
+ import { randomUUID as randomUUID5 } from "crypto";
6707
7742
  import { constants as fsConstants6 } from "fs";
6708
7743
  import {
6709
7744
  access as access6,
6710
- mkdir as mkdir6,
6711
- readFile as readFile7,
6712
- rename as rename4,
6713
- rm as rm7,
6714
- stat as stat4,
6715
- writeFile as writeFile5
7745
+ mkdir as mkdir7,
7746
+ readFile as readFile8,
7747
+ rename as rename5,
7748
+ rm as rm8,
7749
+ stat as stat5,
7750
+ writeFile as writeFile6
6716
7751
  } from "fs/promises";
6717
- import { dirname as dirname6 } from "path";
7752
+ import { dirname as dirname7 } from "path";
6718
7753
  async function readCursorMcpJson(filePath) {
6719
7754
  return (await readCursorMcpJsonWithMtime(filePath)).data;
6720
7755
  }
@@ -6722,8 +7757,8 @@ async function readCursorMcpJsonWithMtime(filePath) {
6722
7757
  if (!await pathExists5(filePath)) {
6723
7758
  return { data: {}, mtimeMs: null };
6724
7759
  }
6725
- const stats = await stat4(filePath);
6726
- const raw = await readFile7(filePath, "utf8");
7760
+ const stats = await stat5(filePath);
7761
+ const raw = await readFile8(filePath, "utf8");
6727
7762
  let parsed;
6728
7763
  try {
6729
7764
  parsed = JSON.parse(raw);
@@ -6752,10 +7787,16 @@ function mergeMcpServers(current, additions) {
6752
7787
  cloned.mcpServers = {};
6753
7788
  }
6754
7789
  for (const [key, config] of Object.entries(additions)) {
6755
- cloned.mcpServers[key] = toCursorStdioEntry(config);
7790
+ cloned.mcpServers[key] = toCursorMcpEntry(config);
6756
7791
  }
6757
7792
  return cloned;
6758
7793
  }
7794
+ function toCursorMcpEntry(config) {
7795
+ if (typeof config.command === "string") {
7796
+ return toCursorStdioEntry({ ...config, command: config.command });
7797
+ }
7798
+ return toCursorRemoteOrUnknownEntry(config);
7799
+ }
6759
7800
  function toCursorStdioEntry(config) {
6760
7801
  const entry = {
6761
7802
  type: "stdio",
@@ -6764,7 +7805,7 @@ function toCursorStdioEntry(config) {
6764
7805
  if (config.args !== void 0) entry.args = [...config.args];
6765
7806
  if (config.env !== void 0) entry.env = { ...config.env };
6766
7807
  if (config.cwd !== void 0) entry.cwd = config.cwd;
6767
- const handledKeys = /* @__PURE__ */ new Set(["command", "args", "env", "cwd"]);
7808
+ const handledKeys = /* @__PURE__ */ new Set(["type", "command", "args", "env", "cwd"]);
6768
7809
  const raw = config;
6769
7810
  for (const [key, value] of Object.entries(raw)) {
6770
7811
  if (handledKeys.has(key)) continue;
@@ -6773,6 +7814,18 @@ function toCursorStdioEntry(config) {
6773
7814
  }
6774
7815
  return entry;
6775
7816
  }
7817
+ function toCursorRemoteOrUnknownEntry(config) {
7818
+ const entry = {};
7819
+ const raw = config;
7820
+ for (const [key, value] of Object.entries(raw)) {
7821
+ if (value === void 0) continue;
7822
+ entry[key] = deepCopyPrimitive(value);
7823
+ }
7824
+ if (typeof config.url === "string" && config.url.length > 0 && typeof config.type !== "string") {
7825
+ entry.type = "http";
7826
+ }
7827
+ return entry;
7828
+ }
6776
7829
  function deepCopyPrimitive(v) {
6777
7830
  if (v === null || typeof v !== "object") return v;
6778
7831
  try {
@@ -6790,15 +7843,15 @@ function removeMcpServers(current, keysToRemove) {
6790
7843
  return cloned;
6791
7844
  }
6792
7845
  async function writeCursorMcpJson(filePath, data) {
6793
- await mkdir6(dirname6(filePath), { recursive: true });
7846
+ await mkdir7(dirname7(filePath), { recursive: true });
6794
7847
  const content = `${JSON.stringify(data, null, 2)}
6795
7848
  `;
6796
- const tmp = `${filePath}.${randomUUID4()}.tmp`;
7849
+ const tmp = `${filePath}.${randomUUID5()}.tmp`;
6797
7850
  try {
6798
- await writeFile5(tmp, content, { encoding: "utf8", flag: "w" });
6799
- await rename4(tmp, filePath);
7851
+ await writeFile6(tmp, content, { encoding: "utf8", flag: "w" });
7852
+ await rename5(tmp, filePath);
6800
7853
  } catch (err) {
6801
- await rm7(tmp, { force: true }).catch(() => {
7854
+ await rm8(tmp, { force: true }).catch(() => {
6802
7855
  });
6803
7856
  throw err;
6804
7857
  }
@@ -6813,25 +7866,25 @@ async function pathExists5(p) {
6813
7866
  }
6814
7867
 
6815
7868
  // src/installers/cursor/paths.ts
6816
- import { resolve as resolve12 } from "path";
7869
+ import { resolve as resolve14 } from "path";
6817
7870
  var CURSOR_RELATIVE_DIR = ".cursor";
6818
7871
  function cursorDir(home) {
6819
- return resolve12(home, CURSOR_RELATIVE_DIR);
7872
+ return resolve14(home, CURSOR_RELATIVE_DIR);
6820
7873
  }
6821
7874
  function cursorMcpJsonPath(home) {
6822
- return resolve12(cursorDir(home), "mcp.json");
7875
+ return resolve14(cursorDir(home), "mcp.json");
6823
7876
  }
6824
7877
  function cursorRulesDir(home) {
6825
- return resolve12(cursorDir(home), "rules");
7878
+ return resolve14(cursorDir(home), "rules");
6826
7879
  }
6827
7880
  function cursorRuleMdcPath(home, ruleName) {
6828
- return resolve12(cursorRulesDir(home), `${ruleName}.mdc`);
7881
+ return resolve14(cursorRulesDir(home), `${ruleName}.mdc`);
6829
7882
  }
6830
7883
  function cursorSkillsDir(home) {
6831
- return resolve12(cursorDir(home), "skills");
7884
+ return resolve14(cursorDir(home), "skills");
6832
7885
  }
6833
7886
  function cursorSkillDir(home, skillName) {
6834
- return resolve12(cursorSkillsDir(home), skillName);
7887
+ return resolve14(cursorSkillsDir(home), skillName);
6835
7888
  }
6836
7889
  function bridgeSkillFileReference(skillName) {
6837
7890
  return `.cursor/skills/${skillName}/SKILL.md`;
@@ -6941,13 +7994,13 @@ function quoteIfNeeded(value) {
6941
7994
  }
6942
7995
 
6943
7996
  // src/installers/cursor/skills.ts
6944
- import { readFile as readFile8 } from "fs/promises";
6945
- import { resolve as resolve13 } from "path";
7997
+ import { readFile as readFile9 } from "fs/promises";
7998
+ import { resolve as resolve15 } from "path";
6946
7999
  async function readSkillDescription(skillSourceDir) {
6947
- const skillMdPath = resolve13(skillSourceDir, "SKILL.md");
8000
+ const skillMdPath = resolve15(skillSourceDir, "SKILL.md");
6948
8001
  let raw;
6949
8002
  try {
6950
- raw = await readFile8(skillMdPath, "utf8");
8003
+ raw = await readFile9(skillMdPath, "utf8");
6951
8004
  } catch {
6952
8005
  return void 0;
6953
8006
  }
@@ -6977,11 +8030,11 @@ async function executeRollback(ledger) {
6977
8030
  if (entry.kind === "restore-file") {
6978
8031
  await atomicWriteFile(entry.path, entry.originalContent);
6979
8032
  } else if (entry.kind === "remove-file") {
6980
- await rm8(entry.path, { force: true });
8033
+ await rm9(entry.path, { force: true });
6981
8034
  } else if (entry.kind === "remove-dir") {
6982
- await rm8(entry.path, { recursive: true, force: true });
8035
+ await rm9(entry.path, { recursive: true, force: true });
6983
8036
  } else {
6984
- await rm8(entry.path, { recursive: true, force: true });
8037
+ await rm9(entry.path, { recursive: true, force: true });
6985
8038
  await safeRename(entry.backupPath, entry.path);
6986
8039
  }
6987
8040
  } catch (err) {
@@ -6993,20 +8046,20 @@ async function executeRollback(ledger) {
6993
8046
  return errors;
6994
8047
  }
6995
8048
  async function atomicWriteFile(filePath, content) {
6996
- await mkdir7(dirname7(filePath), { recursive: true });
6997
- const tmp = `${filePath}.${randomUUID5()}.tmp`;
8049
+ await mkdir8(dirname8(filePath), { recursive: true });
8050
+ const tmp = `${filePath}.${randomUUID6()}.tmp`;
6998
8051
  try {
6999
- await writeFile6(tmp, content, { encoding: "utf8", flag: "w" });
7000
- await rename5(tmp, filePath);
8052
+ await writeFile7(tmp, content, { encoding: "utf8", flag: "w" });
8053
+ await rename6(tmp, filePath);
7001
8054
  } catch (err) {
7002
- await rm8(tmp, { force: true }).catch(() => {
8055
+ await rm9(tmp, { force: true }).catch(() => {
7003
8056
  });
7004
8057
  throw err;
7005
8058
  }
7006
8059
  }
7007
8060
  async function getMcpMtimeMs(filePath) {
7008
8061
  try {
7009
- const s = await stat5(filePath);
8062
+ const s = await stat6(filePath);
7010
8063
  return s.mtimeMs;
7011
8064
  } catch {
7012
8065
  return null;
@@ -7039,7 +8092,7 @@ var CursorInstaller = class {
7039
8092
  target = "cursor";
7040
8093
  home;
7041
8094
  constructor(options = {}) {
7042
- this.home = options.home ?? homedir11();
8095
+ this.home = options.home ?? homedir12();
7043
8096
  }
7044
8097
  // -------------------------------------------------------------------------
7045
8098
  // PluginInstaller 接口
@@ -7239,13 +8292,13 @@ var CursorInstaller = class {
7239
8292
  if (info === "missing") continue;
7240
8293
  if (info === "skill-dir") {
7241
8294
  if (!dryRun) {
7242
- await rm8(filePath, { recursive: true, force: true });
8295
+ await rm9(filePath, { recursive: true, force: true });
7243
8296
  }
7244
8297
  removedFiles.push(filePath);
7245
8298
  continue;
7246
8299
  }
7247
8300
  if (info === "mdc-file") {
7248
- const content = await readFile9(filePath, "utf8").catch(() => "");
8301
+ const content = await readFile10(filePath, "utf8").catch(() => "");
7249
8302
  if (!hasRushAiMarker(content)) {
7250
8303
  warnings.push(
7251
8304
  `${filePath} \u5DF2\u88AB\u4FEE\u6539\uFF08marker \u4E22\u5931\uFF09\uFF0C\u8DF3\u8FC7\u4E0D\u52A8\u2014\u2014\u8BF7\u7528\u6237\u624B\u52A8\u5904\u7406`
@@ -7253,13 +8306,13 @@ var CursorInstaller = class {
7253
8306
  continue;
7254
8307
  }
7255
8308
  if (!dryRun) {
7256
- await rm8(filePath, { force: true });
8309
+ await rm9(filePath, { force: true });
7257
8310
  }
7258
8311
  removedFiles.push(filePath);
7259
8312
  continue;
7260
8313
  }
7261
8314
  if (!dryRun) {
7262
- await rm8(filePath, { force: true });
8315
+ await rm9(filePath, { force: true });
7263
8316
  }
7264
8317
  removedFiles.push(filePath);
7265
8318
  }
@@ -7307,10 +8360,10 @@ var CursorInstaller = class {
7307
8360
  const prevEntry = registryStore.get(plugin.ref);
7308
8361
  const prevFiles = new Set(prevEntry?.targets?.cursor?.files ?? []);
7309
8362
  if (plugin.capabilities.includes("skills")) {
7310
- const skillsSourceDir = resolve14(plugin.sourceDir, "skills");
8363
+ const skillsSourceDir = resolve16(plugin.sourceDir, "skills");
7311
8364
  const skillDirs = await listSkillDirs(skillsSourceDir);
7312
8365
  for (const skillName of skillDirs) {
7313
- const srcDir = resolve14(skillsSourceDir, skillName);
8366
+ const srcDir = resolve16(skillsSourceDir, skillName);
7314
8367
  const destDir = cursorSkillDir(this.home, skillName);
7315
8368
  const bridgeRulePath = cursorRuleMdcPath(this.home, skillName);
7316
8369
  if (await dirExists2(destDir)) {
@@ -7342,10 +8395,10 @@ var CursorInstaller = class {
7342
8395
  }
7343
8396
  }
7344
8397
  if (plugin.capabilities.includes("rules")) {
7345
- const rulesSourceDir = resolve14(plugin.sourceDir, "rules");
8398
+ const rulesSourceDir = resolve16(plugin.sourceDir, "rules");
7346
8399
  const rulesFiles = await listRuleMdFiles(rulesSourceDir);
7347
8400
  for (const ruleFile of rulesFiles) {
7348
- const srcPath = resolve14(rulesSourceDir, ruleFile);
8401
+ const srcPath = resolve16(rulesSourceDir, ruleFile);
7349
8402
  const ruleName = ruleFile.replace(/\.md$/i, "");
7350
8403
  const destPath = cursorRuleMdcPath(this.home, ruleName);
7351
8404
  await assertMdcWritable(destPath, args.force);
@@ -7354,7 +8407,7 @@ var CursorInstaller = class {
7354
8407
  `rule "${ruleName}" \u4E0E skill "${ruleName}" \u7684 bridge rule \u540C\u540D\uFF0Crule \u5185\u5BB9\u4F1A\u8986\u76D6 bridge rule`
7355
8408
  );
7356
8409
  }
7357
- const src = await readFile9(srcPath, "utf8");
8410
+ const src = await readFile10(srcPath, "utf8");
7358
8411
  const parsed = parseMarkdown(src);
7359
8412
  const content = renderMdc(parsed, {
7360
8413
  descriptionFallback: plugin.manifest.description ?? ruleName
@@ -7382,7 +8435,7 @@ var CursorInstaller = class {
7382
8435
  // -------------------------------------------------------------------------
7383
8436
  async writeSkillDir(args) {
7384
8437
  const preExisted = await dirExists2(args.destDir);
7385
- await mkdir7(dirname7(args.destDir), { recursive: true });
8438
+ await mkdir8(dirname8(args.destDir), { recursive: true });
7386
8439
  if (preExisted) {
7387
8440
  const backup = `${args.destDir}.${process.pid}.${Date.now()}.bak`;
7388
8441
  await safeRename(args.destDir, backup);
@@ -7394,12 +8447,12 @@ var CursorInstaller = class {
7394
8447
  } else {
7395
8448
  args.ledger.push({ kind: "remove-dir", path: args.destDir });
7396
8449
  }
7397
- await cp2(args.srcDir, args.destDir, { recursive: true });
8450
+ await cp3(args.srcDir, args.destDir, { recursive: true });
7398
8451
  }
7399
8452
  async writeMdcFile(args) {
7400
8453
  const preExisted = await fileExists(args.path);
7401
8454
  if (preExisted) {
7402
- const original = await readFile9(args.path, "utf8");
8455
+ const original = await readFile10(args.path, "utf8");
7403
8456
  args.ledger.push({
7404
8457
  kind: "restore-file",
7405
8458
  path: args.path,
@@ -7413,7 +8466,7 @@ var CursorInstaller = class {
7413
8466
  async writeMcpMerge(args) {
7414
8467
  const preExisted = await fileExists(args.mcpPath);
7415
8468
  if (preExisted) {
7416
- const original = await readFile9(args.mcpPath, "utf8");
8469
+ const original = await readFile10(args.mcpPath, "utf8");
7417
8470
  args.ledger.push({
7418
8471
  kind: "restore-file",
7419
8472
  path: args.mcpPath,
@@ -7497,7 +8550,7 @@ function skippedResult() {
7497
8550
  }
7498
8551
  async function assertMdcWritable(path4, force) {
7499
8552
  if (!await fileExists(path4)) return;
7500
- const raw = await readFile9(path4, "utf8").catch(() => "");
8553
+ const raw = await readFile10(path4, "utf8").catch(() => "");
7501
8554
  if (hasRushAiMarker(raw)) return;
7502
8555
  if (force) return;
7503
8556
  throw new CursorInstallConflictError(
@@ -7512,7 +8565,7 @@ async function extractMcpAdditions(plugin) {
7512
8565
  if (typeof m === "object") {
7513
8566
  serverMap = m;
7514
8567
  } else if (typeof m === "string") {
7515
- const { readExternalMcpServers: readExternalMcpServers2 } = await import("./mcp-UZYID3GG.js");
8568
+ const { readExternalMcpServers: readExternalMcpServers2 } = await import("./mcp-TROKQRBF.js");
7516
8569
  serverMap = await readExternalMcpServers2(plugin.sourceDir, m);
7517
8570
  }
7518
8571
  if (!serverMap) return null;
@@ -7526,19 +8579,19 @@ async function extractMcpAdditions(plugin) {
7526
8579
  }
7527
8580
  async function listSkillDirs(skillsDir) {
7528
8581
  if (!await dirExists2(skillsDir)) return [];
7529
- const { readdir: readdir5 } = await import("fs/promises");
7530
- const entries = await readdir5(skillsDir, { withFileTypes: true });
8582
+ const { readdir: readdir7 } = await import("fs/promises");
8583
+ const entries = await readdir7(skillsDir, { withFileTypes: true });
7531
8584
  return entries.filter((e) => e.isDirectory()).map((e) => e.name).filter((name) => !name.startsWith(".")).sort();
7532
8585
  }
7533
8586
  async function listRuleMdFiles(rulesDir) {
7534
8587
  if (!await dirExists2(rulesDir)) return [];
7535
- const { readdir: readdir5 } = await import("fs/promises");
7536
- const entries = await readdir5(rulesDir, { withFileTypes: true });
8588
+ const { readdir: readdir7 } = await import("fs/promises");
8589
+ const entries = await readdir7(rulesDir, { withFileTypes: true });
7537
8590
  return entries.filter((e) => e.isFile() && /\.md$/i.test(e.name)).map((e) => e.name).sort();
7538
8591
  }
7539
8592
  async function dirExists2(p) {
7540
8593
  try {
7541
- const s = await stat5(p);
8594
+ const s = await stat6(p);
7542
8595
  return s.isDirectory();
7543
8596
  } catch {
7544
8597
  return false;
@@ -7547,20 +8600,20 @@ async function dirExists2(p) {
7547
8600
  async function fileExists(p) {
7548
8601
  try {
7549
8602
  await access7(p, fsConstants7.F_OK);
7550
- const s = await stat5(p);
8603
+ const s = await stat6(p);
7551
8604
  return s.isFile();
7552
8605
  } catch {
7553
8606
  return false;
7554
8607
  }
7555
8608
  }
7556
8609
  async function safeRename(from, to) {
7557
- const { rename: rename7 } = await import("fs/promises");
7558
- await rename7(from, to);
8610
+ const { rename: rename8 } = await import("fs/promises");
8611
+ await rename8(from, to);
7559
8612
  }
7560
8613
  async function classifyArtifactPath(p) {
7561
8614
  let s;
7562
8615
  try {
7563
- s = await stat5(p);
8616
+ s = await stat6(p);
7564
8617
  } catch {
7565
8618
  return "missing";
7566
8619
  }
@@ -7573,14 +8626,14 @@ async function classifyArtifactPath(p) {
7573
8626
  }
7574
8627
 
7575
8628
  // src/migration/cleanup.ts
7576
- import { lstat as lstat3, rm as rm9, unlink as unlink2 } from "fs/promises";
7577
- import { homedir as homedir13 } from "os";
7578
- import { resolve as resolve16 } from "path";
8629
+ import { lstat as lstat3, rm as rm10, unlink as unlink2 } from "fs/promises";
8630
+ import { homedir as homedir14 } from "os";
8631
+ import { resolve as resolve18 } from "path";
7579
8632
 
7580
8633
  // src/migration/detect.ts
7581
- import { access as access8, lstat as lstat2, readFile as readFile10, readlink as readlink2, stat as stat6 } from "fs/promises";
7582
- import { homedir as homedir12 } from "os";
7583
- import { isAbsolute as isAbsolute3, resolve as resolve15 } from "path";
8634
+ import { access as access8, lstat as lstat2, readFile as readFile11, readlink as readlink2, stat as stat7 } from "fs/promises";
8635
+ import { homedir as homedir13 } from "os";
8636
+ import { isAbsolute as isAbsolute3, resolve as resolve17 } from "path";
7584
8637
  var LEGACY_ASSET_MANIFEST_RELATIVE = ".rush/plugins/claude-code/asset-manifest.json";
7585
8638
  var LEGACY_ASSETS_DIR_RELATIVE = ".rush/plugins/claude-code/assets";
7586
8639
  var LEGACY_CLAUDE_CODE_DIR_RELATIVE = ".rush/plugins/claude-code";
@@ -7599,7 +8652,7 @@ async function isSymlinkPointingInto(linkPath, expectedTarget) {
7599
8652
  const lst = await lstat2(linkPath);
7600
8653
  if (!lst.isSymbolicLink()) return false;
7601
8654
  const rawTarget = await readlink2(linkPath);
7602
- const resolvedTarget = isAbsolute3(rawTarget) ? rawTarget : resolve15(linkPath, "..", rawTarget);
8655
+ const resolvedTarget = isAbsolute3(rawTarget) ? rawTarget : resolve17(linkPath, "..", rawTarget);
7603
8656
  return resolvedTarget === expectedTarget || resolvedTarget.startsWith(`${expectedTarget}/`);
7604
8657
  } catch {
7605
8658
  return false;
@@ -7608,7 +8661,7 @@ async function isSymlinkPointingInto(linkPath, expectedTarget) {
7608
8661
  async function hasLegacyMcpWithoutEnabled(settingsJsonPath) {
7609
8662
  try {
7610
8663
  if (!await pathExists6(settingsJsonPath)) return false;
7611
- const raw = await readFile10(settingsJsonPath, "utf8");
8664
+ const raw = await readFile11(settingsJsonPath, "utf8");
7612
8665
  let parsed;
7613
8666
  try {
7614
8667
  parsed = JSON.parse(raw);
@@ -7635,11 +8688,11 @@ async function hasLegacyMcpWithoutEnabled(settingsJsonPath) {
7635
8688
  }
7636
8689
  }
7637
8690
  async function detectLegacyInstall(opts = {}) {
7638
- const home = opts.home ?? homedir12();
7639
- const assetManifestPath = resolve15(home, LEGACY_ASSET_MANIFEST_RELATIVE);
7640
- const legacyAssetsDir = resolve15(home, LEGACY_ASSETS_DIR_RELATIVE);
7641
- const skillSymlinkPath = resolve15(home, LEGACY_SKILL_SYMLINK_RELATIVE);
7642
- const settingsJsonPath = resolve15(home, CLAUDE_SETTINGS_JSON_RELATIVE);
8691
+ const home = opts.home ?? homedir13();
8692
+ const assetManifestPath = resolve17(home, LEGACY_ASSET_MANIFEST_RELATIVE);
8693
+ const legacyAssetsDir = resolve17(home, LEGACY_ASSETS_DIR_RELATIVE);
8694
+ const skillSymlinkPath = resolve17(home, LEGACY_SKILL_SYMLINK_RELATIVE);
8695
+ const settingsJsonPath = resolve17(home, CLAUDE_SETTINGS_JSON_RELATIVE);
7643
8696
  const [hasAssetManifest, hasLegacySkillSymlink, legacyMcpWithoutEnabled] = await Promise.all([
7644
8697
  pathExists6(assetManifestPath),
7645
8698
  isSymlinkPointingInto(skillSymlinkPath, legacyAssetsDir),
@@ -7653,12 +8706,12 @@ async function detectLegacyInstall(opts = {}) {
7653
8706
  };
7654
8707
  }
7655
8708
  async function detectLegacyVersion(opts = {}) {
7656
- const home = opts.home ?? homedir12();
7657
- const manifestPath = resolve15(home, LEGACY_ASSET_MANIFEST_RELATIVE);
8709
+ const home = opts.home ?? homedir13();
8710
+ const manifestPath = resolve17(home, LEGACY_ASSET_MANIFEST_RELATIVE);
7658
8711
  try {
7659
- const lst = await stat6(manifestPath);
8712
+ const lst = await stat7(manifestPath);
7660
8713
  if (!lst.isFile()) return "0.7.x";
7661
- const raw = await readFile10(manifestPath, "utf8");
8714
+ const raw = await readFile11(manifestPath, "utf8");
7662
8715
  const parsed = JSON.parse(raw);
7663
8716
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
7664
8717
  const v = parsed.version;
@@ -7672,9 +8725,9 @@ async function detectLegacyVersion(opts = {}) {
7672
8725
 
7673
8726
  // src/migration/cleanup.ts
7674
8727
  async function cleanupLegacyDir(home) {
7675
- const dir = resolve16(home, LEGACY_CLAUDE_CODE_DIR_RELATIVE);
8728
+ const dir = resolve18(home, LEGACY_CLAUDE_CODE_DIR_RELATIVE);
7676
8729
  try {
7677
- await rm9(dir, { recursive: true, force: true });
8730
+ await rm10(dir, { recursive: true, force: true });
7678
8731
  return { ok: true };
7679
8732
  } catch (err) {
7680
8733
  return {
@@ -7684,7 +8737,7 @@ async function cleanupLegacyDir(home) {
7684
8737
  }
7685
8738
  }
7686
8739
  async function cleanupLegacySymlink(home) {
7687
- const path4 = resolve16(home, LEGACY_SKILL_SYMLINK_RELATIVE);
8740
+ const path4 = resolve18(home, LEGACY_SKILL_SYMLINK_RELATIVE);
7688
8741
  try {
7689
8742
  let lst;
7690
8743
  try {
@@ -7706,7 +8759,7 @@ async function cleanupLegacySymlink(home) {
7706
8759
  }
7707
8760
  }
7708
8761
  async function cleanupLegacyMcp(home) {
7709
- const path4 = resolve16(home, CLAUDE_SETTINGS_JSON_RELATIVE);
8762
+ const path4 = resolve18(home, CLAUDE_SETTINGS_JSON_RELATIVE);
7710
8763
  try {
7711
8764
  const { data, existed } = await readJsonFile(
7712
8765
  path4,
@@ -7734,7 +8787,7 @@ async function cleanupLegacyMcp(home) {
7734
8787
  }
7735
8788
  }
7736
8789
  async function cleanupLegacyInstall(opts = {}) {
7737
- const home = opts.home ?? homedir13();
8790
+ const home = opts.home ?? homedir14();
7738
8791
  const legacyDir = await cleanupLegacyDir(home);
7739
8792
  const skillSymlink = await cleanupLegacySymlink(home);
7740
8793
  const settingsMcp = await cleanupLegacyMcp(home);
@@ -7762,13 +8815,13 @@ function errorMessage(err) {
7762
8815
  }
7763
8816
 
7764
8817
  // src/migration/log.ts
7765
- import { appendFile as appendFile2, mkdir as mkdir8 } from "fs/promises";
7766
- import { homedir as homedir14 } from "os";
7767
- import { dirname as dirname8, resolve as resolve17 } from "path";
8818
+ import { appendFile as appendFile2, mkdir as mkdir9 } from "fs/promises";
8819
+ import { homedir as homedir15 } from "os";
8820
+ import { dirname as dirname9, resolve as resolve19 } from "path";
7768
8821
  var MIGRATION_LOG_RELATIVE_PATH = ".rush/plugins/migration-failed.log";
7769
8822
  function resolveMigrationLogPath(opts = {}) {
7770
- const home = opts.home ?? homedir14();
7771
- return resolve17(home, MIGRATION_LOG_RELATIVE_PATH);
8823
+ const home = opts.home ?? homedir15();
8824
+ return resolve19(home, MIGRATION_LOG_RELATIVE_PATH);
7772
8825
  }
7773
8826
  async function appendMigrationFailure(reason, opts = {}) {
7774
8827
  const now = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
@@ -7785,20 +8838,20 @@ async function appendMigrationFailure(reason, opts = {}) {
7785
8838
  const payload = `${lines.join("\n")}
7786
8839
  `;
7787
8840
  try {
7788
- await mkdir8(dirname8(logPath), { recursive: true });
8841
+ await mkdir9(dirname9(logPath), { recursive: true });
7789
8842
  await appendFile2(logPath, payload, { encoding: "utf8" });
7790
8843
  } catch {
7791
8844
  }
7792
8845
  }
7793
8846
 
7794
8847
  // src/migration/migrate.ts
7795
- import { access as access11, readFile as readFile12 } from "fs/promises";
7796
- import { homedir as homedir16 } from "os";
8848
+ import { access as access11, readFile as readFile13 } from "fs/promises";
8849
+ import { homedir as homedir17 } from "os";
7797
8850
 
7798
8851
  // src/plugins/resolver.ts
7799
- import { randomUUID as randomUUID6 } from "crypto";
7800
- import { mkdir as mkdir9, rename as rename6, rm as rm10 } from "fs/promises";
7801
- import { homedir as homedir15 } from "os";
8852
+ import { randomUUID as randomUUID7 } from "crypto";
8853
+ import { mkdir as mkdir10, rename as rename7, rm as rm11 } from "fs/promises";
8854
+ import { homedir as homedir16 } from "os";
7802
8855
  import {
7803
8856
  isAbsolute as isAbsolute4,
7804
8857
  relative as pathRelative2,
@@ -7808,8 +8861,8 @@ import {
7808
8861
 
7809
8862
  // src/plugins/capabilities.ts
7810
8863
  import { constants as fsConstants8 } from "fs";
7811
- import { access as access9, readdir as readdir4, stat as stat7 } from "fs/promises";
7812
- import { extname as extname2, resolve as resolve18 } from "path";
8864
+ import { access as access9, readdir as readdir6, stat as stat8 } from "fs/promises";
8865
+ import { extname as extname2, resolve as resolve20 } from "path";
7813
8866
  var CAPABILITY_ORDER = [
7814
8867
  "commands",
7815
8868
  "skills",
@@ -7838,20 +8891,20 @@ async function scanCapabilities(sourceDir, manifest) {
7838
8891
  return CAPABILITY_ORDER.filter((cap) => found.has(cap));
7839
8892
  }
7840
8893
  async function hasCommands(sourceDir) {
7841
- return dirHasFileWithExt(resolve18(sourceDir, "commands"), ".md");
8894
+ return dirHasFileWithExt(resolve20(sourceDir, "commands"), ".md");
7842
8895
  }
7843
8896
  async function hasSkills(sourceDir) {
7844
- const skillsDir = resolve18(sourceDir, "skills");
8897
+ const skillsDir = resolve20(sourceDir, "skills");
7845
8898
  if (await dirExists3(skillsDir)) {
7846
8899
  let entries;
7847
8900
  try {
7848
- entries = await readdir4(skillsDir, { withFileTypes: true });
8901
+ entries = await readdir6(skillsDir, { withFileTypes: true });
7849
8902
  } catch {
7850
8903
  return false;
7851
8904
  }
7852
8905
  for (const entry of entries) {
7853
8906
  if (!entry.isDirectory()) continue;
7854
- const skillMdPath = resolve18(skillsDir, entry.name, "SKILL.md");
8907
+ const skillMdPath = resolve20(skillsDir, entry.name, "SKILL.md");
7855
8908
  if (await fileExists2(skillMdPath)) {
7856
8909
  return true;
7857
8910
  }
@@ -7860,16 +8913,16 @@ async function hasSkills(sourceDir) {
7860
8913
  return hasClaudeStyleSkills(sourceDir);
7861
8914
  }
7862
8915
  async function hasRules(sourceDir) {
7863
- return dirHasFileWithExt(resolve18(sourceDir, "rules"), ".md");
8916
+ return dirHasFileWithExt(resolve20(sourceDir, "rules"), ".md");
7864
8917
  }
7865
8918
  async function hasHooks(sourceDir) {
7866
- const hooksDir = resolve18(sourceDir, "hooks");
8919
+ const hooksDir = resolve20(sourceDir, "hooks");
7867
8920
  if (!await dirExists3(hooksDir)) {
7868
8921
  return false;
7869
8922
  }
7870
8923
  let entries;
7871
8924
  try {
7872
- entries = await readdir4(hooksDir, { withFileTypes: true });
8925
+ entries = await readdir6(hooksDir, { withFileTypes: true });
7873
8926
  } catch {
7874
8927
  return false;
7875
8928
  }
@@ -7895,7 +8948,7 @@ async function dirHasFileWithExt(dirPath, ext) {
7895
8948
  }
7896
8949
  let entries;
7897
8950
  try {
7898
- entries = await readdir4(dirPath, { withFileTypes: true });
8951
+ entries = await readdir6(dirPath, { withFileTypes: true });
7899
8952
  } catch {
7900
8953
  return false;
7901
8954
  }
@@ -7905,19 +8958,19 @@ async function dirHasFileWithExt(dirPath, ext) {
7905
8958
  );
7906
8959
  }
7907
8960
  async function hasClaudeStyleSkills(sourceDir) {
7908
- const dotSkillsDir = resolve18(sourceDir, ".skills");
8961
+ const dotSkillsDir = resolve20(sourceDir, ".skills");
7909
8962
  if (!await dirExists3(dotSkillsDir)) {
7910
8963
  return false;
7911
8964
  }
7912
8965
  async function walk2(dirPath) {
7913
8966
  let entries;
7914
8967
  try {
7915
- entries = await readdir4(dirPath, { withFileTypes: true });
8968
+ entries = await readdir6(dirPath, { withFileTypes: true });
7916
8969
  } catch {
7917
8970
  return false;
7918
8971
  }
7919
8972
  for (const entry of entries) {
7920
- const abs = resolve18(dirPath, entry.name);
8973
+ const abs = resolve20(dirPath, entry.name);
7921
8974
  if (entry.isDirectory()) {
7922
8975
  if (await walk2(abs)) return true;
7923
8976
  continue;
@@ -7932,7 +8985,7 @@ async function hasClaudeStyleSkills(sourceDir) {
7932
8985
  }
7933
8986
  async function dirExists3(p) {
7934
8987
  try {
7935
- const s = await stat7(p);
8988
+ const s = await stat8(p);
7936
8989
  return s.isDirectory();
7937
8990
  } catch {
7938
8991
  return false;
@@ -7941,7 +8994,7 @@ async function dirExists3(p) {
7941
8994
  async function fileExists2(p) {
7942
8995
  try {
7943
8996
  await access9(p, fsConstants8.R_OK);
7944
- const s = await stat7(p);
8997
+ const s = await stat8(p);
7945
8998
  return s.isFile();
7946
8999
  } catch {
7947
9000
  return false;
@@ -8011,17 +9064,17 @@ var PluginCloneFailedError = class extends PluginResolverError {
8011
9064
 
8012
9065
  // src/plugins/manifest.ts
8013
9066
  import { constants as fsConstants9 } from "fs";
8014
- import { access as access10, readFile as readFile11 } from "fs/promises";
8015
- import { resolve as resolve19 } from "path";
9067
+ import { access as access10, readFile as readFile12 } from "fs/promises";
9068
+ import { resolve as resolve21 } from "path";
8016
9069
  var PLUGIN_MANIFEST_RELATIVE_PATH = ".claude-plugin/plugin.json";
8017
9070
  async function readPluginManifest(pluginName, sourceDir) {
8018
- const manifestPath = resolve19(sourceDir, PLUGIN_MANIFEST_RELATIVE_PATH);
9071
+ const manifestPath = resolve21(sourceDir, PLUGIN_MANIFEST_RELATIVE_PATH);
8019
9072
  try {
8020
9073
  await access10(manifestPath, fsConstants9.R_OK);
8021
9074
  } catch {
8022
9075
  throw new PluginManifestNotFoundError(pluginName, manifestPath);
8023
9076
  }
8024
- const raw = await readFile11(manifestPath, "utf8");
9077
+ const raw = await readFile12(manifestPath, "utf8");
8025
9078
  return parsePluginManifest(pluginName, raw, manifestPath);
8026
9079
  }
8027
9080
  function parsePluginManifest(pluginName, raw, sourcePathForError) {
@@ -8236,7 +9289,7 @@ function pluginCacheDir(marketplaceName, pluginName) {
8236
9289
  assertSafePathComponent(marketplaceName, "marketplace name");
8237
9290
  assertSafePathComponent(pluginName, "plugin name");
8238
9291
  return pathResolve(
8239
- homedir15(),
9292
+ homedir16(),
8240
9293
  ".rush",
8241
9294
  "plugin-cache",
8242
9295
  marketplaceName,
@@ -8271,8 +9324,8 @@ async function ensurePluginCloned(ref, marketplace, entry, opts) {
8271
9324
  }
8272
9325
  const git = opts?.runner ?? defaultGitRunner;
8273
9326
  const parent = pathResolve(cacheDir, "..");
8274
- await mkdir9(parent, { recursive: true });
8275
- const tmpDir = `${cacheDir}.${randomUUID6()}.tmp`;
9327
+ await mkdir10(parent, { recursive: true });
9328
+ const tmpDir = `${cacheDir}.${randomUUID7()}.tmp`;
8276
9329
  try {
8277
9330
  const args = ["clone", "--depth", "1"];
8278
9331
  if (typeof src.ref === "string" && src.ref.length > 0) {
@@ -8298,16 +9351,16 @@ async function ensurePluginCloned(ref, marketplace, entry, opts) {
8298
9351
  }
8299
9352
  }
8300
9353
  try {
8301
- await rename6(tmpDir, cacheDir);
9354
+ await rename7(tmpDir, cacheDir);
8302
9355
  } catch (err) {
8303
9356
  if (err.code === "ENOTEMPTY" && await pathExists3(cacheDir)) {
8304
- await rm10(tmpDir, { recursive: true, force: true });
9357
+ await rm11(tmpDir, { recursive: true, force: true });
8305
9358
  return;
8306
9359
  }
8307
9360
  throw err;
8308
9361
  }
8309
9362
  } catch (err) {
8310
- await rm10(tmpDir, { recursive: true, force: true }).catch(() => {
9363
+ await rm11(tmpDir, { recursive: true, force: true }).catch(() => {
8311
9364
  });
8312
9365
  if (err instanceof PluginSourceUnresolvableError) throw err;
8313
9366
  throw new PluginCloneFailedError(ref.name, marketplace.name, err);
@@ -8318,7 +9371,7 @@ async function ensurePluginCloned(ref, marketplace, entry, opts) {
8318
9371
  var LEGACY_MIGRATION_KEY = "legacy-rush-0.7.x";
8319
9372
  var SKIP_MIGRATION_ENV = "RUSH_SKIP_MIGRATION";
8320
9373
  async function maybeRunMigration(input) {
8321
- const home = input.home ?? homedir16();
9374
+ const home = input.home ?? homedir17();
8322
9375
  const now = input.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
8323
9376
  const envGet = input.env ?? ((key) => process.env[key]);
8324
9377
  const reporter = input.reporter ?? {};
@@ -8546,7 +9599,7 @@ async function verifyNewFormat(manifestPath, expectedName, _expectedVersion) {
8546
9599
  }
8547
9600
  let raw;
8548
9601
  try {
8549
- raw = await readFile12(manifestPath, "utf8");
9602
+ raw = await readFile13(manifestPath, "utf8");
8550
9603
  } catch (err) {
8551
9604
  return {
8552
9605
  ok: false,
@@ -8622,18 +9675,22 @@ var DEFAULT_TARGETS2 = [
8622
9675
  "codex",
8623
9676
  "cursor"
8624
9677
  ];
8625
- var VALID_TARGETS = new Set(DEFAULT_TARGETS2);
8626
- function parseTargets2(raw) {
9678
+ var VALID_TARGETS = [
9679
+ ...DEFAULT_TARGETS2,
9680
+ "claude-3p"
9681
+ ];
9682
+ var VALID_TARGET_SET = new Set(VALID_TARGETS);
9683
+ function parseTargets2(raw, defaultTargets = DEFAULT_TARGETS2) {
8627
9684
  if (raw === void 0 || raw.trim().length === 0) {
8628
- return [...DEFAULT_TARGETS2];
9685
+ return [...defaultTargets];
8629
9686
  }
8630
9687
  const segments = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
8631
9688
  const seen = /* @__PURE__ */ new Set();
8632
9689
  const out = [];
8633
9690
  for (const seg of segments) {
8634
- if (!VALID_TARGETS.has(seg)) {
9691
+ if (!VALID_TARGET_SET.has(seg)) {
8635
9692
  throw new RushError(
8636
- `Invalid --target '${seg}'. Expected one of: ${[...DEFAULT_TARGETS2].join(", ")}`,
9693
+ `Invalid --target '${seg}'. Expected one of: ${[...VALID_TARGETS].join(", ")}`,
8637
9694
  { raw: seg },
8638
9695
  "INVALID_TARGET",
8639
9696
  2
@@ -8646,10 +9703,60 @@ function parseTargets2(raw) {
8646
9703
  }
8647
9704
  }
8648
9705
  if (out.length === 0) {
8649
- return [...DEFAULT_TARGETS2];
9706
+ return [...defaultTargets];
9707
+ }
9708
+ return out;
9709
+ }
9710
+ function maintenanceTargetsFromRegistry(registry) {
9711
+ const installedTargets = [];
9712
+ for (const [, entry] of registry.list()) {
9713
+ for (const target of Object.keys(entry.targets)) {
9714
+ if (isInstallTarget(target)) installedTargets.push(target);
9715
+ }
9716
+ }
9717
+ return mergeTargets(DEFAULT_TARGETS2, installedTargets);
9718
+ }
9719
+ function maintenanceTargetsForRef(registry, ref) {
9720
+ const entry = registry.get(ref);
9721
+ if (!entry) return [...DEFAULT_TARGETS2];
9722
+ const installedTargets = Object.keys(entry.targets).filter(isInstallTarget);
9723
+ return installedTargets.length > 0 ? installedTargets : [...DEFAULT_TARGETS2];
9724
+ }
9725
+ function claude3pAccountFromRegistryEntry(entry) {
9726
+ const claude3p = entry?.targets["claude-3p"];
9727
+ if (!claude3p) return void 0;
9728
+ for (const file2 of claude3p.files) {
9729
+ const parsed = parseClaude3pAccountFromPath(file2);
9730
+ if (parsed) return parsed;
9731
+ }
9732
+ return void 0;
9733
+ }
9734
+ function parseClaude3pAccountFromPath(filePath) {
9735
+ const parts = filePath.split(/[\\/]+/).filter(Boolean);
9736
+ const sessionsIdx = parts.lastIndexOf(LOCAL_AGENT_SESSIONS_DIR);
9737
+ if (sessionsIdx < 0) return void 0;
9738
+ const accountUuid = parts[sessionsIdx + 1];
9739
+ const orgUuid = parts[sessionsIdx + 2];
9740
+ const coworkSegment = parts[sessionsIdx + 3];
9741
+ if (accountUuid === void 0 || orgUuid === void 0 || coworkSegment !== COWORK_PLUGINS_DIR || !UUID_V4_RE.test(accountUuid) || !UUID_V4_RE.test(orgUuid)) {
9742
+ return void 0;
9743
+ }
9744
+ return { accountUuid, orgUuid };
9745
+ }
9746
+ function mergeTargets(fallback, extra) {
9747
+ const out = [];
9748
+ const seen = /* @__PURE__ */ new Set();
9749
+ for (const target of [...fallback, ...extra]) {
9750
+ if (!seen.has(target)) {
9751
+ seen.add(target);
9752
+ out.push(target);
9753
+ }
8650
9754
  }
8651
9755
  return out;
8652
9756
  }
9757
+ function isInstallTarget(value) {
9758
+ return VALID_TARGET_SET.has(value);
9759
+ }
8653
9760
  async function parsePluginRef(raw, cache) {
8654
9761
  const trimmed = raw.trim();
8655
9762
  if (trimmed.length === 0) {
@@ -8756,6 +9863,20 @@ function defaultInstallerFactory(target, opts = {}) {
8756
9863
  };
8757
9864
  return new CodexInstaller(cxOpts);
8758
9865
  }
9866
+ case "claude-3p": {
9867
+ const cpOpts = {};
9868
+ if (opts.home !== void 0) cpOpts.home = opts.home;
9869
+ if (opts.claude3pAccount?.accountUuid !== void 0) {
9870
+ cpOpts.accountUuid = opts.claude3pAccount.accountUuid;
9871
+ }
9872
+ if (opts.claude3pAccount?.orgUuid !== void 0) {
9873
+ cpOpts.orgUuid = opts.claude3pAccount.orgUuid;
9874
+ }
9875
+ if (opts.claude3pMarketplaceSource !== void 0) {
9876
+ cpOpts.marketplaceSource = opts.claude3pMarketplaceSource;
9877
+ }
9878
+ return new ClaudeCpInstaller(cpOpts);
9879
+ }
8759
9880
  default: {
8760
9881
  const _exhaustive = target;
8761
9882
  void _exhaustive;
@@ -8813,6 +9934,9 @@ function claudeMarketplaceSourceFrom(marketplace) {
8813
9934
  return void 0;
8814
9935
  }
8815
9936
  }
9937
+ function claude3pMarketplaceSourceFrom(marketplace) {
9938
+ return { rootDir: marketplace.rootDir };
9939
+ }
8816
9940
  function buildRegistryEntry(plugin, results, nowIso) {
8817
9941
  const nonSkipped = results.filter((r) => r.status !== "skipped");
8818
9942
  if (nonSkipped.length === 0) {
@@ -8879,7 +10003,11 @@ async function runInstall(input) {
8879
10003
  const dryRun = input.dryRun === true;
8880
10004
  const now = input.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
8881
10005
  const cache = input.cache ?? new MarketplaceCache(input.home !== void 0 ? { home: input.home } : {});
10006
+ output.dim(` Resolving plugin reference: ${input.ref}`);
8882
10007
  const ref = await parsePluginRef(input.ref, cache);
10008
+ output.dim(
10009
+ ` Loading marketplace '${ref.marketplace}' for plugin '${ref.name}'`
10010
+ );
8883
10011
  let marketplace;
8884
10012
  try {
8885
10013
  marketplace = await cache.get(ref.marketplace);
@@ -8887,13 +10015,19 @@ async function runInstall(input) {
8887
10015
  if (err instanceof MarketplaceNotFoundError) {
8888
10016
  if (ref.marketplace === "rush" || ref.marketplace === "rush-marketplace") {
8889
10017
  const apiHost = getGlobalConfig().api.replace(/^https?:\/\//, "");
10018
+ output.dim(` Registering Rush marketplace from ${apiHost}`);
8890
10019
  const rushSource = parseSource(`rush://${apiHost}`);
8891
10020
  await cache.add(rushSource, { as: ref.marketplace });
8892
10021
  marketplace = await cache.get(ref.marketplace);
8893
10022
  } else if (ref.marketplace === "claude-plugins-official") {
8894
- const source = parseSource("github:anthropics/claude-plugins-official");
8895
- await cache.add(source, { as: "claude-plugins-official" });
8896
- marketplace = await cache.get("claude-plugins-official");
10023
+ throw new RushError(
10024
+ `Marketplace '@claude-plugins-official' is no longer supported. All plugins (Rush + Claude Code \u5B98\u65B9) are now under '@rush'.
10025
+ Try:
10026
+ rush-ai plugin install ${ref.name}@rush`,
10027
+ { marketplaceName: ref.marketplace, pluginName: ref.name },
10028
+ "MARKETPLACE_DEPRECATED",
10029
+ 2
10030
+ );
8897
10031
  } else {
8898
10032
  throw new RushError(
8899
10033
  `Marketplace '${ref.marketplace}' is not in the local cache. Run 'rush-ai marketplace add <source>' first.`,
@@ -8915,6 +10049,7 @@ async function runInstall(input) {
8915
10049
  const cacheEntry = cacheList.find((m) => m.name === ref.marketplace);
8916
10050
  const isStale = cacheEntry?.cachedAt ? Date.now() - new Date(cacheEntry.cachedAt).getTime() > TWENTY_FOUR_HOURS : false;
8917
10051
  if (entryMissing || isStale) {
10052
+ output.dim(` Refreshing marketplace '${ref.marketplace}'`);
8918
10053
  marketplace = await cache.update(ref.marketplace);
8919
10054
  }
8920
10055
  if (!marketplace.manifest.plugins.some((p) => p.name === ref.name)) {
@@ -8927,8 +10062,8 @@ async function runInstall(input) {
8927
10062
  }
8928
10063
  }
8929
10064
  if (marketplace.source.kind === "rush") {
8930
- const pluginDir = resolve20(marketplace.rootDir, "plugins", ref.name);
8931
- const manifestPath = resolve20(pluginDir, ".claude-plugin/plugin.json");
10065
+ const pluginDir = resolve22(marketplace.rootDir, "plugins", ref.name);
10066
+ const manifestPath = resolve22(pluginDir, ".claude-plugin/plugin.json");
8932
10067
  const alreadyMaterialized = await pathExists3(manifestPath);
8933
10068
  const hasNewSecrets = input.secrets && Object.keys(input.secrets).length > 0;
8934
10069
  const shouldMaterialize = !alreadyMaterialized || force || hasNewSecrets;
@@ -8943,6 +10078,7 @@ async function runInstall(input) {
8943
10078
  if (shouldMaterialize && !dryRun) {
8944
10079
  const rushSource = marketplace.source;
8945
10080
  const token = getAuthToken();
10081
+ output.dim(` Fetching plugin manifest: ${ref.name}@${ref.marketplace}`);
8946
10082
  let apiManifest;
8947
10083
  try {
8948
10084
  apiManifest = await fetchRushPlugin(rushSource, ref.name, { token });
@@ -8974,6 +10110,9 @@ async function runInstall(input) {
8974
10110
  secrets = { ...prompted, ...presetSecrets };
8975
10111
  }
8976
10112
  try {
10113
+ output.dim(
10114
+ ` Downloading plugin assets: ${ref.name}@${ref.marketplace}`
10115
+ );
8977
10116
  await materializeRushPlugin(rushSource, ref.name, pluginDir, {
8978
10117
  token,
8979
10118
  secrets
@@ -8994,7 +10133,7 @@ async function runInstall(input) {
8994
10133
  if (force && !dryRun) {
8995
10134
  const entry = marketplace.manifest.plugins.find((p) => p.name === ref.name);
8996
10135
  if (entry && hasUrlSource(entry)) {
8997
- await rm11(pluginCacheDir(ref.marketplace, ref.name), {
10136
+ await rm12(pluginCacheDir(ref.marketplace, ref.name), {
8998
10137
  recursive: true,
8999
10138
  force: true
9000
10139
  });
@@ -9003,6 +10142,9 @@ async function runInstall(input) {
9003
10142
  const resolveFn = input.resolvePluginFn ?? resolvePlugin;
9004
10143
  let plugin;
9005
10144
  try {
10145
+ output.dim(
10146
+ ` Reading local plugin package: ${ref.name}@${ref.marketplace}`
10147
+ );
9006
10148
  plugin = await resolveFn(ref, marketplace, { dryRun });
9007
10149
  } catch (err) {
9008
10150
  if (err instanceof PluginNotFoundInMarketplaceError && marketplace.source.kind === "rush") {
@@ -9077,6 +10219,12 @@ async function runInstall(input) {
9077
10219
  claudeMarketplaceSource: claudeMarketplaceSourceFrom(
9078
10220
  opts.marketplace
9079
10221
  )
10222
+ } : {},
10223
+ ...target === "claude-3p" ? {
10224
+ claude3pMarketplaceSource: claude3pMarketplaceSourceFrom(
10225
+ opts.marketplace
10226
+ ),
10227
+ ...input.claude3pAccount !== void 0 ? { claude3pAccount: input.claude3pAccount } : {}
9080
10228
  } : {}
9081
10229
  }));
9082
10230
  const installer = factory(t, {
@@ -9125,10 +10273,10 @@ async function runInstall(input) {
9125
10273
  if (!dryRun && codexResult?.status === "ok" && !skipCodexMirrorSync(input)) {
9126
10274
  try {
9127
10275
  const [{ syncCodexMarketplaceMirror: syncCodexMarketplaceMirror2 }, { pickContentLoader: pickContentLoader2 }] = await Promise.all([
9128
- import("./mirror-IHLOSPAS.js"),
9129
- import("./_codex-content-loader-Q7KBWZSB.js")
10276
+ import("./mirror-SQ6GNVP5.js"),
10277
+ import("./_codex-content-loader-WAPA56U3.js")
9130
10278
  ]);
9131
- await syncCodexMarketplaceMirror2(input.home ?? homedir17(), marketplace, {
10279
+ await syncCodexMarketplaceMirror2(input.home ?? homedir18(), marketplace, {
9132
10280
  contentLoader: pickContentLoader2(marketplace)
9133
10281
  });
9134
10282
  } catch (err) {
@@ -9174,7 +10322,7 @@ function formatRegistryError(err) {
9174
10322
  }
9175
10323
  function registerInstallCommand(group, _root) {
9176
10324
  group.command("install").description(
9177
- "Install a plugin to one or more IDEs (Claude Code, Codex, Cursor)"
10325
+ "Install a plugin to one or more IDEs (Claude Code, Codex, Cursor, Claude-3p)"
9178
10326
  ).argument("<ref>", "plugin reference: <name> or <name>@<marketplace>").option(
9179
10327
  "--target <list>",
9180
10328
  `comma-separated targets (default: ${[...DEFAULT_TARGETS2].join(",")})`
@@ -9288,6 +10436,8 @@ function targetDisplayName(t) {
9288
10436
  return "Codex";
9289
10437
  case "cursor":
9290
10438
  return "Cursor";
10439
+ case "claude-3p":
10440
+ return "Claude-3p";
9291
10441
  default: {
9292
10442
  const _exhaustive = t;
9293
10443
  void _exhaustive;
@@ -9303,6 +10453,8 @@ function nextStepFor(t) {
9303
10453
  return "fully quit Codex (Cmd+Q on macOS) and reopen \u2014 Codex does not hot-reload config.toml; just opening a new chat is not enough";
9304
10454
  case "cursor":
9305
10455
  return "restart Cursor";
10456
+ case "claude-3p":
10457
+ return "start a new Claude-3p conversation; if the plugin is still missing, fully quit Claude-3p (Cmd+Q on macOS) and reopen";
9306
10458
  default:
9307
10459
  return "restart the IDE";
9308
10460
  }
@@ -9310,11 +10462,14 @@ function nextStepFor(t) {
9310
10462
 
9311
10463
  // src/commands/plugin/list.ts
9312
10464
  async function runList2(input = {}) {
9313
- const targets = parseTargets2(input.targetRaw);
9314
10465
  const cache = input.cache ?? new MarketplaceCache(input.home !== void 0 ? { home: input.home } : {});
9315
10466
  const registry = input.registry ?? await RushRegistryStore.load(
9316
10467
  input.home !== void 0 ? { home: input.home } : {}
9317
10468
  );
10469
+ const targets = parseTargets2(
10470
+ input.targetRaw,
10471
+ maintenanceTargetsFromRegistry(registry)
10472
+ );
9318
10473
  if (input.available) {
9319
10474
  return runAvailable(cache, registry, targets);
9320
10475
  }
@@ -9461,16 +10616,15 @@ function statusIcon2(status) {
9461
10616
 
9462
10617
  // src/commands/plugin/uninstall.ts
9463
10618
  async function runUninstall(input) {
9464
- const targets = parseTargets2(input.targetRaw);
9465
10619
  const targetExplicit = input.targetExplicit ?? input.targetRaw !== void 0;
9466
10620
  const dryRun = input.dryRun === true;
10621
+ const registry = input.registry ?? await RushRegistryStore.load(
10622
+ input.home !== void 0 ? { home: input.home } : {}
10623
+ );
9467
10624
  const cache = input.cache ?? new MarketplaceCache(input.home !== void 0 ? { home: input.home } : {});
9468
10625
  const ref = await parsePluginRef(input.ref, cache).catch(async (err) => {
9469
10626
  if (err instanceof RushError && err.code === "PLUGIN_NOT_FOUND") {
9470
- const reg = input.registry ?? await RushRegistryStore.load(
9471
- input.home !== void 0 ? { home: input.home } : {}
9472
- );
9473
- const all = reg.list();
10627
+ const all = registry.list();
9474
10628
  const matches = all.filter(([r]) => r.name === input.ref.trim());
9475
10629
  if (matches.length === 1) {
9476
10630
  const only = matches[0];
@@ -9488,13 +10642,20 @@ async function runUninstall(input) {
9488
10642
  }
9489
10643
  throw err;
9490
10644
  });
10645
+ const targets = parseTargets2(
10646
+ input.targetRaw,
10647
+ maintenanceTargetsForRef(registry, ref)
10648
+ );
10649
+ const claude3pAccount = claude3pAccountFromRegistryEntry(registry.get(ref));
9491
10650
  const results = [];
9492
10651
  for (const t of targets) {
9493
10652
  const factory = input.installerFactory ?? ((target, opts) => defaultInstallerFactory(target, {
9494
- ...opts.home !== void 0 ? { home: opts.home } : {}
10653
+ ...opts.home !== void 0 ? { home: opts.home } : {},
10654
+ ...target === "claude-3p" && claude3pAccount !== void 0 ? { claude3pAccount } : {}
9495
10655
  }));
9496
10656
  const installer = factory(t, {
9497
- ...input.home !== void 0 ? { home: input.home } : {}
10657
+ ...input.home !== void 0 ? { home: input.home } : {},
10658
+ ...t === "claude-3p" && claude3pAccount !== void 0 ? { claude3pAccount } : {}
9498
10659
  });
9499
10660
  try {
9500
10661
  const result = await installer.uninstall(ref, { dryRun });
@@ -9523,11 +10684,8 @@ async function runUninstall(input) {
9523
10684
  let registryError;
9524
10685
  if (!dryRun) {
9525
10686
  try {
9526
- const store = input.registry ?? await RushRegistryStore.load(
9527
- input.home !== void 0 ? { home: input.home } : {}
9528
- );
9529
10687
  const successTargets = results.filter((r) => r.status === "ok").map((r) => r.target);
9530
- await applyUninstallToRegistry(store, ref, successTargets);
10688
+ await applyUninstallToRegistry(registry, ref, successTargets);
9531
10689
  } catch (err) {
9532
10690
  registryError = formatRegistryError2(err);
9533
10691
  }
@@ -9612,6 +10770,16 @@ function printUninstallSummary(result) {
9612
10770
  }
9613
10771
  }
9614
10772
  }
10773
+ const claude3pOk = results.some(
10774
+ (r) => r.target === "claude-3p" && r.status === "ok"
10775
+ );
10776
+ if (claude3pOk && !dryRun) {
10777
+ output.newline();
10778
+ output.dim("Next steps:");
10779
+ output.dim(
10780
+ " - Claude-3p: start a new Claude-3p conversation; if the plugin is still visible, fully quit Claude-3p (Cmd+Q on macOS) and reopen"
10781
+ );
10782
+ }
9615
10783
  if (result.registryError) {
9616
10784
  output.newline();
9617
10785
  output.warn(result.registryError);
@@ -9642,6 +10810,8 @@ function targetDisplayName2(t) {
9642
10810
  return "Codex";
9643
10811
  case "cursor":
9644
10812
  return "Cursor";
10813
+ case "claude-3p":
10814
+ return "Claude-3p";
9645
10815
  default: {
9646
10816
  const _exhaustive = t;
9647
10817
  void _exhaustive;
@@ -9652,13 +10822,16 @@ function targetDisplayName2(t) {
9652
10822
 
9653
10823
  // src/commands/plugin/update.ts
9654
10824
  async function runUpdate3(input = {}) {
9655
- const targets = parseTargets2(input.targetRaw);
9656
10825
  const targetExplicit = input.targetExplicit ?? input.targetRaw !== void 0;
9657
10826
  const dryRun = input.dryRun === true;
9658
10827
  const cache = input.cache ?? new MarketplaceCache(input.home !== void 0 ? { home: input.home } : {});
9659
10828
  const registry = input.registry ?? await RushRegistryStore.load(
9660
10829
  input.home !== void 0 ? { home: input.home } : {}
9661
10830
  );
10831
+ const targets = parseTargets2(
10832
+ input.targetRaw,
10833
+ maintenanceTargetsFromRegistry(registry)
10834
+ );
9662
10835
  const refs = await collectRefs(input, cache, registry);
9663
10836
  if (refs.length === 0) {
9664
10837
  return {
@@ -9724,14 +10897,16 @@ async function runUpdate3(input = {}) {
9724
10897
  plugins.push({ ref, fromVersion, toVersion, upToDate: false });
9725
10898
  continue;
9726
10899
  }
10900
+ const claude3pAccount = input.targetRaw === void 0 ? claude3pAccountFromRegistryEntry(registry.get(ref)) : void 0;
9727
10901
  const installInput = {
9728
10902
  ref: `${ref.name}@${ref.marketplace}`,
9729
- ...input.targetRaw !== void 0 ? { targetRaw: input.targetRaw } : {},
10903
+ ...input.targetRaw !== void 0 ? { targetRaw: input.targetRaw } : { targetRaw: maintenanceTargetsForRef(registry, ref).join(",") },
9730
10904
  targetExplicit,
9731
10905
  force: true,
9732
10906
  ...input.home !== void 0 ? { home: input.home } : {},
9733
10907
  cache,
9734
- registry
10908
+ registry,
10909
+ ...claude3pAccount !== void 0 ? { claude3pAccount } : {}
9735
10910
  };
9736
10911
  const result = await installRunner(installInput);
9737
10912
  plugins.push({
@@ -9939,7 +11114,7 @@ function getReskillInvocation() {
9939
11114
  };
9940
11115
  }
9941
11116
  function runReskill(args) {
9942
- return new Promise((resolve23, reject) => {
11117
+ return new Promise((resolve25, reject) => {
9943
11118
  const reskill = getReskillInvocation();
9944
11119
  const child = spawn2(reskill.command, [...reskill.args, ...args], {
9945
11120
  env: createReskillEnv(),
@@ -9949,10 +11124,10 @@ function runReskill(args) {
9949
11124
  child.on("close", (code, signal) => {
9950
11125
  if (signal) {
9951
11126
  output.error(`reskill exited from signal ${signal}`);
9952
- resolve23(1);
11127
+ resolve25(1);
9953
11128
  return;
9954
11129
  }
9955
- resolve23(code ?? 1);
11130
+ resolve25(code ?? 1);
9956
11131
  });
9957
11132
  });
9958
11133
  }
@@ -10026,7 +11201,7 @@ function registerSkillCommand(program) {
10026
11201
 
10027
11202
  // src/commands/task/index.ts
10028
11203
  import { createWriteStream } from "fs";
10029
- import { mkdir as mkdir10, readFile as readFile13, stat as stat8 } from "fs/promises";
11204
+ import { mkdir as mkdir11, readFile as readFile14, stat as stat9 } from "fs/promises";
10030
11205
  import path3 from "path";
10031
11206
  import { Readable } from "stream";
10032
11207
  import { pipeline } from "stream/promises";
@@ -10052,13 +11227,13 @@ async function readStdinIfPiped() {
10052
11227
  if (process.stdin.isTTY) {
10053
11228
  return null;
10054
11229
  }
10055
- return new Promise((resolve23, reject) => {
11230
+ return new Promise((resolve25, reject) => {
10056
11231
  const chunks = [];
10057
11232
  process.stdin.on("data", (chunk) => {
10058
11233
  chunks.push(chunk);
10059
11234
  });
10060
11235
  process.stdin.on("end", () => {
10061
- resolve23(Buffer.concat(chunks).toString("utf-8").trim());
11236
+ resolve25(Buffer.concat(chunks).toString("utf-8").trim());
10062
11237
  });
10063
11238
  process.stdin.on("error", reject);
10064
11239
  });
@@ -10259,7 +11434,7 @@ function buildDeployUrl(prefix, env, apiBaseUrl) {
10259
11434
  }
10260
11435
 
10261
11436
  // src/commands/task/push.ts
10262
- import { resolve as resolve21 } from "path";
11437
+ import { resolve as resolve23 } from "path";
10263
11438
  import chalk5 from "chalk";
10264
11439
 
10265
11440
  // src/util/env-file.ts
@@ -10403,7 +11578,7 @@ function registerPushSubcommand(task, program) {
10403
11578
  requireAuth();
10404
11579
  const format = resolveFormat(program.opts());
10405
11580
  const client = createClient();
10406
- const projectPath = resolve21(opts.path);
11581
+ const projectPath = resolve23(opts.path);
10407
11582
  if (format !== "json") {
10408
11583
  output.info("Checking project readiness...");
10409
11584
  }
@@ -10834,7 +12009,7 @@ async function confirmPublish(args) {
10834
12009
  return answer.trim().toLowerCase().startsWith("y");
10835
12010
  }
10836
12011
  function readOneLine() {
10837
- return new Promise((resolve23) => {
12012
+ return new Promise((resolve25) => {
10838
12013
  let acc = "";
10839
12014
  const onData = (chunk) => {
10840
12015
  acc += chunk.toString("utf-8");
@@ -10842,7 +12017,7 @@ function readOneLine() {
10842
12017
  if (nlIdx !== -1) {
10843
12018
  process.stdin.removeListener("data", onData);
10844
12019
  process.stdin.pause();
10845
- resolve23(acc.slice(0, nlIdx));
12020
+ resolve25(acc.slice(0, nlIdx));
10846
12021
  }
10847
12022
  };
10848
12023
  process.stdin.resume();
@@ -11028,12 +12203,12 @@ function registerDomainSubcommand(task, program) {
11028
12203
  }
11029
12204
 
11030
12205
  // src/commands/task/env.ts
11031
- import { resolve as resolve22 } from "path";
12206
+ import { resolve as resolve24 } from "path";
11032
12207
 
11033
12208
  // src/util/prompt.ts
11034
12209
  import { createInterface } from "readline";
11035
12210
  function promptSecret(message) {
11036
- return new Promise((resolve23, reject) => {
12211
+ return new Promise((resolve25, reject) => {
11037
12212
  const rl = createInterface({
11038
12213
  input: process.stdin,
11039
12214
  output: process.stdout,
@@ -11046,7 +12221,7 @@ function promptSecret(message) {
11046
12221
  rl.question("", (answer) => {
11047
12222
  rl.close();
11048
12223
  process.stdout.write("\n");
11049
- resolve23(answer);
12224
+ resolve25(answer);
11050
12225
  });
11051
12226
  rl.on("SIGINT", () => {
11052
12227
  rl.close();
@@ -11069,7 +12244,7 @@ var NO_PROJECT_HINT2 = [
11069
12244
  ].join("\n");
11070
12245
  function resolveProjectId(opts) {
11071
12246
  if (opts.project) return Promise.resolve(opts.project);
11072
- const projectPath = resolve22(opts.path ?? ".");
12247
+ const projectPath = resolve24(opts.path ?? ".");
11073
12248
  const remoteUrl = isGitRepo(projectPath) ? getRemoteUrl(projectPath) : null;
11074
12249
  const idFromRemote = remoteUrl ? extractRushProjectId(remoteUrl) : null;
11075
12250
  if (idFromRemote) return Promise.resolve(idFromRemote);
@@ -11797,7 +12972,7 @@ async function downloadFile(file2, destPath, client) {
11797
12972
  if (!response.body) {
11798
12973
  throw new Error("No response body");
11799
12974
  }
11800
- await mkdir10(path3.dirname(destPath), { recursive: true });
12975
+ await mkdir11(path3.dirname(destPath), { recursive: true });
11801
12976
  const nodeStream = Readable.fromWeb(
11802
12977
  response.body
11803
12978
  );
@@ -12338,7 +13513,7 @@ async function uploadFileForTask(client, localPath) {
12338
13513
  const resolved = path3.resolve(localPath);
12339
13514
  let fileStat;
12340
13515
  try {
12341
- fileStat = await stat8(resolved);
13516
+ fileStat = await stat9(resolved);
12342
13517
  } catch {
12343
13518
  throw new RushError(`File not found: ${localPath}`);
12344
13519
  }
@@ -12352,7 +13527,7 @@ async function uploadFileForTask(client, localPath) {
12352
13527
  }
12353
13528
  const filename = path3.basename(resolved);
12354
13529
  const mediaType = guessMediaType(resolved);
12355
- const buf = await readFile13(resolved);
13530
+ const buf = await readFile14(resolved);
12356
13531
  const blob = new File([buf], filename, { type: mediaType });
12357
13532
  const formData = new FormData();
12358
13533
  formData.append("file", blob);
@@ -12405,9 +13580,9 @@ function registerCommands(program) {
12405
13580
  }
12406
13581
 
12407
13582
  // src/util/update-check.ts
12408
- import { mkdir as mkdir11, readFile as readFile14, writeFile as writeFile7 } from "fs/promises";
12409
- import { homedir as homedir18 } from "os";
12410
- import { dirname as dirname9, join as join10 } from "path";
13583
+ import { mkdir as mkdir12, readFile as readFile15, writeFile as writeFile8 } from "fs/promises";
13584
+ import { homedir as homedir19 } from "os";
13585
+ import { dirname as dirname10, join as join11 } from "path";
12411
13586
  var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
12412
13587
  var FETCH_TIMEOUT_MS = 3e3;
12413
13588
  var REGISTRY_URL = "https://registry.npmjs.org/rush-ai/latest";
@@ -12430,19 +13605,19 @@ function isNewerVersion(current, latest) {
12430
13605
  }
12431
13606
  async function writeLastCheck(checkFile) {
12432
13607
  try {
12433
- await mkdir11(dirname9(checkFile), { recursive: true });
12434
- await writeFile7(checkFile, JSON.stringify({ lastCheck: Date.now() }));
13608
+ await mkdir12(dirname10(checkFile), { recursive: true });
13609
+ await writeFile8(checkFile, JSON.stringify({ lastCheck: Date.now() }));
12435
13610
  } catch {
12436
13611
  }
12437
13612
  }
12438
13613
  async function checkForUpdate(currentVersion) {
12439
- const rushDir = join10(homedir18(), ".rush");
12440
- const checkFile = join10(rushDir, "update-check.json");
13614
+ const rushDir = join11(homedir19(), ".rush");
13615
+ const checkFile = join11(rushDir, "update-check.json");
12441
13616
  try {
12442
13617
  if (process.env.CI) return;
12443
13618
  let lastCheck = 0;
12444
13619
  try {
12445
- const data = JSON.parse(await readFile14(checkFile, "utf-8"));
13620
+ const data = JSON.parse(await readFile15(checkFile, "utf-8"));
12446
13621
  lastCheck = data.lastCheck ?? 0;
12447
13622
  } catch {
12448
13623
  }