ragent-cli 1.6.2 → 1.7.1
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.js +103 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ var require_package = __commonJS({
|
|
|
31
31
|
"package.json"(exports2, module2) {
|
|
32
32
|
module2.exports = {
|
|
33
33
|
name: "ragent-cli",
|
|
34
|
-
version: "1.
|
|
34
|
+
version: "1.7.1",
|
|
35
35
|
description: "CLI agent for rAgent Live \u2014 browser-first terminal control plane for AI coding agents",
|
|
36
36
|
main: "dist/index.js",
|
|
37
37
|
bin: {
|
|
@@ -682,6 +682,43 @@ function decodeJwtExp(token) {
|
|
|
682
682
|
return null;
|
|
683
683
|
}
|
|
684
684
|
}
|
|
685
|
+
async function startSessionWithMachineSecret(params) {
|
|
686
|
+
console.log("[rAgent] Attempting session recovery with machine credential...");
|
|
687
|
+
const response = await fetch(`${params.portal}/api/agent/session/start`, {
|
|
688
|
+
method: "POST",
|
|
689
|
+
headers: { "Content-Type": "application/json" },
|
|
690
|
+
body: JSON.stringify({
|
|
691
|
+
hostId: params.hostId,
|
|
692
|
+
machineSecret: params.machineSecret
|
|
693
|
+
})
|
|
694
|
+
});
|
|
695
|
+
if (response.status === 401 || response.status === 403) {
|
|
696
|
+
throw new AuthError(
|
|
697
|
+
"Machine credential rejected \u2014 agent may be revoked. Re-connect with: ragent connect --token <token>"
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
if (!response.ok) {
|
|
701
|
+
const data2 = await response.json().catch(() => ({}));
|
|
702
|
+
throw new Error(
|
|
703
|
+
`Session start failed: ${data2.error || response.status}`
|
|
704
|
+
);
|
|
705
|
+
}
|
|
706
|
+
const data = await response.json();
|
|
707
|
+
if (!data.agentToken) {
|
|
708
|
+
throw new Error("Session start response missing agentToken");
|
|
709
|
+
}
|
|
710
|
+
const patch = {
|
|
711
|
+
agentToken: data.agentToken,
|
|
712
|
+
tokenExpiresAt: data.expiresAt || ""
|
|
713
|
+
};
|
|
714
|
+
if (data.refreshToken) {
|
|
715
|
+
patch.refreshToken = data.refreshToken;
|
|
716
|
+
patch.refreshExpiresAt = data.refreshExpiresAt || "";
|
|
717
|
+
}
|
|
718
|
+
saveConfigPatch(patch);
|
|
719
|
+
console.log("[rAgent] Session recovered via machine credential.");
|
|
720
|
+
return data.agentToken;
|
|
721
|
+
}
|
|
685
722
|
async function refreshTokenIfNeeded(params) {
|
|
686
723
|
const config = loadConfig();
|
|
687
724
|
const refreshToken = config.refreshToken;
|
|
@@ -707,10 +744,23 @@ async function refreshTokenIfNeeded(params) {
|
|
|
707
744
|
body: JSON.stringify(body)
|
|
708
745
|
});
|
|
709
746
|
if (!response.ok) {
|
|
710
|
-
const
|
|
747
|
+
const errorData = await response.json().catch(() => ({}));
|
|
711
748
|
console.warn(
|
|
712
|
-
`[rAgent] Token refresh failed: ${
|
|
749
|
+
`[rAgent] Token refresh failed: ${errorData.error || response.status}`
|
|
713
750
|
);
|
|
751
|
+
if (config.machineSecret && config.hostId) {
|
|
752
|
+
try {
|
|
753
|
+
return await startSessionWithMachineSecret({
|
|
754
|
+
portal: params.portal,
|
|
755
|
+
hostId: config.hostId,
|
|
756
|
+
machineSecret: config.machineSecret
|
|
757
|
+
});
|
|
758
|
+
} catch (mcError) {
|
|
759
|
+
if (mcError instanceof AuthError) throw mcError;
|
|
760
|
+
const mcMessage = mcError instanceof Error ? mcError.message : String(mcError);
|
|
761
|
+
console.warn(`[rAgent] Machine credential recovery failed: ${mcMessage}`);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
714
764
|
return params.agentToken;
|
|
715
765
|
}
|
|
716
766
|
const data = await response.json();
|
|
@@ -723,10 +773,14 @@ async function refreshTokenIfNeeded(params) {
|
|
|
723
773
|
patch.refreshToken = data.refreshToken;
|
|
724
774
|
patch.refreshExpiresAt = data.refreshExpiresAt || "";
|
|
725
775
|
}
|
|
776
|
+
if (data.machineSecret) {
|
|
777
|
+
patch.machineSecret = data.machineSecret;
|
|
778
|
+
}
|
|
726
779
|
saveConfigPatch(patch);
|
|
727
780
|
console.log("[rAgent] Token refreshed successfully.");
|
|
728
781
|
return data.agentToken;
|
|
729
782
|
} catch (error) {
|
|
783
|
+
if (error instanceof AuthError) throw error;
|
|
730
784
|
const message = error instanceof Error ? error.message : String(error);
|
|
731
785
|
console.warn(`[rAgent] Token refresh error: ${message}`);
|
|
732
786
|
return params.agentToken;
|
|
@@ -753,6 +807,9 @@ async function claimHost(params) {
|
|
|
753
807
|
if (!data.agentToken) {
|
|
754
808
|
throw new Error("Missing connector token in claim response");
|
|
755
809
|
}
|
|
810
|
+
if (data.machineSecret) {
|
|
811
|
+
saveConfigPatch({ machineSecret: data.machineSecret });
|
|
812
|
+
}
|
|
756
813
|
return data;
|
|
757
814
|
}
|
|
758
815
|
async function negotiateAgent(params) {
|
|
@@ -1516,8 +1573,18 @@ var SessionStreamer = class {
|
|
|
1516
1573
|
if (!pid) return false;
|
|
1517
1574
|
if (!(0, import_node_fs.existsSync)(`/proc/${pid}`)) {
|
|
1518
1575
|
console.warn(`[rAgent] Process ${pid} does not exist (no /proc/${pid}).`);
|
|
1576
|
+
this.sendFn(sessionId, "\r\n[rAgent] Process is no longer running. It will be removed on next sync.\r\n");
|
|
1519
1577
|
return false;
|
|
1520
1578
|
}
|
|
1579
|
+
try {
|
|
1580
|
+
const stat = (0, import_node_fs.readFileSync)(`/proc/${pid}/stat`, "utf8");
|
|
1581
|
+
if (stat.includes(") Z")) {
|
|
1582
|
+
console.warn(`[rAgent] Process ${pid} is a zombie.`);
|
|
1583
|
+
this.sendFn(sessionId, "\r\n[rAgent] Process has exited (zombie). It will be removed on next sync.\r\n");
|
|
1584
|
+
return false;
|
|
1585
|
+
}
|
|
1586
|
+
} catch {
|
|
1587
|
+
}
|
|
1521
1588
|
try {
|
|
1522
1589
|
const straceProc = (0, import_node_child_process2.spawn)(
|
|
1523
1590
|
"strace",
|
|
@@ -1575,7 +1642,11 @@ var SessionStreamer = class {
|
|
|
1575
1642
|
const remaining = stream.utf8Decoder.end();
|
|
1576
1643
|
if (remaining) this.sendFn(sessionId, remaining);
|
|
1577
1644
|
if (code === 1) {
|
|
1578
|
-
|
|
1645
|
+
if (pid && !(0, import_node_fs.existsSync)(`/proc/${pid}`)) {
|
|
1646
|
+
this.sendFn(sessionId, "\r\n[rAgent] Process has exited. It will be removed on next sync.\r\n");
|
|
1647
|
+
} else {
|
|
1648
|
+
this.sendFn(sessionId, "\r\n[rAgent] Permission denied: cannot attach to process.\r\nTo enable process tracing, run:\r\n sudo sysctl kernel.yama.ptrace_scope=0\r\n");
|
|
1649
|
+
}
|
|
1579
1650
|
}
|
|
1580
1651
|
stream.stopped = true;
|
|
1581
1652
|
this.active.delete(sessionId);
|
|
@@ -2666,8 +2737,13 @@ var ControlDispatcher = class {
|
|
|
2666
2737
|
process.kill(pid, "SIGTERM");
|
|
2667
2738
|
console.log(`[rAgent] Sent SIGTERM to process ${pid} (${sessionId}).`);
|
|
2668
2739
|
} catch (error) {
|
|
2669
|
-
const
|
|
2670
|
-
|
|
2740
|
+
const code = error.code;
|
|
2741
|
+
if (code === "ESRCH") {
|
|
2742
|
+
console.log(`[rAgent] Process ${pid} already exited, cleaning up.`);
|
|
2743
|
+
} else {
|
|
2744
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2745
|
+
console.warn(`[rAgent] Failed to kill process ${pid}: ${message}`);
|
|
2746
|
+
}
|
|
2671
2747
|
}
|
|
2672
2748
|
await this.syncInventory();
|
|
2673
2749
|
}
|
|
@@ -3667,6 +3743,27 @@ async function runAgent(rawOptions) {
|
|
|
3667
3743
|
});
|
|
3668
3744
|
} catch (error) {
|
|
3669
3745
|
if (error instanceof AuthError) {
|
|
3746
|
+
const cfg = loadConfig();
|
|
3747
|
+
if (cfg.machineSecret && cfg.hostId) {
|
|
3748
|
+
try {
|
|
3749
|
+
options.agentToken = await startSessionWithMachineSecret({
|
|
3750
|
+
portal: options.portal,
|
|
3751
|
+
hostId: cfg.hostId,
|
|
3752
|
+
machineSecret: cfg.machineSecret
|
|
3753
|
+
});
|
|
3754
|
+
inventory.updateOptions(options);
|
|
3755
|
+
dispatcher.updateOptions(options);
|
|
3756
|
+
console.log("[rAgent] Recovered from auth failure via machine credential. Reconnecting...");
|
|
3757
|
+
continue;
|
|
3758
|
+
} catch (mcError) {
|
|
3759
|
+
if (mcError instanceof AuthError) {
|
|
3760
|
+
console.error(`[rAgent] ${mcError.message}`);
|
|
3761
|
+
} else {
|
|
3762
|
+
const mcMsg = mcError instanceof Error ? mcError.message : String(mcError);
|
|
3763
|
+
console.error(`[rAgent] Machine credential recovery failed: ${mcMsg}`);
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3670
3767
|
console.error(`[rAgent] ${error.message}`);
|
|
3671
3768
|
console.error(
|
|
3672
3769
|
"[rAgent] Connector token is invalid or revoked. Stopping. Re-connect with: ragent connect --token <token>"
|