diggylab 0.1.31 → 0.1.33
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 +2 -1
- package/cli.js +71 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ headless Chromium — the Electron app is not involved.
|
|
|
8
8
|
|
|
9
9
|
- Node.js 22+
|
|
10
10
|
- Linux packages: `xvfb`, `x11vnc`, `websockify`, `novnc` (Debian/Ubuntu: `apt install xvfb x11vnc websockify novnc`). The Docker image below bundles them.
|
|
11
|
-
- Chromium for Playwright: `
|
|
11
|
+
- Chromium for Playwright: run `diggylab install-browser` once after installing the CLI.
|
|
12
12
|
|
|
13
13
|
## Install
|
|
14
14
|
|
|
@@ -61,6 +61,7 @@ npm publish apps/desktop-agent/dist-npm --access public
|
|
|
61
61
|
| `login` | Opens the Facebook login page on a virtual screen and prints a noVNC link + QR code. Log in from your phone; the session is stored encrypted on the server. |
|
|
62
62
|
| `run` | Connects the WebSocket worker, receives assigned scans, scans headlessly, uploads results. |
|
|
63
63
|
| `status` | Shows the config directory, API origin, paired device, and Facebook session state. |
|
|
64
|
+
| `install-browser` | Downloads the Chromium build Playwright needs (one time, ~150 MB). Run it once after installing the CLI. |
|
|
64
65
|
| `unpair` | Removes device credentials, the Facebook session, and pending scans. |
|
|
65
66
|
|
|
66
67
|
Useful options: `--api <origin>` (default `https://api.diggylab.com`), `--port` / `--bind` /
|
package/cli.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli/cli.ts
|
|
4
4
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
5
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
5
6
|
import { existsSync as existsSync2, readFileSync as readFileSync2, realpathSync } from "node:fs";
|
|
6
7
|
import { hostname, homedir } from "node:os";
|
|
7
8
|
import { dirname as dirname3, join as join4 } from "node:path";
|
|
@@ -2504,11 +2505,13 @@ Usage:
|
|
|
2504
2505
|
diggylab login [--port 6080] [--bind 0.0.0.0] [--public-host <ip or host>]
|
|
2505
2506
|
diggylab run
|
|
2506
2507
|
diggylab status
|
|
2508
|
+
diggylab install-browser
|
|
2507
2509
|
diggylab unpair
|
|
2508
2510
|
|
|
2509
2511
|
Global options:
|
|
2510
2512
|
--config <directory> Agent state directory (default ~/.diggylab)
|
|
2511
2513
|
--api <origin> API origin (default $DIGGYLAB_API_URL or https://api.diggylab.com)`;
|
|
2514
|
+
var MISSING_BROWSER_HINT = "Chromium for Playwright is not installed yet. Run `diggylab install-browser` once.";
|
|
2512
2515
|
function agentVersion() {
|
|
2513
2516
|
let directory = fileURLToPath(new URL(".", import.meta.url));
|
|
2514
2517
|
for (let depth = 0; depth < 4; depth += 1) {
|
|
@@ -2576,21 +2579,42 @@ function waitForFacebookLogin(login, timeoutMs) {
|
|
|
2576
2579
|
});
|
|
2577
2580
|
});
|
|
2578
2581
|
}
|
|
2582
|
+
function pairErrorMessage(error, origin) {
|
|
2583
|
+
const code = error instanceof DesktopAgentClientError ? error.code : null;
|
|
2584
|
+
switch (code) {
|
|
2585
|
+
case "PAIRING_CODE_INVALID":
|
|
2586
|
+
return "The pairing code is invalid, already used, or older than 10 minutes. Create a new code and pair again.";
|
|
2587
|
+
case "PLAN_RESTRICTED":
|
|
2588
|
+
return "This account's plan does not include the Desktop Agent.";
|
|
2589
|
+
case "CREDENTIAL_REVOKED":
|
|
2590
|
+
return "This device was revoked. Create a new pairing code to pair again.";
|
|
2591
|
+
case "NETWORK_ERROR":
|
|
2592
|
+
case "SERVER_UNAVAILABLE":
|
|
2593
|
+
return `Could not reach ${origin}. Check the --api origin and the network.`;
|
|
2594
|
+
default:
|
|
2595
|
+
return error instanceof Error ? error.message : String(error);
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2579
2598
|
async function commandPair(runtime, options, io) {
|
|
2580
2599
|
const code = options.code?.trim();
|
|
2581
2600
|
if (!code) {
|
|
2582
2601
|
io.error("Missing --code <pairing code>. Create one on the Desktop Agent page of the web app.");
|
|
2583
2602
|
return 2;
|
|
2584
2603
|
}
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2604
|
+
try {
|
|
2605
|
+
const access = await runtime.manager.pair({
|
|
2606
|
+
agentVersion: agentVersion(),
|
|
2607
|
+
code,
|
|
2608
|
+
name: sanitizeDeviceName(options.name?.trim() || hostname()),
|
|
2609
|
+
platform: resolvePlatform()
|
|
2610
|
+
});
|
|
2611
|
+
io.log(`Paired as "${access.session.device.name}".`);
|
|
2612
|
+
io.log("Next: run `diggylab login` to connect a Facebook account.");
|
|
2613
|
+
return 0;
|
|
2614
|
+
} catch (error) {
|
|
2615
|
+
io.error(pairErrorMessage(error, runtime.endpoint.httpOrigin));
|
|
2616
|
+
return 1;
|
|
2617
|
+
}
|
|
2594
2618
|
}
|
|
2595
2619
|
async function commandLogin(runtime, options, io) {
|
|
2596
2620
|
const login = new FacebookLoginService({
|
|
@@ -2612,8 +2636,9 @@ async function commandLogin(runtime, options, io) {
|
|
|
2612
2636
|
}
|
|
2613
2637
|
let display = null;
|
|
2614
2638
|
try {
|
|
2615
|
-
|
|
2616
|
-
|
|
2639
|
+
const needsVirtualDisplay = process.platform === "linux" && !process.env.DISPLAY;
|
|
2640
|
+
if (!needsVirtualDisplay) {
|
|
2641
|
+
io.log(process.env.DISPLAY ? `Opening the Facebook login page on display ${process.env.DISPLAY}.` : "Opening the Facebook login page in a browser window.");
|
|
2617
2642
|
} else {
|
|
2618
2643
|
display = await startVirtualDisplay({
|
|
2619
2644
|
bind: options.bind,
|
|
@@ -2632,11 +2657,44 @@ ${display.url}`);
|
|
|
2632
2657
|
await waitForFacebookLogin(login, LOGIN_TIMEOUT_MS + 6e4);
|
|
2633
2658
|
io.log("Facebook session saved.");
|
|
2634
2659
|
return 0;
|
|
2660
|
+
} catch (error) {
|
|
2661
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2662
|
+
if (/Executable doesn't exist|playwright install/i.test(message)) {
|
|
2663
|
+
io.error(MISSING_BROWSER_HINT);
|
|
2664
|
+
return 1;
|
|
2665
|
+
}
|
|
2666
|
+
throw error;
|
|
2635
2667
|
} finally {
|
|
2636
2668
|
await login.close();
|
|
2637
2669
|
await display?.stop();
|
|
2638
2670
|
}
|
|
2639
2671
|
}
|
|
2672
|
+
function playwrightCliPath() {
|
|
2673
|
+
try {
|
|
2674
|
+
return fileURLToPath(new URL("cli.js", import.meta.resolve("playwright")));
|
|
2675
|
+
} catch {
|
|
2676
|
+
return null;
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
async function commandInstallBrowser(io) {
|
|
2680
|
+
const cli = playwrightCliPath();
|
|
2681
|
+
if (!cli) {
|
|
2682
|
+
io.error("Could not locate the bundled Playwright. Reinstall with `npm install -g diggylab@latest`.");
|
|
2683
|
+
return 1;
|
|
2684
|
+
}
|
|
2685
|
+
io.log("Downloading Chromium for Playwright...");
|
|
2686
|
+
const code = await new Promise((resolve, reject) => {
|
|
2687
|
+
const child = spawn2(process.execPath, [cli, "install", "chromium"], { stdio: "inherit" });
|
|
2688
|
+
child.once("error", reject);
|
|
2689
|
+
child.once("exit", (value) => resolve(value ?? 1));
|
|
2690
|
+
});
|
|
2691
|
+
if (code !== 0) {
|
|
2692
|
+
io.error("Chromium download failed. Check the network and try again.");
|
|
2693
|
+
return code;
|
|
2694
|
+
}
|
|
2695
|
+
io.log("Chromium installed.");
|
|
2696
|
+
return 0;
|
|
2697
|
+
}
|
|
2640
2698
|
async function commandRun(runtime, io) {
|
|
2641
2699
|
const stored = await runtime.manager.load();
|
|
2642
2700
|
if (!stored) {
|
|
@@ -2748,11 +2806,12 @@ async function main(argv, io = console) {
|
|
|
2748
2806
|
io.log(USAGE);
|
|
2749
2807
|
return 0;
|
|
2750
2808
|
}
|
|
2751
|
-
if (!["login", "pair", "run", "status", "unpair"].includes(command)) {
|
|
2809
|
+
if (!["install-browser", "login", "pair", "run", "status", "unpair"].includes(command)) {
|
|
2752
2810
|
io.error(`Unknown command "${command}".`);
|
|
2753
2811
|
io.error(USAGE);
|
|
2754
2812
|
return 2;
|
|
2755
2813
|
}
|
|
2814
|
+
if (command === "install-browser") return commandInstallBrowser(io);
|
|
2756
2815
|
const runtime = createRuntime(parsed.options);
|
|
2757
2816
|
switch (command) {
|
|
2758
2817
|
case "pair":
|