ai-remote 0.4.6 → 0.4.7
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/cli.mjs +40 -4
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -1717,8 +1717,16 @@ var Shell = class {
|
|
|
1717
1717
|
* rejects that, and the engine notes the shell family and asks to be called
|
|
1718
1718
|
* again. That is a detail of how the shell was discovered, not something a
|
|
1719
1719
|
* caller did wrong, so the retry happens here instead of reaching them.
|
|
1720
|
+
*
|
|
1721
|
+
* The wait in front is the same idea one step earlier. "Connected" and "able
|
|
1722
|
+
* to take a command" are not the same moment on Windows: OpenSSH hands out
|
|
1723
|
+
* cmd.exe, the engine swaps it for PowerShell, and readiness is withdrawn in
|
|
1724
|
+
* between. A caller arriving in that window used to be told the shell was
|
|
1725
|
+
* still starting -- true, and useless, because the only thing to do about it
|
|
1726
|
+
* is wait. So it waits.
|
|
1720
1727
|
*/
|
|
1721
1728
|
async runCommand(command) {
|
|
1729
|
+
await this.#waitForPrompt();
|
|
1722
1730
|
let result;
|
|
1723
1731
|
try {
|
|
1724
1732
|
result = await this.session.runCommand(command);
|
|
@@ -1735,14 +1743,19 @@ var Shell = class {
|
|
|
1735
1743
|
durationMs: result.durationMs ?? null
|
|
1736
1744
|
};
|
|
1737
1745
|
}
|
|
1738
|
-
/**
|
|
1746
|
+
/**
|
|
1747
|
+
* Wait until the shell will accept a framed command.
|
|
1748
|
+
*
|
|
1749
|
+
* Returns on the first check when the shell is already settled, which is the
|
|
1750
|
+
* usual case, so this costs a waiting caller nothing.
|
|
1751
|
+
*/
|
|
1739
1752
|
async #waitForPrompt(timeoutMs = 15e3) {
|
|
1740
1753
|
const deadline = Date.now() + timeoutMs;
|
|
1741
1754
|
while (Date.now() < deadline) {
|
|
1742
1755
|
if (this.session.shellOpen && this.session.readySignaled !== false) return;
|
|
1743
1756
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
1744
1757
|
}
|
|
1745
|
-
throw new Error("The SSH shell did not
|
|
1758
|
+
throw new Error("The SSH shell did not become ready for a command.");
|
|
1746
1759
|
}
|
|
1747
1760
|
/** Raw keystrokes, for an interactive terminal. */
|
|
1748
1761
|
write(text) {
|
|
@@ -7753,7 +7766,7 @@ function request(path, op, args = {}, timeoutMs = 12e4) {
|
|
|
7753
7766
|
async function runDaemon(options) {
|
|
7754
7767
|
ensureRunDir();
|
|
7755
7768
|
const session = new RdpSession(options);
|
|
7756
|
-
const
|
|
7769
|
+
const desktopStarting = session.connect();
|
|
7757
7770
|
let shell = null;
|
|
7758
7771
|
let shellStarting = null;
|
|
7759
7772
|
function openShell() {
|
|
@@ -7775,6 +7788,29 @@ async function runDaemon(options) {
|
|
|
7775
7788
|
});
|
|
7776
7789
|
return shellStarting;
|
|
7777
7790
|
}
|
|
7791
|
+
function terminalListening(timeoutMs = 2e3) {
|
|
7792
|
+
return new Promise((resolve) => {
|
|
7793
|
+
const socket = net3.connect({ host: options.host, port: options.sshPort });
|
|
7794
|
+
const answer = (listening) => {
|
|
7795
|
+
socket.destroy();
|
|
7796
|
+
resolve(listening);
|
|
7797
|
+
};
|
|
7798
|
+
socket.setTimeout(timeoutMs);
|
|
7799
|
+
socket.on("connect", () => answer(true));
|
|
7800
|
+
socket.on("timeout", () => answer(false));
|
|
7801
|
+
socket.on("error", () => answer(false));
|
|
7802
|
+
});
|
|
7803
|
+
}
|
|
7804
|
+
const warming = (async () => {
|
|
7805
|
+
if (!options.password) return;
|
|
7806
|
+
if (!(options.sshUsername || bareUsername(options.username))) return;
|
|
7807
|
+
if (!await terminalListening()) return;
|
|
7808
|
+
await openShell();
|
|
7809
|
+
})();
|
|
7810
|
+
warming.catch((error) => {
|
|
7811
|
+
console.log(`[ssh] no warm terminal (${error instanceof Error ? error.message : String(error)}); exec will open one when it is needed`);
|
|
7812
|
+
});
|
|
7813
|
+
const size = await desktopStarting;
|
|
7778
7814
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7779
7815
|
function writeMeta() {
|
|
7780
7816
|
writeFileSync2(metaPath(options.name), JSON.stringify({
|
|
@@ -8066,7 +8102,7 @@ function freeName(base, taken) {
|
|
|
8066
8102
|
// src/cli/cli.ts
|
|
8067
8103
|
function readLog(name) {
|
|
8068
8104
|
try {
|
|
8069
|
-
const lines = readFileSync2(logPath(name), "utf8").split("\n").filter((line) => /[a-z]/i.test(line) && !/^\s/.test(line) && !line.startsWith("[RDP] ")).map((line) => line.trim());
|
|
8105
|
+
const lines = readFileSync2(logPath(name), "utf8").split("\n").filter((line) => /[a-z]/i.test(line) && !/^\s/.test(line) && !line.startsWith("[RDP] ") && !line.startsWith("[ssh] ")).map((line) => line.trim());
|
|
8070
8106
|
return [...new Set(lines)].slice(-3).join("\n");
|
|
8071
8107
|
} catch {
|
|
8072
8108
|
return "";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-remote",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"description": "RDP, VNC and SSH protocol engines that run in Node, a Worker or a browser -- plus `npx ai-remote`, a CLI that drives a machine and shows you what it is doing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|