diggylab 0.1.50 → 0.1.52

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 (3) hide show
  1. package/README.md +228 -225
  2. package/cli.js +921 -134
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,225 +1,228 @@
1
- # Desktop Agent CLI
2
-
3
- The Desktop Agent also runs headless as a CLI worker, for customers who scan from a Linux server
4
- instead of the desktop app. It pairs like any device, receives `DESKTOP` scan jobs, and scans with
5
- headless Chromium — the Electron app is not involved.
6
-
7
- ## Requirements
8
-
9
- - Node.js 20+
10
- - Chromium for Playwright: downloaded automatically during `npm install`; rerun `diggylab install-browser` if that download failed.
11
-
12
- ## Install
13
-
14
- From npm (customers):
15
-
16
- ```bash
17
- npm install -g diggylab
18
- diggylab --help
19
- ```
20
-
21
- From the repository (development):
22
-
23
- ```bash
24
- pnpm install
25
- pnpm --filter jobfinding-desktop-agent cli:build
26
- node apps/desktop-agent/dist-cli/cli/cli.js --help
27
- ```
28
-
29
- State lives in `~/.diggylab` (`--config <directory>` or `DIGGYLAB_AGENT_DIR` overrides it).
30
-
31
- ## Update
32
-
33
- ```bash
34
- diggylab update
35
- ```
36
-
37
- It asks npm for the newest release and upgrades the global install in place; when you are already
38
- current it says so and changes nothing. `diggylab run` checks once a day in the background and
39
- prints `A newer version is available: ...` when there is one, and every other command repeats the
40
- last known notice for free — so an old worker does not go unnoticed. A systemd service needs no
41
- reinstall — the unit points at npm's symlink, so restart it to switch versions (`systemctl restart
42
- diggylab`).
43
-
44
- ## Publishing the npm package
45
-
46
- ```bash
47
- pnpm --filter jobfinding-desktop-agent cli:pack
48
- npm publish apps/desktop-agent/dist-npm --access public
49
- ```
50
-
51
- `cli:pack` bundles the workspace code into a single `cli.js`, so the published package only depends
52
- on `playwright` and `ws`. The packed manifest copies the version from
53
- `apps/desktop-agent/package.json`; use the override below when the app release has not caught up yet.
54
-
55
- ### Publishing ahead of an app release
56
-
57
- To ship a CLI fix before the next app release — without running the Version Release workflow — pack a
58
- specific version. The repo version stays where the release workflow expects it, and that workflow
59
- later lands on the same number:
60
-
61
- ```bash
62
- pnpm --filter jobfinding-desktop-agent cli:pack -- --version 0.1.31
63
- npm publish apps/desktop-agent/dist-npm --access public
64
- ```
65
-
66
- `CLI_PACKAGE_VERSION=0.1.31` works as well.
67
-
68
- ## Local development
69
-
70
- Run the CLI from source against the local API without touching a real installation:
71
-
72
- ```bash
73
- pnpm dev:cli # prints status against http://localhost:4000 and ~/.diggylab-dev
74
- pnpm dev:cli pair # forwards any command to the CLI
75
- pnpm dev:cli --build run # rebuilds dist-cli first, then runs the worker
76
- ```
77
-
78
- The wrapper points `DIGGYLAB_API_URL` at `http://localhost:4000` and `DIGGYLAB_AGENT_DIR` at
79
- `~/.diggylab-dev`; set either variable to override the defaults.
80
-
81
- ## Commands
82
-
83
- | Command | What it does |
84
- | --- | --- |
85
- | `pair [--code <code>] [--name <device name>]` | Pairs the server as a device. Create the code on `/settings/desktop-agent` in the web app; leave `--code` out and the command asks for it. |
86
- | `login` | Opens Facebook's real login page in a browser window when the machine has a screen. On a server without one it asks for `facebook.com` cookies pasted from your own browser, and the session is stored encrypted. |
87
- | `logout` | Removes the stored Facebook session from this server (the device pairing stays). |
88
- | `rename [--name <new name>]` | Renames the device shown in the web app; leave `--name` out and the command asks for it. |
89
- | `run` | Connects the WebSocket worker, receives assigned scans, scans headlessly, uploads results. |
90
- | `status` | Shows the config directory, API origin, paired device, and Facebook session state. |
91
- | `install-browser` | Downloads the Chromium build Playwright needs (~150 MB). It also runs during `npm install`, so you only need it if that download failed. |
92
- | `install-service` | On a Linux server with systemd, writes the unit for `run`, enables it, and starts it now and on every boot. |
93
- | `uninstall-service` | Stops that service and removes the unit. |
94
- | `unpair` | Removes device credentials, the Facebook session, and pending scans. |
95
-
96
- Useful options: `--api <origin>` (default `https://api.diggylab.com`), `--cookies <file>` to import
97
- cookies directly.
98
-
99
- `pair` and `login` finish by printing what is still missing, so you do not need to run `status`
100
- between steps:
101
-
102
- ```
103
- Paired: "DiggyLab" (device-1)
104
- Facebook: missing
105
- Next: run `diggylab login` — on a server without a screen it asks you to paste cookies.
106
- ```
107
-
108
- ## How `login` works
109
-
110
- Two paths, depending on the machine:
111
-
112
- | Machine | What `login` does |
113
- | --- | --- |
114
- | Desktop, or Linux with a display (`$DISPLAY` set) | Opens Chromium on that display with Facebook's real login page; you log in normally. |
115
- | Server without a screen | Prints a short prompt and asks you to paste `facebook.com` cookies exported from your own browser. |
116
-
117
- Both paths save the session encrypted with `~/.diggylab/key`, and `diggylab run` then uses it for scans.
118
-
119
- ### Logging in with cookies from your own browser
120
-
121
- On a machine without a screen this is the only path, and you can also pick it on a desktop with
122
- `diggylab login cookies`:
123
-
124
- 1. Get the `facebook.com` cookies, in whichever way is easiest:
125
- - **DevTools → Network** (fastest): open facebook.com, click any request, copy the whole
126
- `cookie:` value from *Request Headers*.
127
- - **DevTools → Application → Cookies → `https://www.facebook.com`**: select the table and copy the
128
- rows.
129
- - **Cookie-Editor** (Chrome, Edge, Firefox): *Export → JSON*.
130
- 2. On the server, run the friendly form and paste when asked (Enter finishes the paste):
131
-
132
- ```bash
133
- diggylab login cookies
134
- ```
135
-
136
- The equivalents: `diggylab login --cookies 'name=value; ...'` for a quoted one-liner, or
137
- `diggylab login --cookies cookies.json` for a saved file.
138
-
139
- Only `name` and `value` are required; the agent fills in the rest (`.facebook.com`, `/`, session
140
- expiry). Every `facebook.com` cookie is kept. The export must contain `c_user` (the agent rejects it
141
- otherwise) and `xs`, which carries the session — without `xs` Facebook refuses the session during the
142
- check, and `datr` is worth keeping too.
143
-
144
- If you paste cookies, prefer the file form or `--cookies -` over `--cookies '...'`: a value on the
145
- command line stays in your shell history, and pasted text stays in the terminal scrollback.
146
-
147
- Do not use `document.cookie` from the Console: Facebook's `c_user` and `xs` are HttpOnly, so they
148
- never appear there. The DevTools cookie table and the extension do show them.
149
-
150
- The agent saves the cookies encrypted and opens Facebook once to confirm the session before it
151
- accepts it. Cookies exported from a different account, or expired ones, are rejected with a message
152
- instead of failing during a scan.
153
-
154
- Note: Facebook sometimes asks for a security check when a session moves to a server's IP. If that
155
- happens the command says so — approve the login from your phone and import again.
156
-
157
- ## Troubleshooting
158
-
159
- - `socket closed: 1005` followed by `session: ONLINE` about every 14 minutes is **normal**: the access
160
- token lives 15 minutes, so the worker refreshes it one minute early and reconnects with the new one
161
- (the disconnect lasts a second or two, and a running scan keeps going).
162
- - `socket closed: 4009` right after `session: ONLINE` means **two workers use the same device** — for
163
- example the systemd service plus a manual `diggylab run`. The worker that connected last keeps the
164
- device and the older one stops with a message. Check `pgrep -af "diggylab run"` and
165
- `systemctl status diggylab --no-pager`, then keep only one.
166
- - `socket error:` plus `socket closed: 1006` and `RECONNECTING (NETWORK_ERROR)` is a dropped
167
- connection; the worker retries with backoff. If it never settles, check `curl -sS -o /dev/null -w
168
- '%{http_code}\n' https://api.diggylab.com/health` and that the machine clock is right (`date -u`),
169
- because a clock off by more than five minutes makes the server's messages look stale.
170
- - `Facebook: missing` after a login means the session did not survive; run `diggylab login` again.
171
-
172
- ## Security notes
173
-
174
- - `~/.diggylab/key` (mode `600`) encrypts device credentials, the Facebook session, and the
175
- scan spool. Treat it like a password: back it up privately, never share it.
176
- - The Facebook session belongs to the customer's account; run `login` again when `status` reports
177
- it missing (sessions expire, and a sudden IP change can trigger a Facebook checkpoint).
178
- - Unmatched or expired payments are unrelated to this worker — the agent only scans.
179
-
180
- ## Run as a service
181
-
182
- On a Linux server with systemd, let the CLI write the unit for you:
183
-
184
- ```bash
185
- diggylab install-service # writes /etc/systemd/system/diggylab.service, enables + starts it
186
- diggylab uninstall-service # stops it and removes the unit
187
- journalctl -u diggylab -f # follow the worker log
188
- ```
189
-
190
- The unit keeps the same state directory and API origin you are using, restarts the worker if it
191
- crashes, and starts it on boot. It points at npm's `diggylab` symlink, so upgrading the package is
192
- enough — no need to reinstall the service (`diggylab update`, then `systemctl restart diggylab`). Run it as root (or with `sudo`) to write the unit.
193
-
194
- <details>
195
- <summary>Equivalent unit, if you prefer to write it yourself</summary>
196
-
197
- ```ini
198
- [Unit]
199
- Description=DiggyLab Desktop Agent
200
- After=network-online.target
201
- Wants=network-online.target
202
-
203
- [Service]
204
- ExecStart=/usr/local/bin/diggylab run
205
- Environment="DIGGYLAB_AGENT_DIR=/root/.diggylab"
206
- Environment="DIGGYLAB_API_URL=https://api.diggylab.com"
207
- Restart=on-failure
208
- RestartSec=10
209
-
210
- [Install]
211
- WantedBy=multi-user.target
212
- ```
213
-
214
- </details>
215
-
216
- ## Docker
217
-
218
- ```bash
219
- docker build -f apps/desktop-agent/Dockerfile.cli -t diggylab .
220
- docker run -it --rm -v diggylab:/data diggylab pair --code ABC123
221
- docker run -it --rm -v diggylab:/data diggylab login cookies
222
- docker run -d --restart unless-stopped -v diggylab:/data diggylab run
223
- ```
224
-
225
- The image sets `DIGGYLAB_AGENT_DIR=/data`, so the volume keeps the key, credentials, and spool.
1
+ # Desktop Agent CLI
2
+
3
+ The Desktop Agent also runs headless as a CLI worker, for customers who scan from a Linux server
4
+ instead of the desktop app. It pairs like any device, receives `DESKTOP` scan jobs, and scans with
5
+ headless Chromium — the Electron app is not involved.
6
+
7
+ For the platform-run scan worker (admin-managed Proxmox/Linux nodes with one Facebook account and an
8
+ optional proxy), see [worker-agent.md](worker-agent.md).
9
+
10
+ ## Requirements
11
+
12
+ - Node.js 20+
13
+ - Chromium for Playwright: downloaded automatically during `npm install`; rerun `diggylab install-browser` if that download failed.
14
+
15
+ ## Install
16
+
17
+ From npm (customers):
18
+
19
+ ```bash
20
+ npm install -g diggylab
21
+ diggylab --help
22
+ ```
23
+
24
+ From the repository (development):
25
+
26
+ ```bash
27
+ pnpm install
28
+ pnpm --filter jobfinding-desktop-agent cli:build
29
+ node apps/desktop-agent/dist-cli/cli/cli.js --help
30
+ ```
31
+
32
+ State lives in `~/.diggylab` (`--config <directory>` or `DIGGYLAB_AGENT_DIR` overrides it).
33
+
34
+ ## Update
35
+
36
+ ```bash
37
+ diggylab update
38
+ ```
39
+
40
+ It asks npm for the newest release and upgrades the global install in place; when you are already
41
+ current it says so and changes nothing. `diggylab run` checks once a day in the background and
42
+ prints `A newer version is available: ...` when there is one, and every other command repeats the
43
+ last known notice for free — so an old worker does not go unnoticed. A systemd service needs no
44
+ reinstall — the unit points at npm's symlink, so restart it to switch versions (`systemctl restart
45
+ diggylab`).
46
+
47
+ ## Publishing the npm package
48
+
49
+ ```bash
50
+ pnpm --filter jobfinding-desktop-agent cli:pack
51
+ npm publish apps/desktop-agent/dist-npm --access public
52
+ ```
53
+
54
+ `cli:pack` bundles the workspace code into a single `cli.js`, so the published package only depends
55
+ on `playwright` and `ws`. The packed manifest copies the version from
56
+ `apps/desktop-agent/package.json`; use the override below when the app release has not caught up yet.
57
+
58
+ ### Publishing ahead of an app release
59
+
60
+ To ship a CLI fix before the next app release — without running the Version Release workflow — pack a
61
+ specific version. The repo version stays where the release workflow expects it, and that workflow
62
+ later lands on the same number:
63
+
64
+ ```bash
65
+ pnpm --filter jobfinding-desktop-agent cli:pack -- --version 0.1.31
66
+ npm publish apps/desktop-agent/dist-npm --access public
67
+ ```
68
+
69
+ `CLI_PACKAGE_VERSION=0.1.31` works as well.
70
+
71
+ ## Local development
72
+
73
+ Run the CLI from source against the local API without touching a real installation:
74
+
75
+ ```bash
76
+ pnpm dev:cli # prints status against http://localhost:4000 and ~/.diggylab-dev
77
+ pnpm dev:cli pair # forwards any command to the CLI
78
+ pnpm dev:cli --build run # rebuilds dist-cli first, then runs the worker
79
+ ```
80
+
81
+ The wrapper points `DIGGYLAB_API_URL` at `http://localhost:4000` and `DIGGYLAB_AGENT_DIR` at
82
+ `~/.diggylab-dev`; set either variable to override the defaults.
83
+
84
+ ## Commands
85
+
86
+ | Command | What it does |
87
+ | --- | --- |
88
+ | `pair [--code <code>] [--name <device name>]` | Pairs the server as a device. Create the code on `/settings/desktop-agent` in the web app; leave `--code` out and the command asks for it. |
89
+ | `login` | Opens Facebook's real login page in a browser window when the machine has a screen. On a server without one it asks for `facebook.com` cookies pasted from your own browser, and the session is stored encrypted. |
90
+ | `logout` | Removes the stored Facebook session from this server (the device pairing stays). |
91
+ | `rename [--name <new name>]` | Renames the device shown in the web app; leave `--name` out and the command asks for it. |
92
+ | `run` | Connects the WebSocket worker, receives assigned scans, scans headlessly, uploads results. |
93
+ | `status` | Shows the config directory, API origin, paired device, and Facebook session state. |
94
+ | `install-browser` | Downloads the Chromium build Playwright needs (~150 MB). It also runs during `npm install`, so you only need it if that download failed. |
95
+ | `install-service` | On a Linux server with systemd, writes the unit for `run`, enables it, and starts it now and on every boot. |
96
+ | `uninstall-service` | Stops that service and removes the unit. |
97
+ | `unpair` | Removes device credentials, the Facebook session, and pending scans. |
98
+
99
+ Useful options: `--api <origin>` (default `https://api.diggylab.com`), `--cookies <file>` to import
100
+ cookies directly.
101
+
102
+ `pair` and `login` finish by printing what is still missing, so you do not need to run `status`
103
+ between steps:
104
+
105
+ ```
106
+ Paired: "DiggyLab" (device-1)
107
+ Facebook: missing
108
+ Next: run `diggylab login` — on a server without a screen it asks you to paste cookies.
109
+ ```
110
+
111
+ ## How `login` works
112
+
113
+ Two paths, depending on the machine:
114
+
115
+ | Machine | What `login` does |
116
+ | --- | --- |
117
+ | Desktop, or Linux with a display (`$DISPLAY` set) | Opens Chromium on that display with Facebook's real login page; you log in normally. |
118
+ | Server without a screen | Prints a short prompt and asks you to paste `facebook.com` cookies exported from your own browser. |
119
+
120
+ Both paths save the session encrypted with `~/.diggylab/key`, and `diggylab run` then uses it for scans.
121
+
122
+ ### Logging in with cookies from your own browser
123
+
124
+ On a machine without a screen this is the only path, and you can also pick it on a desktop with
125
+ `diggylab login cookies`:
126
+
127
+ 1. Get the `facebook.com` cookies, in whichever way is easiest:
128
+ - **DevTools → Network** (fastest): open facebook.com, click any request, copy the whole
129
+ `cookie:` value from *Request Headers*.
130
+ - **DevTools → Application → Cookies → `https://www.facebook.com`**: select the table and copy the
131
+ rows.
132
+ - **Cookie-Editor** (Chrome, Edge, Firefox): *Export → JSON*.
133
+ 2. On the server, run the friendly form and paste when asked (Enter finishes the paste):
134
+
135
+ ```bash
136
+ diggylab login cookies
137
+ ```
138
+
139
+ The equivalents: `diggylab login --cookies 'name=value; ...'` for a quoted one-liner, or
140
+ `diggylab login --cookies cookies.json` for a saved file.
141
+
142
+ Only `name` and `value` are required; the agent fills in the rest (`.facebook.com`, `/`, session
143
+ expiry). Every `facebook.com` cookie is kept. The export must contain `c_user` (the agent rejects it
144
+ otherwise) and `xs`, which carries the session — without `xs` Facebook refuses the session during the
145
+ check, and `datr` is worth keeping too.
146
+
147
+ If you paste cookies, prefer the file form or `--cookies -` over `--cookies '...'`: a value on the
148
+ command line stays in your shell history, and pasted text stays in the terminal scrollback.
149
+
150
+ Do not use `document.cookie` from the Console: Facebook's `c_user` and `xs` are HttpOnly, so they
151
+ never appear there. The DevTools cookie table and the extension do show them.
152
+
153
+ The agent saves the cookies encrypted and opens Facebook once to confirm the session before it
154
+ accepts it. Cookies exported from a different account, or expired ones, are rejected with a message
155
+ instead of failing during a scan.
156
+
157
+ Note: Facebook sometimes asks for a security check when a session moves to a server's IP. If that
158
+ happens the command says so — approve the login from your phone and import again.
159
+
160
+ ## Troubleshooting
161
+
162
+ - `socket closed: 1005` followed by `session: ONLINE` about every 14 minutes is **normal**: the access
163
+ token lives 15 minutes, so the worker refreshes it one minute early and reconnects with the new one
164
+ (the disconnect lasts a second or two, and a running scan keeps going).
165
+ - `socket closed: 4009` right after `session: ONLINE` means **two workers use the same device** — for
166
+ example the systemd service plus a manual `diggylab run`. The worker that connected last keeps the
167
+ device and the older one stops with a message. Check `pgrep -af "diggylab run"` and
168
+ `systemctl status diggylab --no-pager`, then keep only one.
169
+ - `socket error:` plus `socket closed: 1006` and `RECONNECTING (NETWORK_ERROR)` is a dropped
170
+ connection; the worker retries with backoff. If it never settles, check `curl -sS -o /dev/null -w
171
+ '%{http_code}\n' https://api.diggylab.com/health` and that the machine clock is right (`date -u`),
172
+ because a clock off by more than five minutes makes the server's messages look stale.
173
+ - `Facebook: missing` after a login means the session did not survive; run `diggylab login` again.
174
+
175
+ ## Security notes
176
+
177
+ - `~/.diggylab/key` (mode `600`) encrypts device credentials, the Facebook session, and the
178
+ scan spool. Treat it like a password: back it up privately, never share it.
179
+ - The Facebook session belongs to the customer's account; run `login` again when `status` reports
180
+ it missing (sessions expire, and a sudden IP change can trigger a Facebook checkpoint).
181
+ - Unmatched or expired payments are unrelated to this worker — the agent only scans.
182
+
183
+ ## Run as a service
184
+
185
+ On a Linux server with systemd, let the CLI write the unit for you:
186
+
187
+ ```bash
188
+ diggylab install-service # writes /etc/systemd/system/diggylab.service, enables + starts it
189
+ diggylab uninstall-service # stops it and removes the unit
190
+ journalctl -u diggylab -f # follow the worker log
191
+ ```
192
+
193
+ The unit keeps the same state directory and API origin you are using, restarts the worker if it
194
+ crashes, and starts it on boot. It points at npm's `diggylab` symlink, so upgrading the package is
195
+ enough — no need to reinstall the service (`diggylab update`, then `systemctl restart diggylab`). Run it as root (or with `sudo`) to write the unit.
196
+
197
+ <details>
198
+ <summary>Equivalent unit, if you prefer to write it yourself</summary>
199
+
200
+ ```ini
201
+ [Unit]
202
+ Description=DiggyLab Desktop Agent
203
+ After=network-online.target
204
+ Wants=network-online.target
205
+
206
+ [Service]
207
+ ExecStart=/usr/local/bin/diggylab run
208
+ Environment="DIGGYLAB_AGENT_DIR=/root/.diggylab"
209
+ Environment="DIGGYLAB_API_URL=https://api.diggylab.com"
210
+ Restart=on-failure
211
+ RestartSec=10
212
+
213
+ [Install]
214
+ WantedBy=multi-user.target
215
+ ```
216
+
217
+ </details>
218
+
219
+ ## Docker
220
+
221
+ ```bash
222
+ docker build -f apps/desktop-agent/Dockerfile.cli -t diggylab .
223
+ docker run -it --rm -v diggylab:/data diggylab pair --code ABC123
224
+ docker run -it --rm -v diggylab:/data diggylab login cookies
225
+ docker run -d --restart unless-stopped -v diggylab:/data diggylab run
226
+ ```
227
+
228
+ The image sets `DIGGYLAB_AGENT_DIR=/data`, so the volume keeps the key, credentials, and spool.