traderclaw-cli 1.0.126 → 1.0.128
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.
|
@@ -342,6 +342,7 @@ function buildCommandString(cmd, args = []) {
|
|
|
342
342
|
|
|
343
343
|
function isPrivilegeError(err) {
|
|
344
344
|
const text = `${err?.message || ""}\n${err?.stderr || ""}\n${err?.stdout || ""}`.toLowerCase();
|
|
345
|
+
// Do not match bare "sudo" — OpenClaw prints "try sudo loginctl" in hints; that is not a priv-denied signal.
|
|
345
346
|
return (
|
|
346
347
|
text.includes("permission denied")
|
|
347
348
|
|| text.includes("eacces")
|
|
@@ -349,7 +350,8 @@ function isPrivilegeError(err) {
|
|
|
349
350
|
|| text.includes("operation not permitted")
|
|
350
351
|
|| text.includes("must be root")
|
|
351
352
|
|| text.includes("requires root")
|
|
352
|
-
|| text.includes("sudo")
|
|
353
|
+
|| text.includes("sudo: a password is required")
|
|
354
|
+
|| text.includes("a terminal is required to read the password")
|
|
353
355
|
|| text.includes("authentication is required")
|
|
354
356
|
);
|
|
355
357
|
}
|
|
@@ -367,6 +369,31 @@ function canUseSudoWithoutPrompt() {
|
|
|
367
369
|
}
|
|
368
370
|
}
|
|
369
371
|
|
|
372
|
+
/**
|
|
373
|
+
* NodeSource/deb npm defaults to a root-owned global tree (/usr/lib/node_modules). Non-root
|
|
374
|
+
* `npm install -g` must target a user prefix; `NPM_CONFIG_PREFIX` is applied to every npm child.
|
|
375
|
+
*/
|
|
376
|
+
function ensureNpmUserGlobalPrefixForNonRoot() {
|
|
377
|
+
if (typeof process.getuid !== "function" || process.getuid() === 0) return;
|
|
378
|
+
const prefix = join(homedir(), ".npm-global");
|
|
379
|
+
try {
|
|
380
|
+
mkdirSync(prefix, { recursive: true });
|
|
381
|
+
} catch {
|
|
382
|
+
/* ignore */
|
|
383
|
+
}
|
|
384
|
+
process.env.NPM_CONFIG_PREFIX = prefix;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/** User systemd (openclaw gateway) expects XDG_RUNTIME_DIR under /run/user/<uid> once linger is on. */
|
|
388
|
+
function primeLinuxUserRuntimeEnv() {
|
|
389
|
+
if (process.platform !== "linux" || typeof process.getuid !== "function") return;
|
|
390
|
+
const uid = process.getuid();
|
|
391
|
+
if (uid === 0) return;
|
|
392
|
+
if (!process.env.XDG_RUNTIME_DIR) {
|
|
393
|
+
process.env.XDG_RUNTIME_DIR = `/run/user/${uid}`;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
370
397
|
function tailscalePermissionRemediation() {
|
|
371
398
|
return [
|
|
372
399
|
"Tailscale requires elevated permissions on this host.",
|
|
@@ -587,6 +614,7 @@ function getGlobalOpenClawPackageDir() {
|
|
|
587
614
|
*/
|
|
588
615
|
/** Runs `npm install` in the global `openclaw` package directory (fixes missing `grammy` etc.). */
|
|
589
616
|
export async function ensureOpenClawGlobalPackageDependencies() {
|
|
617
|
+
ensureNpmUserGlobalPrefixForNonRoot();
|
|
590
618
|
const dir = getGlobalOpenClawPackageDir();
|
|
591
619
|
if (!dir) {
|
|
592
620
|
return { skipped: true, reason: "global_openclaw_dir_not_found" };
|
|
@@ -2307,11 +2335,33 @@ export class InstallerStepEngine {
|
|
|
2307
2335
|
}
|
|
2308
2336
|
|
|
2309
2337
|
async runWithPrivilegeGuidance(stepId, cmd, args = [], customLines = []) {
|
|
2338
|
+
primeLinuxUserRuntimeEnv();
|
|
2339
|
+
const onEvent = (evt) =>
|
|
2340
|
+
this.emitLog(stepId, evt.type === "stderr" ? "warn" : "info", evt.text, evt.urls || []);
|
|
2341
|
+
const tryRun = (c, a) => runCommandWithEvents(c, a, { onEvent });
|
|
2342
|
+
|
|
2310
2343
|
try {
|
|
2311
|
-
return await
|
|
2312
|
-
onEvent: (evt) => this.emitLog(stepId, evt.type === "stderr" ? "warn" : "info", evt.text, evt.urls || []),
|
|
2313
|
-
});
|
|
2344
|
+
return await tryRun(cmd, args);
|
|
2314
2345
|
} catch (err) {
|
|
2346
|
+
const sudoOpenclawGateway =
|
|
2347
|
+
cmd === "openclaw" &&
|
|
2348
|
+
Array.isArray(args) &&
|
|
2349
|
+
args[0] === "gateway" &&
|
|
2350
|
+
!isRootUser() &&
|
|
2351
|
+
canUseSudoWithoutPrompt();
|
|
2352
|
+
if (sudoOpenclawGateway) {
|
|
2353
|
+
const bin = getCommandOutput("command -v openclaw")?.trim();
|
|
2354
|
+
if (bin) {
|
|
2355
|
+
try {
|
|
2356
|
+
return await tryRun("sudo", ["-n", bin, ...args]);
|
|
2357
|
+
} catch (e2) {
|
|
2358
|
+
if (isPrivilegeError(e2)) {
|
|
2359
|
+
throw new Error(privilegeRemediationMessage(cmd, args, customLines));
|
|
2360
|
+
}
|
|
2361
|
+
throw e2;
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2315
2365
|
if (isPrivilegeError(err)) {
|
|
2316
2366
|
throw new Error(privilegeRemediationMessage(cmd, args, customLines));
|
|
2317
2367
|
}
|
|
@@ -2490,7 +2540,18 @@ export class InstallerStepEngine {
|
|
|
2490
2540
|
// best effort; gateway install may still surface a clearer error
|
|
2491
2541
|
}
|
|
2492
2542
|
}
|
|
2543
|
+
if (!isRootUser() && canUseSudoWithoutPrompt() && typeof process.getuid === "function") {
|
|
2544
|
+
const uid = process.getuid();
|
|
2545
|
+
try {
|
|
2546
|
+
await runCommandWithEvents("sudo", ["-n", "systemctl", "start", `user@${uid}.service`], {
|
|
2547
|
+
onEvent: (evt) => this.emitLog(stepId, evt.type === "stderr" ? "warn" : "info", evt.text, evt.urls || []),
|
|
2548
|
+
});
|
|
2549
|
+
} catch {
|
|
2550
|
+
// best effort
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2493
2553
|
}
|
|
2554
|
+
primeLinuxUserRuntimeEnv();
|
|
2494
2555
|
|
|
2495
2556
|
try {
|
|
2496
2557
|
await this.runWithPrivilegeGuidance(stepId, "openclaw", ["gateway", "stop"]);
|
|
@@ -2725,6 +2786,7 @@ export class InstallerStepEngine {
|
|
|
2725
2786
|
this.state.status = "running";
|
|
2726
2787
|
this.state.startedAt = nowIso();
|
|
2727
2788
|
try {
|
|
2789
|
+
ensureNpmUserGlobalPrefixForNonRoot();
|
|
2728
2790
|
if (!this.options.skipPreflight) {
|
|
2729
2791
|
await this.runStep("preflight", "Checking prerequisites", async () => {
|
|
2730
2792
|
if (!commandExists("node") || !commandExists("npm")) throw new Error("node and npm are required");
|
|
@@ -2862,7 +2924,29 @@ export class InstallerStepEngine {
|
|
|
2862
2924
|
lingerSnap.username,
|
|
2863
2925
|
]);
|
|
2864
2926
|
}
|
|
2927
|
+
// Linger alone does not always create /run/user/<uid> until user@uid.service runs (SSH-less bootstrap).
|
|
2928
|
+
if (!isRootUser() && canUseSudoWithoutPrompt() && typeof process.getuid === "function") {
|
|
2929
|
+
const uid = process.getuid();
|
|
2930
|
+
try {
|
|
2931
|
+
await runCommandWithEvents("sudo", ["-n", "systemctl", "start", `user@${uid}.service`], {
|
|
2932
|
+
onEvent: (evt) =>
|
|
2933
|
+
this.emitLog(
|
|
2934
|
+
"gateway_bootstrap",
|
|
2935
|
+
evt.type === "stderr" ? "warn" : "info",
|
|
2936
|
+
evt.text,
|
|
2937
|
+
evt.urls || [],
|
|
2938
|
+
),
|
|
2939
|
+
});
|
|
2940
|
+
} catch {
|
|
2941
|
+
this.emitLog(
|
|
2942
|
+
"gateway_bootstrap",
|
|
2943
|
+
"warn",
|
|
2944
|
+
`Could not start user@${uid}.service (non-fatal); gateway install may still work if session exists.`,
|
|
2945
|
+
);
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2865
2948
|
}
|
|
2949
|
+
primeLinuxUserRuntimeEnv();
|
|
2866
2950
|
await this.runWithPrivilegeGuidance("gateway_bootstrap", "openclaw", ["gateway", "install"]);
|
|
2867
2951
|
await this.runWithPrivilegeGuidance("gateway_bootstrap", "openclaw", ["gateway", "restart"]);
|
|
2868
2952
|
if (this.options.skipFunnel) {
|
|
@@ -3123,6 +3207,8 @@ export async function runTraderClawDeepUpdate(options = {}) {
|
|
|
3123
3207
|
onLog({ at: nowIso(), stepId, level, text: clean, urls: [] });
|
|
3124
3208
|
};
|
|
3125
3209
|
|
|
3210
|
+
ensureNpmUserGlobalPrefixForNonRoot();
|
|
3211
|
+
|
|
3126
3212
|
async function runDeepStep(stepId, title, handler) {
|
|
3127
3213
|
onStep({ at: nowIso(), stepId, status: "in_progress", detail: title });
|
|
3128
3214
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "traderclaw-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.128",
|
|
4
4
|
"description": "Global TraderClaw CLI (install --wizard, setup, precheck). Installs solana-traderclaw as a dependency for OpenClaw plugin files.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"node": ">=22"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"solana-traderclaw": "^1.0.
|
|
20
|
+
"solana-traderclaw": "^1.0.128"
|
|
21
21
|
},
|
|
22
22
|
"keywords": [
|
|
23
23
|
"traderclaw",
|