@learnrudi/cli 1.10.7 → 1.10.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +187 -36
- package/dist/packages-manifest.json +18 -18
- package/package.json +3 -3
- package/scripts/generate-manifest.js +25 -4
- package/scripts/postinstall.js +65 -5
package/dist/index.cjs
CHANGED
|
@@ -33,6 +33,35 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
33
33
|
));
|
|
34
34
|
|
|
35
35
|
// packages/env/src/index.js
|
|
36
|
+
function getNodeRuntimeRoot() {
|
|
37
|
+
return import_path.default.join(PATHS.runtimes, "node");
|
|
38
|
+
}
|
|
39
|
+
function resolveNodeRuntimeBin(binName) {
|
|
40
|
+
const root = getNodeRuntimeRoot();
|
|
41
|
+
const isWindows = import_os.default.platform() === "win32";
|
|
42
|
+
const arch = import_os.default.arch() === "arm64" ? "arm64" : "x64";
|
|
43
|
+
const binDir = isWindows ? "Scripts" : "bin";
|
|
44
|
+
const candidates = [];
|
|
45
|
+
if (isWindows) {
|
|
46
|
+
const names = [`${binName}.cmd`, `${binName}.exe`, binName];
|
|
47
|
+
for (const name of names) {
|
|
48
|
+
candidates.push(import_path.default.join(root, arch, binDir, name));
|
|
49
|
+
candidates.push(import_path.default.join(root, binDir, name));
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
candidates.push(import_path.default.join(root, arch, binDir, binName));
|
|
53
|
+
candidates.push(import_path.default.join(root, binDir, binName));
|
|
54
|
+
}
|
|
55
|
+
for (const candidate of candidates) {
|
|
56
|
+
if (import_fs.default.existsSync(candidate)) {
|
|
57
|
+
return candidate;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return candidates[candidates.length - 1];
|
|
61
|
+
}
|
|
62
|
+
function getNodeRuntimeBinDir() {
|
|
63
|
+
return import_path.default.dirname(resolveNodeRuntimeBin("node"));
|
|
64
|
+
}
|
|
36
65
|
function getPlatformArch() {
|
|
37
66
|
const platform = import_os.default.platform();
|
|
38
67
|
const arch = import_os.default.arch();
|
|
@@ -118,8 +147,20 @@ function isPackageInstalled(id) {
|
|
|
118
147
|
return false;
|
|
119
148
|
}
|
|
120
149
|
if (kind2 === "agent") {
|
|
121
|
-
const
|
|
122
|
-
|
|
150
|
+
const manifestPath = import_path.default.join(packagePath, "manifest.json");
|
|
151
|
+
let bins = [];
|
|
152
|
+
if (import_fs.default.existsSync(manifestPath)) {
|
|
153
|
+
try {
|
|
154
|
+
const manifest = JSON.parse(import_fs.default.readFileSync(manifestPath, "utf-8"));
|
|
155
|
+
bins = manifest.bins || manifest.binaries || [];
|
|
156
|
+
} catch {
|
|
157
|
+
bins = [];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (bins.length === 0) {
|
|
161
|
+
bins = [name];
|
|
162
|
+
}
|
|
163
|
+
return bins.some((bin) => import_fs.default.existsSync(resolveNodeRuntimeBin(bin)));
|
|
123
164
|
}
|
|
124
165
|
try {
|
|
125
166
|
const contents = import_fs.default.readdirSync(packagePath);
|
|
@@ -8726,6 +8767,8 @@ function resolveBinTarget(manifest, bin) {
|
|
|
8726
8767
|
return import_path5.default.join(manifest.installDir, bin);
|
|
8727
8768
|
case "npm":
|
|
8728
8769
|
return import_path5.default.join(manifest.installDir, "node_modules", ".bin", bin);
|
|
8770
|
+
case "npm-global":
|
|
8771
|
+
return resolveNodeRuntimeBin(bin);
|
|
8729
8772
|
case "pip":
|
|
8730
8773
|
return import_path5.default.join(manifest.installDir, "venv", "bin", bin);
|
|
8731
8774
|
case "system":
|
|
@@ -8830,9 +8873,18 @@ var init_shims = __esm({
|
|
|
8830
8873
|
});
|
|
8831
8874
|
|
|
8832
8875
|
// packages/core/src/installer.js
|
|
8833
|
-
function
|
|
8876
|
+
function getNpmModulesRoot(installRoot, scope = "local") {
|
|
8877
|
+
if (scope === "global") {
|
|
8878
|
+
return import_path6.default.join(installRoot, "lib", "node_modules");
|
|
8879
|
+
}
|
|
8880
|
+
return import_path6.default.join(installRoot, "node_modules");
|
|
8881
|
+
}
|
|
8882
|
+
function getNpmPackageJsonPath(installRoot, packageName, scope = "local") {
|
|
8883
|
+
return import_path6.default.join(getNpmModulesRoot(installRoot, scope), packageName, "package.json");
|
|
8884
|
+
}
|
|
8885
|
+
function discoverNpmBins(installRoot, packageName, scope = "local") {
|
|
8834
8886
|
try {
|
|
8835
|
-
const pkgJsonPath =
|
|
8887
|
+
const pkgJsonPath = getNpmPackageJsonPath(installRoot, packageName, scope);
|
|
8836
8888
|
if (!import_fs5.default.existsSync(pkgJsonPath)) {
|
|
8837
8889
|
console.warn(`[Installer] Warning: Could not find package.json at ${pkgJsonPath}`);
|
|
8838
8890
|
return [];
|
|
@@ -8853,9 +8905,9 @@ function discoverNpmBins(installPath, packageName) {
|
|
|
8853
8905
|
return [];
|
|
8854
8906
|
}
|
|
8855
8907
|
}
|
|
8856
|
-
function hasInstallScripts(
|
|
8908
|
+
function hasInstallScripts(installRoot, packageName, scope = "local") {
|
|
8857
8909
|
try {
|
|
8858
|
-
const pkgJsonPath =
|
|
8910
|
+
const pkgJsonPath = getNpmPackageJsonPath(installRoot, packageName, scope);
|
|
8859
8911
|
if (!import_fs5.default.existsSync(pkgJsonPath)) {
|
|
8860
8912
|
return false;
|
|
8861
8913
|
}
|
|
@@ -8910,35 +8962,60 @@ async function installPackage(id, options = {}) {
|
|
|
8910
8962
|
async function installSinglePackage(pkg, options = {}) {
|
|
8911
8963
|
const { force = false, allowScripts = false, onProgress } = options;
|
|
8912
8964
|
const installPath = getPackagePath(pkg.id);
|
|
8965
|
+
const pkgName = pkg.id.replace(/^(runtime|binary|agent):/, "");
|
|
8966
|
+
const isAgentNpm = pkg.kind === "agent" && pkg.npmPackage;
|
|
8913
8967
|
if (import_fs5.default.existsSync(installPath) && !force) {
|
|
8914
|
-
|
|
8968
|
+
if (!isAgentNpm) {
|
|
8969
|
+
return { success: true, id: pkg.id, path: installPath, skipped: true };
|
|
8970
|
+
}
|
|
8971
|
+
const manifestPath = import_path6.default.join(installPath, "manifest.json");
|
|
8972
|
+
let bins = pkg.bins || [];
|
|
8973
|
+
if (import_fs5.default.existsSync(manifestPath)) {
|
|
8974
|
+
try {
|
|
8975
|
+
const manifest2 = JSON.parse(import_fs5.default.readFileSync(manifestPath, "utf-8"));
|
|
8976
|
+
bins = manifest2.bins || manifest2.binaries || bins;
|
|
8977
|
+
} catch {
|
|
8978
|
+
}
|
|
8979
|
+
}
|
|
8980
|
+
if (bins.length === 0) {
|
|
8981
|
+
bins = [pkgName];
|
|
8982
|
+
}
|
|
8983
|
+
const hasGlobalBin = bins.some((bin) => import_fs5.default.existsSync(resolveNodeRuntimeBin(bin)));
|
|
8984
|
+
if (hasGlobalBin) {
|
|
8985
|
+
return { success: true, id: pkg.id, path: installPath, skipped: true };
|
|
8986
|
+
}
|
|
8915
8987
|
}
|
|
8916
8988
|
if (pkg.kind === "runtime" || pkg.kind === "binary" || pkg.kind === "agent") {
|
|
8917
|
-
const pkgName = pkg.id.replace(/^(runtime|binary|agent):/, "");
|
|
8918
8989
|
onProgress?.({ phase: "downloading", package: pkg.id });
|
|
8919
8990
|
if (pkg.npmPackage) {
|
|
8920
8991
|
try {
|
|
8921
8992
|
const { execSync: execSync11 } = await import("child_process");
|
|
8993
|
+
const npmInstallRoot = isAgentNpm ? getNodeRuntimeRoot() : installPath;
|
|
8994
|
+
const npmScope = isAgentNpm ? "global" : "local";
|
|
8922
8995
|
if (!import_fs5.default.existsSync(installPath)) {
|
|
8923
8996
|
import_fs5.default.mkdirSync(installPath, { recursive: true });
|
|
8924
8997
|
}
|
|
8998
|
+
if (isAgentNpm && !import_fs5.default.existsSync(npmInstallRoot)) {
|
|
8999
|
+
import_fs5.default.mkdirSync(npmInstallRoot, { recursive: true });
|
|
9000
|
+
}
|
|
8925
9001
|
onProgress?.({ phase: "installing", package: pkg.id, message: `npm install ${pkg.npmPackage}` });
|
|
8926
9002
|
const resourcesPath = process.env.RESOURCES_PATH;
|
|
8927
|
-
const npmCmd = resourcesPath ? import_path6.default.join(resourcesPath, "bundled-runtimes", "node", "bin", "npm") :
|
|
8928
|
-
if (!import_fs5.default.existsSync(import_path6.default.join(installPath, "package.json"))) {
|
|
9003
|
+
const npmCmd = resourcesPath ? import_path6.default.join(resourcesPath, "bundled-runtimes", "node", "bin", "npm") : await findNpmExecutable();
|
|
9004
|
+
if (!isAgentNpm && !import_fs5.default.existsSync(import_path6.default.join(installPath, "package.json"))) {
|
|
8929
9005
|
execSync11(`"${npmCmd}" init -y`, { cwd: installPath, stdio: "pipe" });
|
|
8930
9006
|
}
|
|
8931
9007
|
const shouldIgnoreScripts = pkg.source?.type === "npm" && !allowScripts;
|
|
8932
9008
|
const installFlags = shouldIgnoreScripts ? "--ignore-scripts --no-audit --no-fund" : "--no-audit --no-fund";
|
|
8933
|
-
|
|
9009
|
+
const installCmd = isAgentNpm ? `install -g ${pkg.npmPackage} ${installFlags} --prefix "${npmInstallRoot}"` : `install ${pkg.npmPackage} ${installFlags}`;
|
|
9010
|
+
execSync11(`"${npmCmd}" ${installCmd}`, { cwd: installPath, stdio: "pipe" });
|
|
8934
9011
|
let bins = pkg.bins;
|
|
8935
9012
|
if (!bins || bins.length === 0) {
|
|
8936
|
-
bins = discoverNpmBins(
|
|
9013
|
+
bins = discoverNpmBins(npmInstallRoot, pkg.npmPackage, npmScope);
|
|
8937
9014
|
console.log(`[Installer] Discovered binaries: ${bins.join(", ") || "(none)"}`);
|
|
8938
9015
|
}
|
|
8939
9016
|
let installedVersion = pkg.version || "latest";
|
|
8940
9017
|
try {
|
|
8941
|
-
const pkgJsonPath =
|
|
9018
|
+
const pkgJsonPath = getNpmPackageJsonPath(npmInstallRoot, pkg.npmPackage, npmScope);
|
|
8942
9019
|
if (import_fs5.default.existsSync(pkgJsonPath)) {
|
|
8943
9020
|
const pkgJson = JSON.parse(import_fs5.default.readFileSync(pkgJsonPath, "utf8"));
|
|
8944
9021
|
installedVersion = pkgJson.version;
|
|
@@ -8947,13 +9024,21 @@ async function installSinglePackage(pkg, options = {}) {
|
|
|
8947
9024
|
}
|
|
8948
9025
|
if (pkg.postInstall) {
|
|
8949
9026
|
onProgress?.({ phase: "postInstall", package: pkg.id, message: pkg.postInstall });
|
|
9027
|
+
const binDir = isAgentNpm ? getNodeRuntimeBinDir() : import_path6.default.join(installPath, "node_modules", ".bin");
|
|
8950
9028
|
const postInstallCmd = pkg.postInstall.replace(
|
|
8951
9029
|
/^npx\s+(\S+)/,
|
|
8952
|
-
`"${import_path6.default.join(
|
|
9030
|
+
`"${import_path6.default.join(binDir, "$1")}"`
|
|
8953
9031
|
);
|
|
8954
|
-
execSync11(postInstallCmd, {
|
|
9032
|
+
execSync11(postInstallCmd, {
|
|
9033
|
+
cwd: installPath,
|
|
9034
|
+
stdio: "pipe",
|
|
9035
|
+
env: {
|
|
9036
|
+
...process.env,
|
|
9037
|
+
PATH: `${binDir}${import_path6.default.delimiter}${process.env.PATH || ""}`
|
|
9038
|
+
}
|
|
9039
|
+
});
|
|
8955
9040
|
}
|
|
8956
|
-
const scriptsDetected = hasInstallScripts(
|
|
9041
|
+
const scriptsDetected = hasInstallScripts(npmInstallRoot, pkg.npmPackage, npmScope);
|
|
8957
9042
|
const scriptsPolicy = installFlags.includes("--ignore-scripts") ? "ignore" : "allow";
|
|
8958
9043
|
if (scriptsDetected && scriptsPolicy === "ignore") {
|
|
8959
9044
|
console.warn(`
|
|
@@ -8972,6 +9057,8 @@ async function installSinglePackage(pkg, options = {}) {
|
|
|
8972
9057
|
hasInstallScripts: scriptsDetected,
|
|
8973
9058
|
scriptsPolicy,
|
|
8974
9059
|
postInstall: pkg.postInstall,
|
|
9060
|
+
installType: isAgentNpm ? "npm-global" : "npm",
|
|
9061
|
+
npmPrefix: isAgentNpm ? npmInstallRoot : void 0,
|
|
8975
9062
|
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8976
9063
|
source: pkg.source || { type: "npm" }
|
|
8977
9064
|
};
|
|
@@ -8982,14 +9069,20 @@ async function installSinglePackage(pkg, options = {}) {
|
|
|
8982
9069
|
if (bins && bins.length > 0) {
|
|
8983
9070
|
await createShimsForTool({
|
|
8984
9071
|
id: pkg.id,
|
|
8985
|
-
installType: "npm",
|
|
8986
|
-
installDir:
|
|
9072
|
+
installType: isAgentNpm ? "npm-global" : "npm",
|
|
9073
|
+
installDir: npmInstallRoot,
|
|
8987
9074
|
bins,
|
|
8988
9075
|
name: pkgName
|
|
8989
9076
|
});
|
|
8990
9077
|
} else {
|
|
8991
9078
|
console.warn(`[Installer] Warning: No binaries found for ${pkg.npmPackage}`);
|
|
8992
9079
|
}
|
|
9080
|
+
if (isAgentNpm) {
|
|
9081
|
+
const legacyPath = import_path6.default.join(installPath, "node_modules");
|
|
9082
|
+
if (import_fs5.default.existsSync(legacyPath)) {
|
|
9083
|
+
import_fs5.default.rmSync(legacyPath, { recursive: true, force: true });
|
|
9084
|
+
}
|
|
9085
|
+
}
|
|
8993
9086
|
return { success: true, id: pkg.id, path: installPath };
|
|
8994
9087
|
} catch (error) {
|
|
8995
9088
|
throw new Error(`Failed to install ${pkg.npmPackage}: ${error.message}`);
|
|
@@ -9138,17 +9231,30 @@ async function uninstallPackage(id) {
|
|
|
9138
9231
|
}
|
|
9139
9232
|
try {
|
|
9140
9233
|
let bins = [];
|
|
9234
|
+
let manifest = null;
|
|
9141
9235
|
if (kind2 !== "prompt") {
|
|
9142
9236
|
const manifestPath = import_path6.default.join(installPath, "manifest.json");
|
|
9143
9237
|
if (import_fs5.default.existsSync(manifestPath)) {
|
|
9144
9238
|
try {
|
|
9145
|
-
|
|
9239
|
+
manifest = JSON.parse(import_fs5.default.readFileSync(manifestPath, "utf-8"));
|
|
9146
9240
|
bins = manifest.bins || manifest.binaries || [];
|
|
9147
9241
|
} catch {
|
|
9148
9242
|
bins = [name];
|
|
9149
9243
|
}
|
|
9150
9244
|
}
|
|
9151
9245
|
}
|
|
9246
|
+
if (kind2 === "agent" && manifest?.npmPackage) {
|
|
9247
|
+
try {
|
|
9248
|
+
const { execSync: execSync11 } = await import("child_process");
|
|
9249
|
+
const npmCmd = await findNpmExecutable();
|
|
9250
|
+
const npmPrefix = getNodeRuntimeRoot();
|
|
9251
|
+
execSync11(`"${npmCmd}" uninstall -g ${manifest.npmPackage} --prefix "${npmPrefix}" --no-audit --no-fund`, {
|
|
9252
|
+
stdio: "pipe"
|
|
9253
|
+
});
|
|
9254
|
+
} catch (error) {
|
|
9255
|
+
console.warn(`[Installer] Warning: Failed to uninstall ${manifest.npmPackage}: ${error.message}`);
|
|
9256
|
+
}
|
|
9257
|
+
}
|
|
9152
9258
|
if (bins.length > 0) {
|
|
9153
9259
|
removeShims(bins);
|
|
9154
9260
|
}
|
|
@@ -10358,6 +10464,8 @@ __export(src_exports2, {
|
|
|
10358
10464
|
getInstallOrder: () => getInstallOrder,
|
|
10359
10465
|
getInstalledPackages: () => getInstalledPackages,
|
|
10360
10466
|
getLockfilePath: () => getLockfilePath,
|
|
10467
|
+
getNodeRuntimeBinDir: () => getNodeRuntimeBinDir,
|
|
10468
|
+
getNodeRuntimeRoot: () => getNodeRuntimeRoot,
|
|
10361
10469
|
getPackage: () => getPackage,
|
|
10362
10470
|
getPackagePath: () => getPackagePath,
|
|
10363
10471
|
getShimOwner: () => getShimOwner,
|
|
@@ -10379,6 +10487,7 @@ __export(src_exports2, {
|
|
|
10379
10487
|
registerSystemBinary: () => registerSystemBinary,
|
|
10380
10488
|
removeShims: () => removeShims,
|
|
10381
10489
|
removeStack: () => removeStack,
|
|
10490
|
+
resolveNodeRuntimeBin: () => resolveNodeRuntimeBin,
|
|
10382
10491
|
resolvePackage: () => resolvePackage,
|
|
10383
10492
|
resolvePackages: () => resolvePackages,
|
|
10384
10493
|
rudiConfigExists: () => rudiConfigExists,
|
|
@@ -39332,10 +39441,31 @@ function getVersion2(command, versionFlag) {
|
|
|
39332
39441
|
return null;
|
|
39333
39442
|
}
|
|
39334
39443
|
}
|
|
39444
|
+
function getAgentBins(agentId) {
|
|
39445
|
+
const manifestPath = import_path22.default.join(PATHS.agents, agentId, "manifest.json");
|
|
39446
|
+
if (import_fs24.default.existsSync(manifestPath)) {
|
|
39447
|
+
try {
|
|
39448
|
+
const manifest = JSON.parse(import_fs24.default.readFileSync(manifestPath, "utf-8"));
|
|
39449
|
+
const bins = manifest.bins || manifest.binaries || [];
|
|
39450
|
+
if (bins.length > 0) return bins;
|
|
39451
|
+
} catch {
|
|
39452
|
+
}
|
|
39453
|
+
}
|
|
39454
|
+
return [agentId];
|
|
39455
|
+
}
|
|
39456
|
+
function findRudiAgentBin(agentId) {
|
|
39457
|
+
const bins = getAgentBins(agentId);
|
|
39458
|
+
for (const bin of bins) {
|
|
39459
|
+
const binPath = resolveNodeRuntimeBin(bin);
|
|
39460
|
+
if (import_fs24.default.existsSync(binPath)) return binPath;
|
|
39461
|
+
}
|
|
39462
|
+
return null;
|
|
39463
|
+
}
|
|
39335
39464
|
function findBinary(command, kind2 = "binary") {
|
|
39336
39465
|
const rudiPaths = [
|
|
39337
39466
|
import_path22.default.join(PATHS.agents, command, "node_modules", ".bin", command),
|
|
39338
39467
|
import_path22.default.join(PATHS.runtimes, command, "bin", command),
|
|
39468
|
+
resolveNodeRuntimeBin(command),
|
|
39339
39469
|
import_path22.default.join(PATHS.binaries, command, command),
|
|
39340
39470
|
import_path22.default.join(PATHS.binaries, command)
|
|
39341
39471
|
];
|
|
@@ -39358,8 +39488,8 @@ function findBinary(command, kind2 = "binary") {
|
|
|
39358
39488
|
return { found: false, path: null, source: null };
|
|
39359
39489
|
}
|
|
39360
39490
|
function getAgentStatus(agent) {
|
|
39361
|
-
const rudiPath =
|
|
39362
|
-
const rudiInstalled =
|
|
39491
|
+
const rudiPath = findRudiAgentBin(agent.id);
|
|
39492
|
+
const rudiInstalled = !!rudiPath;
|
|
39363
39493
|
let globalPath = null;
|
|
39364
39494
|
let globalInstalled = false;
|
|
39365
39495
|
if (!rudiInstalled) {
|
|
@@ -39590,9 +39720,30 @@ function getVersion3(binaryPath, versionFlag = "--version") {
|
|
|
39590
39720
|
return null;
|
|
39591
39721
|
}
|
|
39592
39722
|
}
|
|
39723
|
+
function getAgentBins2(name) {
|
|
39724
|
+
const manifestPath = import_path23.default.join(PATHS.agents, name, "manifest.json");
|
|
39725
|
+
if (import_fs25.default.existsSync(manifestPath)) {
|
|
39726
|
+
try {
|
|
39727
|
+
const manifest = JSON.parse(import_fs25.default.readFileSync(manifestPath, "utf-8"));
|
|
39728
|
+
const bins = manifest.bins || manifest.binaries || [];
|
|
39729
|
+
if (bins.length > 0) return bins;
|
|
39730
|
+
} catch {
|
|
39731
|
+
}
|
|
39732
|
+
}
|
|
39733
|
+
return [name];
|
|
39734
|
+
}
|
|
39735
|
+
function findRudiAgentBin2(name) {
|
|
39736
|
+
const bins = getAgentBins2(name);
|
|
39737
|
+
for (const bin of bins) {
|
|
39738
|
+
const binPath = resolveNodeRuntimeBin(bin);
|
|
39739
|
+
if (import_fs25.default.existsSync(binPath)) return binPath;
|
|
39740
|
+
}
|
|
39741
|
+
return null;
|
|
39742
|
+
}
|
|
39593
39743
|
function detectKindFromFilesystem(name) {
|
|
39594
|
-
const
|
|
39595
|
-
if (import_fs25.default.existsSync(
|
|
39744
|
+
const agentManifestPath = import_path23.default.join(PATHS.agents, name, "manifest.json");
|
|
39745
|
+
if (import_fs25.default.existsSync(agentManifestPath)) return "agent";
|
|
39746
|
+
if (findRudiAgentBin2(name)) return "agent";
|
|
39596
39747
|
const runtimePath = import_path23.default.join(PATHS.runtimes, name, "bin", name);
|
|
39597
39748
|
if (import_fs25.default.existsSync(runtimePath)) return "runtime";
|
|
39598
39749
|
const binaryPath = import_path23.default.join(PATHS.binaries, name, name);
|
|
@@ -39645,8 +39796,8 @@ async function cmdCheck(args, flags) {
|
|
|
39645
39796
|
};
|
|
39646
39797
|
switch (kind2) {
|
|
39647
39798
|
case "agent": {
|
|
39648
|
-
const rudiPath =
|
|
39649
|
-
const rudiInstalled =
|
|
39799
|
+
const rudiPath = findRudiAgentBin2(name);
|
|
39800
|
+
const rudiInstalled = !!rudiPath;
|
|
39650
39801
|
let globalPath = null;
|
|
39651
39802
|
let globalInstalled = false;
|
|
39652
39803
|
if (!rudiInstalled) {
|
|
@@ -39801,16 +39952,6 @@ function getShimTarget(name, shimPath, type) {
|
|
|
39801
39952
|
}
|
|
39802
39953
|
function getPackageFromShim(shimName, target) {
|
|
39803
39954
|
if (!target) return null;
|
|
39804
|
-
const match = target.match(/\/(binaries|runtimes|agents)\/([^\/]+)/);
|
|
39805
|
-
if (match) {
|
|
39806
|
-
const [, kind2, pkgName] = match;
|
|
39807
|
-
const kindMap = {
|
|
39808
|
-
"binaries": "binary",
|
|
39809
|
-
"runtimes": "runtime",
|
|
39810
|
-
"agents": "agent"
|
|
39811
|
-
};
|
|
39812
|
-
return `${kindMap[kind2]}:${pkgName}`;
|
|
39813
|
-
}
|
|
39814
39955
|
const manifestDirs = [
|
|
39815
39956
|
import_path24.default.join(PATHS.binaries),
|
|
39816
39957
|
import_path24.default.join(PATHS.runtimes),
|
|
@@ -39834,6 +39975,16 @@ function getPackageFromShim(shimName, target) {
|
|
|
39834
39975
|
}
|
|
39835
39976
|
}
|
|
39836
39977
|
}
|
|
39978
|
+
const match = target.match(/\/(binaries|runtimes|agents)\/([^\/]+)/);
|
|
39979
|
+
if (match) {
|
|
39980
|
+
const [, kind2, pkgName] = match;
|
|
39981
|
+
const kindMap = {
|
|
39982
|
+
"binaries": "binary",
|
|
39983
|
+
"runtimes": "runtime",
|
|
39984
|
+
"agents": "agent"
|
|
39985
|
+
};
|
|
39986
|
+
return `${kindMap[kind2]}:${pkgName}`;
|
|
39987
|
+
}
|
|
39837
39988
|
return null;
|
|
39838
39989
|
}
|
|
39839
39990
|
function formatShimStatus(shim, flags) {
|
|
@@ -40670,7 +40821,7 @@ async function cmdStudio(args, flags) {
|
|
|
40670
40821
|
}
|
|
40671
40822
|
|
|
40672
40823
|
// src/index.js
|
|
40673
|
-
var VERSION2 = "
|
|
40824
|
+
var VERSION2 = true ? "1.10.9" : process.env.npm_package_version || "0.0.0";
|
|
40674
40825
|
async function main() {
|
|
40675
40826
|
const { command, args, flags } = parseArgs(process.argv.slice(2));
|
|
40676
40827
|
if (flags.version || flags.v) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "1.0.0",
|
|
3
|
-
"generated": "2026-01-
|
|
3
|
+
"generated": "2026-01-11T19:52:17.979Z",
|
|
4
4
|
"packages": {
|
|
5
5
|
"runtimes": [
|
|
6
6
|
{
|
|
@@ -122,13 +122,13 @@
|
|
|
122
122
|
"id": "claude",
|
|
123
123
|
"name": "Claude Code",
|
|
124
124
|
"kind": "agent",
|
|
125
|
-
"installDir": "
|
|
126
|
-
"basePath": "
|
|
127
|
-
"installType": "npm",
|
|
125
|
+
"installDir": "node",
|
|
126
|
+
"basePath": "runtimes",
|
|
127
|
+
"installType": "npm-global",
|
|
128
128
|
"commands": [
|
|
129
129
|
{
|
|
130
130
|
"name": "claude",
|
|
131
|
-
"bin": "
|
|
131
|
+
"bin": "bin/claude",
|
|
132
132
|
"args": null
|
|
133
133
|
}
|
|
134
134
|
]
|
|
@@ -137,13 +137,13 @@
|
|
|
137
137
|
"id": "codex",
|
|
138
138
|
"name": "OpenAI Codex",
|
|
139
139
|
"kind": "agent",
|
|
140
|
-
"installDir": "
|
|
141
|
-
"basePath": "
|
|
142
|
-
"installType": "npm",
|
|
140
|
+
"installDir": "node",
|
|
141
|
+
"basePath": "runtimes",
|
|
142
|
+
"installType": "npm-global",
|
|
143
143
|
"commands": [
|
|
144
144
|
{
|
|
145
145
|
"name": "codex",
|
|
146
|
-
"bin": "
|
|
146
|
+
"bin": "bin/codex",
|
|
147
147
|
"args": null
|
|
148
148
|
}
|
|
149
149
|
]
|
|
@@ -152,18 +152,18 @@
|
|
|
152
152
|
"id": "copilot",
|
|
153
153
|
"name": "GitHub Copilot",
|
|
154
154
|
"kind": "agent",
|
|
155
|
-
"installDir": "
|
|
156
|
-
"basePath": "
|
|
157
|
-
"installType": "npm",
|
|
155
|
+
"installDir": "node",
|
|
156
|
+
"basePath": "runtimes",
|
|
157
|
+
"installType": "npm-global",
|
|
158
158
|
"commands": [
|
|
159
159
|
{
|
|
160
160
|
"name": "copilot",
|
|
161
|
-
"bin": "
|
|
161
|
+
"bin": "bin/github-copilot-cli",
|
|
162
162
|
"args": null
|
|
163
163
|
},
|
|
164
164
|
{
|
|
165
165
|
"name": "github-copilot-cli",
|
|
166
|
-
"bin": "
|
|
166
|
+
"bin": "bin/github-copilot-cli",
|
|
167
167
|
"args": null
|
|
168
168
|
}
|
|
169
169
|
]
|
|
@@ -172,13 +172,13 @@
|
|
|
172
172
|
"id": "gemini",
|
|
173
173
|
"name": "Gemini CLI",
|
|
174
174
|
"kind": "agent",
|
|
175
|
-
"installDir": "
|
|
176
|
-
"basePath": "
|
|
177
|
-
"installType": "npm",
|
|
175
|
+
"installDir": "node",
|
|
176
|
+
"basePath": "runtimes",
|
|
177
|
+
"installType": "npm-global",
|
|
178
178
|
"commands": [
|
|
179
179
|
{
|
|
180
180
|
"name": "gemini",
|
|
181
|
-
"bin": "
|
|
181
|
+
"bin": "bin/gemini",
|
|
182
182
|
"args": null
|
|
183
183
|
}
|
|
184
184
|
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@learnrudi/cli",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.9",
|
|
4
4
|
"description": "RUDI CLI - Install and manage MCP stacks, runtimes, and AI agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"scripts": {
|
|
16
16
|
"start": "node src/index.js",
|
|
17
17
|
"prebuild": "node scripts/generate-manifest.js",
|
|
18
|
-
"build": "esbuild src/index.js --bundle --platform=node --format=cjs --outfile=dist/index.cjs --external:better-sqlite3 && cp src/router-mcp.js dist/router-mcp.js && cp src/packages-manifest.json dist/packages-manifest.json",
|
|
18
|
+
"build": "esbuild src/index.js --bundle --platform=node --format=cjs --outfile=dist/index.cjs --define:__RUDI_CLI_VERSION__=$(node -p \"JSON.stringify(require('./package.json').version)\") --external:better-sqlite3 && cp src/router-mcp.js dist/router-mcp.js && cp src/packages-manifest.json dist/packages-manifest.json",
|
|
19
19
|
"postinstall": "node scripts/postinstall.js",
|
|
20
20
|
"prepublishOnly": "npm run build",
|
|
21
21
|
"test": "node --test src/__tests__/"
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
],
|
|
52
52
|
"repository": {
|
|
53
53
|
"type": "git",
|
|
54
|
-
"url": "https://github.com/learn-rudi/cli.git"
|
|
54
|
+
"url": "git+https://github.com/learn-rudi/cli.git"
|
|
55
55
|
},
|
|
56
56
|
"homepage": "https://learnrudi.com",
|
|
57
57
|
"publishConfig": {
|
|
@@ -113,6 +113,17 @@ function getKindBasePath(kind) {
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
function normalizeGlobalNpmCommands(commands) {
|
|
117
|
+
return commands.map(cmd => {
|
|
118
|
+
const binName = path.basename(cmd.bin || cmd.name);
|
|
119
|
+
return {
|
|
120
|
+
name: cmd.name,
|
|
121
|
+
bin: path.posix.join('bin', binName),
|
|
122
|
+
args: cmd.args || null,
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
116
127
|
/**
|
|
117
128
|
* Process packages from a catalog directory
|
|
118
129
|
*/
|
|
@@ -122,8 +133,18 @@ function processPackages(catalogPath, kind) {
|
|
|
122
133
|
|
|
123
134
|
return packages.map(pkg => {
|
|
124
135
|
const id = pkg.id.replace(/^(runtime|binary|agent):/, '');
|
|
125
|
-
|
|
126
|
-
|
|
136
|
+
let installDir = getInstallDir(pkg, kind);
|
|
137
|
+
let basePath = getKindBasePath(kind);
|
|
138
|
+
let installType = pkg.installType || 'binary';
|
|
139
|
+
let commands = extractCommands(pkg, kind);
|
|
140
|
+
|
|
141
|
+
const isGlobalNpmAgent = kind === 'agent' && (installType === 'npm' || pkg.npmPackage);
|
|
142
|
+
if (isGlobalNpmAgent) {
|
|
143
|
+
basePath = 'runtimes';
|
|
144
|
+
installDir = 'node';
|
|
145
|
+
installType = 'npm-global';
|
|
146
|
+
commands = normalizeGlobalNpmCommands(commands);
|
|
147
|
+
}
|
|
127
148
|
|
|
128
149
|
return {
|
|
129
150
|
id,
|
|
@@ -131,8 +152,8 @@ function processPackages(catalogPath, kind) {
|
|
|
131
152
|
kind,
|
|
132
153
|
installDir,
|
|
133
154
|
basePath,
|
|
134
|
-
installType
|
|
135
|
-
commands
|
|
155
|
+
installType,
|
|
156
|
+
commands,
|
|
136
157
|
};
|
|
137
158
|
});
|
|
138
159
|
}
|
package/scripts/postinstall.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Fetches runtime manifests from registry and downloads:
|
|
6
6
|
* 1. Node.js runtime → ~/.rudi/runtimes/node/
|
|
7
7
|
* 2. Python runtime → ~/.rudi/runtimes/python/
|
|
8
|
-
* 3. Creates shims → ~/.rudi/
|
|
8
|
+
* 3. Creates shims → ~/.rudi/bins/
|
|
9
9
|
* 4. Initializes rudi.json → ~/.rudi/rudi.json
|
|
10
10
|
*/
|
|
11
11
|
|
|
@@ -287,6 +287,37 @@ function loadPackagesManifest() {
|
|
|
287
287
|
return { packages: { runtimes: [], agents: [], binaries: [] } };
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
+
function resolveNodeRuntimeBinDir() {
|
|
291
|
+
const isWindows = process.platform === 'win32';
|
|
292
|
+
const arch = process.arch === 'arm64' ? 'arm64' : 'x64';
|
|
293
|
+
const binDir = isWindows ? 'Scripts' : 'bin';
|
|
294
|
+
const nodeRoot = path.join(RUDI_HOME, 'runtimes', 'node');
|
|
295
|
+
const archBin = path.join(nodeRoot, arch, binDir);
|
|
296
|
+
const flatBin = path.join(nodeRoot, binDir);
|
|
297
|
+
const nodeExe = isWindows ? 'node.exe' : 'node';
|
|
298
|
+
|
|
299
|
+
if (fs.existsSync(path.join(archBin, nodeExe))) {
|
|
300
|
+
return archBin;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return flatBin;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function getCliEntryPath() {
|
|
307
|
+
const candidates = [
|
|
308
|
+
path.join(path.dirname(process.argv[1]), '..', 'dist', 'index.cjs'),
|
|
309
|
+
path.join(path.dirname(process.argv[1]), '..', 'src', 'index.js'),
|
|
310
|
+
];
|
|
311
|
+
|
|
312
|
+
for (const candidate of candidates) {
|
|
313
|
+
if (fs.existsSync(candidate)) {
|
|
314
|
+
return candidate;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
|
|
290
321
|
/**
|
|
291
322
|
* Build a shim script that executes a target binary
|
|
292
323
|
* Shows helpful error if binary not installed
|
|
@@ -338,6 +369,7 @@ function createShims() {
|
|
|
338
369
|
|
|
339
370
|
const manifest = loadPackagesManifest();
|
|
340
371
|
const shimDefs = [];
|
|
372
|
+
const nodeBinDir = resolveNodeRuntimeBinDir();
|
|
341
373
|
|
|
342
374
|
// ---------------------------------------------------------------------------
|
|
343
375
|
// GENERATE SHIMS FROM MANIFEST (only for installed packages)
|
|
@@ -350,7 +382,10 @@ function createShims() {
|
|
|
350
382
|
];
|
|
351
383
|
|
|
352
384
|
for (const pkg of allPackages) {
|
|
353
|
-
const
|
|
385
|
+
const isAgentNpm = pkg.kind === 'agent' && (pkg.installType === 'npm' || pkg.installType === 'npm-global');
|
|
386
|
+
const installPath = isAgentNpm
|
|
387
|
+
? path.join(RUDI_HOME, 'runtimes', 'node')
|
|
388
|
+
: path.join(RUDI_HOME, pkg.basePath, pkg.installDir);
|
|
354
389
|
|
|
355
390
|
// Only create shims for packages that are actually installed
|
|
356
391
|
// Check if the install directory exists
|
|
@@ -359,7 +394,10 @@ function createShims() {
|
|
|
359
394
|
}
|
|
360
395
|
|
|
361
396
|
for (const cmd of pkg.commands) {
|
|
362
|
-
const
|
|
397
|
+
const binName = isAgentNpm ? path.basename(cmd.bin) : cmd.bin;
|
|
398
|
+
const binPath = isAgentNpm
|
|
399
|
+
? path.join(nodeBinDir, binName)
|
|
400
|
+
: path.join(installPath, cmd.bin);
|
|
363
401
|
|
|
364
402
|
// Only create shim if the target binary exists
|
|
365
403
|
if (!fs.existsSync(binPath)) {
|
|
@@ -386,6 +424,26 @@ function createShims() {
|
|
|
386
424
|
// RUDI SHIMS (router, mcp) - always included
|
|
387
425
|
// ---------------------------------------------------------------------------
|
|
388
426
|
|
|
427
|
+
const cliEntryPath = getCliEntryPath();
|
|
428
|
+
if (cliEntryPath) {
|
|
429
|
+
const nodeBin = path.join(nodeBinDir, isWindows ? 'node.exe' : 'node');
|
|
430
|
+
shimDefs.push({
|
|
431
|
+
name: 'rudi',
|
|
432
|
+
script: `#!/bin/sh
|
|
433
|
+
CLI_ENTRY="${cliEntryPath.replace(/"/g, '\\"')}"
|
|
434
|
+
NODE_BIN="${nodeBin.replace(/"/g, '\\"')}"
|
|
435
|
+
if [ -x "$CLI_ENTRY" ]; then
|
|
436
|
+
if [ -x "$NODE_BIN" ]; then
|
|
437
|
+
exec "$NODE_BIN" "$CLI_ENTRY" "$@"
|
|
438
|
+
fi
|
|
439
|
+
exec node "$CLI_ENTRY" "$@"
|
|
440
|
+
fi
|
|
441
|
+
echo "RUDI: CLI entry not found at $CLI_ENTRY" 1>&2
|
|
442
|
+
exit 127
|
|
443
|
+
`
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
|
|
389
447
|
// rudi-mcp shim for direct stack access
|
|
390
448
|
shimDefs.push({
|
|
391
449
|
name: 'rudi-mcp',
|
|
@@ -397,14 +455,16 @@ exec rudi mcp "$@"
|
|
|
397
455
|
});
|
|
398
456
|
|
|
399
457
|
// rudi-router shim for aggregated MCP server
|
|
458
|
+
const routerNodeBin = path.join(nodeBinDir, isWindows ? 'node.exe' : 'node');
|
|
400
459
|
shimDefs.push({
|
|
401
460
|
name: 'rudi-router',
|
|
402
461
|
script: `#!/bin/bash
|
|
403
462
|
# RUDI Router - Master MCP server for all installed stacks
|
|
404
463
|
# Reads ~/.rudi/rudi.json and proxies tool calls to correct stack
|
|
405
464
|
RUDI_HOME="$HOME/.rudi"
|
|
406
|
-
|
|
407
|
-
|
|
465
|
+
NODE_BIN="${routerNodeBin.replace(/"/g, '\\"')}"
|
|
466
|
+
if [ -x "$NODE_BIN" ]; then
|
|
467
|
+
exec "$NODE_BIN" "$RUDI_HOME/router/router-mcp.js" "$@"
|
|
408
468
|
else
|
|
409
469
|
exec node "$RUDI_HOME/router/router-mcp.js" "$@"
|
|
410
470
|
fi
|