@learnrudi/cli 1.10.8 → 1.10.10
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 +201 -38
- package/dist/packages-manifest.json +18 -18
- package/package.json +1 -1
- 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"))) {
|
|
8929
|
-
execSync11(`"${npmCmd}" init -y`, { cwd: installPath, stdio: "pipe" });
|
|
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"))) {
|
|
9005
|
+
execSync11(`"${npmCmd}" init -y`, { cwd: installPath, stdio: "pipe", env: buildNpmEnv(npmCmd) });
|
|
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", env: buildNpmEnv(npmCmd) });
|
|
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,31 @@ 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
|
+
env: buildNpmEnv(npmCmd)
|
|
9254
|
+
});
|
|
9255
|
+
} catch (error) {
|
|
9256
|
+
console.warn(`[Installer] Warning: Failed to uninstall ${manifest.npmPackage}: ${error.message}`);
|
|
9257
|
+
}
|
|
9258
|
+
}
|
|
9152
9259
|
if (bins.length > 0) {
|
|
9153
9260
|
removeShims(bins);
|
|
9154
9261
|
}
|
|
@@ -9328,7 +9435,7 @@ async function installStackDependencies(stackPath, onProgress) {
|
|
|
9328
9435
|
onProgress?.({ phase: "installing-deps", message: "Installing Node.js dependencies..." });
|
|
9329
9436
|
try {
|
|
9330
9437
|
const npmCmd = await findNpmExecutable();
|
|
9331
|
-
execSync11(`"${npmCmd}" install`, { cwd: nodePath, stdio: "pipe" });
|
|
9438
|
+
execSync11(`"${npmCmd}" install`, { cwd: nodePath, stdio: "pipe", env: buildNpmEnv(npmCmd) });
|
|
9332
9439
|
} catch (error) {
|
|
9333
9440
|
console.warn(`Warning: Failed to install Node.js dependencies: ${error.message}`);
|
|
9334
9441
|
}
|
|
@@ -9346,6 +9453,17 @@ async function installStackDependencies(stackPath, onProgress) {
|
|
|
9346
9453
|
}
|
|
9347
9454
|
}
|
|
9348
9455
|
}
|
|
9456
|
+
function buildNpmEnv(npmCmd) {
|
|
9457
|
+
if (!import_path6.default.isAbsolute(npmCmd)) {
|
|
9458
|
+
return process.env;
|
|
9459
|
+
}
|
|
9460
|
+
const npmBinDir = import_path6.default.dirname(npmCmd);
|
|
9461
|
+
const basePath = process.env.PATH || "";
|
|
9462
|
+
return {
|
|
9463
|
+
...process.env,
|
|
9464
|
+
PATH: [npmBinDir, basePath].join(import_path6.default.delimiter)
|
|
9465
|
+
};
|
|
9466
|
+
}
|
|
9349
9467
|
async function findNpmExecutable() {
|
|
9350
9468
|
const isWindows = process.platform === "win32";
|
|
9351
9469
|
const arch = process.arch === "arm64" ? "arm64" : "x64";
|
|
@@ -10358,6 +10476,8 @@ __export(src_exports2, {
|
|
|
10358
10476
|
getInstallOrder: () => getInstallOrder,
|
|
10359
10477
|
getInstalledPackages: () => getInstalledPackages,
|
|
10360
10478
|
getLockfilePath: () => getLockfilePath,
|
|
10479
|
+
getNodeRuntimeBinDir: () => getNodeRuntimeBinDir,
|
|
10480
|
+
getNodeRuntimeRoot: () => getNodeRuntimeRoot,
|
|
10361
10481
|
getPackage: () => getPackage,
|
|
10362
10482
|
getPackagePath: () => getPackagePath,
|
|
10363
10483
|
getShimOwner: () => getShimOwner,
|
|
@@ -10379,6 +10499,7 @@ __export(src_exports2, {
|
|
|
10379
10499
|
registerSystemBinary: () => registerSystemBinary,
|
|
10380
10500
|
removeShims: () => removeShims,
|
|
10381
10501
|
removeStack: () => removeStack,
|
|
10502
|
+
resolveNodeRuntimeBin: () => resolveNodeRuntimeBin,
|
|
10382
10503
|
resolvePackage: () => resolvePackage,
|
|
10383
10504
|
resolvePackages: () => resolvePackages,
|
|
10384
10505
|
rudiConfigExists: () => rudiConfigExists,
|
|
@@ -39332,10 +39453,31 @@ function getVersion2(command, versionFlag) {
|
|
|
39332
39453
|
return null;
|
|
39333
39454
|
}
|
|
39334
39455
|
}
|
|
39456
|
+
function getAgentBins(agentId) {
|
|
39457
|
+
const manifestPath = import_path22.default.join(PATHS.agents, agentId, "manifest.json");
|
|
39458
|
+
if (import_fs24.default.existsSync(manifestPath)) {
|
|
39459
|
+
try {
|
|
39460
|
+
const manifest = JSON.parse(import_fs24.default.readFileSync(manifestPath, "utf-8"));
|
|
39461
|
+
const bins = manifest.bins || manifest.binaries || [];
|
|
39462
|
+
if (bins.length > 0) return bins;
|
|
39463
|
+
} catch {
|
|
39464
|
+
}
|
|
39465
|
+
}
|
|
39466
|
+
return [agentId];
|
|
39467
|
+
}
|
|
39468
|
+
function findRudiAgentBin(agentId) {
|
|
39469
|
+
const bins = getAgentBins(agentId);
|
|
39470
|
+
for (const bin of bins) {
|
|
39471
|
+
const binPath = resolveNodeRuntimeBin(bin);
|
|
39472
|
+
if (import_fs24.default.existsSync(binPath)) return binPath;
|
|
39473
|
+
}
|
|
39474
|
+
return null;
|
|
39475
|
+
}
|
|
39335
39476
|
function findBinary(command, kind2 = "binary") {
|
|
39336
39477
|
const rudiPaths = [
|
|
39337
39478
|
import_path22.default.join(PATHS.agents, command, "node_modules", ".bin", command),
|
|
39338
39479
|
import_path22.default.join(PATHS.runtimes, command, "bin", command),
|
|
39480
|
+
resolveNodeRuntimeBin(command),
|
|
39339
39481
|
import_path22.default.join(PATHS.binaries, command, command),
|
|
39340
39482
|
import_path22.default.join(PATHS.binaries, command)
|
|
39341
39483
|
];
|
|
@@ -39358,8 +39500,8 @@ function findBinary(command, kind2 = "binary") {
|
|
|
39358
39500
|
return { found: false, path: null, source: null };
|
|
39359
39501
|
}
|
|
39360
39502
|
function getAgentStatus(agent) {
|
|
39361
|
-
const rudiPath =
|
|
39362
|
-
const rudiInstalled =
|
|
39503
|
+
const rudiPath = findRudiAgentBin(agent.id);
|
|
39504
|
+
const rudiInstalled = !!rudiPath;
|
|
39363
39505
|
let globalPath = null;
|
|
39364
39506
|
let globalInstalled = false;
|
|
39365
39507
|
if (!rudiInstalled) {
|
|
@@ -39590,9 +39732,30 @@ function getVersion3(binaryPath, versionFlag = "--version") {
|
|
|
39590
39732
|
return null;
|
|
39591
39733
|
}
|
|
39592
39734
|
}
|
|
39735
|
+
function getAgentBins2(name) {
|
|
39736
|
+
const manifestPath = import_path23.default.join(PATHS.agents, name, "manifest.json");
|
|
39737
|
+
if (import_fs25.default.existsSync(manifestPath)) {
|
|
39738
|
+
try {
|
|
39739
|
+
const manifest = JSON.parse(import_fs25.default.readFileSync(manifestPath, "utf-8"));
|
|
39740
|
+
const bins = manifest.bins || manifest.binaries || [];
|
|
39741
|
+
if (bins.length > 0) return bins;
|
|
39742
|
+
} catch {
|
|
39743
|
+
}
|
|
39744
|
+
}
|
|
39745
|
+
return [name];
|
|
39746
|
+
}
|
|
39747
|
+
function findRudiAgentBin2(name) {
|
|
39748
|
+
const bins = getAgentBins2(name);
|
|
39749
|
+
for (const bin of bins) {
|
|
39750
|
+
const binPath = resolveNodeRuntimeBin(bin);
|
|
39751
|
+
if (import_fs25.default.existsSync(binPath)) return binPath;
|
|
39752
|
+
}
|
|
39753
|
+
return null;
|
|
39754
|
+
}
|
|
39593
39755
|
function detectKindFromFilesystem(name) {
|
|
39594
|
-
const
|
|
39595
|
-
if (import_fs25.default.existsSync(
|
|
39756
|
+
const agentManifestPath = import_path23.default.join(PATHS.agents, name, "manifest.json");
|
|
39757
|
+
if (import_fs25.default.existsSync(agentManifestPath)) return "agent";
|
|
39758
|
+
if (findRudiAgentBin2(name)) return "agent";
|
|
39596
39759
|
const runtimePath = import_path23.default.join(PATHS.runtimes, name, "bin", name);
|
|
39597
39760
|
if (import_fs25.default.existsSync(runtimePath)) return "runtime";
|
|
39598
39761
|
const binaryPath = import_path23.default.join(PATHS.binaries, name, name);
|
|
@@ -39645,8 +39808,8 @@ async function cmdCheck(args, flags) {
|
|
|
39645
39808
|
};
|
|
39646
39809
|
switch (kind2) {
|
|
39647
39810
|
case "agent": {
|
|
39648
|
-
const rudiPath =
|
|
39649
|
-
const rudiInstalled =
|
|
39811
|
+
const rudiPath = findRudiAgentBin2(name);
|
|
39812
|
+
const rudiInstalled = !!rudiPath;
|
|
39650
39813
|
let globalPath = null;
|
|
39651
39814
|
let globalInstalled = false;
|
|
39652
39815
|
if (!rudiInstalled) {
|
|
@@ -39801,16 +39964,6 @@ function getShimTarget(name, shimPath, type) {
|
|
|
39801
39964
|
}
|
|
39802
39965
|
function getPackageFromShim(shimName, target) {
|
|
39803
39966
|
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
39967
|
const manifestDirs = [
|
|
39815
39968
|
import_path24.default.join(PATHS.binaries),
|
|
39816
39969
|
import_path24.default.join(PATHS.runtimes),
|
|
@@ -39834,6 +39987,16 @@ function getPackageFromShim(shimName, target) {
|
|
|
39834
39987
|
}
|
|
39835
39988
|
}
|
|
39836
39989
|
}
|
|
39990
|
+
const match = target.match(/\/(binaries|runtimes|agents)\/([^\/]+)/);
|
|
39991
|
+
if (match) {
|
|
39992
|
+
const [, kind2, pkgName] = match;
|
|
39993
|
+
const kindMap = {
|
|
39994
|
+
"binaries": "binary",
|
|
39995
|
+
"runtimes": "runtime",
|
|
39996
|
+
"agents": "agent"
|
|
39997
|
+
};
|
|
39998
|
+
return `${kindMap[kind2]}:${pkgName}`;
|
|
39999
|
+
}
|
|
39837
40000
|
return null;
|
|
39838
40001
|
}
|
|
39839
40002
|
function formatShimStatus(shim, flags) {
|
|
@@ -40670,7 +40833,7 @@ async function cmdStudio(args, flags) {
|
|
|
40670
40833
|
}
|
|
40671
40834
|
|
|
40672
40835
|
// src/index.js
|
|
40673
|
-
var VERSION2 = true ? "1.10.
|
|
40836
|
+
var VERSION2 = true ? "1.10.10" : process.env.npm_package_version || "0.0.0";
|
|
40674
40837
|
async function main() {
|
|
40675
40838
|
const { command, args, flags } = parseArgs(process.argv.slice(2));
|
|
40676
40839
|
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-11T22:42:52.951Z",
|
|
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
|
@@ -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
|