ai-remote 0.4.7 → 0.4.8

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.
Files changed (47) hide show
  1. package/README.md +84 -2
  2. package/SKILL.md +49 -1
  3. package/dist/apple-dh.d.ts +27 -0
  4. package/dist/apple-dh.js +1 -0
  5. package/dist/cli.mjs +2978 -210
  6. package/dist/protocols/rdp/buffer.d.ts +38 -0
  7. package/dist/protocols/rdp/caps.d.ts +49 -0
  8. package/dist/protocols/rdp/cert.d.ts +18 -0
  9. package/dist/protocols/rdp/client.d.ts +56 -0
  10. package/dist/protocols/rdp/cliprdr.d.ts +27 -0
  11. package/dist/protocols/rdp/credssp.d.ts +34 -0
  12. package/dist/protocols/rdp/crypto.d.ts +63 -0
  13. package/dist/protocols/rdp/display.d.ts +38 -0
  14. package/dist/protocols/rdp/gcc.d.ts +23 -0
  15. package/dist/protocols/rdp/keymap.d.ts +9 -0
  16. package/dist/protocols/rdp/mcs.d.ts +40 -0
  17. package/dist/protocols/rdp/ntlm.d.ts +61 -0
  18. package/dist/protocols/rdp/pdu.d.ts +155 -0
  19. package/dist/protocols/rdp/rail.d.ts +119 -0
  20. package/dist/protocols/rdp/rle.d.ts +13 -0
  21. package/dist/protocols/rdp/sec.d.ts +59 -0
  22. package/dist/protocols/rdp/session.d.ts +62 -0
  23. package/dist/protocols/rdp/tls.d.ts +18 -0
  24. package/dist/protocols/rdp/vchannel.d.ts +28 -0
  25. package/dist/protocols/rdp/x224.d.ts +40 -0
  26. package/dist/protocols/ssh/identity.d.ts +39 -0
  27. package/dist/protocols/ssh/kex.d.ts +97 -0
  28. package/dist/protocols/ssh/messages.d.ts +52 -0
  29. package/dist/protocols/ssh/session.d.ts +67 -0
  30. package/dist/protocols/ssh/terminal.d.ts +46 -0
  31. package/dist/protocols/ssh/transport.d.ts +62 -0
  32. package/dist/protocols/ssh/wire.d.ts +52 -0
  33. package/dist/protocols/types.d.ts +127 -0
  34. package/dist/protocols/vnc/des.d.ts +25 -0
  35. package/dist/protocols/vnc/input.d.ts +5 -0
  36. package/dist/protocols/vnc/keysyms.d.ts +16 -0
  37. package/dist/protocols/vnc/rfb.d.ts +64 -0
  38. package/dist/protocols/vnc/session.d.ts +12 -0
  39. package/dist/protocols.js +13 -13
  40. package/dist/shared/connection.d.ts +81 -0
  41. package/dist/shared/device.d.ts +26 -0
  42. package/dist/shared/hosts.d.ts +63 -0
  43. package/dist/shared/icons.d.ts +46 -0
  44. package/dist/shared/protocol.d.ts +32 -0
  45. package/dist/shared/signals.d.ts +37 -0
  46. package/package.json +8 -3
  47. /package/dist/{protocols.d.ts → protocols/index.d.ts} +0 -0
