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 CHANGED
@@ -111,6 +111,8 @@ why `npx` is still what the examples here use.
111
111
  ai-remote key <Code> press keys, e.g. MetaLeft, ControlLeft+KeyA
112
112
  ai-remote exec "cmd" run a command in the terminal (SSH)
113
113
  ai-remote shell an interactive terminal
114
+ ai-remote reconnect a new terminal: fresh login, fresh PATH
115
+ ai-remote clipboard [on|off] share this machine's clipboard both ways
114
116
  ai-remote cp <src> <dst> copy files; a remote path starts with ':'
115
117
  ai-remote do "steps" several actions in one go
116
118
  ai-remote view open the window on the session
@@ -214,6 +216,79 @@ npx ai-remote exec "uname -a"
214
216
  npx ai-remote shell # Ctrl-] to leave
215
217
  ```
216
218
 
219
+ ### The clipboard
220
+
221
+ Off by default, and turned on either from the **clipboard button in the window's
222
+ toolbar** or from a command line:
223
+
224
+ ```bash
225
+ npx ai-remote clipboard on # both directions, until turned off
226
+ npx ai-remote clipboard # what it is doing now
227
+ npx ai-remote open 192.168.1.50 -u owner --clipboard
228
+ ```
229
+
230
+ While it is on, text copied on this machine reaches the remote clipboard and text
231
+ copied there reaches this one. Only a desktop carries a clipboard -- RDP
232
+ negotiates a `cliprdr` channel and VNC has cut-text in the protocol -- so a
233
+ terminal-only session has none and the toolbar button does not appear.
234
+
235
+ **The bridge is the session's, not the page's.** The obvious place to put it
236
+ would be the viewer, using the browser's `navigator.clipboard` -- but a browser
237
+ only grants a page the clipboard while that page is focused, and the moment
238
+ somebody wants the remote clipboard is exactly the moment they have clicked away
239
+ into a local application to paste it. So the session does the copying, on this
240
+ machine, whether or not a window is open; the toolbar button turns it on rather
241
+ than doing it. Two windows on one session are two views of one switch.
242
+
243
+ Two consequences worth knowing:
244
+
245
+ - **It polls.** No platform gives Node a clipboard-change event, so the local
246
+ side is read twice a second while sharing is on. That is why it is a toggle
247
+ and not always on, and why off is a real off: the timer is not running and the
248
+ host's clipboard messages are dropped.
249
+ - **Nothing goes round in circles.** Text that arrived from the host is not then
250
+ noticed by the poller and pushed back to it, and what was already on the
251
+ clipboard when sharing started is not treated as a change -- so turning
252
+ sharing on does not send something copied an hour ago.
253
+
254
+ It uses whatever the platform has: `pbcopy`/`pbpaste` on macOS,
255
+ `Set-Clipboard`/`Get-Clipboard` on Windows, and `wl-clipboard`, `xclip` or
256
+ `xsel` on Linux. A machine with none reports the clipboard as unavailable and
257
+ the button stays hidden rather than offering a switch that cannot work.
258
+
259
+ Sharing sits behind the same control gate as keyboard and pointer input: a
260
+ watch-only viewer can read the screen and cannot reach either clipboard.
261
+
262
+ ### A new terminal, after installing something
263
+
264
+ A shell inherits its environment when it signs in, and nothing can change a
265
+ running process's inherited environment from outside it. So a program installed
266
+ a moment ago is simply not on the PATH of the shell that installed it, and
267
+ running the command again will not find it however many times it is tried.
268
+
269
+ `reconnect` is the fix, and it is the same one a person reaches for -- close the
270
+ terminal, open another:
271
+
272
+ ```bash
273
+ npx ai-remote exec "winget install OpenJS.NodeJS"
274
+ npx ai-remote reconnect
275
+ npx ai-remote exec "node --version"
276
+
277
+ npx ai-remote exec --reconnect "node --version" # or both in one call
278
+ ```
279
+
280
+ The session, the desktop and the window stay exactly where they are; only the
281
+ terminal is new. That also means the working directory and any exported
282
+ variables are gone, which is the point -- it is a new login, not a refresh.
283
+
284
+ On Windows a fresh login can still inherit a stale environment, because sshd
285
+ built its own environment block when the service started. Reading the PATH
286
+ straight out of the registry works regardless:
287
+
288
+ ```bash
289
+ npx ai-remote exec '$env:Path = [Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [Environment]::GetEnvironmentVariable("Path","User")'
290
+ ```
291
+
217
292
  ### Copying files
218
293
 
219
294
  `cp` is `scp` with the session standing in for the host: a remote path starts
@@ -280,6 +355,7 @@ where a decrypted key belongs, and it is offered from there.
280
355
  - `-s, --security MODE`: `auto` | `nla` | `tls` | `rdp` (default: `auto`).
281
356
  - `-W, --width N` / `-H, --height N`: Desktop resolution (default: 1280x800).
282
357
  - `--idle MINUTES`: Close an unused session (default: 0, never).
358
+ - `--clipboard`: Share this machine's clipboard with the desktop, both ways.
283
359
  - `--headless` / `--no-view`: Run headless without opening the viewer window.
284
360
  - `--no-reuse`: A second session beside one that is already open.
285
361
  - `--save`: Keep the password for next time, once it has worked.
@@ -289,6 +365,7 @@ where a decrypted key belongs, and it is offered from there.
289
365
  - `--session NAME`: Which session to drive (default: the one opened last).
290
366
  - `-o, --out FILE`: Screenshot output file path (default: `screen.png`).
291
367
  - `-r, --recursive`: For `cp`, copy a directory.
368
+ - `--reconnect`: For `exec`, open a new terminal first, then run the command.
292
369
  - `--max-edge N`: Shrink a screenshot to fit N.
293
370
  - `--json`: Output machine-readable JSON results on stdout.
294
371
 
package/SKILL.md CHANGED
@@ -149,6 +149,50 @@ leave) — that one is for a human, not for an agent, because it never returns.
149
149
  Reach for the GUI when the task is genuinely graphical. Reach for `exec` for
150
150
  anything a shell can do.
151
151
 
152
+ **After installing anything, reconnect.** A shell's environment is fixed when it
153
+ signs in, so a `node` installed a moment ago is not on the PATH of the shell that
154
+ installed it, and asking again will never find it:
155
+
156
+ ```bash
157
+ npx ai-remote exec "winget install OpenJS.NodeJS"
158
+ npx ai-remote reconnect # a new login, so a new PATH
159
+ npx ai-remote exec "node --version"
160
+
161
+ npx ai-remote exec --reconnect "node --version" # or both in one call
162
+ ```
163
+
164
+ The session, the desktop and the window all stay put — only the terminal is new,
165
+ which also means the working directory and any exported variables are gone. On
166
+ Windows, if a fresh login still cannot see it, sshd handed down its own stale
167
+ environment; read the PATH straight out of the registry instead:
168
+
169
+ ```bash
170
+ npx ai-remote exec '$env:Path = [Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [Environment]::GetEnvironmentVariable("Path","User")'
171
+ ```
172
+
173
+ Note `&&` is not valid in PowerShell 5.1 — use `;` to chain, or `if ($?) { ... }`
174
+ when the second command should only run if the first worked.
175
+
176
+ ## The clipboard
177
+
178
+ Off by default. The **clipboard button in the window's toolbar** turns it on, or
179
+ from a command line:
180
+
181
+ ```bash
182
+ npx ai-remote clipboard on # both directions, until turned off
183
+ npx ai-remote clipboard # what it is doing now
184
+ npx ai-remote open HOST -u USER --clipboard # on from the start
185
+ ```
186
+
187
+ While it is on, text copied on this machine reaches the remote clipboard and
188
+ text copied there reaches this one — so a password, a path or a stack trace
189
+ moves without being typed. Only a desktop has a clipboard: RDP negotiates one
190
+ and VNC has it in the protocol, while an `--ssh` session has none and the button
191
+ does not appear.
192
+
193
+ Turn it off before copying anything on this machine that the remote end should
194
+ not see. Off is a real off — nothing is read and nothing is written.
195
+
152
196
  ## Copying files
153
197
 
154
198
  `cp` is scp with the session standing in for the host. A remote path starts with
@@ -370,7 +414,9 @@ npx ai-remote click X,Y [--button right|middle] [--double]
370
414
  npx ai-remote type "text"
371
415
  npx ai-remote key ControlLeft+KeyA
372
416
  npx ai-remote do "key MetaLeft; wait 800; type notepad; shot s.png"
373
- npx ai-remote exec "command"
417
+ npx ai-remote exec "command" [--reconnect]
418
+ npx ai-remote reconnect # a new login: fresh PATH
419
+ npx ai-remote clipboard [on|off] # share text both ways
374
420
  npx ai-remote cp [-r] SRC DST # ':path' is on the session
375
421
  npx ai-remote view [--watch-only] [--close]
376
422
  npx ai-remote status | list | close [--all]
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SshSession,
3
3
  TcpTransport
4
- } from "./cli-chunk-EYQCDSPT.mjs";
4
+ } from "./cli-chunk-S2TWL5LF.mjs";
5
5
 
6
6
  // src/cli/shell.ts
7
7
  function bareUsername(username) {
@@ -935,6 +935,18 @@ function filterDisplay(session, bytes) {
935
935
  }
936
936
  return shown ? encodeUtf8(shown) : NO_BYTES;
937
937
  }
938
+ function announceCommand(session, command) {
939
+ const shown = command.replace(/\r?\n/g, " \u23CE ").trimEnd();
940
+ if (!shown) return;
941
+ session.dispatchEvent(new CustomEvent("data", {
942
+ detail: {
943
+ bytes: NO_BYTES,
944
+ display: encodeUtf8(`\x1B[1m${shown}\x1B[0m\r
945
+ `),
946
+ isStderr: false
947
+ }
948
+ }));
949
+ }
938
950
  function releaseDisplayFilter(session) {
939
951
  const filter = session.displayFilter;
940
952
  session.displayFilter = null;
@@ -1092,6 +1104,7 @@ var SshSession = class extends EventTarget {
1092
1104
  this.commandInFlight = true;
1093
1105
  const startedAt = Date.now();
1094
1106
  this.displayFilter = { begin, end, stage: "before", pending: "" };
1107
+ announceCommand(this, text);
1095
1108
  this.dispatchEvent(new CustomEvent("command", {
1096
1109
  detail: { phase: "start", id, command: text }
1097
1110
  }));
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SshSession,
3
3
  TcpTransport
4
- } from "./cli-chunk-EYQCDSPT.mjs";
4
+ } from "./cli-chunk-S2TWL5LF.mjs";
5
5
  import {
6
6
  SshReader,
7
7
  SshWriter