rush-ai 0.20.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
@@ -32,7 +32,7 @@ import {
32
32
  fetchRushPlugin,
33
33
  materializeRushPlugin,
34
34
  pickContentLoader
35
- } from "./chunk-E2CKW6JZ.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
  });
@@ -5550,34 +5550,1040 @@ function registerPlaybookCommand(program) {
5550
5550
  }
5551
5551
 
5552
5552
  // src/commands/plugin/install.ts
5553
- import { rm as rm11 } from "fs/promises";
5554
- import { homedir as homedir17 } from "os";
5555
- import { resolve as resolve20 } from "path";
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
+ }
6471
+ }
6472
+ return null;
6473
+ }
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") };
6477
+ }
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);
6485
+ }
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 };
6493
+ }
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);
6498
+ }
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
+ }
6517
+ }
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
+ }
6530
+ }
6531
+ await walk2(dir);
6532
+ return out;
6533
+ }
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
+ }
6561
+ }
5556
6562
 
5557
6563
  // src/installers/claude-code/installer.ts
5558
- import { randomUUID as randomUUID3 } from "crypto";
6564
+ import { randomUUID as randomUUID4 } from "crypto";
5559
6565
  import {
5560
6566
  copyFile,
5561
6567
  lstat,
5562
- mkdir as mkdir5,
5563
- readdir as readdir3,
5564
- readFile as readFile6,
6568
+ mkdir as mkdir6,
6569
+ readdir as readdir5,
6570
+ readFile as readFile7,
5565
6571
  readlink,
5566
- rename as rename3,
5567
- rm as rm6,
5568
- stat as stat3,
6572
+ rename as rename4,
6573
+ rm as rm7,
6574
+ stat as stat4,
5569
6575
  symlink,
5570
6576
  unlink
5571
6577
  } from "fs/promises";
5572
- import { homedir as homedir10 } from "os";
5573
- 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";
5574
6580
 
5575
6581
  // src/installers/claude-code/paths.ts
5576
- import { resolve as resolve10 } from "path";
6582
+ import { resolve as resolve12 } from "path";
5577
6583
  var CLAUDE_DIR = ".claude";
5578
6584
  var PLUGINS_SUBDIR = "plugins";
5579
6585
  var CACHE_SUBDIR = "cache";
