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/README.md +18 -9
- package/dist/{_codex-content-loader-EXSX7ZGI.js → _codex-content-loader-WAPA56U3.js} +2 -2
- package/dist/{chunk-X45FKY3L.js → chunk-22YQT6XF.js} +18 -7
- package/dist/chunk-22YQT6XF.js.map +1 -0
- package/dist/{chunk-E2CKW6JZ.js → chunk-C7KJUHEF.js} +66 -7
- package/dist/chunk-C7KJUHEF.js.map +1 -0
- package/dist/index.js +1414 -273
- package/dist/index.js.map +1 -1
- package/dist/{mcp-UZYID3GG.js → mcp-TROKQRBF.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-E2CKW6JZ.js.map +0 -1
- package/dist/chunk-X45FKY3L.js.map +0 -1
- /package/dist/{_codex-content-loader-EXSX7ZGI.js.map → _codex-content-loader-WAPA56U3.js.map} +0 -0
- /package/dist/{mcp-UZYID3GG.js.map → mcp-TROKQRBF.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
fetchRushPlugin,
|
|
33
33
|
materializeRushPlugin,
|
|
34
34
|
pickContentLoader
|
|
35
|
-
} from "./chunk-
|
|
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-
|
|
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((
|
|
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
|
-
|
|
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:
|
|
3361
|
-
await
|
|
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
|
|
5554
|
-
import { homedir as
|
|
5555
|
-
import { resolve as
|
|
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
|
|
6564
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
5559
6565
|
import {
|
|
5560
6566
|
copyFile,
|
|
5561
6567
|
lstat,
|
|
5562
|
-
mkdir as
|
|
5563
|
-
readdir as
|
|
5564
|
-
readFile as
|
|
6568
|
+
mkdir as mkdir6,
|
|
6569
|
+
readdir as readdir5,
|
|
6570
|
+
readFile as readFile7,
|
|
5565
6571
|
readlink,
|
|
5566
|
-
rename as
|
|
5567
|
-
rm as
|
|
5568
|
-
stat as
|
|
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
|
|
5573
|
-
import { dirname as
|
|
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
|
|
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
|
|
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
|
|
6600
|
+
return resolve12(this.home, CLAUDE_DIR);
|
|
5595
6601
|
}
|
|
5596
6602
|
/** `<home>/.claude/settings.json` */
|
|
5597
6603
|
get settingsJson() {
|
|
5598
|
-
return
|
|
6604
|
+
return resolve12(this.claudeDir, "settings.json");
|
|
5599
6605
|
}
|
|
5600
6606
|
/** `<home>/.claude/plugins/` */
|
|
5601
6607
|
get pluginsDir() {
|
|
5602
|
-
return
|
|
6608
|
+
return resolve12(this.claudeDir, PLUGINS_SUBDIR);
|
|
5603
6609
|
}
|
|
5604
6610
|
/** `<home>/.claude/plugins/known_marketplaces.json` */
|
|
5605
6611
|
get knownMarketplacesJson() {
|
|
5606
|
-
return
|
|
6612
|
+
return resolve12(this.pluginsDir, "known_marketplaces.json");
|
|
5607
6613
|
}
|
|
5608
6614
|
/** `<home>/.claude/plugins/installed_plugins.json` */
|
|
5609
6615
|
get installedPluginsJson() {
|
|
5610
|
-
return
|
|
6616
|
+
return resolve12(this.pluginsDir, "installed_plugins.json");
|
|
5611
6617
|
}
|
|
5612
6618
|
/** `<home>/.claude/plugins/cache/` */
|
|
5613
6619
|
get cacheDir() {
|
|
5614
|
-
return
|
|
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
|
|
6630
|
+
return resolve12(this.pluginsDir, "marketplaces");
|
|
5625
6631
|
}
|
|
5626
6632
|
/** `<home>/.claude/plugins/marketplaces/<mkt>/` */
|
|
5627
6633
|
marketplaceInstallDir(marketplace) {
|
|
5628
|
-
return
|
|
6634
|
+
return resolve12(this.marketplacesRootDir, marketplace);
|
|
5629
6635
|
}
|
|
5630
6636
|
/** `<home>/.claude/plugins/cache/<mkt>/` */
|
|
5631
6637
|
marketplaceCacheDir(marketplace) {
|
|
5632
|
-
return
|
|
6638
|
+
return resolve12(this.cacheDir, marketplace);
|
|
5633
6639
|
}
|
|
5634
6640
|
/** `<home>/.claude/plugins/cache/<mkt>/<plugin>/` */
|
|
5635
6641
|
pluginCacheDir(ref) {
|
|
5636
|
-
return
|
|
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
|
|
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
|
|
6650
|
+
return resolve12(
|
|
5645
6651
|
this.pluginVersionDir(ref, version),
|
|
5646
|
-
|
|
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
|
|
6657
|
+
return resolve12(this.pluginVersionDir(ref, version), capability);
|
|
5652
6658
|
}
|
|
5653
6659
|
};
|
|
5654
|
-
function
|
|
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 ??
|
|
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?.[
|
|
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 =
|
|
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 =
|
|
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
|
|
6771
|
+
await mkdir6(pluginVersionDir, { recursive: true });
|
|
5766
6772
|
writtenFiles.push(pluginVersionDir);
|
|
5767
6773
|
for (const cap of CAPABILITY_DIRS) {
|
|
5768
|
-
const srcDir =
|
|
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
|
|
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 =
|
|
6789
|
+
const mcpJsonPath = resolve13(pluginVersionDir, ".mcp.json");
|
|
5784
6790
|
await writeJsonFile(mcpJsonPath, { mcpServers: normalizedMcp });
|
|
5785
6791
|
writtenFiles.push(mcpJsonPath);
|
|
5786
6792
|
}
|
|
5787
|
-
const pluginJsonContent =
|
|
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 =
|
|
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(
|
|
5912
|
-
await
|
|
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
|
|
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 ?
|
|
5988
|
-
if (resolvedTarget && resolvedTarget ===
|
|
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 =
|
|
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
|
|
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?.[
|
|
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 =
|
|
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
|
|
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(
|
|
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(
|
|
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 =
|
|
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-${
|
|
6186
|
-
await
|
|
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
|
|
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
|
|
6221
|
-
await
|
|
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
|
|
7229
|
+
await rm7(snap.pluginVersionDir, { recursive: true, force: true });
|
|
6224
7230
|
}
|
|
6225
7231
|
if (snap.preexistedPlugin === "missing") {
|
|
6226
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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?.[
|
|
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 =
|
|
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?.[
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
7657
|
+
async function listDirFilesRecursive2(srcDir, dstDir) {
|
|
6652
7658
|
const planned = [];
|
|
6653
|
-
const entries = await
|
|
7659
|
+
const entries = await readdir5(srcDir, { withFileTypes: true });
|
|
6654
7660
|
for (const entry of entries) {
|
|
6655
|
-
const srcPath =
|
|
6656
|
-
const dstPath =
|
|
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
|
|
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
|
|
7675
|
+
const entries = await readdir5(srcDir, { withFileTypes: true });
|
|
6670
7676
|
for (const entry of entries) {
|
|
6671
|
-
const srcPath =
|
|
6672
|
-
const dstPath =
|
|
7677
|
+
const srcPath = join10(srcDir, entry.name);
|
|
7678
|
+
const dstPath = join10(dstDir, entry.name);
|
|
6673
7679
|
if (entry.isDirectory()) {
|
|
6674
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
6718
|
-
mkdir as
|
|
6719
|
-
readFile as
|
|
6720
|
-
rename as
|
|
6721
|
-
rm as
|
|
6722
|
-
stat as
|
|
6723
|
-
writeFile as
|
|
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
|
|
6726
|
-
import { dirname as
|
|
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
|
|
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
|
|
6740
|
-
readFile as
|
|
6741
|
-
rename as
|
|
6742
|
-
rm as
|
|
6743
|
-
stat as
|
|
6744
|
-
writeFile as
|
|
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
|
|
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
|
|
6755
|
-
const raw = await
|
|
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] =
|
|
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
|
|
7846
|
+
await mkdir7(dirname7(filePath), { recursive: true });
|
|
6823
7847
|
const content = `${JSON.stringify(data, null, 2)}
|
|
6824
7848
|
`;
|
|
6825
|
-
const tmp = `${filePath}.${
|
|
7849
|
+
const tmp = `${filePath}.${randomUUID5()}.tmp`;
|
|
6826
7850
|
try {
|
|
6827
|
-
await
|
|
6828
|
-
await
|
|
7851
|
+
await writeFile6(tmp, content, { encoding: "utf8", flag: "w" });
|
|
7852
|
+
await rename5(tmp, filePath);
|
|
6829
7853
|
} catch (err) {
|
|
6830
|
-
await
|
|
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
|
|
7869
|
+
import { resolve as resolve14 } from "path";
|
|
6846
7870
|
var CURSOR_RELATIVE_DIR = ".cursor";
|
|
6847
7871
|
function cursorDir(home) {
|
|
6848
|
-
return
|
|
7872
|
+
return resolve14(home, CURSOR_RELATIVE_DIR);
|
|
6849
7873
|
}
|
|
6850
7874
|
function cursorMcpJsonPath(home) {
|
|
6851
|
-
return
|
|
7875
|
+
return resolve14(cursorDir(home), "mcp.json");
|
|
6852
7876
|
}
|
|
6853
7877
|
function cursorRulesDir(home) {
|
|
6854
|
-
return
|
|
7878
|
+
return resolve14(cursorDir(home), "rules");
|
|
6855
7879
|
}
|
|
6856
7880
|
function cursorRuleMdcPath(home, ruleName) {
|
|
6857
|
-
return
|
|
7881
|
+
return resolve14(cursorRulesDir(home), `${ruleName}.mdc`);
|
|
6858
7882
|
}
|
|
6859
7883
|
function cursorSkillsDir(home) {
|
|
6860
|
-
return
|
|
7884
|
+
return resolve14(cursorDir(home), "skills");
|
|
6861
7885
|
}
|
|
6862
7886
|
function cursorSkillDir(home, skillName) {
|
|
6863
|
-
return
|
|
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
|
|
6974
|
-
import { resolve as
|
|
7997
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
7998
|
+
import { resolve as resolve15 } from "path";
|
|
6975
7999
|
async function readSkillDescription(skillSourceDir) {
|
|
6976
|
-
const skillMdPath =
|
|
8000
|
+
const skillMdPath = resolve15(skillSourceDir, "SKILL.md");
|
|
6977
8001
|
let raw;
|
|
6978
8002
|
try {
|
|
6979
|
-
raw = await
|
|
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
|
|
8033
|
+
await rm9(entry.path, { force: true });
|
|
7010
8034
|
} else if (entry.kind === "remove-dir") {
|
|
7011
|
-
await
|
|
8035
|
+
await rm9(entry.path, { recursive: true, force: true });
|
|
7012
8036
|
} else {
|
|
7013
|
-
await
|
|
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
|
|
7026
|
-
const tmp = `${filePath}.${
|
|
8049
|
+
await mkdir8(dirname8(filePath), { recursive: true });
|
|
8050
|
+
const tmp = `${filePath}.${randomUUID6()}.tmp`;
|
|
7027
8051
|
try {
|
|
7028
|
-
await
|
|
7029
|
-
await
|
|
8052
|
+
await writeFile7(tmp, content, { encoding: "utf8", flag: "w" });
|
|
8053
|
+
await rename6(tmp, filePath);
|
|
7030
8054
|
} catch (err) {
|
|
7031
|
-
await
|
|
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
|
|
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 ??
|
|
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
|
|
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
|
|
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
|
|
8309
|
+
await rm9(filePath, { force: true });
|
|
7286
8310
|
}
|
|
7287
8311
|
removedFiles.push(filePath);
|
|
7288
8312
|
continue;
|
|
7289
8313
|
}
|
|
7290
8314
|
if (!dryRun) {
|
|
7291
|
-
await
|
|
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 =
|
|
8363
|
+
const skillsSourceDir = resolve16(plugin.sourceDir, "skills");
|
|
7340
8364
|
const skillDirs = await listSkillDirs(skillsSourceDir);
|
|
7341
8365
|
for (const skillName of skillDirs) {
|
|
7342
|
-
const srcDir =
|
|
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 =
|
|
8398
|
+
const rulesSourceDir = resolve16(plugin.sourceDir, "rules");
|
|
7375
8399
|
const rulesFiles = await listRuleMdFiles(rulesSourceDir);
|
|
7376
8400
|
for (const ruleFile of rulesFiles) {
|
|
7377
|
-
const srcPath =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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-
|
|
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:
|
|
7559
|
-
const entries = await
|
|
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:
|
|
7565
|
-
const entries = await
|
|
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
|
|
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
|
|
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:
|
|
7587
|
-
await
|
|
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
|
|
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
|
|
7606
|
-
import { homedir as
|
|
7607
|
-
import { resolve as
|
|
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
|
|
7611
|
-
import { homedir as
|
|
7612
|
-
import { isAbsolute as isAbsolute3, resolve as
|
|
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 :
|
|
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
|
|
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 ??
|
|
7668
|
-
const assetManifestPath =
|
|
7669
|
-
const legacyAssetsDir =
|
|
7670
|
-
const skillSymlinkPath =
|
|
7671
|
-
const settingsJsonPath =
|
|
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 ??
|
|
7686
|
-
const manifestPath =
|
|
8709
|
+
const home = opts.home ?? homedir13();
|
|
8710
|
+
const manifestPath = resolve17(home, LEGACY_ASSET_MANIFEST_RELATIVE);
|
|
7687
8711
|
try {
|
|
7688
|
-
const lst = await
|
|
8712
|
+
const lst = await stat7(manifestPath);
|
|
7689
8713
|
if (!lst.isFile()) return "0.7.x";
|
|
7690
|
-
const raw = await
|
|
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 =
|
|
8728
|
+
const dir = resolve18(home, LEGACY_CLAUDE_CODE_DIR_RELATIVE);
|
|
7705
8729
|
try {
|
|
7706
|
-
await
|
|
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 =
|
|
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 =
|
|
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 ??
|
|
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
|
|
7795
|
-
import { homedir as
|
|
7796
|
-
import { dirname as
|
|
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 ??
|
|
7800
|
-
return
|
|
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
|
|
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
|
|
7825
|
-
import { homedir as
|
|
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
|
|
7829
|
-
import { mkdir as
|
|
7830
|
-
import { homedir as
|
|
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
|
|
7841
|
-
import { extname as extname2, resolve as
|
|
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(
|
|
8894
|
+
return dirHasFileWithExt(resolve20(sourceDir, "commands"), ".md");
|
|
7871
8895
|
}
|
|
7872
8896
|
async function hasSkills(sourceDir) {
|
|
7873
|
-
const skillsDir =
|
|
8897
|
+
const skillsDir = resolve20(sourceDir, "skills");
|
|
7874
8898
|
if (await dirExists3(skillsDir)) {
|
|
7875
8899
|
let entries;
|
|
7876
8900
|
try {
|
|
7877
|
-
entries = await
|
|
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 =
|
|
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(
|
|
8916
|
+
return dirHasFileWithExt(resolve20(sourceDir, "rules"), ".md");
|
|
7893
8917
|
}
|
|
7894
8918
|
async function hasHooks(sourceDir) {
|
|
7895
|
-
const hooksDir =
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
8044
|
-
import { resolve as
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
|
8304
|
-
const tmpDir = `${cacheDir}.${
|
|
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
|
|
9354
|
+
await rename7(tmpDir, cacheDir);
|
|
8331
9355
|
} catch (err) {
|
|
8332
9356
|
if (err.code === "ENOTEMPTY" && await pathExists3(cacheDir)) {
|
|
8333
|
-
await
|
|
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
|
|
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 ??
|
|
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
|
|
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 =
|
|
8655
|
-
|
|
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 [...
|
|
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 (!
|
|
9691
|
+
if (!VALID_TARGET_SET.has(seg)) {
|
|
8664
9692
|
throw new RushError(
|
|
8665
|
-
`Invalid --target '${seg}'. Expected one of: ${[...
|
|
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 [...
|
|
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 =
|
|
8965
|
-
const manifestPath =
|
|
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
|
|
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-
|
|
10277
|
+
import("./_codex-content-loader-WAPA56U3.js")
|
|
9164
10278
|
]);
|
|
9165
|
-
await syncCodexMarketplaceMirror2(input.home ??
|
|
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
|
|
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(
|
|
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((
|
|
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
|
-
|
|
11127
|
+
resolve25(1);
|
|
9987
11128
|
return;
|
|
9988
11129
|
}
|
|
9989
|
-
|
|
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
|
|
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((
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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((
|
|
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
|
-
|
|
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
|
|
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((
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
12443
|
-
import { homedir as
|
|
12444
|
-
import { dirname as
|
|
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
|
|
12468
|
-
await
|
|
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 =
|
|
12474
|
-
const checkFile =
|
|
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
|
|
13620
|
+
const data = JSON.parse(await readFile15(checkFile, "utf-8"));
|
|
12480
13621
|
lastCheck = data.lastCheck ?? 0;
|
|
12481
13622
|
} catch {
|
|
12482
13623
|
}
|