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