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.
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  Shell,
3
3
  bareUsername
4
- } from "./cli-chunk-RBCU3NX4.mjs";
5
- import "./cli-chunk-EYQCDSPT.mjs";
4
+ } from "./cli-chunk-Q33YGIDO.mjs";
5
+ import "./cli-chunk-S2TWL5LF.mjs";
6
6
  import "./cli-chunk-XT2FISR5.mjs";
7
7
  export {
8
8
  Shell,
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-LU4LHDCH.mjs");
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-TE6DLBIB.mjs");
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-NRXMTHID.mjs");
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-TE6DLBIB.mjs");
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;