ai-remote 0.3.1 → 0.4.0

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/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "ai-remote",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
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": {
7
- "ai-remote": "./dist/cli.mjs",
8
- "remotectl": "./dist/cli.mjs"
7
+ "ai-remote": "dist/cli.mjs",
8
+ "remotectl": "dist/cli.mjs"
9
9
  },
10
10
  "license": "MIT",
11
11
  "author": {
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "repository": {
17
17
  "type": "git",
18
- "url": "https://github.com/guocity/vnc-node-worker.git"
18
+ "url": "git+https://github.com/guocity/vnc-node-worker.git"
19
19
  },
20
20
  "keywords": [
21
21
  "remote-desktop",
@@ -88,5 +88,8 @@
88
88
  },
89
89
  "engines": {
90
90
  "node": ">=22"
91
+ },
92
+ "optionalDependencies": {
93
+ "@webviewjs/webview": "^0.4.3"
91
94
  }
92
95
  }
package/src/cli/cli.ts CHANGED
@@ -12,6 +12,7 @@ import { spawn } from 'node:child_process';
12
12
  import { readFileSync, readdirSync, existsSync, openSync, unlinkSync } from 'node:fs';
13
13
  import { bareUsername, Shell } from './shell';
14
14
  import { runDaemon } from './daemon';
15
+ import { runWindow } from './window';
15
16
  import { request } from './ipc';
16
17
  import { ensureRunDir, logPath, metaPath, RUN_DIR, sessionName, socketPath } from './paths';
17
18
 
@@ -187,6 +188,8 @@ async function startSession(args: Args, name: string, host: string, port: number
187
188
  ];
188
189
  if (has(args, 'no-view', 'headless')) daemonArgs.push('--no-view');
189
190
  if (has(args, 'no-open')) daemonArgs.push('--no-open');
191
+ if (has(args, 'tab')) daemonArgs.push('--tab');
192
+ if (has(args, 'fullscreen')) daemonArgs.push('--fullscreen');
190
193
 
191
194
  // Its output goes to a file rather than nowhere: a session that fails to
192
195
  // start is the one moment its log is worth having.
@@ -274,6 +277,8 @@ async function main(): Promise<void> {
274
277
  viewPort: Number(flag(args, 'view-port') ?? 7373),
275
278
  sshUsername: flag(args, 'ssh-user') ?? flag(args, 'u', 'user') ?? '',
276
279
  sshPort: Number(flag(args, 'ssh-port') ?? 22),
280
+ tab: has(args, 'tab'),
281
+ fullscreen: has(args, 'fullscreen'),
277
282
  // Zero by default: a session stays open until it is closed. An agent
278
283
  // that pauses to think is not an agent that has finished.
279
284
  idleMs: Math.max(0, Number(flag(args, 'idle') ?? 0)) * 60_000,
@@ -281,6 +286,9 @@ async function main(): Promise<void> {
281
286
  return;
282
287
  }
283
288
 
289
+ // The hidden command the native window runs as.
290
+ if (args.command === '__window') { await runWindow(process.argv.slice(3)); return; }
291
+
284
292
  if (args.command === 'shell') { await interactiveShell(args, host); return; }
285
293
 
286
294
  // Everything else runs against a session: the one already open, or a new one.
@@ -297,7 +305,7 @@ async function main(): Promise<void> {
297
305
  if (!has(args, 'no-view', 'headless') && !status.viewer) {
298
306
  Object.assign(status, await ask(name, 'view-open', { launch: !has(args, 'no-open') }));
299
307
  }
300
- Object.assign(report, { viewer: status.viewer });
308
+ Object.assign(report, { viewer: status.viewer, window: status.window, viewers: status.viewers });
301
309
  break;
302
310
 
303
311
  case 'view': {
@@ -424,8 +432,10 @@ function describe(command: string, report: Record<string, unknown>): string {
424
432
  const where = report.reused ? 'the open session' : 'a new session';
425
433
 
426
434
  if (command === 'open') {
427
- return `${report.reused ? 'Already connected' : 'Connected'} to ${report.host}:${report.port} at ${size}.`
428
- + `${report.viewer ? `\nWindow: ${report.viewer}` : ''}`
435
+ const window = report.window === 'window' ? 'A window is open on it.'
436
+ : report.window === 'tab' ? 'It opened in your browser.'
437
+ : report.viewer ? `Open it at ${report.viewer}` : 'No window (headless).';
438
+ return `${report.reused ? 'Already connected' : 'Connected'} to ${report.host}:${report.port} at ${size}. ${window}`
429
439
  + `\nRun more commands against it, then \`${NAME} close ${report.host}\` when you are done.`;
430
440
  }
431
441
  if (command === 'view') {
package/src/cli/daemon.ts CHANGED
@@ -26,6 +26,10 @@ export interface DaemonOptions extends SessionOptions {
26
26
  viewPort: number;
27
27
  /** Account for the terminal, when one is wanted. Blank leaves SSH unopened. */
28
28
  sshUsername: string;
29
+ /** Open in the default browser rather than a window of its own. */
30
+ tab: boolean;
31
+ /** Start the window already filling the display. */
32
+ fullscreen: boolean;
29
33
  sshPort: number;
30
34
  idleMs: number;
31
35
  }
@@ -104,7 +108,12 @@ export async function runDaemon(options: DaemonOptions): Promise<void> {
104
108
  if (launch) viewer.launch();
105
109
  return viewer;
106
110
  }
107
- viewer = await startViewer(session, options.viewPort, { launch, openShell });
111
+ viewer = await startViewer(session, options.viewPort, {
112
+ launch,
113
+ openShell,
114
+ tab: options.tab,
115
+ fullscreen: options.fullscreen,
116
+ });
108
117
  writeMeta();
109
118
  return viewer;
110
119
  }
@@ -147,7 +156,7 @@ export async function runDaemon(options: DaemonOptions): Promise<void> {
147
156
  switch (message.op) {
148
157
  case 'view-open': {
149
158
  const opened = await openViewer(args.launch !== false);
150
- return { viewer: opened.url };
159
+ return { viewer: opened.url, window: opened.window?.kind ?? null };
151
160
  }
152
161
 
153
162
  case 'view-close':
@@ -162,6 +171,8 @@ export async function runDaemon(options: DaemonOptions): Promise<void> {
162
171
  height: session.framebuffer.height,
163
172
  connected: session.connected,
164
173
  viewer: viewer?.url ?? null,
174
+ window: viewer?.window?.kind ?? null,
175
+ viewers: viewer?.viewers ?? 0,
165
176
  shell: shell ? 'open' : shellStarting ? 'opening' : 'closed',
166
177
  pid: process.pid,
167
178
  };