5580
- var PLUGIN_MANIFEST_RELATIVE = ".claude-plugin/plugin.json";
6586
+ var PLUGIN_MANIFEST_RELATIVE2 = ".claude-plugin/plugin.json";
5581
6587
  var CAPABILITY_DIRS = [
5582
6588
  "commands",
5583
6589
  "skills",
@@ -5591,27 +6597,27 @@ var ClaudeCodePaths = class {
5591
6597
  }
5592
6598
  /** `<home>/.claude/` */
5593
6599
  get claudeDir() {
5594
- return resolve10(this.home, CLAUDE_DIR);
6600
+ return resolve12(this.home, CLAUDE_DIR);
5595
6601
  }
5596
6602
  /** `<home>/.claude/settings.json` */
5597
6603
  get settingsJson() {
5598
- return resolve10(this.claudeDir, "settings.json");
6604
+ return resolve12(this.claudeDir, "settings.json");
5599
6605
  }
5600
6606
  /** `<home>/.claude/plugins/` */
5601
6607
  get pluginsDir() {
5602
- return resolve10(this.claudeDir, PLUGINS_SUBDIR);
6608
+ return resolve12(this.claudeDir, PLUGINS_SUBDIR);
5603
6609
  }
5604
6610
  /** `<home>/.claude/plugins/known_marketplaces.json` */
5605
6611
  get knownMarketplacesJson() {
5606
- return resolve10(this.pluginsDir, "known_marketplaces.json");
6612
+ return resolve12(this.pluginsDir, "known_marketplaces.json");
5607
6613
  }
5608
6614
  /** `<home>/.claude/plugins/installed_plugins.json` */
5609
6615
  get installedPluginsJson() {
5610
- return resolve10(this.pluginsDir, "installed_plugins.json");
6616
+ return resolve12(this.pluginsDir, "installed_plugins.json");
5611
6617
  }
5612
6618
  /** `<home>/.claude/plugins/cache/` */
5613
6619
  get cacheDir() {
5614
- return resolve10(this.pluginsDir, CACHE_SUBDIR);
6620
+ return resolve12(this.pluginsDir, CACHE_SUBDIR);
5615
6621
  }
5616
6622
  /**
5617
6623
  * `<home>/.claude/plugins/marketplaces/`。
@@ -5621,37 +6627,37 @@ var ClaudeCodePaths = class {
5621
6627
  * Claude Code 会识别不到 plugin 条目(regression fix,bug #4)。
5622
6628
  */
5623
6629
  get marketplacesRootDir() {
5624
- return resolve10(this.pluginsDir, "marketplaces");
6630
+ return resolve12(this.pluginsDir, "marketplaces");
5625
6631
  }
5626
6632
  /** `<home>/.claude/plugins/marketplaces/<mkt>/` */
5627
6633
  marketplaceInstallDir(marketplace) {
5628
- return resolve10(this.marketplacesRootDir, marketplace);
6634
+ return resolve12(this.marketplacesRootDir, marketplace);
5629
6635
  }
5630
6636
  /** `<home>/.claude/plugins/cache/<mkt>/` */
5631
6637
  marketplaceCacheDir(marketplace) {
5632
- return resolve10(this.cacheDir, marketplace);
6638
+ return resolve12(this.cacheDir, marketplace);
5633
6639
  }
5634
6640
  /** `<home>/.claude/plugins/cache/<mkt>/<plugin>/` */
5635
6641
  pluginCacheDir(ref) {
5636
- return resolve10(this.marketplaceCacheDir(ref.marketplace), ref.name);
6642
+ return resolve12(this.marketplaceCacheDir(ref.marketplace), ref.name);
5637
6643
  }
5638
6644
  /** `<home>/.claude/plugins/cache/<mkt>/<plugin>/<version>/` */
5639
6645
  pluginVersionDir(ref, version) {
5640
- return resolve10(this.pluginCacheDir(ref), version);
6646
+ return resolve12(this.pluginCacheDir(ref), version);
5641
6647
  }
5642
6648
  /** `<home>/.claude/plugins/cache/<mkt>/<plugin>/<version>/.claude-plugin/plugin.json` */
5643
6649
  pluginManifestPath(ref, version) {
5644
- return resolve10(
6650
+ return resolve12(
5645
6651
  this.pluginVersionDir(ref, version),
5646
- PLUGIN_MANIFEST_RELATIVE
6652
+ PLUGIN_MANIFEST_RELATIVE2
5647
6653
  );
5648
6654
  }
5649
6655
  /** `<home>/.claude/plugins/cache/<mkt>/<plugin>/<version>/<capability>/` */
5650
6656
  capabilityDir(ref, version, capability) {
5651
- return resolve10(this.pluginVersionDir(ref, version), capability);
6657
+ return resolve12(this.pluginVersionDir(ref, version), capability);
5652
6658
  }
5653
6659
  };
5654
- function pluginKey(ref) {
6660
+ function pluginKey2(ref) {
5655
6661
  return `${ref.name}@${ref.marketplace}`;
5656
6662
  }
5657
6663
 
@@ -5664,7 +6670,7 @@ var ClaudeCodeInstaller = class {
5664
6670
  marketplaceSource;
5665
6671
  symlinkRunner;
5666
6672
  constructor(opts = {}) {
5667
- const home = opts.home ?? homedir10();
6673
+ const home = opts.home ?? homedir11();
5668
6674
  this.paths = new ClaudeCodePaths(home);
5669
6675
  this.rushBinaryResolver = opts.rushBinaryResolver ?? defaultRushBinaryResolver;
5670
6676
  this.now = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
@@ -5687,7 +6693,7 @@ var ClaudeCodeInstaller = class {
5687
6693
  this.paths.installedPluginsJson,
5688
6694
  () => ({ version: 2, plugins: {} })
5689
6695
  );
5690
- const entries = data.plugins?.[pluginKey(ref)];
6696
+ const entries = data.plugins?.[pluginKey2(ref)];
5691
6697
  return Array.isArray(entries) && entries.length > 0;
5692
6698
  }
5693
6699
  async list() {
@@ -5701,7 +6707,7 @@ var ClaudeCodeInstaller = class {
5701
6707
  const out = [];
5702
6708
  for (const [key, scopeEntries] of Object.entries(data.plugins ?? {})) {
5703
6709
  if (!Array.isArray(scopeEntries) || scopeEntries.length === 0) continue;
5704
- const ref = parsePluginKey2(key);
6710
+ const ref = parsePluginKey3(key);
5705
6711
  if (!ref) continue;
5706
6712
  const pick = scopeEntries.find((e) => e.scope === "user") ?? scopeEntries[0];
5707
6713
  if (!pick) continue;
@@ -5729,7 +6735,7 @@ var ClaudeCodeInstaller = class {
5729
6735
  }
5730
6736
  const { ref, version } = plugin;
5731
6737
  const pluginVersionDir = this.paths.pluginVersionDir(ref, version);
5732
- const key = pluginKey(ref);
6738
+ const key = pluginKey2(ref);
5733
6739
  if (!opts.force && version !== "unknown") {
5734
6740
  let already = false;
5735
6741
  try {
@@ -5762,13 +6768,13 @@ var ClaudeCodeInstaller = class {
5762
6768
  }
5763
6769
  try {
5764
6770
  const writtenFiles = [];
5765
- await mkdir5(pluginVersionDir, { recursive: true });
6771
+ await mkdir6(pluginVersionDir, { recursive: true });
5766
6772
  writtenFiles.push(pluginVersionDir);
5767
6773
  for (const cap of CAPABILITY_DIRS) {
5768
- const srcDir = resolve11(plugin.sourceDir, cap);
6774
+ const srcDir = resolve13(plugin.sourceDir, cap);
5769
6775
  if (!await dirExists(srcDir)) continue;
5770
6776
  const dstDir = this.paths.capabilityDir(ref, version, cap);
5771
- await mkdir5(dstDir, { recursive: true });
6777
+ await mkdir6(dstDir, { recursive: true });
5772
6778
  writtenFiles.push(dstDir);
5773
6779
  const copied = await copyDirTracked(srcDir, dstDir);
5774
6780
  writtenFiles.push(...copied);
@@ -5780,11 +6786,11 @@ var ClaudeCodeInstaller = class {
5780
6786
  this.rushBinaryResolver
5781
6787
  );
5782
6788
  if (normalizedMcp && Object.keys(normalizedMcp).length > 0) {
5783
- const mcpJsonPath = resolve11(pluginVersionDir, ".mcp.json");
6789
+ const mcpJsonPath = resolve13(pluginVersionDir, ".mcp.json");
5784
6790
  await writeJsonFile(mcpJsonPath, { mcpServers: normalizedMcp });
5785
6791
  writtenFiles.push(mcpJsonPath);
5786
6792
  }
5787
- const pluginJsonContent = buildPluginJson(plugin, normalizedMcp);
6793
+ const pluginJsonContent = buildPluginJson2(plugin, normalizedMcp);
5788
6794
  await writeJsonFile(manifestPath, pluginJsonContent);
5789
6795
  writtenFiles.push(manifestPath);
5790
6796
  const mcpKeys = normalizedMcp ? Object.keys(normalizedMcp) : [];
@@ -5849,7 +6855,7 @@ var ClaudeCodeInstaller = class {
5849
6855
  artifacts: { files: [], mcpKeys: [] }
5850
6856
  };
5851
6857
  }
5852
- const key = pluginKey(ref);
6858
+ const key = pluginKey2(ref);
5853
6859
  const touchedFiles = [];
5854
6860
  const installedMcpKeys = await this.collectMcpKeysFromInstalled(ref);
5855
6861
  if (opts.dryRun) {
@@ -5908,8 +6914,8 @@ var ClaudeCodeInstaller = class {
5908
6914
  await unlink(mktDir);
5909
6915
  files.push(mktDir);
5910
6916
  } else if (kind === "dir") {
5911
- if (await pathExists(join9(mktDir, ".rush-marketplace-source.json"))) {
5912
- 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 });
5913
6919
  files.push(mktDir);
5914
6920
  }
5915
6921
  }
@@ -5980,12 +6986,12 @@ var ClaudeCodeInstaller = class {
5980
6986
  return { written: false, path: "" };
5981
6987
  }
5982
6988
  const mktDir = this.paths.marketplaceInstallDir(marketplaceName);
5983
- await mkdir5(this.paths.marketplacesRootDir, { recursive: true });
6989
+ await mkdir6(this.paths.marketplacesRootDir, { recursive: true });
5984
6990
  const kind = await inodeKind(mktDir);
5985
6991
  if (kind === "symlink") {
5986
6992
  const target = await readlink(mktDir).catch(() => null);
5987
- const resolvedTarget = target !== null ? resolve11(dirname5(mktDir), target) : null;
5988
- if (resolvedTarget && resolvedTarget === resolve11(src.rootDir)) {
6993
+ const resolvedTarget = target !== null ? resolve13(dirname6(mktDir), target) : null;
6994
+ if (resolvedTarget && resolvedTarget === resolve13(src.rootDir)) {
5989
6995
  return { written: false, path: mktDir };
5990
6996
  }
5991
6997
  throw new Error(
@@ -5993,7 +6999,7 @@ var ClaudeCodeInstaller = class {
5993
6999
  );
5994
7000
  }
5995
7001
  if (kind === "dir") {
5996
- const metaPath = join9(mktDir, ".rush-marketplace-source.json");
7002
+ const metaPath = join10(mktDir, ".rush-marketplace-source.json");
5997
7003
  if (await pathExists(metaPath)) {
5998
7004
  const metaSourceRaw = await readMarketplaceCacheSource(metaPath);
5999
7005
  const currentSourceRaw = descriptorToSourceRaw(src.descriptor);
@@ -6018,7 +7024,7 @@ var ClaudeCodeInstaller = class {
6018
7024
  return { written: true, path: mktDir };
6019
7025
  }
6020
7026
  await copyDirTracked(src.rootDir, mktDir).catch(async (err) => {
6021
- await rm6(mktDir, { recursive: true, force: true }).catch(() => {
7027
+ await rm7(mktDir, { recursive: true, force: true }).catch(() => {
6022
7028
  });
6023
7029
  throw err;
6024
7030
  });
@@ -6045,7 +7051,7 @@ var ClaudeCodeInstaller = class {
6045
7051
  this.paths.installedPluginsJson,
6046
7052
  () => ({ version: 2, plugins: {} })
6047
7053
  );
6048
- const entries = data.plugins?.[pluginKey(ref)];
7054
+ const entries = data.plugins?.[pluginKey2(ref)];
6049
7055
  if (!Array.isArray(entries)) return false;
6050
7056
  return entries.some((e) => e.scope === "user" && e.version === version);
6051
7057
  }
@@ -6054,11 +7060,11 @@ var ClaudeCodeInstaller = class {
6054
7060
  const pluginVersionDir = this.paths.pluginVersionDir(ref, version);
6055
7061
  const dryFiles = [pluginVersionDir];
6056
7062
  for (const cap of CAPABILITY_DIRS) {
6057
- const srcDir = resolve11(plugin.sourceDir, cap);
7063
+ const srcDir = resolve13(plugin.sourceDir, cap);
6058
7064
  if (!await dirExists(srcDir)) continue;
6059
7065
  const dstDir = this.paths.capabilityDir(ref, version, cap);
6060
7066
  dryFiles.push(dstDir);
6061
- const plannedFiles = await listDirFilesRecursive(srcDir, dstDir);
7067
+ const plannedFiles = await listDirFilesRecursive2(srcDir, dstDir);
6062
7068
  dryFiles.push(...plannedFiles);
6063
7069
  }
6064
7070
  dryFiles.push(this.paths.pluginManifestPath(ref, version));
@@ -6068,7 +7074,7 @@ var ClaudeCodeInstaller = class {
6068
7074
  this.rushBinaryResolver
6069
7075
  );
6070
7076
  if (normalizedMcpDry && Object.keys(normalizedMcpDry).length > 0) {
6071
- dryFiles.push(resolve11(pluginVersionDir, ".mcp.json"));
7077
+ dryFiles.push(resolve13(pluginVersionDir, ".mcp.json"));
6072
7078
  }
6073
7079
  if (this.marketplaceSource) {
6074
7080
  const mktInstallDir = this.paths.marketplaceInstallDir(ref.marketplace);
@@ -6082,7 +7088,7 @@ var ClaudeCodeInstaller = class {
6082
7088
  if (await this.wouldInstalledPluginsChange(ref, version, pluginVersionDir)) {
6083
7089
  dryFiles.push(this.paths.installedPluginsJson);
6084
7090
  }
6085
- if (await this.wouldSettingsChange(pluginKey(ref))) {
7091
+ if (await this.wouldSettingsChange(pluginKey2(ref))) {
6086
7092
  dryFiles.push(this.paths.settingsJson);
6087
7093
  }
6088
7094
  const normalizedMcp = await resolveClaudeMcpServers(
@@ -6117,7 +7123,7 @@ var ClaudeCodeInstaller = class {
6117
7123
  this.paths.installedPluginsJson,
6118
7124
  () => ({ version: 2, plugins: {} })
6119
7125
  );
6120
- const key = pluginKey(ref);
7126
+ const key = pluginKey2(ref);
6121
7127
  const entries = data.plugins?.[key] ?? [];
6122
7128
  const userEntry = entries.find((e) => e.scope === "user");
6123
7129
  if (!userEntry) return true;
@@ -6182,8 +7188,8 @@ var ClaudeCodeInstaller = class {
6182
7188
  const settings = await this.readRawJsonForRollback(this.paths.settingsJson);
6183
7189
  let backupVersionDir = null;
6184
7190
  if (preexistedVersion === "dir") {
6185
- backupVersionDir = `${pluginVersionDir}.rollback-${randomUUID3()}`;
6186
- await rename3(pluginVersionDir, backupVersionDir);
7191
+ backupVersionDir = `${pluginVersionDir}.rollback-${randomUUID4()}`;
7192
+ await rename4(pluginVersionDir, backupVersionDir);
6187
7193
  }
6188
7194
  return {
6189
7195
  ref,
@@ -6204,7 +7210,7 @@ var ClaudeCodeInstaller = class {
6204
7210
  */
6205
7211
  async finalizeRollback(snap) {
6206
7212
  if (snap.backupVersionDir) {
6207
- await rm6(snap.backupVersionDir, { recursive: true, force: true });
7213
+ await rm7(snap.backupVersionDir, { recursive: true, force: true });
6208
7214
  }
6209
7215
  }
6210
7216
  /**
@@ -6217,19 +7223,19 @@ var ClaudeCodeInstaller = class {
6217
7223
  */
6218
7224
  async applyRollback(snap) {
6219
7225
  if (snap.preexistedVersion === "dir" && snap.backupVersionDir) {
6220
- await rm6(snap.pluginVersionDir, { recursive: true, force: true });
6221
- await rename3(snap.backupVersionDir, snap.pluginVersionDir);
7226
+ await rm7(snap.pluginVersionDir, { recursive: true, force: true });
7227
+ await rename4(snap.backupVersionDir, snap.pluginVersionDir);
6222
7228
  } else if (snap.preexistedVersion === "missing") {
6223
- await rm6(snap.pluginVersionDir, { recursive: true, force: true });
7229
+ await rm7(snap.pluginVersionDir, { recursive: true, force: true });
6224
7230
  }
6225
7231
  if (snap.preexistedPlugin === "missing") {
6226
- await rm6(this.paths.pluginCacheDir(snap.ref), {
7232
+ await rm7(this.paths.pluginCacheDir(snap.ref), {
6227
7233
  recursive: true,
6228
7234
  force: true
6229
7235
  });
6230
7236
  }
6231
7237
  if (snap.preexistedMarketplace === "missing") {
6232
- await rm6(this.paths.marketplaceCacheDir(snap.ref.marketplace), {
7238
+ await rm7(this.paths.marketplaceCacheDir(snap.ref.marketplace), {
6233
7239
  recursive: true,
6234
7240
  force: true
6235
7241
  });
@@ -6243,7 +7249,7 @@ var ClaudeCodeInstaller = class {
6243
7249
  await unlink(mktInstallDir).catch(() => {
6244
7250
  });
6245
7251
  } else if (currentKind !== "missing") {
6246
- await rm6(mktInstallDir, { recursive: true, force: true }).catch(
7252
+ await rm7(mktInstallDir, { recursive: true, force: true }).catch(
6247
7253
  () => {
6248
7254
  }
6249
7255
  );
@@ -6266,7 +7272,7 @@ var ClaudeCodeInstaller = class {
6266
7272
  async restoreRawJson(path4, state) {
6267
7273
  if (!state.existed) {
6268
7274
  if (await pathExists(path4)) {
6269
- await rm6(path4, { force: true });
7275
+ await rm7(path4, { force: true });
6270
7276
  }
6271
7277
  return;
6272
7278
  }
@@ -6361,7 +7367,7 @@ var ClaudeCodeInstaller = class {
6361
7367
  this.paths.installedPluginsJson,
6362
7368
  () => ({ version: 2, plugins: {} })
6363
7369
  );
6364
- const key = pluginKey(ref);
7370
+ const key = pluginKey2(ref);
6365
7371
  const now = this.now();
6366
7372
  const existingEntries = data.plugins?.[key] ?? [];
6367
7373
  const userIdx = existingEntries.findIndex((e) => e.scope === "user");
@@ -6435,7 +7441,7 @@ var ClaudeCodeInstaller = class {
6435
7441
  this.paths.installedPluginsJson,
6436
7442
  () => ({ version: 2, plugins: {} })
6437
7443
  );
6438
- const key = pluginKey(ref);
7444
+ const key = pluginKey2(ref);
6439
7445
  const existingEntries = data.plugins?.[key];
6440
7446
  if (!Array.isArray(existingEntries) || existingEntries.length === 0) {
6441
7447
  return false;
@@ -6490,7 +7496,7 @@ var ClaudeCodeInstaller = class {
6490
7496
  this.paths.installedPluginsJson,
6491
7497
  () => ({ version: 2, plugins: {} })
6492
7498
  );
6493
- const entries = data.plugins?.[pluginKey(ref)];
7499
+ const entries = data.plugins?.[pluginKey2(ref)];
6494
7500
  if (!Array.isArray(entries) || entries.length === 0) return false;
6495
7501
  return entries.some((e) => e.scope === "user");
6496
7502
  }
@@ -6518,7 +7524,7 @@ var ClaudeCodeInstaller = class {
6518
7524
  );
6519
7525
  const servers = data.mcpServers;
6520
7526
  if (typeof servers === "string") {
6521
- const mcpJsonPath = resolve11(dirname5(manifestPath), "..", servers);
7527
+ const mcpJsonPath = resolve13(dirname6(manifestPath), "..", servers);
6522
7528
  if (!await pathExists(mcpJsonPath)) return [];
6523
7529
  const { data: mcpData } = await readJsonFile(
6524
7530
  mcpJsonPath,
@@ -6543,11 +7549,11 @@ var ClaudeCodeInstaller = class {
6543
7549
  this.paths.installedPluginsJson,
6544
7550
  () => ({ version: 2, plugins: {} })
6545
7551
  );
6546
- const entries = data.plugins?.[pluginKey(ref)];
7552
+ const entries = data.plugins?.[pluginKey2(ref)];
6547
7553
  if (!Array.isArray(entries) || entries.length === 0) return null;
6548
7554
  const userEntry = entries.find((e) => e.scope === "user") ?? entries[0];
6549
7555
  if (!userEntry) return null;
6550
- const manifestPath = join9(
7556
+ const manifestPath = join10(
6551
7557
  userEntry.installPath,
6552
7558
  ".claude-plugin",
6553
7559
  "plugin.json"
@@ -6558,7 +7564,7 @@ var ClaudeCodeInstaller = class {
6558
7564
  return null;
6559
7565
  }
6560
7566
  };
6561
- function parsePluginKey2(key) {
7567
+ function parsePluginKey3(key) {
6562
7568
  const at = key.indexOf("@");
6563
7569
  if (at <= 0 || at === key.length - 1) return null;
6564
7570
  return { name: key.slice(0, at), marketplace: key.slice(at + 1) };
@@ -6580,7 +7586,7 @@ async function resolveClaudeMcpServers(ref, plugin, rushBinaryResolver) {
6580
7586
  }
6581
7587
  return void 0;
6582
7588
  }
6583
- function buildPluginJson(plugin, mcpServers) {
7589
+ function buildPluginJson2(plugin, mcpServers) {
6584
7590
  const { manifest } = plugin;
6585
7591
  const {
6586
7592
  mcpServers: _origMcp,
@@ -6596,7 +7602,7 @@ function buildPluginJson(plugin, mcpServers) {
6596
7602
  }
6597
7603
  async function readMarketplaceCacheSource(metaPath) {
6598
7604
  try {
6599
- const raw = await readFile6(metaPath, "utf8");
7605
+ const raw = await readFile7(metaPath, "utf8");
6600
7606
  const parsed = JSON.parse(raw);
6601
7607
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
6602
7608
  const sourceRaw = parsed.sourceRaw;
@@ -6631,7 +7637,7 @@ async function defaultSymlinkRunner(target, linkPath) {
6631
7637
  }
6632
7638
  async function dirExists(p) {
6633
7639
  try {
6634
- const s = await stat3(p);
7640
+ const s = await stat4(p);
6635
7641
  return s.isDirectory();
6636
7642
  } catch {
6637
7643
  return false;
@@ -6648,15 +7654,15 @@ async function inodeKind(p) {
6648
7654
  return "missing";
6649
7655
  }
6650
7656
  }
6651
- async function listDirFilesRecursive(srcDir, dstDir) {
7657
+ async function listDirFilesRecursive2(srcDir, dstDir) {
6652
7658
  const planned = [];
6653
- const entries = await readdir3(srcDir, { withFileTypes: true });
7659
+ const entries = await readdir5(srcDir, { withFileTypes: true });
6654
7660
  for (const entry of entries) {
6655
- const srcPath = join9(srcDir, entry.name);
6656
- const dstPath = join9(dstDir, entry.name);
7661
+ const srcPath = join10(srcDir, entry.name);
7662
+ const dstPath = join10(dstDir, entry.name);
6657
7663
  if (entry.isDirectory()) {
6658
7664
  planned.push(dstPath);
6659
- const sub = await listDirFilesRecursive(srcPath, dstPath);
7665
+ const sub = await listDirFilesRecursive2(srcPath, dstPath);
6660
7666
  planned.push(...sub);
6661
7667
  } else if (entry.isFile()) {
6662
7668
  planned.push(dstPath);
@@ -6666,17 +7672,17 @@ async function listDirFilesRecursive(srcDir, dstDir) {
6666
7672
  }
6667
7673
  async function copyDirTracked(srcDir, dstDir) {
6668
7674
  const written = [];
6669
- const entries = await readdir3(srcDir, { withFileTypes: true });
7675
+ const entries = await readdir5(srcDir, { withFileTypes: true });
6670
7676
  for (const entry of entries) {
6671
- const srcPath = join9(srcDir, entry.name);
6672
- const dstPath = join9(dstDir, entry.name);
7677
+ const srcPath = join10(srcDir, entry.name);
7678
+ const dstPath = join10(dstDir, entry.name);
6673
7679
  if (entry.isDirectory()) {
6674
- await mkdir5(dstPath, { recursive: true });
7680
+ await mkdir6(dstPath, { recursive: true });
6675
7681
  written.push(dstPath);
6676
7682
  const subWritten = await copyDirTracked(srcPath, dstPath);
6677
7683
  written.push(...subWritten);
6678
7684
  } else if (entry.isFile()) {
6679
- await mkdir5(dirname5(dstPath), { recursive: true });
7685
+ await mkdir6(dirname6(dstPath), { recursive: true });
6680
7686
  await copyFile(srcPath, dstPath);
6681
7687
  written.push(dstPath);
6682
7688
  }
@@ -6687,7 +7693,7 @@ async function writeAtomicWithMtimeCheck(filePath, data, expectedMtimeMs) {
6687
7693
  if (expectedMtimeMs !== null) {
6688
7694
  let currentMtime = null;
6689
7695
  try {
6690
- const s = await stat3(filePath);
7696
+ const s = await stat4(filePath);
6691
7697
  currentMtime = s.mtimeMs;
6692
7698
  } catch {
6693
7699
  currentMtime = null;
@@ -6710,20 +7716,20 @@ async function retryOnConflict(fn) {
6710
7716
  }
6711
7717
 
6712
7718
  // src/installers/cursor/installer.ts
6713
- import { randomUUID as randomUUID5 } from "crypto";
7719
+ import { randomUUID as randomUUID6 } from "crypto";
6714
7720
  import { constants as fsConstants7 } from "fs";
6715
7721
  import {
6716
7722
  access as access7,
6717
- cp as cp2,
6718
- mkdir as mkdir7,
6719
- readFile as readFile9,
6720
- rename as rename5,
6721
- rm as rm8,
6722
- stat as stat5,
6723
- 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
6724
7730
  } from "fs/promises";
6725
- import { homedir as homedir11 } from "os";
6726
- 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";
6727
7733
 
6728
7734
  // src/installers/cursor/marker.ts
6729
7735
  var RUSH_AI_MARKER = "<!-- rush-ai:auto-generated -->";
@@ -6732,18 +7738,18 @@ function hasRushAiMarker(fileContent) {
6732
7738
  }
6733
7739
 
6734
7740
  // src/installers/cursor/mcp.ts
6735
- import { randomUUID as randomUUID4 } from "crypto";
7741
+ import { randomUUID as randomUUID5 } from "crypto";
6736
7742
  import { constants as fsConstants6 } from "fs";
6737
7743
  import {
6738
7744
  access as access6,
6739
- mkdir as mkdir6,
6740
- readFile as readFile7,
6741
- rename as rename4,
6742
- rm as rm7,
6743
- stat as stat4,
6744
- 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
6745
7751
  } from "fs/promises";
6746
- import { dirname as dirname6 } from "path";
7752
+ import { dirname as dirname7 } from "path";
6747
7753
  async function readCursorMcpJson(filePath) {
6748
7754
  return (await readCursorMcpJsonWithMtime(filePath)).data;
6749
7755
  }
@@ -6751,8 +7757,8 @@ async function readCursorMcpJsonWithMtime(filePath) {
6751
7757
  if (!await pathExists5(filePath)) {
6752
7758
  return { data: {}, mtimeMs: null };
6753
7759
  }
6754
- const stats = await stat4(filePath);
6755
- const raw = await readFile7(filePath, "utf8");
7760
+ const stats = await stat5(filePath);
7761
+ const raw = await readFile8(filePath, "utf8");
6756
7762
  let parsed;
6757
7763
  try {
6758
7764
  parsed = JSON.parse(raw);
@@ -6781,10 +7787,16 @@ function mergeMcpServers(current, additions) {
6781
7787
  cloned.mcpServers = {};
6782
7788
  }
6783
7789
  for (const [key, config] of Object.entries(additions)) {
6784
- cloned.mcpServers[key] = toCursorStdioEntry(config);
7790
+ cloned.mcpServers[key] = toCursorMcpEntry(config);
6785
7791
  }
6786
7792
  return cloned;
6787
7793
  }
7794
+ function toCursorMcpEntry(config) {
7795
+ if (typeof config.command === "string") {
7796
+ return toCursorStdioEntry({ ...config, command: config.command });
7797
+ }
7798
+ return toCursorRemoteOrUnknownEntry(config);
7799
+ }
6788
7800
  function toCursorStdioEntry(config) {
6789
7801
  const entry = {
6790
7802
  type: "stdio",
@@ -6793,7 +7805,7 @@ function toCursorStdioEntry(config) {
6793
7805
  if (config.args !== void 0) entry.args = [...config.args];
6794
7806
  if (config.env !== void 0) entry.env = { ...config.env };
6795
7807
  if (config.cwd !== void 0) entry.cwd = config.cwd;
6796
- const handledKeys = /* @__PURE__ */ new Set(["command", "args", "env", "cwd"]);
7808
+ const handledKeys = /* @__PURE__ */ new Set(["type", "command", "args", "env", "cwd"]);
6797
7809
  const raw = config;
6798
7810
  for (const [key, value] of Object.entries(raw)) {
6799
7811
  if (handledKeys.has(key)) continue;
@@ -6802,6 +7814,18 @@ function toCursorStdioEntry(config) {
6802
7814
  }
6803
7815
  return entry;
6804
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
+ }
6805
7829
  function deepCopyPrimitive(v) {
6806
7830
  if (v === null || typeof v !== "object") return v;
6807
7831
  try {
@@ -6819,15 +7843,15 @@ function removeMcpServers(current, keysToRemove) {
6819
7843
  return cloned;
6820
7844
  }
6821
7845
  async function writeCursorMcpJson(filePath, data) {
6822
- await mkdir6(dirname6(filePath), { recursive: true });
7846
+ await mkdir7(dirname7(filePath), { recursive: true });
6823
7847
  const content = `${JSON.stringify(data, null, 2)}
6824
7848
  `;
6825
- const tmp = `${filePath}.${randomUUID4()}.tmp`;
7849
+ const tmp = `${filePath}.${randomUUID5()}.tmp`;
6826
7850
  try {
6827
- await writeFile5(tmp, content, { encoding: "utf8", flag: "w" });
6828
- await rename4(tmp, filePath);
7851
+ await writeFile6(tmp, content, { encoding: "utf8", flag: "w" });
7852
+ await rename5(tmp, filePath);
6829
7853
  } catch (err) {
6830
- await rm7(tmp, { force: true }).catch(() => {
7854
+ await rm8(tmp, { force: true }).catch(() => {
6831
7855
  });
6832
7856
  throw err;
6833
7857
  }
@@ -6842,25 +7866,25 @@ async function pathExists5(p) {
6842
7866
  }
6843
7867
 
6844
7868
  // src/installers/cursor/paths.ts
6845
- import { resolve as resolve12 } from "path";
7869
+ import { resolve as resolve14 } from "path";
6846
7870
  var CURSOR_RELATIVE_DIR = ".cursor";
6847
7871
  function cursorDir(home) {
6848
- return resolve12(home, CURSOR_RELATIVE_DIR);
7872
+ return resolve14(home, CURSOR_RELATIVE_DIR);
6849
7873
  }
6850
7874
  function cursorMcpJsonPath(home) {
6851
- return resolve12(cursorDir(home), "mcp.json");
7875
+ return resolve14(cursorDir(home), "mcp.json");
6852
7876
  }
6853
7877
  function cursorRulesDir(home) {
6854
- return resolve12(cursorDir(home), "rules");
7878
+ return resolve14(cursorDir(home), "rules");
6855
7879
  }
6856
7880
  function cursorRuleMdcPath(home, ruleName) {
6857
- return resolve12(cursorRulesDir(home), `${ruleName}.mdc`);
7881
+ return resolve14(cursorRulesDir(home), `${ruleName}.mdc`);
6858
7882
  }
6859
7883
  function cursorSkillsDir(home) {
6860
- return resolve12(cursorDir(home), "skills");
7884
+ return resolve14(cursorDir(home), "skills");
6861
7885
  }
6862
7886
  function cursorSkillDir(home, skillName) {
6863
- return resolve12(cursorSkillsDir(home), skillName);
7887
+ return resolve14(cursorSkillsDir(home), skillName);
6864
7888
  }
6865
7889
  function bridgeSkillFileReference(skillName) {
6866
7890
  return `.cursor/skills/${skillName}/SKILL.md`;
@@ -6970,13 +7994,13 @@ function quoteIfNeeded(value) {
6970
7994
  }
6971
7995
 
6972
7996
  // src/installers/cursor/skills.ts
6973
- import { readFile as readFile8 } from "fs/promises";
6974
- import { resolve as resolve13 } from "path";
7997
+ import { readFile as readFile9 } from "fs/promises";
7998
+ import { resolve as resolve15 } from "path";
6975
7999
  async function readSkillDescription(skillSourceDir) {
6976
- const skillMdPath = resolve13(skillSourceDir, "SKILL.md");
8000
+ const skillMdPath = resolve15(skillSourceDir, "SKILL.md");
6977
8001
  let raw;
6978
8002
  try {
6979
- raw = await readFile8(skillMdPath, "utf8");
8003
+ raw = await readFile9(skillMdPath, "utf8");
6980
8004
  } catch {
6981
8005
  return void 0;
6982
8006
  }
@@ -7006,11 +8030,11 @@ async function executeRollback(ledger) {
7006
8030
  if (entry.kind === "restore-file") {
7007
8031
  await atomicWriteFile(entry.path, entry.originalContent);
7008
8032
  } else if (entry.kind === "remove-file") {
7009
- await rm8(entry.path, { force: true });
8033
+ await rm9(entry.path, { force: true });
7010
8034
  } else if (entry.kind === "remove-dir") {
7011
- await rm8(entry.path, { recursive: true, force: true });
8035
+ await rm9(entry.path, { recursive: true, force: true });
7012
8036
  } else {
7013
- await rm8(entry.path, { recursive: true, force: true });
8037
+ await rm9(entry.path, { recursive: true, force: true });
7014
8038
  await safeRename(entry.backupPath, entry.path);
7015
8039
  }
7016
8040
  } catch (err) {
@@ -7022,20 +8046,20 @@ async function executeRollback(ledger) {
7022
8046
  return errors;
7023
8047
  }
7024
8048
  async function atomicWriteFile(filePath, content) {
7025
- await mkdir7(dirname7(filePath), { recursive: true });
7026
- const tmp = `${filePath}.${randomUUID5()}.tmp`;
8049
+ await mkdir8(dirname8(filePath), { recursive: true });
8050
+ const tmp = `${filePath}.${randomUUID6()}.tmp`;
7027
8051
  try {
7028
- await writeFile6(tmp, content, { encoding: "utf8", flag: "w" });
7029
- await rename5(tmp, filePath);
8052
+ await writeFile7(tmp, content, { encoding: "utf8", flag: "w" });
8053
+ await rename6(tmp, filePath);
7030
8054
  } catch (err) {
7031
- await rm8(tmp, { force: true }).catch(() => {
8055
+ await rm9(tmp, { force: true }).catch(() => {
7032
8056
  });
7033
8057
  throw err;
7034
8058
  }
7035
8059
  }
7036
8060
  async function getMcpMtimeMs(filePath) {
7037
8061
  try {
7038
- const s = await stat5(filePath);
8062
+ const s = await stat6(filePath);
7039
8063
  return s.mtimeMs;
7040
8064
  } catch {
7041
8065
  return null;
@@ -7068,7 +8092,7 @@ var CursorInstaller = class {
7068
8092
  target = "cursor";
7069
8093
  home;
7070
8094
  constructor(options = {}) {
7071
- this.home = options.home ?? homedir11();
8095
+ this.home = options.home ?? homedir12();
7072
8096
  }
7073
8097
  // -------------------------------------------------------------------------
7074
8098
  // PluginInstaller 接口
@@ -7268,13 +8292,13 @@ var CursorInstaller = class {
7268
8292
  if (info === "missing") continue;
7269
8293
  if (info === "skill-dir") {
7270
8294
  if (!dryRun) {
7271
- await rm8(filePath, { recursive: true, force: true });
8295
+ await rm9(filePath, { recursive: true, force: true });
7272
8296
  }
7273
8297
  removedFiles.push(filePath);
7274
8298
  continue;
7275
8299
  }
7276
8300
  if (info === "mdc-file") {
7277
- const content = await readFile9(filePath, "utf8").catch(() => "");
8301
+ const content = await readFile10(filePath, "utf8").catch(() => "");
7278
8302
  if (!hasRushAiMarker(content)) {
7279
8303
  warnings.push(
7280
8304
  `${filePath} \u5DF2\u88AB\u4FEE\u6539\uFF08marker \u4E22\u5931\uFF09\uFF0C\u8DF3\u8FC7\u4E0D\u52A8\u2014\u2014\u8BF7\u7528\u6237\u624B\u52A8\u5904\u7406`
@@ -7282,13 +8306,13 @@ var CursorInstaller = class {
7282
8306
  continue;
7283
8307
  }
7284
8308
  if (!dryRun) {
7285
- await rm8(filePath, { force: true });
8309
+ await rm9(filePath, { force: true });
7286
8310
  }
7287
8311
  removedFiles.push(filePath);
7288
8312
  continue;
7289
8313
  }
7290
8314
  if (!dryRun) {
7291
- await rm8(filePath, { force: true });
8315
+ await rm9(filePath, { force: true });
7292
8316
  }
7293
8317
  removedFiles.push(filePath);
7294
8318
  }
@@ -7336,10 +8360,10 @@ var CursorInstaller = class {
7336
8360
  const prevEntry = registryStore.get(plugin.ref);
7337
8361
  const prevFiles = new Set(prevEntry?.targets?.cursor?.files ?? []);
7338
8362
  if (plugin.capabilities.includes("skills")) {
7339
- const skillsSourceDir = resolve14(plugin.sourceDir, "skills");
8363
+ const skillsSourceDir = resolve16(plugin.sourceDir, "skills");
7340
8364
  const skillDirs = await listSkillDirs(skillsSourceDir);
7341
8365
  for (const skillName of skillDirs) {
7342
- const srcDir = resolve14(skillsSourceDir, skillName);
8366
+ const srcDir = resolve16(skillsSourceDir, skillName);
7343
8367
  const destDir = cursorSkillDir(this.home, skillName);
7344
8368
  const bridgeRulePath = cursorRuleMdcPath(this.home, skillName);
7345
8369
  if (await dirExists2(destDir)) {
@@ -7371,10 +8395,10 @@ var CursorInstaller = class {
7371
8395
  }
7372
8396
  }
7373
8397
  if (plugin.capabilities.includes("rules")) {
7374
- const rulesSourceDir = resolve14(plugin.sourceDir, "rules");
8398
+ const rulesSourceDir = resolve16(plugin.sourceDir, "rules");
7375
8399
  const rulesFiles = await listRuleMdFiles(rulesSourceDir);
7376
8400
  for (const ruleFile of rulesFiles) {
7377
- const srcPath = resolve14(rulesSourceDir, ruleFile);
8401
+ const srcPath = resolve16(rulesSourceDir, ruleFile);
7378
8402
  const ruleName = ruleFile.replace(/\.md$/i, "");
7379
8403
  const destPath = cursorRuleMdcPath(this.home, ruleName);
7380
8404
  await assertMdcWritable(destPath, args.force);
@@ -7383,7 +8407,7 @@ var CursorInstaller = class {
7383
8407
  `rule "${ruleName}" \u4E0E skill "${ruleName}" \u7684 bridge rule \u540C\u540D\uFF0Crule \u5185\u5BB9\u4F1A\u8986\u76D6 bridge rule`
7384
8408
  );
7385
8409
  }
7386
- const src = await readFile9(srcPath, "utf8");
8410
+ const src = await readFile10(srcPath, "utf8");
7387
8411
  const parsed = parseMarkdown(src);
7388
8412
  const content = renderMdc(parsed, {
7389
8413
  descriptionFallback: plugin.manifest.description ?? ruleName
@@ -7411,7 +8435,7 @@ var CursorInstaller = class {
7411
8435
  // -------------------------------------------------------------------------
7412
8436
  async writeSkillDir(args) {
7413
8437
  const preExisted = await dirExists2(args.destDir);
7414
- await mkdir7(dirname7(args.destDir), { recursive: true });
8438
+ await mkdir8(dirname8(args.destDir), { recursive: true });
7415
8439
  if (preExisted) {
7416
8440
  const backup = `${args.destDir}.${process.pid}.${Date.now()}.bak`;
7417
8441
  await safeRename(args.destDir, backup);
@@ -7423,12 +8447,12 @@ var CursorInstaller = class {
7423
8447
  } else {
7424
8448
  args.ledger.push({ kind: "remove-dir", path: args.destDir });
7425
8449
  }
7426
- await cp2(args.srcDir, args.destDir, { recursive: true });
8450
+ await cp3(args.srcDir, args.destDir, { recursive: true });
7427
8451
  }
7428
8452
  async writeMdcFile(args) {
7429
8453
  const preExisted = await fileExists(args.path);
7430
8454
  if (preExisted) {
7431
- const original = await readFile9(args.path, "utf8");
8455
+ const original = await readFile10(args.path, "utf8");
7432
8456
  args.ledger.push({
7433
8457
  kind: "restore-file",
7434
8458
  path: args.path,
@@ -7442,7 +8466,7 @@ var CursorInstaller = class {
7442
8466
  async writeMcpMerge(args) {
7443
8467
  const preExisted = await fileExists(args.mcpPath);
7444
8468
  if (preExisted) {
7445
- const original = await readFile9(args.mcpPath, "utf8");
8469
+ const original = await readFile10(args.mcpPath, "utf8");
7446
8470
  args.ledger.push({
7447
8471
  kind: "restore-file",
7448
8472
  path: args.mcpPath,
@@ -7526,7 +8550,7 @@ function skippedResult() {
7526
8550
  }
7527
8551
  async function assertMdcWritable(path4, force) {
7528
8552
  if (!await fileExists(path4)) return;
7529
- const raw = await readFile9(path4, "utf8").catch(() => "");
8553
+ const raw = await readFile10(path4, "utf8").catch(() => "");
7530
8554
  if (hasRushAiMarker(raw)) return;
7531
8555
  if (force) return;
7532
8556
  throw new CursorInstallConflictError(
@@ -7541,7 +8565,7 @@ async function extractMcpAdditions(plugin) {
7541
8565
  if (typeof m === "object") {
7542
8566
  serverMap = m;
7543
8567
  } else if (typeof m === "string") {
7544
- const { readExternalMcpServers: readExternalMcpServers2 } = await import("./mcp-UZYID3GG.js");
8568
+ const { readExternalMcpServers: readExternalMcpServers2 } = await import("./mcp-TROKQRBF.js");
7545
8569
  serverMap = await readExternalMcpServers2(plugin.sourceDir, m);
7546
8570
  }
7547
8571
  if (!serverMap) return null;
@@ -7555,19 +8579,19 @@ async function extractMcpAdditions(plugin) {
7555
8579
  }
7556
8580
  async function listSkillDirs(skillsDir) {
7557
8581
  if (!await dirExists2(skillsDir)) return [];
7558
- const { readdir: readdir5 } = await import("fs/promises");
7559
- const entries = await readdir5(skillsDir, { withFileTypes: true });
8582
+ const { readdir: readdir7 } = await import("fs/promises");
8583
+ const entries = await readdir7(skillsDir, { withFileTypes: true });
7560
8584
  return entries.filter((e) => e.isDirectory()).map((e) => e.name).filter((name) => !name.startsWith(".")).sort();
7561
8585
  }
7562
8586
  async function listRuleMdFiles(rulesDir) {
7563
8587
  if (!await dirExists2(rulesDir)) return [];
7564
- const { readdir: readdir5 } = await import("fs/promises");
7565
- const entries = await readdir5(rulesDir, { withFileTypes: true });
8588
+ const { readdir: readdir7 } = await import("fs/promises");
8589
+ const entries = await readdir7(rulesDir, { withFileTypes: true });
7566
8590
  return entries.filter((e) => e.isFile() && /\.md$/i.test(e.name)).map((e) => e.name).sort();
7567
8591
  }
7568
8592
  async function dirExists2(p) {
7569
8593
  try {
7570
- const s = await stat5(p);
8594
+ const s = await stat6(p);
7571
8595
  return s.isDirectory();
7572
8596
  } catch {
7573
8597
  return false;
@@ -7576,20 +8600,20 @@ async function dirExists2(p) {
7576
8600
  async function fileExists(p) {
7577
8601
  try {
7578
8602
  await access7(p, fsConstants7.F_OK);
7579
- const s = await stat5(p);
8603
+ const s = await stat6(p);
7580
8604
  return s.isFile();
7581
8605
  } catch {
7582
8606
  return false;
7583
8607
  }
7584
8608
  }
7585
8609
  async function safeRename(from, to) {
7586
- const { rename: rename7 } = await import("fs/promises");
7587
- await rename7(from, to);
8610
+ const { rename: rename8 } = await import("fs/promises");
8611
+ await rename8(from, to);
7588
8612
  }
7589
8613
  async function classifyArtifactPath(p) {
7590
8614
  let s;
7591
8615
  try {
7592
- s = await stat5(p);
8616
+ s = await stat6(p);
7593
8617
  } catch {
7594
8618
  return "missing";
7595
8619
  }
@@ -7602,14 +8626,14 @@ async function classifyArtifactPath(p) {
7602
8626
  }
7603
8627
 
7604
8628
  // src/migration/cleanup.ts
7605
- import { lstat as lstat3, rm as rm9, unlink as unlink2 } from "fs/promises";
7606
- import { homedir as homedir13 } from "os";
7607
- 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";
7608
8632
 
7609
8633
  // src/migration/detect.ts
7610
- import { access as access8, lstat as lstat2, readFile as readFile10, readlink as readlink2, stat as stat6 } from "fs/promises";
7611
- import { homedir as homedir12 } from "os";
7612
- 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";
7613
8637
  var LEGACY_ASSET_MANIFEST_RELATIVE = ".rush/plugins/claude-code/asset-manifest.json";
7614
8638
  var LEGACY_ASSETS_DIR_RELATIVE = ".rush/plugins/claude-code/assets";
7615
8639
  var LEGACY_CLAUDE_CODE_DIR_RELATIVE = ".rush/plugins/claude-code";
@@ -7628,7 +8652,7 @@ async function isSymlinkPointingInto(linkPath, expectedTarget) {
7628
8652
  const lst = await lstat2(linkPath);
7629
8653
  if (!lst.isSymbolicLink()) return false;
7630
8654
  const rawTarget = await readlink2(linkPath);
7631
- const resolvedTarget = isAbsolute3(rawTarget) ? rawTarget : resolve15(linkPath, "..", rawTarget);
8655
+ const resolvedTarget = isAbsolute3(rawTarget) ? rawTarget : resolve17(linkPath, "..", rawTarget);
7632
8656
  return resolvedTarget === expectedTarget || resolvedTarget.startsWith(`${expectedTarget}/`);
7633
8657
  } catch {
7634
8658
  return false;
@@ -7637,7 +8661,7 @@ async function isSymlinkPointingInto(linkPath, expectedTarget) {
7637
8661
  async function hasLegacyMcpWithoutEnabled(settingsJsonPath) {
7638
8662
  try {
7639
8663
  if (!await pathExists6(settingsJsonPath)) return false;
7640
- const raw = await readFile10(settingsJsonPath, "utf8");
8664
+ const raw = await readFile11(settingsJsonPath, "utf8");
7641
8665
  let parsed;
7642
8666
  try {
7643
8667
  parsed = JSON.parse(raw);
@@ -7664,11 +8688,11 @@ async function hasLegacyMcpWithoutEnabled(settingsJsonPath) {
7664
8688
  }
7665
8689
  }
7666
8690
  async function detectLegacyInstall(opts = {}) {
7667
- const home = opts.home ?? homedir12();
7668
- const assetManifestPath = resolve15(home, LEGACY_ASSET_MANIFEST_RELATIVE);
7669
- const legacyAssetsDir = resolve15(home, LEGACY_ASSETS_DIR_RELATIVE);
7670
- const skillSymlinkPath = resolve15(home, LEGACY_SKILL_SYMLINK_RELATIVE);
7671
- 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);
7672
8696
  const [hasAssetManifest, hasLegacySkillSymlink, legacyMcpWithoutEnabled] = await Promise.all([
7673
8697
  pathExists6(assetManifestPath),
7674
8698
  isSymlinkPointingInto(skillSymlinkPath, legacyAssetsDir),
@@ -7682,12 +8706,12 @@ async function detectLegacyInstall(opts = {}) {
7682
8706
  };
7683
8707
  }
7684
8708
  async function detectLegacyVersion(opts = {}) {
7685
- const home = opts.home ?? homedir12();
7686
- const manifestPath = resolve15(home, LEGACY_ASSET_MANIFEST_RELATIVE);
8709
+ const home = opts.home ?? homedir13();
8710
+ const manifestPath = resolve17(home, LEGACY_ASSET_MANIFEST_RELATIVE);
7687
8711
  try {
7688
- const lst = await stat6(manifestPath);
8712
+ const lst = await stat7(manifestPath);
7689
8713
  if (!lst.isFile()) return "0.7.x";
7690
- const raw = await readFile10(manifestPath, "utf8");
8714
+ const raw = await readFile11(manifestPath, "utf8");
7691
8715
  const parsed = JSON.parse(raw);
7692
8716
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
7693
8717
  const v = parsed.version;
@@ -7701,9 +8725,9 @@ async function detectLegacyVersion(opts = {}) {
7701
8725
 
7702
8726
  // src/migration/cleanup.ts
7703
8727
  async function cleanupLegacyDir(home) {
7704
- const dir = resolve16(home, LEGACY_CLAUDE_CODE_DIR_RELATIVE);
8728
+ const dir = resolve18(home, LEGACY_CLAUDE_CODE_DIR_RELATIVE);
7705
8729
  try {
7706
- await rm9(dir, { recursive: true, force: true });
8730
+ await rm10(dir, { recursive: true, force: true });
7707
8731
  return { ok: true };
7708
8732
  } catch (err) {
7709
8733
  return {
@@ -7713,7 +8737,7 @@ async function cleanupLegacyDir(home) {
7713
8737
  }
7714
8738
  }
7715
8739
  async function cleanupLegacySymlink(home) {
7716
- const path4 = resolve16(home, LEGACY_SKILL_SYMLINK_RELATIVE);
8740
+ const path4 = resolve18(home, LEGACY_SKILL_SYMLINK_RELATIVE);
7717
8741
  try {
7718
8742
  let lst;
7719
8743
  try {
@@ -7735,7 +8759,7 @@ async function cleanupLegacySymlink(home) {
7735
8759
  }
7736
8760
  }
7737
8761
  async function cleanupLegacyMcp(home) {
7738
- const path4 = resolve16(home, CLAUDE_SETTINGS_JSON_RELATIVE);
8762
+ const path4 = resolve18(home, CLAUDE_SETTINGS_JSON_RELATIVE);
7739
8763
  try {
7740
8764
  const { data, existed } = await readJsonFile(
7741
8765
  path4,
@@ -7763,7 +8787,7 @@ async function cleanupLegacyMcp(home) {
7763
8787
  }
7764
8788
  }
7765
8789
  async function cleanupLegacyInstall(opts = {}) {
7766
- const home = opts.home ?? homedir13();
8790
+ const home = opts.home ?? homedir14();
7767
8791
  const legacyDir = await cleanupLegacyDir(home);
7768
8792
  const skillSymlink = await cleanupLegacySymlink(home);
7769
8793
  const settingsMcp = await cleanupLegacyMcp(home);
@@ -7791,13 +8815,13 @@ function errorMessage(err) {
7791
8815
  }
7792
8816
 
7793
8817
  // src/migration/log.ts
7794
- import { appendFile as appendFile2, mkdir as mkdir8 } from "fs/promises";
7795
- import { homedir as homedir14 } from "os";
7796
- 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";
7797
8821
  var MIGRATION_LOG_RELATIVE_PATH = ".rush/plugins/migration-failed.log";
7798
8822
  function resolveMigrationLogPath(opts = {}) {
7799
- const home = opts.home ?? homedir14();
7800
- return resolve17(home, MIGRATION_LOG_RELATIVE_PATH);
8823
+ const home = opts.home ?? homedir15();
8824
+ return resolve19(home, MIGRATION_LOG_RELATIVE_PATH);
7801
8825
  }
7802
8826
  async function appendMigrationFailure(reason, opts = {}) {
7803
8827
  const now = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
@@ -7814,20 +8838,20 @@ async function appendMigrationFailure(reason, opts = {}) {
7814
8838
  const payload = `${lines.join("\n")}
7815
8839
  `;
7816
8840
  try {
7817
- await mkdir8(dirname8(logPath), { recursive: true });
8841
+ await mkdir9(dirname9(logPath), { recursive: true });
7818
8842
  await appendFile2(logPath, payload, { encoding: "utf8" });
7819
8843
  } catch {
7820
8844
  }
7821
8845
  }
7822
8846
 
7823
8847
  // src/migration/migrate.ts
7824
- import { access as access11, readFile as readFile12 } from "fs/promises";
7825
- import { homedir as homedir16 } from "os";
8848
+ import { access as access11, readFile as readFile13 } from "fs/promises";
8849
+ import { homedir as homedir17 } from "os";
7826
8850
 
7827
8851
  // src/plugins/resolver.ts
7828
- import { randomUUID as randomUUID6 } from "crypto";
7829
- import { mkdir as mkdir9, rename as rename6, rm as rm10 } from "fs/promises";
7830
- 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";
7831
8855
  import {
7832
8856
  isAbsolute as isAbsolute4,
7833
8857
  relative as pathRelative2,
@@ -7837,8 +8861,8 @@ import {
7837
8861
 
7838
8862
  // src/plugins/capabilities.ts
7839
8863
  import { constants as fsConstants8 } from "fs";
7840
- import { access as access9, readdir as readdir4, stat as stat7 } from "fs/promises";
7841
- 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";
7842
8866
  var CAPABILITY_ORDER = [
7843
8867
  "commands",
7844
8868
  "skills",
@@ -7867,20 +8891,20 @@ async function scanCapabilities(sourceDir, manifest) {
7867
8891
  return CAPABILITY_ORDER.filter((cap) => found.has(cap));
7868
8892
  }
7869
8893
  async function hasCommands(sourceDir) {
7870
- return dirHasFileWithExt(resolve18(sourceDir, "commands"), ".md");
8894
+ return dirHasFileWithExt(resolve20(sourceDir, "commands"), ".md");
7871
8895
  }
7872
8896
  async function hasSkills(sourceDir) {
7873
- const skillsDir = resolve18(sourceDir, "skills");
8897
+ const skillsDir = resolve20(sourceDir, "skills");
7874
8898
  if (await dirExists3(skillsDir)) {
7875
8899
  let entries;
7876
8900
  try {
7877
- entries = await readdir4(skillsDir, { withFileTypes: true });
8901
+ entries = await readdir6(skillsDir, { withFileTypes: true });
7878
8902
  } catch {
7879
8903
  return false;
7880
8904
  }
7881
8905
  for (const entry of entries) {
7882
8906
  if (!entry.isDirectory()) continue;
7883
- const skillMdPath = resolve18(skillsDir, entry.name, "SKILL.md");
8907
+ const skillMdPath = resolve20(skillsDir, entry.name, "SKILL.md");
7884
8908
  if (await fileExists2(skillMdPath)) {
7885
8909
  return true;
7886
8910
  }
@@ -7889,16 +8913,16 @@ async function hasSkills(sourceDir) {
7889
8913
  return hasClaudeStyleSkills(sourceDir);
7890
8914
  }
7891
8915
  async function hasRules(sourceDir) {
7892
- return dirHasFileWithExt(resolve18(sourceDir, "rules"), ".md");
8916
+ return dirHasFileWithExt(resolve20(sourceDir, "rules"), ".md");
7893
8917
  }
7894
8918
  async function hasHooks(sourceDir) {
7895
- const hooksDir = resolve18(sourceDir, "hooks");
8919
+ const hooksDir = resolve20(sourceDir, "hooks");
7896
8920
  if (!await dirExists3(hooksDir)) {
7897
8921
  return false;
7898
8922
  }
7899
8923
  let entries;
7900
8924
  try {
7901
- entries = await readdir4(hooksDir, { withFileTypes: true });
8925
+ entries = await readdir6(hooksDir, { withFileTypes: true });
7902
8926
  } catch {
7903
8927
  return false;
7904
8928
  }
@@ -7924,7 +8948,7 @@ async function dirHasFileWithExt(dirPath, ext) {
7924
8948
  }
7925
8949
  let entries;
7926
8950
  try {
7927
- entries = await readdir4(dirPath, { withFileTypes: true });
8951
+ entries = await readdir6(dirPath, { withFileTypes: true });
7928
8952
  } catch {
7929
8953
  return false;
7930
8954
  }
@@ -7934,19 +8958,19 @@ async function dirHasFileWithExt(dirPath, ext) {
7934
8958
  );
7935
8959
  }
7936
8960
  async function hasClaudeStyleSkills(sourceDir) {
7937
- const dotSkillsDir = resolve18(sourceDir, ".skills");
8961
+ const dotSkillsDir = resolve20(sourceDir, ".skills");
7938
8962
  if (!await dirExists3(dotSkillsDir)) {
7939
8963
  return false;
7940
8964
  }
7941
8965
  async function walk2(dirPath) {
7942
8966
  let entries;
7943
8967
  try {
7944
- entries = await readdir4(dirPath, { withFileTypes: true });
8968
+ entries = await readdir6(dirPath, { withFileTypes: true });
7945
8969
  } catch {
7946
8970
  return false;
7947
8971
  }
7948
8972
  for (const entry of entries) {
7949
- const abs = resolve18(dirPath, entry.name);
8973
+ const abs = resolve20(dirPath, entry.name);
7950
8974
  if (entry.isDirectory()) {
7951
8975
  if (await walk2(abs)) return true;
7952
8976
  continue;
@@ -7961,7 +8985,7 @@ async function hasClaudeStyleSkills(sourceDir) {
7961
8985
  }
7962
8986
  async function dirExists3(p) {
7963
8987
  try {
7964
- const s = await stat7(p);
8988
+ const s = await stat8(p);
7965
8989
  return s.isDirectory();
7966
8990
  } catch {
7967
8991
  return false;
@@ -7970,7 +8994,7 @@ async function dirExists3(p) {
7970
8994
  async function fileExists2(p) {
7971
8995
  try {
7972
8996
  await access9(p, fsConstants8.R_OK);
7973
- const s = await stat7(p);
8997
+ const s = await stat8(p);
7974
8998
  return s.isFile();
7975
8999
  } catch {
7976
9000
  return false;
@@ -8040,17 +9064,17 @@ var PluginCloneFailedError = class extends PluginResolverError {
8040
9064
 
8041
9065
  // src/plugins/manifest.ts
8042
9066
  import { constants as fsConstants9 } from "fs";
8043
- import { access as access10, readFile as readFile11 } from "fs/promises";
8044
- import { resolve as resolve19 } from "path";
9067
+ import { access as access10, readFile as readFile12 } from "fs/promises";
9068
+ import { resolve as resolve21 } from "path";
8045
9069
  var PLUGIN_MANIFEST_RELATIVE_PATH = ".claude-plugin/plugin.json";
8046
9070
  async function readPluginManifest(pluginName, sourceDir) {
8047
- const manifestPath = resolve19(sourceDir, PLUGIN_MANIFEST_RELATIVE_PATH);
9071
+ const manifestPath = resolve21(sourceDir, PLUGIN_MANIFEST_RELATIVE_PATH);
8048
9072
  try {
8049
9073
  await access10(manifestPath, fsConstants9.R_OK);
8050
9074
  } catch {
8051
9075
  throw new PluginManifestNotFoundError(pluginName, manifestPath);
8052
9076
  }
8053
- const raw = await readFile11(manifestPath, "utf8");
9077
+ const raw = await readFile12(manifestPath, "utf8");
8054
9078
  return parsePluginManifest(pluginName, raw, manifestPath);
8055
9079
  }
8056
9080
  function parsePluginManifest(pluginName, raw, sourcePathForError) {
@@ -8265,7 +9289,7 @@ function pluginCacheDir(marketplaceName, pluginName) {
8265
9289
  assertSafePathComponent(marketplaceName, "marketplace name");
8266
9290
  assertSafePathComponent(pluginName, "plugin name");
8267
9291
  return pathResolve(
8268
- homedir15(),
9292
+ homedir16(),
8269
9293
  ".rush",
8270
9294
  "plugin-cache",
8271
9295
  marketplaceName,
@@ -8300,8 +9324,8 @@ async function ensurePluginCloned(ref, marketplace, entry, opts) {
8300
9324
  }
8301
9325
  const git = opts?.runner ?? defaultGitRunner;
8302
9326
  const parent = pathResolve(cacheDir, "..");
8303
- await mkdir9(parent, { recursive: true });
8304
- const tmpDir = `${cacheDir}.${randomUUID6()}.tmp`;
9327
+ await mkdir10(parent, { recursive: true });
9328
+ const tmpDir = `${cacheDir}.${randomUUID7()}.tmp`;
8305
9329
  try {
8306
9330
  const args = ["clone", "--depth", "1"];
8307
9331
  if (typeof src.ref === "string" && src.ref.length > 0) {
@@ -8327,16 +9351,16 @@ async function ensurePluginCloned(ref, marketplace, entry, opts) {
8327
9351
  }
8328
9352
  }
8329
9353
  try {
8330
- await rename6(tmpDir, cacheDir);
9354
+ await rename7(tmpDir, cacheDir);
8331
9355
  } catch (err) {
8332
9356
  if (err.code === "ENOTEMPTY" && await pathExists3(cacheDir)) {
8333
- await rm10(tmpDir, { recursive: true, force: true });
9357
+ await rm11(tmpDir, { recursive: true, force: true });
8334
9358
  return;
8335
9359
  }
8336
9360
  throw err;
8337
9361
  }
8338
9362
  } catch (err) {
8339
- await rm10(tmpDir, { recursive: true, force: true }).catch(() => {
9363
+ await rm11(tmpDir, { recursive: true, force: true }).catch(() => {
8340
9364
  });
8341
9365
  if (err instanceof PluginSourceUnresolvableError) throw err;
8342
9366
  throw new PluginCloneFailedError(ref.name, marketplace.name, err);
@@ -8347,7 +9371,7 @@ async function ensurePluginCloned(ref, marketplace, entry, opts) {
8347
9371
  var LEGACY_MIGRATION_KEY = "legacy-rush-0.7.x";
8348
9372
  var SKIP_MIGRATION_ENV = "RUSH_SKIP_MIGRATION";
8349
9373
  async function maybeRunMigration(input) {
8350
- const home = input.home ?? homedir16();
9374
+ const home = input.home ?? homedir17();
8351
9375
  const now = input.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
8352
9376
  const envGet = input.env ?? ((key) => process.env[key]);
8353
9377
  const reporter = input.reporter ?? {};
@@ -8575,7 +9599,7 @@ async function verifyNewFormat(manifestPath, expectedName, _expectedVersion) {
8575
9599
  }
8576
9600
  let raw;
8577
9601
  try {
8578
- raw = await readFile12(manifestPath, "utf8");
9602
+ raw = await readFile13(manifestPath, "utf8");
8579
9603
  } catch (err) {
8580
9604
  return {
8581
9605
  ok: false,
@@ -8651,18 +9675,22 @@ var DEFAULT_TARGETS2 = [
8651
9675
  "codex",
8652
9676
  "cursor"
8653
9677
  ];
8654
- var VALID_TARGETS = new Set(DEFAULT_TARGETS2);
8655
- 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) {
8656
9684
  if (raw === void 0 || raw.trim().length === 0) {
8657
- return [...DEFAULT_TARGETS2];
9685
+ return [...defaultTargets];
8658
9686
  }
8659
9687
  const segments = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
8660
9688
  const seen = /* @__PURE__ */ new Set();
8661
9689
  const out = [];
8662
9690
  for (const seg of segments) {
8663
- if (!VALID_TARGETS.has(seg)) {
9691
+ if (!VALID_TARGET_SET.has(seg)) {
8664
9692
  throw new RushError(
8665
- `Invalid --target '${seg}'. Expected one of: ${[...DEFAULT_TARGETS2].join(", ")}`,
9693
+ `Invalid --target '${seg}'. Expected one of: ${[...VALID_TARGETS].join(", ")}`,
8666
9694
  { raw: seg },
8667
9695
  "INVALID_TARGET",
8668
9696
  2
@@ -8675,10 +9703,60 @@ function parseTargets2(raw) {
8675
9703
  }
8676
9704
  }
8677
9705
  if (out.length === 0) {
8678
- 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
+ }
8679
9754
  }
8680
9755
  return out;
8681
9756
  }
9757
+ function isInstallTarget(value) {
9758
+ return VALID_TARGET_SET.has(value);
9759
+ }
8682
9760
  async function parsePluginRef(raw, cache) {
8683
9761
  const trimmed = raw.trim();
8684
9762
  if (trimmed.length === 0) {
@@ -8785,6 +9863,20 @@ function defaultInstallerFactory(target, opts = {}) {
8785
9863
  };
8786
9864
  return new CodexInstaller(cxOpts);
8787
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
+ }
8788
9880
  default: {
8789
9881
  const _exhaustive = target;
8790
9882
  void _exhaustive;
@@ -8842,6 +9934,9 @@ function claudeMarketplaceSourceFrom(marketplace) {
8842
9934
  return void 0;
8843
9935
  }
8844
9936
  }
9937
+ function claude3pMarketplaceSourceFrom(marketplace) {
9938
+ return { rootDir: marketplace.rootDir };
9939
+ }
8845
9940
  function buildRegistryEntry(plugin, results, nowIso) {
8846
9941
  const nonSkipped = results.filter((r) => r.status !== "skipped");
8847
9942
  if (nonSkipped.length === 0) {
@@ -8908,7 +10003,11 @@ async function runInstall(input) {
8908
10003
  const dryRun = input.dryRun === true;
8909
10004
  const now = input.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
8910
10005
  const cache = input.cache ?? new MarketplaceCache(input.home !== void 0 ? { home: input.home } : {});
10006
+ output.dim(` Resolving plugin reference: ${input.ref}`);
8911
10007
  const ref = await parsePluginRef(input.ref, cache);
10008
+ output.dim(
10009
+ ` Loading marketplace '${ref.marketplace}' for plugin '${ref.name}'`
10010
+ );
8912
10011
  let marketplace;
8913
10012
  try {
8914
10013
  marketplace = await cache.get(ref.marketplace);
@@ -8916,6 +10015,7 @@ async function runInstall(input) {
8916
10015
  if (err instanceof MarketplaceNotFoundError) {
8917
10016
  if (ref.marketplace === "rush" || ref.marketplace === "rush-marketplace") {
8918
10017
  const apiHost = getGlobalConfig().api.replace(/^https?:\/\//, "");
10018
+ output.dim(` Registering Rush marketplace from ${apiHost}`);
8919
10019
  const rushSource = parseSource(`rush://${apiHost}`);
8920
10020
  await cache.add(rushSource, { as: ref.marketplace });
8921
10021
  marketplace = await cache.get(ref.marketplace);
@@ -8949,6 +10049,7 @@ Try:
8949
10049
  const cacheEntry = cacheList.find((m) => m.name === ref.marketplace);
8950
10050
  const isStale = cacheEntry?.cachedAt ? Date.now() - new Date(cacheEntry.cachedAt).getTime() > TWENTY_FOUR_HOURS : false;
8951
10051
  if (entryMissing || isStale) {
10052
+ output.dim(` Refreshing marketplace '${ref.marketplace}'`);
8952
10053
  marketplace = await cache.update(ref.marketplace);
8953
10054
  }
8954
10055
  if (!marketplace.manifest.plugins.some((p) => p.name === ref.name)) {
@@ -8961,8 +10062,8 @@ Try:
8961
10062
  }
8962
10063
  }
8963
10064
  if (marketplace.source.kind === "rush") {
8964
- const pluginDir = resolve20(marketplace.rootDir, "plugins", ref.name);
8965
- 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");
8966
10067
  const alreadyMaterialized = await pathExists3(manifestPath);
8967
10068
  const hasNewSecrets = input.secrets && Object.keys(input.secrets).length > 0;
8968
10069
  const shouldMaterialize = !alreadyMaterialized || force || hasNewSecrets;
@@ -8977,6 +10078,7 @@ Try:
8977
10078
  if (shouldMaterialize && !dryRun) {
8978
10079
  const rushSource = marketplace.source;
8979
10080
  const token = getAuthToken();
10081
+ output.dim(` Fetching plugin manifest: ${ref.name}@${ref.marketplace}`);
8980
10082
  let apiManifest;
8981
10083
  try {
8982
10084
  apiManifest = await fetchRushPlugin(rushSource, ref.name, { token });
@@ -9008,6 +10110,9 @@ Try:
9008
10110
  secrets = { ...prompted, ...presetSecrets };
9009
10111
  }
9010
10112
  try {
10113
+ output.dim(
10114
+ ` Downloading plugin assets: ${ref.name}@${ref.marketplace}`
10115
+ );
9011
10116
  await materializeRushPlugin(rushSource, ref.name, pluginDir, {
9012
10117
  token,
9013
10118
  secrets
@@ -9028,7 +10133,7 @@ Try:
9028
10133
  if (force && !dryRun) {
9029
10134
  const entry = marketplace.manifest.plugins.find((p) => p.name === ref.name);
9030
10135
  if (entry && hasUrlSource(entry)) {
9031
- await rm11(pluginCacheDir(ref.marketplace, ref.name), {
10136
+ await rm12(pluginCacheDir(ref.marketplace, ref.name), {
9032
10137
  recursive: true,
9033
10138
  force: true
9034
10139
  });
@@ -9037,6 +10142,9 @@ Try:
9037
10142
  const resolveFn = input.resolvePluginFn ?? resolvePlugin;
9038
10143
  let plugin;
9039
10144
  try {
10145
+ output.dim(
10146
+ ` Reading local plugin package: ${ref.name}@${ref.marketplace}`
10147
+ );
9040
10148
  plugin = await resolveFn(ref, marketplace, { dryRun });
9041
10149
  } catch (err) {
9042
10150
  if (err instanceof PluginNotFoundInMarketplaceError && marketplace.source.kind === "rush") {
@@ -9111,6 +10219,12 @@ Try:
9111
10219
  claudeMarketplaceSource: claudeMarketplaceSourceFrom(
9112
10220
  opts.marketplace
9113
10221
  )
10222
+ } : {},
10223
+ ...target === "claude-3p" ? {
10224
+ claude3pMarketplaceSource: claude3pMarketplaceSourceFrom(
10225
+ opts.marketplace
10226
+ ),
10227
+ ...input.claude3pAccount !== void 0 ? { claude3pAccount: input.claude3pAccount } : {}
9114
10228
  } : {}
9115
10229
  }));
9116
10230
  const installer = factory(t, {
@@ -9160,9 +10274,9 @@ Try:
9160
10274
  try {
9161
10275
  const [{ syncCodexMarketplaceMirror: syncCodexMarketplaceMirror2 }, { pickContentLoader: pickContentLoader2 }] = await Promise.all([
9162
10276
  import("./mirror-SQ6GNVP5.js"),
9163
- import("./_codex-content-loader-EXSX7ZGI.js")
10277
+ import("./_codex-content-loader-WAPA56U3.js")
9164
10278
  ]);
9165
- await syncCodexMarketplaceMirror2(input.home ?? homedir17(), marketplace, {
10279
+ await syncCodexMarketplaceMirror2(input.home ?? homedir18(), marketplace, {
9166
10280
  contentLoader: pickContentLoader2(marketplace)
9167
10281
  });
9168
10282
  } catch (err) {
@@ -9208,7 +10322,7 @@ function formatRegistryError(err) {
9208
10322
  }
9209
10323
  function registerInstallCommand(group, _root) {
9210
10324
  group.command("install").description(
9211
- "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)"
9212
10326
  ).argument("<ref>", "plugin reference: <name> or <name>@<marketplace>").option(
9213
10327
  "--target <list>",
9214
10328
  `comma-separated targets (default: ${[...DEFAULT_TARGETS2].join(",")})`
@@ -9322,6 +10436,8 @@ function targetDisplayName(t) {
9322
10436
  return "Codex";
9323
10437
  case "cursor":
9324
10438
  return "Cursor";
10439
+ case "claude-3p":
10440
+ return "Claude-3p";
9325
10441
  default: {
9326
10442
  const _exhaustive = t;
9327
10443
  void _exhaustive;
@@ -9337,6 +10453,8 @@ function nextStepFor(t) {
9337
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";
9338
10454
  case "cursor":
9339
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";
9340
10458
  default:
9341
10459
  return "restart the IDE";
9342
10460
  }
@@ -9344,11 +10462,14 @@ function nextStepFor(t) {
9344
10462
 
9345
10463
  // src/commands/plugin/list.ts
9346
10464
  async function runList2(input = {}) {
9347
- const targets = parseTargets2(input.targetRaw);
9348
10465
  const cache = input.cache ?? new MarketplaceCache(input.home !== void 0 ? { home: input.home } : {});
9349
10466
  const registry = input.registry ?? await RushRegistryStore.load(
9350
10467
  input.home !== void 0 ? { home: input.home } : {}
9351
10468
  );
10469
+ const targets = parseTargets2(
10470
+ input.targetRaw,
10471
+ maintenanceTargetsFromRegistry(registry)
10472
+ );
9352
10473
  if (input.available) {
9353
10474
  return runAvailable(cache, registry, targets);
9354
10475
  }
@@ -9495,16 +10616,15 @@ function statusIcon2(status) {
9495
10616
 
9496
10617
  // src/commands/plugin/uninstall.ts
9497
10618
  async function runUninstall(input) {
9498
- const targets = parseTargets2(input.targetRaw);
9499
10619
  const targetExplicit = input.targetExplicit ?? input.targetRaw !== void 0;
9500
10620
  const dryRun = input.dryRun === true;
10621
+ const registry = input.registry ?? await RushRegistryStore.load(
10622
+ input.home !== void 0 ? { home: input.home } : {}
10623
+ );
9501
10624
  const cache = input.cache ?? new MarketplaceCache(input.home !== void 0 ? { home: input.home } : {});
9502
10625
  const ref = await parsePluginRef(input.ref, cache).catch(async (err) => {
9503
10626
  if (err instanceof RushError && err.code === "PLUGIN_NOT_FOUND") {
9504
- const reg = input.registry ?? await RushRegistryStore.load(
9505
- input.home !== void 0 ? { home: input.home } : {}
9506
- );
9507
- const all = reg.list();
10627
+ const all = registry.list();
9508
10628
  const matches = all.filter(([r]) => r.name === input.ref.trim());
9509
10629
  if (matches.length === 1) {
9510
10630
  const only = matches[0];
@@ -9522,13 +10642,20 @@ async function runUninstall(input) {
9522
10642
  }
9523
10643
  throw err;
9524
10644
  });
10645
+ const targets = parseTargets2(
10646
+ input.targetRaw,
10647
+ maintenanceTargetsForRef(registry, ref)
10648
+ );
10649
+ const claude3pAccount = claude3pAccountFromRegistryEntry(registry.get(ref));
9525
10650
  const results = [];
9526
10651
  for (const t of targets) {
9527
10652
  const factory = input.installerFactory ?? ((target, opts) => defaultInstallerFactory(target, {
9528
- ...opts.home !== void 0 ? { home: opts.home } : {}
10653
+ ...opts.home !== void 0 ? { home: opts.home } : {},
10654
+ ...target === "claude-3p" && claude3pAccount !== void 0 ? { claude3pAccount } : {}
9529
10655
  }));
9530
10656
  const installer = factory(t, {
9531
- ...input.home !== void 0 ? { home: input.home } : {}
10657
+ ...input.home !== void 0 ? { home: input.home } : {},
10658
+ ...t === "claude-3p" && claude3pAccount !== void 0 ? { claude3pAccount } : {}
9532
10659
  });
9533
10660
  try {
9534
10661
  const result = await installer.uninstall(ref, { dryRun });
@@ -9557,11 +10684,8 @@ async function runUninstall(input) {
9557
10684
  let registryError;
9558
10685
  if (!dryRun) {
9559
10686
  try {
9560
- const store = input.registry ?? await RushRegistryStore.load(
9561
- input.home !== void 0 ? { home: input.home } : {}
9562
- );
9563
10687
  const successTargets = results.filter((r) => r.status === "ok").map((r) => r.target);
9564
- await applyUninstallToRegistry(store, ref, successTargets);
10688
+ await applyUninstallToRegistry(registry, ref, successTargets);
9565
10689
  } catch (err) {
9566
10690
  registryError = formatRegistryError2(err);
9567
10691
  }
@@ -9646,6 +10770,16 @@ function printUninstallSummary(result) {
9646
10770
  }
9647
10771
  }
9648
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
+ }
9649
10783
  if (result.registryError) {
9650
10784
  output.newline();
9651
10785
  output.warn(result.registryError);
@@ -9676,6 +10810,8 @@ function targetDisplayName2(t) {
9676
10810
  return "Codex";
9677
10811
  case "cursor":
9678
10812
  return "Cursor";
10813
+ case "claude-3p":
10814
+ return "Claude-3p";
9679
10815
  default: {
9680
10816
  const _exhaustive = t;
9681
10817
  void _exhaustive;
@@ -9686,13 +10822,16 @@ function targetDisplayName2(t) {
9686
10822
 
9687
10823
  // src/commands/plugin/update.ts
9688
10824
  async function runUpdate3(input = {}) {
9689
- const targets = parseTargets2(input.targetRaw);
9690
10825
  const targetExplicit = input.targetExplicit ?? input.targetRaw !== void 0;
9691
10826
  const dryRun = input.dryRun === true;
9692
10827
  const cache = input.cache ?? new MarketplaceCache(input.home !== void 0 ? { home: input.home } : {});
9693
10828
  const registry = input.registry ?? await RushRegistryStore.load(
9694
10829
  input.home !== void 0 ? { home: input.home } : {}
9695
10830
  );
10831
+ const targets = parseTargets2(
10832
+ input.targetRaw,
10833
+ maintenanceTargetsFromRegistry(registry)
10834
+ );
9696
10835
  const refs = await collectRefs(input, cache, registry);
9697
10836
  if (refs.length === 0) {
9698
10837
  return {
@@ -9758,14 +10897,16 @@ async function runUpdate3(input = {}) {
9758
10897
  plugins.push({ ref, fromVersion, toVersion, upToDate: false });
9759
10898
  continue;
9760
10899
  }
10900
+ const claude3pAccount = input.targetRaw === void 0 ? claude3pAccountFromRegistryEntry(registry.get(ref)) : void 0;
9761
10901
  const installInput = {
9762
10902
  ref: `${ref.name}@${ref.marketplace}`,
9763
- ...input.targetRaw !== void 0 ? { targetRaw: input.targetRaw } : {},
10903
+ ...input.targetRaw !== void 0 ? { targetRaw: input.targetRaw } : { targetRaw: maintenanceTargetsForRef(registry, ref).join(",") },
9764
10904
  targetExplicit,
9765
10905
  force: true,
9766
10906
  ...input.home !== void 0 ? { home: input.home } : {},
9767
10907
  cache,
9768
- registry
10908
+ registry,
10909
+ ...claude3pAccount !== void 0 ? { claude3pAccount } : {}
9769
10910
  };
9770
10911
  const result = await installRunner(installInput);
9771
10912
  plugins.push({
@@ -9973,7 +11114,7 @@ function getReskillInvocation() {
9973
11114
  };
9974
11115
  }
9975
11116
  function runReskill(args) {
9976
- return new Promise((resolve23, reject) => {
11117
+ return new Promise((resolve25, reject) => {
9977
11118
  const reskill = getReskillInvocation();
9978
11119
  const child = spawn2(reskill.command, [...reskill.args, ...args], {
9979
11120
  env: createReskillEnv(),
@@ -9983,10 +11124,10 @@ function runReskill(args) {
9983
11124
  child.on("close", (code, signal) => {
9984
11125
  if (signal) {
9985
11126
  output.error(`reskill exited from signal ${signal}`);
9986
- resolve23(1);
11127
+ resolve25(1);
9987
11128
  return;
9988
11129
  }
9989
- resolve23(code ?? 1);
11130
+ resolve25(code ?? 1);
9990
11131
  });
9991
11132
  });
9992
11133
  }
@@ -10060,7 +11201,7 @@ function registerSkillCommand(program) {
10060
11201
 
10061
11202
  // src/commands/task/index.ts
10062
11203
  import { createWriteStream } from "fs";
10063
- 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";
10064
11205
  import path3 from "path";
10065
11206
  import { Readable } from "stream";
10066
11207
  import { pipeline } from "stream/promises";
@@ -10086,13 +11227,13 @@ async function readStdinIfPiped() {
10086
11227
  if (process.stdin.isTTY) {
10087
11228
  return null;
10088
11229
  }
10089
- return new Promise((resolve23, reject) => {
11230
+ return new Promise((resolve25, reject) => {
10090
11231
  const chunks = [];
10091
11232
  process.stdin.on("data", (chunk) => {
10092
11233
  chunks.push(chunk);
10093
11234
  });
10094
11235
  process.stdin.on("end", () => {
10095
- resolve23(Buffer.concat(chunks).toString("utf-8").trim());
11236
+ resolve25(Buffer.concat(chunks).toString("utf-8").trim());
10096
11237
  });
10097
11238
  process.stdin.on("error", reject);
10098
11239
  });
@@ -10293,7 +11434,7 @@ function buildDeployUrl(prefix, env, apiBaseUrl) {
10293
11434
  }
10294
11435
 
10295
11436
  // src/commands/task/push.ts
10296
- import { resolve as resolve21 } from "path";
11437
+ import { resolve as resolve23 } from "path";
10297
11438
  import chalk5 from "chalk";
10298
11439
 
10299
11440
  // src/util/env-file.ts
@@ -10437,7 +11578,7 @@ function registerPushSubcommand(task, program) {
10437
11578
  requireAuth();
10438
11579
  const format = resolveFormat(program.opts());
10439
11580
  const client = createClient();
10440
- const projectPath = resolve21(opts.path);
11581
+ const projectPath = resolve23(opts.path);
10441
11582
  if (format !== "json") {
10442
11583
  output.info("Checking project readiness...");
10443
11584
  }
@@ -10868,7 +12009,7 @@ async function confirmPublish(args) {
10868
12009
  return answer.trim().toLowerCase().startsWith("y");
10869
12010
  }
10870
12011
  function readOneLine() {
10871
- return new Promise((resolve23) => {
12012
+ return new Promise((resolve25) => {
10872
12013
  let acc = "";
10873
12014
  const onData = (chunk) => {
10874
12015
  acc += chunk.toString("utf-8");
@@ -10876,7 +12017,7 @@ function readOneLine() {
10876
12017
  if (nlIdx !== -1) {
10877
12018
  process.stdin.removeListener("data", onData);
10878
12019
  process.stdin.pause();
10879
- resolve23(acc.slice(0, nlIdx));
12020
+ resolve25(acc.slice(0, nlIdx));
10880
12021
  }
10881
12022
  };
10882
12023
  process.stdin.resume();
@@ -11062,12 +12203,12 @@ function registerDomainSubcommand(task, program) {
11062
12203
  }
11063
12204
 
11064
12205
  // src/commands/task/env.ts
11065
- import { resolve as resolve22 } from "path";
12206
+ import { resolve as resolve24 } from "path";
11066
12207
 
11067
12208
  // src/util/prompt.ts
11068
12209
  import { createInterface } from "readline";
11069
12210
  function promptSecret(message) {
11070
- return new Promise((resolve23, reject) => {
12211
+ return new Promise((resolve25, reject) => {
11071
12212
  const rl = createInterface({
11072
12213
  input: process.stdin,
11073
12214
  output: process.stdout,
@@ -11080,7 +12221,7 @@ function promptSecret(message) {
11080
12221
  rl.question("", (answer) => {
11081
12222
  rl.close();
11082
12223
  process.stdout.write("\n");
11083
- resolve23(answer);
12224
+ resolve25(answer);
11084
12225
  });
11085
12226
  rl.on("SIGINT", () => {
11086
12227
  rl.close();
@@ -11103,7 +12244,7 @@ var NO_PROJECT_HINT2 = [
11103
12244
  ].join("\n");
11104
12245
  function resolveProjectId(opts) {
11105
12246
  if (opts.project) return Promise.resolve(opts.project);
11106
- const projectPath = resolve22(opts.path ?? ".");
12247
+ const projectPath = resolve24(opts.path ?? ".");
11107
12248
  const remoteUrl = isGitRepo(projectPath) ? getRemoteUrl(projectPath) : null;
11108
12249
  const idFromRemote = remoteUrl ? extractRushProjectId(remoteUrl) : null;
11109
12250
  if (idFromRemote) return Promise.resolve(idFromRemote);
@@ -11831,7 +12972,7 @@ async function downloadFile(file2, destPath, client) {
11831
12972
  if (!response.body) {
11832
12973
  throw new Error("No response body");
11833
12974
  }
11834
- await mkdir10(path3.dirname(destPath), { recursive: true });
12975
+ await mkdir11(path3.dirname(destPath), { recursive: true });
11835
12976
  const nodeStream = Readable.fromWeb(
11836
12977
  response.body
11837
12978
  );
@@ -12372,7 +13513,7 @@ async function uploadFileForTask(client, localPath) {
12372
13513
  const resolved = path3.resolve(localPath);
12373
13514
  let fileStat;
12374
13515
  try {
12375
- fileStat = await stat8(resolved);
13516
+ fileStat = await stat9(resolved);
12376
13517
  } catch {
12377
13518
  throw new RushError(`File not found: ${localPath}`);
12378
13519
  }
@@ -12386,7 +13527,7 @@ async function uploadFileForTask(client, localPath) {
12386
13527
  }
12387
13528
  const filename = path3.basename(resolved);
12388
13529
  const mediaType = guessMediaType(resolved);
12389
- const buf = await readFile13(resolved);
13530
+ const buf = await readFile14(resolved);
12390
13531
  const blob = new File([buf], filename, { type: mediaType });
12391
13532
  const formData = new FormData();
12392
13533
  formData.append("file", blob);
@@ -12439,9 +13580,9 @@ function registerCommands(program) {
12439
13580
  }
12440
13581
 
12441
13582
  // src/util/update-check.ts
12442
- import { mkdir as mkdir11, readFile as readFile14, writeFile as writeFile7 } from "fs/promises";
12443
- import { homedir as homedir18 } from "os";
12444
- 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";
12445
13586
  var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
12446
13587
  var FETCH_TIMEOUT_MS = 3e3;
12447
13588
  var REGISTRY_URL = "https://registry.npmjs.org/rush-ai/latest";
@@ -12464,19 +13605,19 @@ function isNewerVersion(current, latest) {
12464
13605
  }
12465
13606
  async function writeLastCheck(checkFile) {
12466
13607
  try {
12467
- await mkdir11(dirname9(checkFile), { recursive: true });
12468
- await writeFile7(checkFile, JSON.stringify({ lastCheck: Date.now() }));
13608
+ await mkdir12(dirname10(checkFile), { recursive: true });
13609
+ await writeFile8(checkFile, JSON.stringify({ lastCheck: Date.now() }));
12469
13610
  } catch {
12470
13611
  }
12471
13612
  }
12472
13613
  async function checkForUpdate(currentVersion) {
12473
- const rushDir = join10(homedir18(), ".rush");
12474
- const checkFile = join10(rushDir, "update-check.json");
13614
+ const rushDir = join11(homedir19(), ".rush");
13615
+ const checkFile = join11(rushDir, "update-check.json");
12475
13616
  try {
12476
13617
  if (process.env.CI) return;
12477
13618
  let lastCheck = 0;
12478
13619
  try {
12479
- const data = JSON.parse(await readFile14(checkFile, "utf-8"));
13620
+ const data = JSON.parse(await readFile15(checkFile, "utf-8"));
12480
13621
  lastCheck = data.lastCheck ?? 0;
12481
13622
  } catch {
12482
13623
  }