ai-remote 0.4.15 → 0.4.16
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/README.md +77 -0
- package/SKILL.md +47 -1
- package/dist/{cli-chunk-RBCU3NX4.mjs → cli-chunk-Q33YGIDO.mjs} +1 -1
- package/dist/{cli-chunk-EYQCDSPT.mjs → cli-chunk-S2TWL5LF.mjs} +13 -0
- package/dist/{cli-copy-NRXMTHID.mjs → cli-copy-BOF44DWQ.mjs} +1 -1
- package/dist/{cli-daemon-LU4LHDCH.mjs → cli-daemon-4VU67MLE.mjs} +316 -7
- package/dist/{cli-shell-TE6DLBIB.mjs → cli-shell-45XRTE7O.mjs} +2 -2
- package/dist/cli.mjs +63 -6
- package/dist/protocols.js +12 -11
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -169,6 +169,8 @@ The rest drive that session, and take no host:
|
|
|
169
169
|
${NAME} key <Code> press keys, e.g. MetaLeft, ControlLeft+KeyA
|
|
170
170
|
${NAME} exec "cmd" run a command in the terminal (SSH)
|
|
171
171
|
${NAME} shell an interactive terminal
|
|
172
|
+
${NAME} reconnect a new terminal: fresh login, fresh PATH
|
|
173
|
+
${NAME} clipboard [on|off] share this machine's clipboard both ways
|
|
172
174
|
${NAME} cp <src> <dst> copy files; a remote path starts with ':'
|
|
173
175
|
${NAME} do "steps" several actions in one go
|
|
174
176
|
${NAME} vnc give this session a screen over VNC
|
|
@@ -217,6 +219,7 @@ Options for open
|
|
|
217
219
|
--fullscreen fill the display; RDP uses its current resolution
|
|
218
220
|
--side-panel open the SSH terminal docked on the right
|
|
219
221
|
--audio play the remote computer's sound in the window (RDP)
|
|
222
|
+
--clipboard share this machine's clipboard with the desktop
|
|
220
223
|
--view-port N port for the window (default: 7373)
|
|
221
224
|
--idle MINUTES close an unused session (default: 0, never)
|
|
222
225
|
--headless no window (same as --no-view)
|
|
@@ -230,6 +233,7 @@ Options for open
|
|
|
230
233
|
Options for the rest
|
|
231
234
|
--session NAME which session to drive (default: the last opened)
|
|
232
235
|
-r, --recursive for cp: copy a directory
|
|
236
|
+
--reconnect for exec: a new terminal first, then the command
|
|
233
237
|
-o, --out FILE where a screenshot goes (default: screen.png)
|
|
234
238
|
--max-edge N shrink a screenshot to fit N
|
|
235
239
|
--json machine-readable result on stdout
|
|
@@ -377,7 +381,7 @@ function refuseTarget(command, token) {
|
|
|
377
381
|
);
|
|
378
382
|
}
|
|
379
383
|
var DESKTOP_ONLY = /* @__PURE__ */ new Set(["shot", "click", "type", "key", "do"]);
|
|
380
|
-
var TAKES_NOTHING = /* @__PURE__ */ new Set(["shot", "view", "status", "shell", "close", "vnc"]);
|
|
384
|
+
var TAKES_NOTHING = /* @__PURE__ */ new Set(["shot", "view", "status", "shell", "close", "vnc", "reconnect"]);
|
|
381
385
|
var COORDINATE = /^-?\d+\s*,\s*-?\d+$/;
|
|
382
386
|
function refuseLegacyTarget(args) {
|
|
383
387
|
const { command, rest } = args;
|
|
@@ -405,7 +409,17 @@ async function ask(name, op, args = {}, timeoutMs) {
|
|
|
405
409
|
return response.result;
|
|
406
410
|
}
|
|
407
411
|
async function tell(session, op, args = {}, timeoutMs) {
|
|
408
|
-
const result = await ask(session.name, op, args, timeoutMs)
|
|
412
|
+
const result = await ask(session.name, op, args, timeoutMs).catch((error) => {
|
|
413
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
414
|
+
if (/^Unknown operation/.test(message)) {
|
|
415
|
+
throw new CliError(
|
|
416
|
+
`The session ${session.name} does not support \`${op}\`: it was started by an older version of ${NAME} and is still running it.
|
|
417
|
+
${NAME} close --session ${session.name} then open it again`,
|
|
418
|
+
12
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
throw error;
|
|
422
|
+
});
|
|
409
423
|
if (result === null) {
|
|
410
424
|
cleanup(session.name);
|
|
411
425
|
throw new CliError(`The session ${session.name} is no longer answering. It has been cleaned up.`, 12);
|
|
@@ -542,7 +556,7 @@ async function main() {
|
|
|
542
556
|
if (args.command === "__session") {
|
|
543
557
|
const mode = modeFor(args, args.rest[0]);
|
|
544
558
|
const { host, port } = splitTarget(args.rest[0] ?? "", defaultPort(mode));
|
|
545
|
-
const { runDaemon } = await import("./cli-daemon-
|
|
559
|
+
const { runDaemon } = await import("./cli-daemon-4VU67MLE.mjs");
|
|
546
560
|
await runDaemon({
|
|
547
561
|
name: sessionName(host, port, flag(args, "name", "session")),
|
|
548
562
|
host,
|
|
@@ -665,6 +679,13 @@ Saved, nothing open (\`${NAME} open <host>\` needs no password):
|
|
|
665
679
|
sidePanel: has(args, "side-panel")
|
|
666
680
|
}));
|
|
667
681
|
}
|
|
682
|
+
if (has(args, "clipboard")) {
|
|
683
|
+
const shared = await ask(name2, "clipboard", { on: true });
|
|
684
|
+
if (!shared?.available) {
|
|
685
|
+
process.stderr.write("The clipboard cannot be shared with this session (it needs a desktop at the far end and a clipboard tool here).\n");
|
|
686
|
+
}
|
|
687
|
+
Object.assign(status, { clipboard: shared });
|
|
688
|
+
}
|
|
668
689
|
setCurrent(name2);
|
|
669
690
|
report(json, "open", {
|
|
670
691
|
host,
|
|
@@ -759,6 +780,32 @@ Saved, nothing open (\`${NAME} open <host>\` needs no password):
|
|
|
759
780
|
}
|
|
760
781
|
const session = currentSession(args);
|
|
761
782
|
const { name } = session;
|
|
783
|
+
if (args.command === "reconnect") {
|
|
784
|
+
const before = await ask(name, "status", {}, 5e3);
|
|
785
|
+
const result = await tell(session, "shell-reconnect");
|
|
786
|
+
report(json, "reconnect", {
|
|
787
|
+
name,
|
|
788
|
+
host: session.host,
|
|
789
|
+
port: session.port,
|
|
790
|
+
replaced: result.replaced,
|
|
791
|
+
previous: before?.shell ?? "unknown",
|
|
792
|
+
shell: result.shell
|
|
793
|
+
});
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
if (args.command === "clipboard") {
|
|
797
|
+
const asked = args.rest[0]?.toLowerCase();
|
|
798
|
+
if (asked && !["on", "off"].includes(asked)) {
|
|
799
|
+
throw new CliError(`\`${NAME} clipboard\` takes "on", "off", or nothing to report.`, 12);
|
|
800
|
+
}
|
|
801
|
+
const state = await tell(
|
|
802
|
+
session,
|
|
803
|
+
"clipboard",
|
|
804
|
+
asked ? { on: asked === "on" } : {}
|
|
805
|
+
);
|
|
806
|
+
report(json, "clipboard", { name, ...state });
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
762
809
|
if (args.command === "shell") {
|
|
763
810
|
await interactiveShell(args, session);
|
|
764
811
|
return;
|
|
@@ -886,6 +933,7 @@ Open the host again without --ssh for a desktop.`,
|
|
|
886
933
|
refuseSessionHost(args, "exec", session);
|
|
887
934
|
const command = args.rest.join(" ");
|
|
888
935
|
if (!command) throw new CliError("exec needs a command to run", 12);
|
|
936
|
+
if (has(args, "reconnect", "fresh")) await tell(session, "shell-reconnect");
|
|
889
937
|
const result = await tell(session, "exec", { command });
|
|
890
938
|
Object.assign(summary, result);
|
|
891
939
|
if (!json) {
|
|
@@ -911,7 +959,7 @@ function report(json, command, summary) {
|
|
|
911
959
|
`);
|
|
912
960
|
}
|
|
913
961
|
async function sshLogin(args, session, what) {
|
|
914
|
-
const { bareUsername } = await import("./cli-shell-
|
|
962
|
+
const { bareUsername } = await import("./cli-shell-45XRTE7O.mjs");
|
|
915
963
|
const username = bareUsername(flag(args, "ssh-user") ?? session.sshUser ?? "");
|
|
916
964
|
if (!username) {
|
|
917
965
|
throw new CliError(
|
|
@@ -993,7 +1041,7 @@ async function copyFiles(args, json) {
|
|
|
993
1041
|
upload,
|
|
994
1042
|
walkLocal,
|
|
995
1043
|
walkRemote
|
|
996
|
-
} = await import("./cli-copy-
|
|
1044
|
+
} = await import("./cli-copy-BOF44DWQ.mjs");
|
|
997
1045
|
const from = resolveEndpoint(args, parseEndpoint(args.rest[0]));
|
|
998
1046
|
const to = resolveEndpoint(args, parseEndpoint(args.rest[1]));
|
|
999
1047
|
if (!from.endpoint.remote && !to.endpoint.remote) {
|
|
@@ -1071,7 +1119,7 @@ async function copyFiles(args, json) {
|
|
|
1071
1119
|
}
|
|
1072
1120
|
}
|
|
1073
1121
|
async function interactiveShell(args, session) {
|
|
1074
|
-
const { Shell } = await import("./cli-shell-
|
|
1122
|
+
const { Shell } = await import("./cli-shell-45XRTE7O.mjs");
|
|
1075
1123
|
const login = await sshLogin(args, session, "a terminal");
|
|
1076
1124
|
const { username, port, identities } = login;
|
|
1077
1125
|
const prompts = prompting(args);
|
|
@@ -1172,6 +1220,15 @@ The password is saved in ${summary.saved}.` : ""}`;
|
|
|
1172
1220
|
const what = files === 1 ? "" : `${files} files, `;
|
|
1173
1221
|
return `Copied ${what}${summary.size} from ${summary.from} to ${summary.to}${summary.rate ? ` at ${summary.rate}` : ""}.`;
|
|
1174
1222
|
}
|
|
1223
|
+
if (command === "clipboard") {
|
|
1224
|
+
if (!summary.available) {
|
|
1225
|
+
return "The clipboard cannot be shared with this session: it needs a desktop at the far end and a clipboard tool on this machine.";
|
|
1226
|
+
}
|
|
1227
|
+
return summary.on ? `Clipboard sharing is on for ${summary.name} (${summary.tool}). Copy here and paste there, or the other way round.` : `Clipboard sharing is off for ${summary.name}.`;
|
|
1228
|
+
}
|
|
1229
|
+
if (command === "reconnect") {
|
|
1230
|
+
return `${summary.replaced ? "Replaced" : "Opened"} the terminal on ${summary.name}. It is a new login, so it sees whatever the PATH says now -- and has forgotten the working directory and any exported variables.`;
|
|
1231
|
+
}
|
|
1175
1232
|
if (command === "shot") return `Wrote ${summary.file} (${summary.width}x${summary.height}) from ${summary.name}.`;
|
|
1176
1233
|
if (command === "click") {
|
|
1177
1234
|
const { x, y } = summary.clicked;
|