@@ -0,0 +1,62 @@
1
+ export declare const CLIENT_VERSION = "SSH-2.0-CloudflareGateway_1.0";
2
+ /** Pick the first client preference the host also offered (RFC 4253 7.1). */
3
+ export declare function negotiate(clientNames: any, serverNames: any): any;
4
+ export declare class SshTransport extends EventTarget {
5
+ #private;
6
+ url: string;
7
+ verifyHost: (info: any) => Promise<boolean> | boolean;
8
+ log: (...args: any[]) => void;
9
+ socket: WebSocket | null;
10
+ openTransport: ((url: string) => any) | null;
11
+ closed: boolean;
12
+ buffer: Uint8Array;
13
+ serverVersion: string;
14
+ greeting: string[];
15
+ sendSequence: number;
16
+ receiveSequence: number;
17
+ outgoing: any;
18
+ incoming: any;
19
+ sessionId: Uint8Array | null;
20
+ kex: any;
21
+ kexQueue: Uint8Array[];
22
+ keepaliveTimer: any;
23
+ bytesSent: number;
24
+ bytesReceived: number;
25
+ encryptChain?: Promise<void>;
26
+ newKeysBarrier?: Promise<void> | null;
27
+ releaseNewKeys?: (() => void) | null;
28
+ pendingServerKexInit?: Uint8Array | null;
29
+ established?: boolean;
30
+ /**
31
+ * @param {string} url gateway WebSocket URL
32
+ * @param {object} options
33
+ * @param {(info: object) => Promise<boolean>} options.verifyHost decides
34
+ * whether an unknown or changed host key may be used.
35
+ */
36
+ constructor(url: string, { verifyHost, log, openTransport }?: {
37
+ verifyHost?: (info: any) => Promise<boolean> | boolean;
38
+ log?: (...args: any[]) => void;
39
+ /** Returns a WebSocket-shaped transport for `url`; default is a real one. */
40
+ openTransport?: ((url: string) => any) | null;
41
+ });
42
+ connect(): void;
43
+ disconnect(message?: string): void;
44
+ fail(error: unknown): void;
45
+ /** Application packets wait while a key exchange is in flight (RFC 4253 7.1). */
46
+ send(payload: Uint8Array): boolean;
47
+ }
48
+ /** Padding for a GCM packet: only the encrypted part is block aligned. */
49
+ export declare function gcmPaddingLength(payloadLength: any): number;
50
+ /** A packet before any keys exist: the whole thing is block aligned. */
51
+ export declare function framePlain(payload: Uint8Array): Uint8Array<ArrayBufferLike>;
52
+ export declare function buildKexInit(offer: any): Uint8Array<ArrayBufferLike>;
53
+ export declare function parseKexInit(payload: Uint8Array): {
54
+ kex: string[];
55
+ hostKey: string[];
56
+ cipherClientToServer: string[];
57
+ cipherServerToClient: string[];
58
+ macClientToServer: string[];
59
+ macServerToClient: string[];
60
+ compressionClientToServer: string[];
61
+ compressionServerToClient: string[];
62
+ };
@@ -0,0 +1,52 @@
1
+ export declare function encodeUtf8(text: string): Uint8Array;
2
+ export declare function decodeUtf8(bytes: Uint8Array): string;
3
+ export declare function concatBytes(...parts: readonly Uint8Array[]): Uint8Array;
4
+ /** Constant-time-ish equality. Used for authentication tags and fingerprints. */
5
+ export declare function bytesEqual(a: Uint8Array, b: Uint8Array): boolean;
6
+ export declare function toBase64(bytes: Uint8Array): string;
7
+ export declare function fromBase64(text: string): Uint8Array;
8
+ /** Base64url without padding, which is what a JSON Web Key wants. */
9
+ export declare function toBase64Url(bytes: Uint8Array): string;
10
+ export declare class SshWriter {
11
+ #private;
12
+ private bytes;
13
+ private view;
14
+ private offset;
15
+ constructor(capacity?: number);
16
+ u8(value: number): this;
17
+ boolean(value: boolean): this;
18
+ u32(value: number): this;
19
+ raw(bytes: Uint8Array): this;
20
+ /** A length-prefixed string. Text is encoded as UTF-8. */
21
+ string(value: string | Uint8Array): this;
22
+ nameList(names: readonly string[]): this;
23
+ /**
24
+ * An mpint: two's complement, big endian, with no leading zero bytes except
25
+ * the one that keeps a positive number from looking negative.
26
+ */
27
+ mpint(bytes: Uint8Array): this;
28
+ get length(): number;
29
+ take(): Uint8Array;
30
+ }
31
+ export declare class SshReader {
32
+ #private;
33
+ private readonly bytes;
34
+ private readonly view;
35
+ offset: number;
36
+ constructor(bytes: Uint8Array, offset?: number);
37
+ get remaining(): number;
38
+ u8(): number;
39
+ boolean(): boolean;
40
+ u32(): number;
41
+ raw(count: number): Uint8Array;
42
+ /** The bytes of a length-prefixed string. */
43
+ stringBytes(): Uint8Array;
44
+ string(): string;
45
+ nameList(): string[];
46
+ /** An mpint's magnitude, with the sign byte removed. */
47
+ mpint(): Uint8Array;
48
+ skip(count: number): this;
49
+ rest(): Uint8Array;
50
+ }
51
+ /** Pad a magnitude out to a fixed width, which raw curve points need. */
52
+ export declare function padStart(bytes: Uint8Array, width: number): Uint8Array;
@@ -0,0 +1,127 @@
1
+ /**
2
+ * The interface every remote-desktop protocol presents to the UI.
3
+ *
4
+ * The workspace -- toolbar, stats rail, on-screen keyboard, reconnects -- does
5
+ * not care whether a session is VNC or RDP. Everything that does differ is
6
+ * reached through this interface instead of branching at each call site.
7
+ */
8
+ import type { ConnectionSettings, RemoteAppLaunch } from '../shared/connection';
9
+ import type { RdpSecurity, RemoteProtocol } from '../shared/protocol';
10
+ /** Where the pointer may go, in framebuffer pixels. */
11
+ export interface ScreenGeometry {
12
+ width: number;
13
+ height: number;
14
+ viewport: {
15
+ x: number;
16
+ y: number;
17
+ width: number;
18
+ height: number;
19
+ };
20
+ }
21
+ /** Mouse buttons, as the UI names them. */
22
+ export type PointerButton = 0 | 1 | 2;
23
+ /** Wheel movement in discrete remote-protocol notches. Positive is right/down. */
24
+ export interface ScrollDelta {
25
+ x: number;
26
+ y: number;
27
+ }
28
+ /**
29
+ * A live session. Both drivers expose this, so the AI pane's screen tool and
30
+ * the toolbar never have to ask which protocol they are driving.
31
+ */
32
+ export interface RemoteSession extends EventTarget {
33
+ readonly protocol: RemoteProtocol;
34
+ disconnect(): void;
35
+ /** True once the desktop has been reached. */
36
+ readonly connected: boolean;
37
+ /** Fit the remote desktop to the pane rather than scrolling it. */
38
+ scaleViewport: boolean;
39
+ /** Watch without sending keyboard or pointer input. */
40
+ viewOnly: boolean;
41
+ /** RFB quality level. RDP ignores it. */
42
+ qualityLevel?: number;
43
+ /** RFB compression level. RDP ignores it. */
44
+ compressionLevel?: number;
45
+ /** The transport the metrics rail instruments. Can appear a tick after construction. */
46
+ readonly socket?: WebSocket | null;
47
+ readonly screenGeometry: ScreenGeometry;
48
+ movePointer(x: number, y: number): boolean;
49
+ clickPointer(x: number, y: number, button?: PointerButton): boolean;
50
+ pointerButton(x: number, y: number, button?: PointerButton, pressed?: boolean): boolean;
51
+ scrollPointer(x: number, y: number, delta: ScrollDelta): boolean;
52
+ typeText(text: string): boolean;
53
+ /** Prefer the protocol clipboard for longer text when it can paste reliably. */
54
+ pasteText?(text: string): boolean | Promise<boolean>;
55
+ /** Press or release one key by keysym. */
56
+ sendKey(keysym: number, code: string | null, down?: boolean): void;
57
+ /** Send text to the host's clipboard, when the protocol carries one. */
58
+ sendClipboard?(text: string): void;
59
+ /**
60
+ * Stop taking keystrokes: the workspace has given the keyboard to something
61
+ * local, such as the terminal or the assistant's message box.
62
+ *
63
+ * Both protocols listen on the element they paint into, so a key only leaves
64
+ * for the host while that element holds focus. Handing focus back is the
65
+ * whole mechanism -- plus, for RDP, letting go of anything still held down,
66
+ * which would otherwise stay down on the far side.
67
+ */
68
+ releaseKeyboard?(): void;
69
+ /** Ask the host for a different desktop size, when the protocol allows it. */
70
+ requestDesktopSize?(width: number, height: number): void;
71
+ /** The canvas the session paints into, for screenshots and thumbnails. */
72
+ readonly canvas?: HTMLCanvasElement | null;
73
+ }
74
+ /** What the workspace hands a driver to open a session. */
75
+ export interface SessionOptions {
76
+ credentials: {
77
+ username: string;
78
+ password: string;
79
+ };
80
+ domain: string;
81
+ security: RdpSecurity;
82
+ remoteApp: RemoteAppLaunch | null;
83
+ /** Desktop size to ask the host for. */
84
+ width: number;
85
+ height: number;
86
+ /** False on a phone, where resizing the host would make a portrait strip of it. */
87
+ allowRemoteResize: boolean;
88
+ scaleViewport: boolean;
89
+ viewOnly: boolean;
90
+ quality: number;
91
+ compression: number;
92
+ /** Shown in this driver's own log lines. */
93
+ hostLabel: string;
94
+ }
95
+ /** Wording for the one connect dialog, which is shared markup across protocols. */
96
+ export interface DialogCopy {
97
+ usernameLabel: string;
98
+ usernamePlaceholder: string;
99
+ usernameHelp: string;
100
+ passwordLabel: string;
101
+ passwordPlaceholder: string;
102
+ passwordHelp: string;
103
+ /** A VNC session needs some secret; RDP can sign in on the host's own screen. */
104
+ requiresPassword: boolean;
105
+ }
106
+ /** Everything the UI knows about a close, before anyone tries to explain it. */
107
+ export interface DisconnectContext {
108
+ code?: number;
109
+ reason: string;
110
+ /** Pre-rendered ` (WebSocket 1006: ...)` tail, so wording stays consistent. */
111
+ suffix: string;
112
+ }
113
+ /** One protocol implementation. */
114
+ export interface ProtocolDriver {
115
+ readonly protocol: RemoteProtocol;
116
+ /** Used as the prefix of this driver's console lines. */
117
+ readonly label: string;
118
+ readonly defaultPort: number;
119
+ readonly dialog: DialogCopy;
120
+ /** The gateway endpoint for this connection, including any query it needs. */
121
+ buildUrl(origin: string, settings: ConnectionSettings): string;
122
+ createSession(container: HTMLElement, url: string, options: SessionOptions): RemoteSession;
123
+ /** Extra detail worth logging once the first server frame has been parsed. */
124
+ describeState(session: RemoteSession): Record<string, unknown>;
125
+ /** Protocol-specific wording for a close, or null to fall back to the shared text. */
126
+ describeDisconnect(context: DisconnectContext): string | null;
127
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * DES, for the one thing VNC still needs it for.
3
+ *
4
+ * The classic VNC password challenge (security type 2) is a single-block DES
5
+ * encryption, and there is no getting round it: it is what every host from
6
+ * x11vnc to RealVNC expects. Node's own crypto cannot help -- OpenSSL 3 moved
7
+ * DES to the legacy provider, which is off in most builds -- and Web Crypto
8
+ * never had it. So it is here, in about a hundred lines of tables.
9
+ *
10
+ * Nothing else in this repository should use this. DES is broken, and the only
11
+ * reason it is here is that a protocol from 1998 froze it into a handshake.
12
+ * The implementation is the textbook one, bit by bit: two blocks per sign-in
13
+ * makes speed irrelevant and clarity worth having.
14
+ */
15
+ /** One 8-byte block, encrypted under an 8-byte key. */
16
+ export declare function desEncryptBlock(key: Uint8Array, block: Uint8Array): Uint8Array;
17
+ /**
18
+ * The key VNC makes out of a password.
19
+ *
20
+ * Eight bytes, padded with zeros, and every byte's bits reversed -- an accident
21
+ * of the original implementation that every host has copied ever since.
22
+ */
23
+ export declare function vncKey(password: string): Uint8Array;
24
+ /** The answer to a host's 16-byte challenge: both halves, encrypted. */
25
+ export declare function vncChallengeResponse(password: string, challenge: Uint8Array): Uint8Array;
@@ -0,0 +1,5 @@
1
+ /** RFB wheel buttons for a bounded two-axis scroll, in wire order. */
2
+ export declare function vncWheelMasks(delta: {
3
+ x: number;
4
+ y: number;
5
+ }): number[];
@@ -0,0 +1,16 @@
1
+ /**
2
+ * DOM key codes as X11 keysyms, which is what RFB sends.
3
+ *
4
+ * RDP sends scancodes, so the keyboard map on that side is a hardware table.
5
+ * VNC sends keysyms -- what the key *means* rather than where it sits -- and
6
+ * the useful consequence is that a character needs no modifier bookkeeping:
7
+ * asking for `A` asks for a capital A, and the host works out that its own
8
+ * keyboard would need shift for that.
9
+ *
10
+ * Latin-1 characters are their own code point. Everything above that is the
11
+ * Unicode escape from the X protocol: 0x01000000 plus the code point.
12
+ */
13
+ /** A character's keysym: itself in Latin-1, and escaped above it. */
14
+ export declare function keysymForChar(character: string): number;
15
+ /** A DOM `code`'s keysym, or 0 for a key this does not know. */
16
+ export declare function keysymForCode(code: string): number;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * An RFB client that needs no browser.
3
+ *
4
+ * The VNC path in this repository has always been noVNC in a tab with the
5
+ * gateway doing the handshake, which is fine for a tab and no use at all to a
6
+ * command line: `RFB` wants a DOM element to paint into, and the half of the
7
+ * handshake macOS requires lives in the Worker. This is the protocol on its
8
+ * own -- version, security, pixels and input -- speaking to an injected
9
+ * transport, so the CLI can hold a desktop the same way it holds an RDP one.
10
+ *
11
+ * The handshake reads as a straight line rather than a state machine, because
12
+ * that is what it is: each step waits for the bytes it needs. Everything after
13
+ * it is a message loop.
14
+ *
15
+ * Two pieces of the protocol need primitives no runtime offers portably --
16
+ * DES for the classic password challenge, MD5 and AES for Apple's key
17
+ * exchange -- so they arrive as an injected `crypto`, the same seam the
18
+ * transport uses.
19
+ */
20
+ export interface RfbCrypto {
21
+ /** Security type 2: the 16-byte answer to the host's challenge. */
22
+ vncChallenge(password: string, challenge: Uint8Array): Uint8Array;
23
+ /** Security type 30: what macOS Screen Sharing asks for instead of a challenge. */
24
+ appleDh(params: Uint8Array, username: string, password: string): Uint8Array;
25
+ }
26
+ /** One painted area. `copyFrom` is a rectangle the host says is already on screen. */
27
+ export interface RfbRect {
28
+ left: number;
29
+ top: number;
30
+ width: number;
31
+ height: number;
32
+ /** RGBA, row-major. Absent for a copy. */
33
+ rgba?: Uint8Array;
34
+ copyFrom?: {
35
+ x: number;
36
+ y: number;
37
+ };
38
+ }
39
+ export interface RfbOptions {
40
+ username?: string;
41
+ password?: string;
42
+ /** Let other viewers stay connected. Always true here: a session is watched. */
43
+ shared?: boolean;
44
+ crypto: RfbCrypto;
45
+ openTransport: () => any;
46
+ log?: (step: string, detail?: unknown) => void;
47
+ }
48
+ export declare class RfbClient extends EventTarget {
49
+ #private;
50
+ readonly options: RfbOptions;
51
+ width: number;
52
+ height: number;
53
+ name: string;
54
+ connected: boolean;
55
+ constructor(options: RfbOptions);
56
+ connect(): void;
57
+ disconnect(): void;
58
+ /** `mask` is RFB's own numbering: 1 left, 2 middle, 4 right, 8/16 wheel. */
59
+ pointer(x: number, y: number, mask?: number): void;
60
+ key(keysym: number, pressed: boolean): void;
61
+ cutText(text: string): void;
62
+ /** Ask for the whole desktop again rather than what has changed. */
63
+ refresh(): void;
64
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Everything VNC-specific, behind the driver interface the RDP side also
3
+ * implements. noVNC's RFB object does the protocol work; this module decides
4
+ * how it is addressed, constructed, controlled and explained.
5
+ *
6
+ * VNC splits the handshake differently from RDP: noVNC hands authentication to
7
+ * the Worker, because macOS Screen Sharing needs the Apple Diffie-Hellman
8
+ * (type 30) exchange that noVNC does not implement. That is why credentials
9
+ * travel in the URL here and never do for RDP.
10
+ */
11
+ import type { ProtocolDriver } from '../types';
12
+ export declare const vncDriver: ProtocolDriver;