@intentic/desktop 1.176.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Artur Kurowski
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # @intentic/desktop
2
+
3
+ Drive a desktop from Node: capture the screen, move the pointer, click, type, press chords, scroll and drag —
4
+ on Windows and Linux, with **no native modules**.
5
+
6
+ ```ts
7
+ import { desktop } from "@intentic/desktop";
8
+
9
+ const screen = desktop();
10
+ const { width, height } = await screen.frame();
11
+ const png = await screen.capture();
12
+ await screen.click({ x: 840, y: 512 }, "left");
13
+ await screen.type("hello world");
14
+ await screen.key("ctrl+s");
15
+
16
+ // …and operating applications, not just pixels
17
+ await screen.launch("https://example.com");
18
+ const open = await screen.windows(); // app, title, bounds, focused
19
+ await screen.focusWindow(open[0]!.id); // typing goes to the FOCUSED window
20
+ await screen.writeClipboard("some text");
21
+ ```
22
+
23
+ ## What this package is not
24
+
25
+ It knows nothing about agents, capabilities, permissions or sandboxes. It takes coordinates and text and makes a
26
+ computer do something; *whether that is allowed* is a question asked before these methods are ever called. Its
27
+ one consumer today is `@intentic/host`, which owns that question — and the split is what makes the policy
28
+ testable, since a real click can only be verified by a human watching a screen.
29
+
30
+ ## How it works, per platform
31
+
32
+ **Windows** — PowerShell into `user32.dll`. `SetCursorPos` + `mouse_event` for the pointer, `keybd_event` for
33
+ chords, and `SendKeys` for text only. The split is deliberate: SendKeys is the only one that handles arbitrary
34
+ unicode sensibly, and the only one that *cannot press the Windows key* — so text uses it and chords do not.
35
+ Screen capture is `System.Drawing`. No install step, nothing left resident.
36
+
37
+ **Linux** — two backends behind one interface. X11 lets any client synthesise input, so `xdotool` does
38
+ everything with no privileges. Wayland does not, so the pointer goes through `ydotool` (which needs
39
+ `/dev/uinput`) and text/keys prefer `wtype` (which does not). Missing tools raise a `DesktopError` carrying the
40
+ one-line install for the specific thing that is absent.
41
+
42
+ **macOS** — capture works, input does not. The methods throw rather than silently doing nothing.
43
+
44
+ **Windows enumeration** — `Get-Process` already knows every process with a main window and its title; the
45
+ P/Invoke is only for the two things it does not carry, the window rectangle and which window is in front.
46
+
47
+ **Wayland enumeration mostly cannot happen**, and that is a design decision rather than a gap: a compositor does
48
+ not let one client enumerate another's windows, the same protection that stops it synthesising input. The
49
+ wlroots family (sway, Hyprland) answers `swaymsg -t get_tree` to anyone who can reach the socket, so those are
50
+ supported; everything else gets a sentence explaining why, rather than an empty list that reads as "nothing is
51
+ open".
52
+
53
+ ## Two details worth knowing
54
+
55
+ **Coordinates are screenshot pixels.** `frame()` also reports the virtual desktop's `origin`, which is not
56
+ always (0,0) — a second monitor to the left of the primary one gives Windows a negative left edge. The backends
57
+ add it back, so callers work in screenshot pixels throughout and multi-monitor setups stop being a source of
58
+ silent misclicks.
59
+
60
+ **One key vocabulary, three renderings.** `keys.ts` fixes the names (X11 keysyms: `Return`, `Escape`,
61
+ `BackSpace`, `Page_Up`, plus `ctrl`/`alt`/`shift`/`super` and the aliases people actually type — `enter`, `esc`,
62
+ `win`, `cmd`) and each backend translates. Without it every caller would be platform-aware, which is the exact
63
+ coupling this package exists to remove.
@@ -0,0 +1,9 @@
1
+ import { type WindowInfo } from "./types.js";
2
+ export declare const linuxApps: {
3
+ windows: () => Promise<WindowInfo[]>;
4
+ focusWindow: (id: string) => Promise<void>;
5
+ launch: (target: string) => Promise<void>;
6
+ readClipboard: () => Promise<string>;
7
+ writeClipboard: (text: string) => Promise<void>;
8
+ };
9
+ //# sourceMappingURL=apps-linux.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps-linux.d.ts","sourceRoot":"","sources":["../src/apps-linux.ts"],"names":[],"mappings":"AAKA,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAmB3D,eAAO,MAAM,SAAS;IAClB,OAAO,QAAY,OAAO,CAAC,UAAU,EAAE,CAAC;IAexC,WAAW,OAAa,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;IAqB9C,MAAM,WAAiB,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;IAkB7C,aAAa,QAAY,OAAO,CAAC,MAAM,CAAC;IAKxC,cAAc,SAAe,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;CAWtD,CAAC"}
@@ -0,0 +1,64 @@
1
+ import { spawn } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ import { looksLikeUrl, parseSwayTree, parseWmctrl } from "./parse.js";
4
+ import { has, run } from "./run.js";
5
+ import { isWayland } from "./screen.js";
6
+ import { DesktopError } from "./types.js";
7
+ const WMCTRL_INSTALL = "sudo apt install wmctrl (or your distro's package)";
8
+ const XDOTOOL_INSTALL = "sudo apt install xdotool (or your distro's package)";
9
+ const CLIP_INSTALL_X11 = "sudo apt install xclip";
10
+ const CLIP_INSTALL_WAYLAND = "sudo apt install wl-clipboard";
11
+ const swayRunning = () => process.env["SWAYSOCK"] !== undefined || process.env["I3SOCK"] !== undefined;
12
+ export const linuxApps = {
13
+ windows: async () => {
14
+ if (isWayland()) {
15
+ if (swayRunning() && (await has("swaymsg"))) {
16
+ return parseSwayTree(await run("swaymsg", ["-t", "get_tree"]));
17
+ }
18
+ throw new DesktopError("This Wayland session does not let a program list other windows — the compositor refuses it by design, and only sway/Hyprland offer an IPC that answers. Use a screenshot to see what is open, or log in to an X11 session for full window control.");
19
+ }
20
+ const active = await run("xdotool", ["getactivewindow"], XDOTOOL_INSTALL).catch(() => "");
21
+ const listed = await run("wmctrl", ["-lGpx"], WMCTRL_INSTALL);
22
+ return parseWmctrl(listed, active.trim() === "" ? undefined : active.trim());
23
+ },
24
+ focusWindow: async (id) => {
25
+ if (isWayland()) {
26
+ if (swayRunning() && (await has("swaymsg"))) {
27
+ await run("swaymsg", ["[con_id=" + id + "]", "focus"]);
28
+ return;
29
+ }
30
+ throw new DesktopError("This Wayland session does not let a program focus another window. Click it with the pointer instead, or use an X11 session.");
31
+ }
32
+ await run("xdotool", ["windowactivate", "--sync", id], XDOTOOL_INSTALL);
33
+ },
34
+ launch: async (target) => {
35
+ const viaOpener = looksLikeUrl(target) || existsSync(target);
36
+ if (viaOpener && !(await has("xdg-open"))) {
37
+ throw new DesktopError(`This computer has no "xdg-open" to open "${target}" with.`, "sudo apt install xdg-utils");
38
+ }
39
+ const [command, args] = viaOpener
40
+ ? ["xdg-open", [target]]
41
+ : [target.split(/\s+/)[0] ?? target, target.split(/\s+/).slice(1)];
42
+ const child = spawn(command, [...args], { detached: true, stdio: "ignore" });
43
+ child.unref();
44
+ await new Promise((resolvePromise, reject) => {
45
+ child.once("error", (error) => reject(new DesktopError(`Could not start "${target}": ${error.message}`)));
46
+ setTimeout(resolvePromise, 50);
47
+ });
48
+ },
49
+ readClipboard: async () => isWayland()
50
+ ? await run("wl-paste", ["--no-newline"], CLIP_INSTALL_WAYLAND)
51
+ : await run("xclip", ["-selection", "clipboard", "-o"], CLIP_INSTALL_X11),
52
+ writeClipboard: async (text) => {
53
+ const [command, args, install] = isWayland()
54
+ ? ["wl-copy", [], CLIP_INSTALL_WAYLAND]
55
+ : ["xclip", ["-selection", "clipboard"], CLIP_INSTALL_X11];
56
+ await new Promise((resolvePromise, reject) => {
57
+ const child = spawn(command, [...args], { stdio: ["pipe", "ignore", "ignore"] });
58
+ child.once("error", (error) => reject(new DesktopError(`Could not set the clipboard with "${command}": ${error.message}`, install)));
59
+ child.once("close", () => resolvePromise());
60
+ child.stdin.end(text);
61
+ });
62
+ },
63
+ };
64
+ //# sourceMappingURL=apps-linux.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps-linux.js","sourceRoot":"","sources":["../src/apps-linux.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { WindowInfo } from "./types.js";
2
+ export declare const windowsApps: {
3
+ windows: () => Promise<WindowInfo[]>;
4
+ focusWindow: (id: string) => Promise<void>;
5
+ launch: (target: string) => Promise<void>;
6
+ readClipboard: () => Promise<string>;
7
+ writeClipboard: (text: string) => Promise<void>;
8
+ };
9
+ //# sourceMappingURL=apps-windows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps-windows.d.ts","sourceRoot":"","sources":["../src/apps-windows.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA6C7C,eAAO,MAAM,WAAW;IACpB,OAAO,QAAY,OAAO,CAAC,UAAU,EAAE,CAAC;IAExC,WAAW,OAAa,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;IAU9C,MAAM,WAAiB,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;IAK7C,aAAa,QAAY,OAAO,CAAC,MAAM,CAAC;IAExC,cAAc,SAAe,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;CAKtD,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { parseWindowsJson } from "./parse.js";
2
+ import { run } from "./run.js";
3
+ const SHIM = `
4
+ Add-Type -TypeDefinition @"
5
+ using System;
6
+ using System.Runtime.InteropServices;
7
+ public class IntenticWin {
8
+ [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
9
+ [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);
10
+ [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
11
+ [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h);
12
+ [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr h, int cmd);
13
+ [DllImport("user32.dll")] public static extern bool IsIconic(IntPtr h);
14
+ }
15
+ "@ -ErrorAction SilentlyContinue;
16
+ `;
17
+ const SW_RESTORE = 9;
18
+ const LIST = `
19
+ $fg = [IntenticWin]::GetForegroundWindow();
20
+ $items = @(Get-Process | Where-Object { $_.MainWindowHandle -ne 0 -and $_.MainWindowTitle -ne '' } | ForEach-Object {
21
+ $r = New-Object IntenticWin+RECT;
22
+ [void][IntenticWin]::GetWindowRect($_.MainWindowHandle, [ref]$r);
23
+ [pscustomobject]@{
24
+ id = [string]$_.MainWindowHandle; title = $_.MainWindowTitle; app = $_.ProcessName;
25
+ x = $r.Left; y = $r.Top; width = ($r.Right - $r.Left); height = ($r.Bottom - $r.Top);
26
+ focused = ($_.MainWindowHandle -eq $fg)
27
+ }
28
+ });
29
+ ConvertTo-Json -Compress -Depth 3 -InputObject $items;
30
+ `;
31
+ const powershell = (script) => run("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", `${SHIM}${script}`]);
32
+ export const windowsApps = {
33
+ windows: async () => parseWindowsJson((await powershell(LIST)).trim()),
34
+ focusWindow: async (id) => {
35
+ await powershell(`$h = [IntPtr]::new([int64]${JSON.stringify(id)}); ` +
36
+ `if ([IntenticWin]::IsIconic($h)) { [void][IntenticWin]::ShowWindow($h, ${SW_RESTORE}) }; ` +
37
+ `[void][IntenticWin]::SetForegroundWindow($h);`);
38
+ },
39
+ launch: async (target) => {
40
+ await powershell(`Start-Process -FilePath ${JSON.stringify(target)};`);
41
+ },
42
+ readClipboard: async () => await powershell("Get-Clipboard -Raw;"),
43
+ writeClipboard: async (text) => {
44
+ await powershell(`Set-Clipboard -Value '${text.replace(/'/g, "''")}';`);
45
+ },
46
+ };
47
+ //# sourceMappingURL=apps-windows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps-windows.js","sourceRoot":"","sources":["../src/apps-windows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAW/B,MAAM,IAAI,GAAG;;;;;;;;;;;;;CAaZ,CAAC;AAIF,MAAM,UAAU,GAAG,CAAC,CAAC;AAErB,MAAM,IAAI,GAAG;;;;;;;;;;;;CAYZ,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,MAAc,EAAmB,EAAE,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,GAAG,IAAI,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC;AAEjJ,MAAM,CAAC,MAAM,WAAW,GAAG;IACvB,OAAO,EAAE,KAAK,IAA2B,EAAE,CAAC,gBAAgB,CAAC,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAE7F,WAAW,EAAE,KAAK,EAAE,EAAU,EAAiB,EAAE;QAC7C,MAAM,UAAU,CACZ,6BAA6B,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK;YAChD,0EAA0E,UAAU,OAAO;YAC3F,+CAA+C,CACtD,CAAC;IACN,CAAC;IAID,MAAM,EAAE,KAAK,EAAE,MAAc,EAAiB,EAAE;QAC5C,MAAM,UAAU,CAAC,2BAA2B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3E,CAAC;IAGD,aAAa,EAAE,KAAK,IAAqB,EAAE,CAAC,MAAM,UAAU,CAAC,qBAAqB,CAAC;IAEnF,cAAc,EAAE,KAAK,EAAE,IAAY,EAAiB,EAAE;QAGlD,MAAM,UAAU,CAAC,yBAAyB,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5E,CAAC;CACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { type Desktop } from "./types.js";
2
+ export { parseChord, windowsChord, wtypeArgs, xdotoolChord, type Chord, type Modifier } from "./keys.js";
3
+ export { looksLikeUrl, parseSwayTree, parseWindowsJson, parseWmctrl } from "./parse.js";
4
+ export { capture, frame, hasGraphicalSession, isWayland, pngSize } from "./screen.js";
5
+ export { DesktopError, type Desktop, type MouseButton, type Point, type ScreenFrame, type ScrollDirection, type WindowInfo } from "./types.js";
6
+ export declare const desktop: () => Desktop;
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,OAAO,EAAgB,MAAM,YAAY,CAAC;AAExD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AACzG,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,KAAK,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,KAAK,EAAE,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAkB/I,eAAO,MAAM,OAAO,QAAO,OAkC1B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,49 @@
1
+ import { linuxApps } from "./apps-linux.js";
2
+ import { windowsApps } from "./apps-windows.js";
3
+ import { linuxInput } from "./input-linux.js";
4
+ import { windowsInput } from "./input-windows.js";
5
+ import { capture, frame } from "./screen.js";
6
+ import { DesktopError } from "./types.js";
7
+ export { parseChord, windowsChord, wtypeArgs, xdotoolChord } from "./keys.js";
8
+ export { looksLikeUrl, parseSwayTree, parseWindowsJson, parseWmctrl } from "./parse.js";
9
+ export { capture, frame, hasGraphicalSession, isWayland, pngSize } from "./screen.js";
10
+ export { DesktopError } from "./types.js";
11
+ const unsupported = async () => {
12
+ throw new DesktopError(`Controlling the screen is not supported on ${process.platform} yet — only Windows and Linux.`);
13
+ };
14
+ export const desktop = () => {
15
+ if (process.platform === "win32") {
16
+ return {
17
+ frame,
18
+ capture,
19
+ move: async (to) => await windowsInput.move(to, (await frame()).origin),
20
+ click: async (at, button) => await windowsInput.click(at, button, (await frame()).origin),
21
+ doubleClick: async (at) => await windowsInput.doubleClick(at, (await frame()).origin),
22
+ drag: async (from, to) => await windowsInput.drag(from, to, (await frame()).origin),
23
+ type: windowsInput.type,
24
+ key: windowsInput.key,
25
+ scroll: async (at, direction, amount) => await windowsInput.scroll(at, direction, amount, (await frame()).origin),
26
+ ...windowsApps,
27
+ };
28
+ }
29
+ if (process.platform === "linux") {
30
+ return { frame, capture, ...linuxInput, ...linuxApps };
31
+ }
32
+ return {
33
+ frame,
34
+ capture,
35
+ move: unsupported,
36
+ click: unsupported,
37
+ doubleClick: unsupported,
38
+ drag: unsupported,
39
+ type: unsupported,
40
+ key: unsupported,
41
+ scroll: unsupported,
42
+ windows: unsupported,
43
+ focusWindow: unsupported,
44
+ launch: unsupported,
45
+ readClipboard: unsupported,
46
+ writeClipboard: unsupported,
47
+ };
48
+ };
49
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAgB,YAAY,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAA6B,MAAM,WAAW,CAAC;AACzG,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,EAAE,YAAY,EAAuG,MAAM,YAAY,CAAC;AAc/I,MAAM,WAAW,GAAG,KAAK,IAAoB,EAAE;IAC3C,MAAM,IAAI,YAAY,CAAC,8CAA8C,OAAO,CAAC,QAAQ,gCAAgC,CAAC,CAAC;AAC3H,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAG,GAAY,EAAE;IACjC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAC/B,OAAO;YACH,KAAK;YACL,OAAO;YACP,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;YACvE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,YAAY,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;YACzF,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,MAAM,YAAY,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;YACrF,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;YACnF,IAAI,EAAE,YAAY,CAAC,IAAI;YACvB,GAAG,EAAE,YAAY,CAAC,GAAG;YACrB,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,YAAY,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;YACjH,GAAG,WAAW;SACjB,CAAC;IACN,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAC/B,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,GAAG,SAAS,EAAE,CAAC;IAC3D,CAAC;IACD,OAAO;QACH,KAAK;QACL,OAAO;QACP,IAAI,EAAE,WAAW;QACjB,KAAK,EAAE,WAAW;QAClB,WAAW,EAAE,WAAW;QACxB,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,WAAW;QACjB,GAAG,EAAE,WAAW;QAChB,MAAM,EAAE,WAAW;QACnB,OAAO,EAAE,WAAW;QACpB,WAAW,EAAE,WAAW;QACxB,MAAM,EAAE,WAAW;QACnB,aAAa,EAAE,WAAW;QAC1B,cAAc,EAAE,WAAW;KAC9B,CAAC;AACN,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { type MouseButton, type Point, type ScrollDirection } from "./types.js";
2
+ export declare const linuxInput: {
3
+ move: (to: Point) => Promise<void>;
4
+ click: (at: Point, button: MouseButton) => Promise<void>;
5
+ doubleClick: (at: Point) => Promise<void>;
6
+ drag: (from: Point, to: Point) => Promise<void>;
7
+ type: (text: string) => Promise<void>;
8
+ key: (combo: string) => Promise<void>;
9
+ scroll: (at: Point, direction: ScrollDirection, amount: number) => Promise<void>;
10
+ };
11
+ //# sourceMappingURL=input-linux.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-linux.d.ts","sourceRoot":"","sources":["../src/input-linux.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,WAAW,EAAE,KAAK,KAAK,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AA4B9F,eAAO,MAAM,UAAU;IACnB,IAAI,OAAa,KAAK,KAAG,OAAO,CAAC,IAAI,CAAC;IAQtC,KAAK,OAAa,KAAK,UAAU,WAAW,KAAG,OAAO,CAAC,IAAI,CAAC;IAS5D,WAAW,OAAa,KAAK,KAAG,OAAO,CAAC,IAAI,CAAC;IAqB7C,IAAI,SAAe,KAAK,MAAM,KAAK,KAAG,OAAO,CAAC,IAAI,CAAC;IAcnD,IAAI,SAAe,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;IAczC,GAAG,UAAgB,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;IAazC,MAAM,OAAa,KAAK,aAAa,eAAe,UAAU,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;CAavF,CAAC"}
@@ -0,0 +1,94 @@
1
+ import { wtypeArgs, xdotoolChord } from "./keys.js";
2
+ import { has, run } from "./run.js";
3
+ import { isWayland } from "./screen.js";
4
+ import { DesktopError } from "./types.js";
5
+ const XDOTOOL_INSTALL = "sudo apt install xdotool (or your distro's package)";
6
+ const YDOTOOL_INSTALL = "sudo apt install ydotool, then add yourself to the input group: sudo usermod -aG input $USER (log out and back in)";
7
+ const WTYPE_INSTALL = "sudo apt install wtype";
8
+ const XDOTOOL_BUTTON = { left: "1", middle: "2", right: "3" };
9
+ const YDOTOOL_BUTTON = { left: "0xC0", right: "0xC1", middle: "0xC2" };
10
+ const wayland = () => isWayland();
11
+ const xdotool = (args) => run("xdotool", args, XDOTOOL_INSTALL);
12
+ const ydotool = (args) => run("ydotool", args, YDOTOOL_INSTALL);
13
+ export const linuxInput = {
14
+ move: async (to) => {
15
+ if (wayland()) {
16
+ await ydotool(["mousemove", "--absolute", "-x", String(Math.round(to.x)), "-y", String(Math.round(to.y))]);
17
+ return;
18
+ }
19
+ await xdotool(["mousemove", String(Math.round(to.x)), String(Math.round(to.y))]);
20
+ },
21
+ click: async (at, button) => {
22
+ if (wayland()) {
23
+ await linuxInput.move(at);
24
+ await ydotool(["click", YDOTOOL_BUTTON[button]]);
25
+ return;
26
+ }
27
+ await xdotool(["mousemove", String(Math.round(at.x)), String(Math.round(at.y)), "click", XDOTOOL_BUTTON[button]]);
28
+ },
29
+ doubleClick: async (at) => {
30
+ if (wayland()) {
31
+ await linuxInput.move(at);
32
+ await ydotool(["click", YDOTOOL_BUTTON.left]);
33
+ await ydotool(["click", YDOTOOL_BUTTON.left]);
34
+ return;
35
+ }
36
+ await xdotool([
37
+ "mousemove",
38
+ String(Math.round(at.x)),
39
+ String(Math.round(at.y)),
40
+ "click",
41
+ "--repeat",
42
+ "2",
43
+ "--delay",
44
+ "40",
45
+ XDOTOOL_BUTTON.left,
46
+ ]);
47
+ },
48
+ drag: async (from, to) => {
49
+ if (wayland()) {
50
+ await linuxInput.move(from);
51
+ await ydotool(["click", "0x40"]);
52
+ await linuxInput.move(to);
53
+ await ydotool(["click", "0x80"]);
54
+ return;
55
+ }
56
+ await xdotool(["mousemove", String(Math.round(from.x)), String(Math.round(from.y)), "mousedown", "1"]);
57
+ await xdotool(["mousemove", String(Math.round(to.x)), String(Math.round(to.y))]);
58
+ await xdotool(["mouseup", "1"]);
59
+ },
60
+ type: async (text) => {
61
+ if (wayland()) {
62
+ if (await has("wtype")) {
63
+ await run("wtype", ["--", text], WTYPE_INSTALL);
64
+ return;
65
+ }
66
+ await ydotool(["type", "--", text]);
67
+ return;
68
+ }
69
+ await xdotool(["type", "--delay", "12", "--", text]);
70
+ },
71
+ key: async (combo) => {
72
+ if (wayland()) {
73
+ if (await has("wtype")) {
74
+ await run("wtype", wtypeArgs(combo), WTYPE_INSTALL);
75
+ return;
76
+ }
77
+ throw new DesktopError("Pressing key combinations on Wayland needs wtype.", WTYPE_INSTALL);
78
+ }
79
+ await xdotool(["key", "--clearmodifiers", xdotoolChord(combo)]);
80
+ },
81
+ scroll: async (at, direction, amount) => {
82
+ const clicks = Math.max(1, Math.round(amount));
83
+ if (wayland()) {
84
+ await linuxInput.move(at);
85
+ const axis = direction === "up" || direction === "down" ? "--wheel" : "--hwheel";
86
+ const sign = direction === "down" || direction === "right" ? 1 : -1;
87
+ await ydotool(["mousemove", axis, String(sign * clicks)]);
88
+ return;
89
+ }
90
+ const button = { up: "4", down: "5", left: "6", right: "7" }[direction];
91
+ await xdotool(["mousemove", String(Math.round(at.x)), String(Math.round(at.y)), "click", "--repeat", String(clicks), button]);
92
+ },
93
+ };
94
+ //# sourceMappingURL=input-linux.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-linux.js","sourceRoot":"","sources":["../src/input-linux.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { MouseButton, Point, ScrollDirection } from "./types.js";
2
+ export declare const windowsInput: {
3
+ move: (to: Point, origin: Point) => Promise<void>;
4
+ click: (at: Point, button: MouseButton, origin: Point) => Promise<void>;
5
+ doubleClick: (at: Point, origin: Point) => Promise<void>;
6
+ drag: (from: Point, to: Point, origin: Point) => Promise<void>;
7
+ type: (text: string) => Promise<void>;
8
+ key: (combo: string) => Promise<void>;
9
+ scroll: (at: Point, direction: ScrollDirection, amount: number, origin: Point) => Promise<void>;
10
+ };
11
+ //# sourceMappingURL=input-windows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-windows.d.ts","sourceRoot":"","sources":["../src/input-windows.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAsEtE,eAAO,MAAM,YAAY;IACrB,IAAI,OAAa,KAAK,UAAU,KAAK,KAAG,OAAO,CAAC,IAAI,CAAC;IAErD,KAAK,OAAa,KAAK,UAAU,WAAW,UAAU,KAAK,KAAG,OAAO,CAAC,IAAI,CAAC;IAG3E,WAAW,OAAa,KAAK,UAAU,KAAK,KAAG,OAAO,CAAC,IAAI,CAAC;IAO5D,IAAI,SAAe,KAAK,MAAM,KAAK,UAAU,KAAK,KAAG,OAAO,CAAC,IAAI,CAAC;IAalE,IAAI,SAAe,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;IAYzC,GAAG,UAAgB,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;IAiBzC,MAAM,OAAa,KAAK,aAAa,eAAe,UAAU,MAAM,UAAU,KAAK,KAAG,OAAO,CAAC,IAAI,CAAC;CAQtG,CAAC"}
@@ -0,0 +1,69 @@
1
+ import { windowsChord } from "./keys.js";
2
+ import { run } from "./run.js";
3
+ const SHIM = `
4
+ Add-Type -Namespace IntenticDesktop -Name Native -MemberDefinition @'
5
+ [DllImport("user32.dll")] public static extern bool SetCursorPos(int X, int Y);
6
+ [DllImport("user32.dll")] public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, System.IntPtr dwExtraInfo);
7
+ [DllImport("user32.dll")] public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, System.IntPtr dwExtraInfo);
8
+ '@;
9
+ `;
10
+ const DOWN = { left: 0x0002, right: 0x0008, middle: 0x0020 };
11
+ const UP = { left: 0x0004, right: 0x0010, middle: 0x0040 };
12
+ const WHEEL = 0x0800;
13
+ const HWHEEL = 0x01000;
14
+ const KEYUP = 0x0002;
15
+ const WHEEL_DELTA = 120;
16
+ const powershell = async (script) => {
17
+ await run("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", `${SHIM}${script}`]);
18
+ };
19
+ const absolute = (at, origin) => ({ x: Math.round(at.x + origin.x), y: Math.round(at.y + origin.y) });
20
+ const moveScript = (at, origin) => {
21
+ const { x, y } = absolute(at, origin);
22
+ return `[IntenticDesktop.Native]::SetCursorPos(${x}, ${y}) | Out-Null;`;
23
+ };
24
+ const clickScript = (button) => `[IntenticDesktop.Native]::mouse_event(${DOWN[button]}, 0, 0, 0, [System.IntPtr]::Zero); ` +
25
+ `Start-Sleep -Milliseconds 20; ` +
26
+ `[IntenticDesktop.Native]::mouse_event(${UP[button]}, 0, 0, 0, [System.IntPtr]::Zero);`;
27
+ const escapeText = (text) => text.replace(/[+^%~(){}[\]]/g, (character) => `{${character}}`);
28
+ export const windowsInput = {
29
+ move: async (to, origin) => await powershell(moveScript(to, origin)),
30
+ click: async (at, button, origin) => await powershell(`${moveScript(at, origin)} Start-Sleep -Milliseconds 20; ${clickScript(button)}`),
31
+ doubleClick: async (at, origin) => await powershell(`${moveScript(at, origin)} Start-Sleep -Milliseconds 20; ${clickScript("left")} Start-Sleep -Milliseconds 40; ${clickScript("left")}`),
32
+ drag: async (from, to, origin) => await powershell([
33
+ moveScript(from, origin),
34
+ "Start-Sleep -Milliseconds 40;",
35
+ `[IntenticDesktop.Native]::mouse_event(${DOWN.left}, 0, 0, 0, [System.IntPtr]::Zero);`,
36
+ "Start-Sleep -Milliseconds 60;",
37
+ moveScript(to, origin),
38
+ "Start-Sleep -Milliseconds 60;",
39
+ `[IntenticDesktop.Native]::mouse_event(${UP.left}, 0, 0, 0, [System.IntPtr]::Zero);`,
40
+ ].join(" ")),
41
+ type: async (text) => {
42
+ const parts = text.split(/\r?\n/);
43
+ const script = parts
44
+ .map((part, index) => {
45
+ const send = part === "" ? "" : `[System.Windows.Forms.SendKeys]::SendWait('${escapeText(part).replace(/'/g, "''")}');`;
46
+ return index < parts.length - 1 ? `${send} [System.Windows.Forms.SendKeys]::SendWait('{ENTER}');` : send;
47
+ })
48
+ .join(" ");
49
+ await powershell(`Add-Type -AssemblyName System.Windows.Forms; ${script}`);
50
+ },
51
+ key: async (combo) => {
52
+ const chord = windowsChord(combo);
53
+ const press = (code, up) => `[IntenticDesktop.Native]::keybd_event(${code}, 0, ${up ? KEYUP : 0}, [System.IntPtr]::Zero);`;
54
+ await powershell([
55
+ ...chord.modifiers.map((code) => press(code, false)),
56
+ press(chord.key, false),
57
+ "Start-Sleep -Milliseconds 20;",
58
+ press(chord.key, true),
59
+ ...chord.modifiers.toReversed().map((code) => press(code, true)),
60
+ ].join(" "));
61
+ },
62
+ scroll: async (at, direction, amount, origin) => {
63
+ const horizontal = direction === "left" || direction === "right";
64
+ const sign = direction === "down" || direction === "left" ? -1 : 1;
65
+ const delta = sign * WHEEL_DELTA * Math.max(1, Math.round(amount));
66
+ await powershell(`${moveScript(at, origin)} [IntenticDesktop.Native]::mouse_event(${horizontal ? HWHEEL : WHEEL}, 0, 0, ${delta}, [System.IntPtr]::Zero);`);
67
+ },
68
+ };
69
+ //# sourceMappingURL=input-windows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-windows.js","sourceRoot":"","sources":["../src/input-windows.ts"],"names":[],"mappings":"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"}
package/dist/keys.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export type Modifier = "ctrl" | "alt" | "shift" | "super";
2
+ export interface Chord {
3
+ readonly modifiers: readonly Modifier[];
4
+ readonly key: string;
5
+ }
6
+ export declare const parseChord: (combo: string) => Chord;
7
+ export declare const xdotoolChord: (combo: string) => string;
8
+ export declare const wtypeArgs: (combo: string) => string[];
9
+ export interface WindowsChord {
10
+ readonly modifiers: readonly number[];
11
+ readonly key: number;
12
+ }
13
+ export declare const windowsChord: (combo: string) => WindowsChord;
14
+ //# sourceMappingURL=keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,OAAO,CAAC;AAE1D,MAAM,WAAW,KAAK;IAClB,QAAQ,CAAC,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC;IAExC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACxB;AA6DD,eAAO,MAAM,UAAU,UAAW,MAAM,KAAG,KAuB1C,CAAC;AAGF,eAAO,MAAM,YAAY,UAAW,MAAM,KAAG,MAG5C,CAAC;AAGF,eAAO,MAAM,SAAS,UAAW,MAAM,KAAG,MAAM,EAG/C,CAAC;AA2BF,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,YAAY,UAAW,MAAM,KAAG,YAyB5C,CAAC"}
package/dist/keys.js ADDED
@@ -0,0 +1,126 @@
1
+ import { DesktopError } from "./types.js";
2
+ const MODIFIERS = {
3
+ ctrl: "ctrl",
4
+ control: "ctrl",
5
+ alt: "alt",
6
+ option: "alt",
7
+ opt: "alt",
8
+ shift: "shift",
9
+ super: "super",
10
+ win: "super",
11
+ windows: "super",
12
+ cmd: "super",
13
+ command: "super",
14
+ meta: "super",
15
+ };
16
+ const ALIASES = {
17
+ enter: "Return",
18
+ return: "Return",
19
+ esc: "Escape",
20
+ escape: "Escape",
21
+ backspace: "BackSpace",
22
+ del: "Delete",
23
+ delete: "Delete",
24
+ ins: "Insert",
25
+ insert: "Insert",
26
+ space: "space",
27
+ spacebar: "space",
28
+ tab: "Tab",
29
+ up: "Up",
30
+ down: "Down",
31
+ left: "Left",
32
+ right: "Right",
33
+ home: "Home",
34
+ end: "End",
35
+ pageup: "Page_Up",
36
+ page_up: "Page_Up",
37
+ pgup: "Page_Up",
38
+ pagedown: "Page_Down",
39
+ page_down: "Page_Down",
40
+ pgdn: "Page_Down",
41
+ };
42
+ const segments = (combo) => {
43
+ if (combo === "+") {
44
+ return ["+"];
45
+ }
46
+ const parts = combo.split("+");
47
+ if (parts.length >= 3 && parts[parts.length - 1] === "" && parts[parts.length - 2] === "") {
48
+ return [...parts.slice(0, -2), "+"];
49
+ }
50
+ return parts;
51
+ };
52
+ export const parseChord = (combo) => {
53
+ const trimmed = combo.trim();
54
+ if (trimmed === "") {
55
+ throw new DesktopError("No key given.");
56
+ }
57
+ const parts = segments(trimmed);
58
+ const key = parts[parts.length - 1] ?? "";
59
+ const modifiers = [];
60
+ for (const part of parts.slice(0, -1)) {
61
+ const modifier = MODIFIERS[part.trim().toLowerCase()];
62
+ if (modifier === undefined) {
63
+ throw new DesktopError(`"${part}" is not a modifier. Use ctrl, alt, shift or super (win/cmd).`);
64
+ }
65
+ if (!modifiers.includes(modifier)) {
66
+ modifiers.push(modifier);
67
+ }
68
+ }
69
+ if (key === "") {
70
+ throw new DesktopError(`"${combo}" has modifiers but no key.`);
71
+ }
72
+ const canonical = key.length === 1 ? key : (ALIASES[key.toLowerCase()] ?? key);
73
+ return { modifiers, key: canonical };
74
+ };
75
+ export const xdotoolChord = (combo) => {
76
+ const chord = parseChord(combo);
77
+ return [...chord.modifiers.map((modifier) => (modifier === "super" ? "super" : modifier)), chord.key].join("+");
78
+ };
79
+ export const wtypeArgs = (combo) => {
80
+ const chord = parseChord(combo);
81
+ return [...chord.modifiers.flatMap((modifier) => ["-M", modifier === "super" ? "logo" : modifier]), "-k", chord.key];
82
+ };
83
+ const VK = {
84
+ ctrl: 0x11,
85
+ alt: 0x12,
86
+ shift: 0x10,
87
+ super: 0x5b,
88
+ Return: 0x0d,
89
+ Tab: 0x09,
90
+ Escape: 0x1b,
91
+ BackSpace: 0x08,
92
+ Delete: 0x2e,
93
+ Insert: 0x2d,
94
+ space: 0x20,
95
+ Left: 0x25,
96
+ Up: 0x26,
97
+ Right: 0x27,
98
+ Down: 0x28,
99
+ Home: 0x24,
100
+ End: 0x23,
101
+ Page_Up: 0x21,
102
+ Page_Down: 0x22,
103
+ };
104
+ export const windowsChord = (combo) => {
105
+ const chord = parseChord(combo);
106
+ const modifiers = chord.modifiers.map((modifier) => VK[modifier] ?? 0);
107
+ const named = VK[chord.key];
108
+ if (named !== undefined) {
109
+ return { modifiers, key: named };
110
+ }
111
+ const fkey = /^[fF](\d{1,2})$/.exec(chord.key);
112
+ if (fkey?.[1] !== undefined) {
113
+ const index = Number(fkey[1]);
114
+ if (index >= 1 && index <= 24) {
115
+ return { modifiers, key: 0x6f + index };
116
+ }
117
+ }
118
+ if (chord.key.length === 1) {
119
+ const code = chord.key.toUpperCase().charCodeAt(0);
120
+ if ((code >= 0x30 && code <= 0x39) || (code >= 0x41 && code <= 0x5a)) {
121
+ return { modifiers, key: code };
122
+ }
123
+ }
124
+ throw new DesktopError(`This computer cannot press "${chord.key}" — name it as a letter, a digit, F1–F24, or a key like Return, Tab, Escape, Page_Up.`);
125
+ };
126
+ //# sourceMappingURL=keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { WindowInfo } from "./types.js";
2
+ export declare const parseWmctrl: (output: string, focusedId?: string) => WindowInfo[];
3
+ export declare const parseSwayTree: (json: string) => WindowInfo[];
4
+ export declare const parseWindowsJson: (json: string) => WindowInfo[];
5
+ export declare const looksLikeUrl: (target: string) => boolean;
6
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAiB7C,eAAO,MAAM,WAAW,WAAY,MAAM,cAAc,MAAM,KAAG,UAAU,EA8BjE,CAAC;AAsCX,eAAO,MAAM,aAAa,SAAU,MAAM,KAAG,UAAU,EAMtD,CAAC;AAKF,eAAO,MAAM,gBAAgB,SAAU,MAAM,KAAG,UAAU,EA6BzD,CAAC;AAKF,eAAO,MAAM,YAAY,WAAY,MAAM,KAAG,OAAsF,CAAC"}
package/dist/parse.js ADDED
@@ -0,0 +1,85 @@
1
+ export const parseWmctrl = (output, focusedId) => output
2
+ .split(/\r?\n/)
3
+ .map((line) => line.trim())
4
+ .filter((line) => line !== "")
5
+ .flatMap((line) => {
6
+ const fields = /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*)$/.exec(line);
7
+ if (fields === null) {
8
+ return [];
9
+ }
10
+ const [, id, , , x, y, width, height, wmClass, , rawTitle] = fields;
11
+ if (id === undefined || wmClass === undefined) {
12
+ return [];
13
+ }
14
+ const title = (rawTitle ?? "").trim();
15
+ const app = wmClass.includes(".") ? (wmClass.split(".").pop() ?? wmClass) : wmClass;
16
+ return [
17
+ {
18
+ id,
19
+ title,
20
+ app,
21
+ bounds: { x: Number(x), y: Number(y), width: Number(width), height: Number(height) },
22
+ focused: focusedId !== undefined && Number(id) === Number(focusedId),
23
+ },
24
+ ];
25
+ });
26
+ const walkSwayNode = (node) => {
27
+ const children = [...(node.nodes ?? []), ...(node.floating_nodes ?? [])];
28
+ const descendants = children.flatMap(walkSwayNode);
29
+ const name = node.name ?? "";
30
+ const app = node.app_id ?? node.window_properties?.class ?? "";
31
+ if (children.length > 0 || name === "" || node.rect === undefined || node.id === undefined) {
32
+ return descendants;
33
+ }
34
+ return [
35
+ {
36
+ id: String(node.id),
37
+ title: name,
38
+ app: app === "" ? "unknown" : app,
39
+ bounds: { x: node.rect.x, y: node.rect.y, width: node.rect.width, height: node.rect.height },
40
+ focused: node.focused === true,
41
+ },
42
+ ...descendants,
43
+ ];
44
+ };
45
+ export const parseSwayTree = (json) => {
46
+ try {
47
+ return walkSwayNode(JSON.parse(json));
48
+ }
49
+ catch {
50
+ return [];
51
+ }
52
+ };
53
+ export const parseWindowsJson = (json) => {
54
+ let parsed;
55
+ try {
56
+ parsed = JSON.parse(json);
57
+ }
58
+ catch {
59
+ return [];
60
+ }
61
+ const rows = Array.isArray(parsed) ? parsed : [parsed];
62
+ return rows.flatMap((row) => {
63
+ const record = row;
64
+ const id = record["id"];
65
+ if (typeof id !== "string" || id === "" || id === "0") {
66
+ return [];
67
+ }
68
+ return [
69
+ {
70
+ id,
71
+ title: String(record["title"] ?? ""),
72
+ app: String(record["app"] ?? "unknown"),
73
+ bounds: {
74
+ x: Number(record["x"] ?? 0),
75
+ y: Number(record["y"] ?? 0),
76
+ width: Number(record["width"] ?? 0),
77
+ height: Number(record["height"] ?? 0),
78
+ },
79
+ focused: record["focused"] === true,
80
+ },
81
+ ];
82
+ });
83
+ };
84
+ export const looksLikeUrl = (target) => /^[a-z][a-z0-9+.-]*:\/\//i.test(target) || /^(www\.|mailto:)/i.test(target);
85
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}
package/dist/run.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export declare const run: (command: string, args: readonly string[], install?: string) => Promise<string>;
2
+ export declare const has: (command: string) => Promise<boolean>;
3
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,GAAG,YAAmB,MAAM,QAAQ,SAAS,MAAM,EAAE,YAAY,MAAM,KAAG,OAAO,CAAC,MAAM,CAc/F,CAAC;AAIP,eAAO,MAAM,GAAG,YAAmB,MAAM,KAAG,OAAO,CAAC,OAAO,CAQ1D,CAAC"}
package/dist/run.js ADDED
@@ -0,0 +1,28 @@
1
+ import { execFile } from "node:child_process";
2
+ import { DesktopError } from "./types.js";
3
+ const TIMEOUT_MS = 15_000;
4
+ export const run = async (command, args, install) => await new Promise((resolvePromise, reject) => {
5
+ execFile(command, [...args], { timeout: TIMEOUT_MS, windowsHide: true }, (error, stdout, stderr) => {
6
+ if (error === null) {
7
+ resolvePromise(stdout);
8
+ return;
9
+ }
10
+ if (error.code === "ENOENT") {
11
+ reject(new DesktopError(`This computer has no "${command}".`, install));
12
+ return;
13
+ }
14
+ const said = `${stderr}`.trim();
15
+ reject(new DesktopError(said === "" ? `"${command}" failed: ${error.message}` : `"${command}" failed: ${said}`, install));
16
+ });
17
+ });
18
+ export const has = async (command) => {
19
+ const probe = process.platform === "win32" ? "where" : "which";
20
+ try {
21
+ await run(probe, [command]);
22
+ return true;
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ };
28
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAU1C,MAAM,UAAU,GAAG,MAAM,CAAC;AAE1B,MAAM,CAAC,MAAM,GAAG,GAAG,KAAK,EAAE,OAAe,EAAE,IAAuB,EAAE,OAAgB,EAAmB,EAAE,CACrG,MAAM,IAAI,OAAO,CAAS,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE;IACjD,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;QAC/F,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACjB,cAAc,CAAC,MAAM,CAAC,CAAC;YACvB,OAAO;QACX,CAAC;QACD,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,MAAM,CAAC,IAAI,YAAY,CAAC,yBAAyB,OAAO,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;YACxE,OAAO;QACX,CAAC;QACD,MAAM,IAAI,GAAG,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;QAChC,MAAM,CAAC,IAAI,YAAY,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,OAAO,aAAa,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,OAAO,aAAa,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9H,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC;AAIP,MAAM,CAAC,MAAM,GAAG,GAAG,KAAK,EAAE,OAAe,EAAoB,EAAE;IAC3D,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/D,IAAI,CAAC;QACD,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QAC5B,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { type ScreenFrame } from "./types.js";
2
+ export declare const isWayland: () => boolean;
3
+ export declare const hasGraphicalSession: () => boolean;
4
+ export declare const capture: () => Promise<Buffer>;
5
+ export declare const pngSize: (png: Buffer) => {
6
+ width: number;
7
+ height: number;
8
+ };
9
+ export declare const frame: () => Promise<ScreenFrame>;
10
+ //# sourceMappingURL=screen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../src/screen.ts"],"names":[],"mappings":"AAKA,OAAO,EAAgB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAgC5D,eAAO,MAAM,SAAS,QAAO,OAAwG,CAAC;AA4BtI,eAAO,MAAM,mBAAmB,QAAO,OACiF,CAAC;AAEzH,eAAO,MAAM,OAAO,QAAa,OAAO,CAAC,MAAM,CAyB9C,CAAC;AAMF,eAAO,MAAM,OAAO,QAAS,MAAM,KAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAKpE,CAAC;AAOF,eAAO,MAAM,KAAK,QAAa,OAAO,CAAC,WAAW,CAqBjD,CAAC"}
package/dist/screen.js ADDED
@@ -0,0 +1,91 @@
1
+ import { spawn } from "node:child_process";
2
+ import { readFile, rm } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { run } from "./run.js";
6
+ import { DesktopError } from "./types.js";
7
+ const pngPath = () => join(tmpdir(), `intentic-desktop-${process.pid}-${Date.now()}.png`);
8
+ const WINDOWS_CAPTURE = (out) => [
9
+ "Add-Type -AssemblyName System.Windows.Forms,System.Drawing;",
10
+ "$b = [System.Windows.Forms.SystemInformation]::VirtualScreen;",
11
+ "$bmp = New-Object System.Drawing.Bitmap $b.Width, $b.Height;",
12
+ "$g = [System.Drawing.Graphics]::FromImage($bmp);",
13
+ "$g.CopyFromScreen($b.Left, $b.Top, 0, 0, $bmp.Size);",
14
+ `$bmp.Save('${out}', [System.Drawing.Imaging.ImageFormat]::Png);`,
15
+ "$g.Dispose(); $bmp.Dispose();",
16
+ ].join(" ");
17
+ export const isWayland = () => process.env["XDG_SESSION_TYPE"] === "wayland" || process.env["WAYLAND_DISPLAY"] !== undefined;
18
+ const grabbers = (out) => {
19
+ if (process.platform === "win32") {
20
+ return [{ command: "powershell.exe", args: () => ["-NoProfile", "-NonInteractive", "-Command", WINDOWS_CAPTURE(out)], install: "" }];
21
+ }
22
+ const waylandTools = [
23
+ { command: "grim", args: (path) => [path], install: "sudo apt install grim (or your distro's package)" },
24
+ { command: "gnome-screenshot", args: (path) => ["-f", path], install: "sudo apt install gnome-screenshot" },
25
+ { command: "spectacle", args: (path) => ["-b", "-n", "-o", path], install: "sudo apt install kde-spectacle" },
26
+ ];
27
+ const x11Tools = [
28
+ { command: "import", args: (path) => ["-window", "root", path], install: "sudo apt install imagemagick" },
29
+ { command: "scrot", args: (path) => [path], install: "sudo apt install scrot" },
30
+ { command: "gnome-screenshot", args: (path) => ["-f", path], install: "sudo apt install gnome-screenshot" },
31
+ ];
32
+ return isWayland() ? [...waylandTools, ...x11Tools] : [...x11Tools, ...waylandTools];
33
+ };
34
+ const attempt = (command, args) => new Promise((resolvePromise) => {
35
+ const child = spawn(command, [...args], { windowsHide: true });
36
+ child.on("error", () => resolvePromise(false));
37
+ child.on("close", (code) => resolvePromise(code === 0));
38
+ });
39
+ export const hasGraphicalSession = () => process.platform === "win32" || process.env["DISPLAY"] !== undefined || process.env["WAYLAND_DISPLAY"] !== undefined;
40
+ export const capture = async () => {
41
+ if (!hasGraphicalSession()) {
42
+ throw new DesktopError("This computer has no graphical session right now (no DISPLAY or WAYLAND_DISPLAY), so there is no screen.");
43
+ }
44
+ const out = pngPath();
45
+ try {
46
+ for (const grabber of grabbers(out)) {
47
+ if (!(await attempt(grabber.command, grabber.args(out)))) {
48
+ continue;
49
+ }
50
+ const png = await readFile(out).catch(() => undefined);
51
+ if (png !== undefined && png.length > 0) {
52
+ return png;
53
+ }
54
+ }
55
+ const installs = grabbers(out)
56
+ .map((grabber) => grabber.install)
57
+ .filter((install) => install !== "");
58
+ throw new DesktopError(installs.length === 0 ? "Could not capture the screen." : "No screenshot tool on this computer.", installs.length === 0 ? undefined : installs.join(" — or — "));
59
+ }
60
+ finally {
61
+ await rm(out, { force: true }).catch(() => undefined);
62
+ }
63
+ };
64
+ export const pngSize = (png) => {
65
+ if (png.length < 24 || png.readUInt32BE(0) !== 0x89504e47) {
66
+ throw new DesktopError("That is not a PNG, so its size cannot be read.");
67
+ }
68
+ return { width: png.readUInt32BE(16), height: png.readUInt32BE(20) };
69
+ };
70
+ const WINDOWS_FRAME = "Add-Type -AssemblyName System.Windows.Forms; " +
71
+ "$b = [System.Windows.Forms.SystemInformation]::VirtualScreen; " +
72
+ 'Write-Output "$($b.Width) $($b.Height) $($b.Left) $($b.Top)"';
73
+ export const frame = async () => {
74
+ if (process.platform === "win32") {
75
+ const out = await run("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", WINDOWS_FRAME]);
76
+ const [width, height, left, top] = out.trim().split(/\s+/).map(Number);
77
+ if (width === undefined || height === undefined || Number.isNaN(width) || Number.isNaN(height)) {
78
+ throw new DesktopError("Could not read this computer's screen size.");
79
+ }
80
+ return { width, height, origin: { x: left ?? 0, y: top ?? 0 } };
81
+ }
82
+ if (!isWayland()) {
83
+ const out = await run("xdotool", ["getdisplaygeometry"], "sudo apt install xdotool");
84
+ const [width, height] = out.trim().split(/\s+/).map(Number);
85
+ if (width !== undefined && height !== undefined && !Number.isNaN(width) && !Number.isNaN(height)) {
86
+ return { width, height, origin: { x: 0, y: 0 } };
87
+ }
88
+ }
89
+ return { ...pngSize(await capture()), origin: { x: 0, y: 0 } };
90
+ };
91
+ //# sourceMappingURL=screen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen.js","sourceRoot":"","sources":["../src/screen.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ export interface Point {
2
+ readonly x: number;
3
+ readonly y: number;
4
+ }
5
+ export type MouseButton = "left" | "right" | "middle";
6
+ export type ScrollDirection = "up" | "down" | "left" | "right";
7
+ export interface ScreenFrame {
8
+ readonly width: number;
9
+ readonly height: number;
10
+ readonly origin: Point;
11
+ }
12
+ export interface WindowInfo {
13
+ readonly id: string;
14
+ readonly title: string;
15
+ readonly app: string;
16
+ readonly bounds: {
17
+ readonly x: number;
18
+ readonly y: number;
19
+ readonly width: number;
20
+ readonly height: number;
21
+ };
22
+ readonly focused: boolean;
23
+ }
24
+ export interface Desktop {
25
+ readonly frame: () => Promise<ScreenFrame>;
26
+ readonly capture: () => Promise<Buffer>;
27
+ readonly move: (to: Point) => Promise<void>;
28
+ readonly click: (at: Point, button: MouseButton) => Promise<void>;
29
+ readonly doubleClick: (at: Point) => Promise<void>;
30
+ readonly drag: (from: Point, to: Point) => Promise<void>;
31
+ readonly type: (text: string) => Promise<void>;
32
+ readonly key: (combo: string) => Promise<void>;
33
+ readonly scroll: (at: Point, direction: ScrollDirection, amount: number) => Promise<void>;
34
+ readonly windows: () => Promise<WindowInfo[]>;
35
+ readonly focusWindow: (id: string) => Promise<void>;
36
+ readonly launch: (target: string) => Promise<void>;
37
+ readonly readClipboard: () => Promise<string>;
38
+ readonly writeClipboard: (text: string) => Promise<void>;
39
+ }
40
+ export declare class DesktopError extends Error {
41
+ readonly install: string | undefined;
42
+ constructor(message: string, install?: string);
43
+ }
44
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,KAAK;IAClB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;AACtD,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAO/D,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;CAC1B;AAQD,MAAM,WAAW,UAAU;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7G,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC7B;AAGD,MAAM,WAAW,OAAO;IAGpB,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;IAE3C,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,QAAQ,CAAC,WAAW,EAAE,CAAC,EAAE,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzD,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/C,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAI1F,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAE9C,QAAQ,CAAC,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAIpD,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,QAAQ,CAAC,aAAa,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,QAAQ,CAAC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D;AAQD,qBAAa,YAAa,SAAQ,KAAK;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAI5C;CACJ"}
package/dist/types.js ADDED
@@ -0,0 +1,9 @@
1
+ export class DesktopError extends Error {
2
+ install;
3
+ constructor(message, install) {
4
+ super(message);
5
+ this.name = "DesktopError";
6
+ this.install = install;
7
+ }
8
+ }
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA8EA,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC1B,OAAO,CAAqB;IACrC,YAAY,OAAe,EAAE,OAAgB;QACzC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;CACJ"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@intentic/desktop",
3
+ "version": "1.176.0",
4
+ "description": "Drive a desktop from Node: capture the screen, move the pointer, click, type and scroll — Windows and Linux, no native modules",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://gitlab.com/radarsu/intentic.git",
10
+ "directory": "_libs/desktop"
11
+ },
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "publishConfig": {
16
+ "access": "public",
17
+ "registry": "https://registry.npmjs.org/"
18
+ },
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": {
23
+ "@intentic/src": "./src/index.ts",
24
+ "default": "./dist/index.js"
25
+ },
26
+ "require": {
27
+ "@intentic/src": "./src/index.ts",
28
+ "default": "./dist/index.js"
29
+ }
30
+ }
31
+ },
32
+ "dependencies": {
33
+ "tslib": "2.8.1"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "24.13.2",
37
+ "@typescript/native-preview": "7.0.0-dev.20260707.2",
38
+ "vitest": "4.1.10",
39
+ "@intentic/tsconfig": "0.0.0"
40
+ },
41
+ "scripts": {
42
+ "build": "tsgo",
43
+ "typecheck": "tsgo --noEmit -p tsconfig.test.json",
44
+ "watch": "tsgo --build --watch",
45
+ "test": "vitest run",
46
+ "test:watch": "vitest"
47
+ }
48
+ }