diggylab 0.1.48 → 0.1.49

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 +14 -1
  2. package/cli.js +127 -5
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -28,6 +28,19 @@ node apps/desktop-agent/dist-cli/cli/cli.js --help
28
28
 
29
29
  State lives in `~/.diggylab` (`--config <directory>` or `DIGGYLAB_AGENT_DIR` overrides it).
30
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
+
31
44
  ## Publishing the npm package
32
45
 
33
46
  ```bash
@@ -176,7 +189,7 @@ journalctl -u diggylab -f # follow the worker log
176
189
 
177
190
  The unit keeps the same state directory and API origin you are using, restarts the worker if it
178
191
  crashes, and starts it on boot. It points at npm's `diggylab` symlink, so upgrading the package is
179
- enough — no need to reinstall the service. Run it as root (or with `sudo`) to write the unit.
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.
180
193
 
181
194
  <details>
182
195
  <summary>Equivalent unit, if you prefer to write it yourself</summary>
package/cli.js CHANGED
@@ -3218,6 +3218,7 @@ Usage:
3218
3218
  diggylab install-service (systemd: start "run" on boot)
3219
3219
  diggylab uninstall-service
3220
3220
  diggylab status
3221
+ diggylab update (upgrades the installed npm package)
3221
3222
  diggylab install-browser
3222
3223
  diggylab unpair
3223
3224
 
@@ -3225,20 +3226,25 @@ Global options:
3225
3226
  --config <directory> Agent state directory (default ~/.diggylab)
3226
3227
  --api <origin> API origin (default $DIGGYLAB_API_URL or https://api.diggylab.com)`;
3227
3228
  var MISSING_BROWSER_HINT = "Chromium for Playwright is not installed yet. Run `diggylab install-browser` once.";
3228
- function agentVersion() {
3229
+ function readAgentManifest() {
3229
3230
  let directory = fileURLToPath(new URL(".", import.meta.url));
3230
3231
  for (let depth = 0; depth < 4; depth += 1) {
3231
3232
  const manifest = join4(directory, "package.json");
3232
3233
  if (existsSync2(manifest)) {
3233
3234
  try {
3234
- const version = JSON.parse(readFileSync2(manifest, "utf8")).version;
3235
- if (typeof version === "string" && version) return version;
3235
+ const parsed = JSON.parse(readFileSync2(manifest, "utf8"));
3236
+ if (typeof parsed.version === "string" && parsed.version) {
3237
+ return { name: typeof parsed.name === "string" ? parsed.name : "", version: parsed.version };
3238
+ }
3236
3239
  } catch {
3237
3240
  }
3238
3241
  }
3239
3242
  directory = dirname3(directory);
3240
3243
  }
3241
- return "0.0.0";
3244
+ return { name: "", version: "0.0.0" };
3245
+ }
3246
+ function agentVersion() {
3247
+ return readAgentManifest().version;
3242
3248
  }
3243
3249
  function resolvePlatform() {
3244
3250
  if (process.platform === "darwin") return "MACOS";
@@ -3591,6 +3597,7 @@ async function commandRun(runtime, io) {
3591
3597
  io.error("This agent is not paired yet. Run `diggylab pair --code <code>` first.");
3592
3598
  return 2;
3593
3599
  }
3600
+ startUpdateRefresh(runtime.directory, io);
3594
3601
  const recordActivity = (message, code, options = {}) => {
3595
3602
  void runtime.activity.append({
3596
3603
  category: options.category ?? "CONNECTION",
@@ -3748,6 +3755,119 @@ async function commandStatus(runtime, io) {
3748
3755
  io.log(`Facebook: ${hasUser ? "connected" : "missing \u2014 run `diggylab login`"}`);
3749
3756
  return 0;
3750
3757
  }
3758
+ function npmExecutable() {
3759
+ return process.platform === "win32" ? "npm.cmd" : "npm";
3760
+ }
3761
+ function runNpm(args, capture) {
3762
+ return new Promise((resolve, reject) => {
3763
+ const child = spawn(npmExecutable(), args, {
3764
+ shell: process.platform === "win32",
3765
+ stdio: capture ? ["ignore", "pipe", "pipe"] : "inherit"
3766
+ });
3767
+ let stderr = "";
3768
+ let stdout = "";
3769
+ child.stdout?.on("data", (chunk) => {
3770
+ stdout += String(chunk);
3771
+ });
3772
+ child.stderr?.on("data", (chunk) => {
3773
+ stderr += String(chunk);
3774
+ });
3775
+ child.once("error", reject);
3776
+ child.once("exit", (value) => resolve({ code: value ?? 1, stderr, stdout }));
3777
+ });
3778
+ }
3779
+ function compareVersions(current, latest) {
3780
+ const currentParts = current.split(".").map((part) => Number.parseInt(part, 10) || 0);
3781
+ const latestParts = latest.split(".").map((part) => Number.parseInt(part, 10) || 0);
3782
+ for (let index = 0; index < 3; index += 1) {
3783
+ const difference = (currentParts[index] ?? 0) - (latestParts[index] ?? 0);
3784
+ if (difference !== 0) return difference;
3785
+ }
3786
+ return 0;
3787
+ }
3788
+ async function commandUpdate(options, io) {
3789
+ const manifest = readAgentManifest();
3790
+ if (manifest.name !== "diggylab") {
3791
+ io.error("This is a development build; update the repository instead (git pull && pnpm install).");
3792
+ return 1;
3793
+ }
3794
+ const directory = resolveConfigDirectory(options);
3795
+ let latest = "";
3796
+ try {
3797
+ const check = await runNpm(["view", "diggylab", "version", "--json"], true);
3798
+ if (check.code !== 0) {
3799
+ io.error("Could not ask npm for the latest version. Check the network and the npm registry, then try again.");
3800
+ if (check.stderr.trim()) io.error(check.stderr.trim());
3801
+ return 1;
3802
+ }
3803
+ latest = check.stdout.trim().replace(/^"(.*)"$/, "$1");
3804
+ } catch (error) {
3805
+ io.error(`Could not run npm: ${error instanceof Error ? error.message : String(error)}`);
3806
+ return 1;
3807
+ }
3808
+ if (!/^\d+\.\d+\.\d+/.test(latest)) {
3809
+ io.error(`npm returned an unexpected version "${latest.slice(0, 40)}".`);
3810
+ return 1;
3811
+ }
3812
+ writeUpdateCache(directory, latest);
3813
+ if (compareVersions(manifest.version, latest) >= 0) {
3814
+ io.log(`Already on the latest version (${manifest.version}).`);
3815
+ return 0;
3816
+ }
3817
+ io.log(`Updating diggylab ${manifest.version} -> ${latest}...`);
3818
+ try {
3819
+ const install = await runNpm(["install", "-g", "diggylab@latest"], false);
3820
+ if (install.code !== 0) {
3821
+ io.error("The npm upgrade failed. If npm reported a permissions error, fix the global prefix or run the command with sudo.");
3822
+ return 1;
3823
+ }
3824
+ } catch (error) {
3825
+ io.error(`Could not run npm: ${error instanceof Error ? error.message : String(error)}`);
3826
+ return 1;
3827
+ }
3828
+ io.log(`Updated to ${latest}. Start a new diggylab command to use it; a service picks it up on its next restart.`);
3829
+ return 0;
3830
+ }
3831
+ var UPDATE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
3832
+ function readUpdateCache(directory) {
3833
+ try {
3834
+ const parsed = JSON.parse(readFileSync2(join4(directory, "update-check.json"), "utf8"));
3835
+ if (typeof parsed.latest === "string" && /^\d+\.\d+\.\d+/.test(parsed.latest) && typeof parsed.checkedAt === "number") {
3836
+ return { checkedAt: parsed.checkedAt, latest: parsed.latest };
3837
+ }
3838
+ } catch {
3839
+ }
3840
+ return void 0;
3841
+ }
3842
+ function writeUpdateCache(directory, latest) {
3843
+ try {
3844
+ writeFileSync2(join4(directory, "update-check.json"), `${JSON.stringify({ checkedAt: Date.now(), latest })}
3845
+ `);
3846
+ } catch {
3847
+ }
3848
+ }
3849
+ function logUpdateNotice(io, current, latest) {
3850
+ io.log(`A newer version is available: ${current} -> ${latest} (run \`diggylab update\`).`);
3851
+ }
3852
+ function logCachedUpdateNotice(directory, io) {
3853
+ const manifest = readAgentManifest();
3854
+ if (manifest.name !== "diggylab") return;
3855
+ const cache = readUpdateCache(directory);
3856
+ if (cache && compareVersions(manifest.version, cache.latest) < 0) logUpdateNotice(io, manifest.version, cache.latest);
3857
+ }
3858
+ function startUpdateRefresh(directory, io) {
3859
+ const manifest = readAgentManifest();
3860
+ if (manifest.name !== "diggylab") return;
3861
+ const cache = readUpdateCache(directory);
3862
+ if (cache && Date.now() - cache.checkedAt < UPDATE_CHECK_INTERVAL_MS) return;
3863
+ void runNpm(["view", "diggylab", "version", "--json"], true).then((check) => {
3864
+ if (check.code !== 0) return;
3865
+ const latest = check.stdout.trim().replace(/^"(.*)"$/, "$1");
3866
+ if (!/^\d+\.\d+\.\d+/.test(latest)) return;
3867
+ writeUpdateCache(directory, latest);
3868
+ if (compareVersions(manifest.version, latest) < 0) logUpdateNotice(io, manifest.version, latest);
3869
+ }).catch(() => void 0);
3870
+ }
3751
3871
  async function commandUnpair(runtime, io) {
3752
3872
  await runtime.manager.clear();
3753
3873
  await runtime.facebook.clear();
@@ -3836,12 +3956,14 @@ async function main(argv, io = console) {
3836
3956
  io.log(USAGE);
3837
3957
  return 0;
3838
3958
  }
3839
- if (!["install-browser", "install-service", "login", "logout", "pair", "rename", "run", "status", "uninstall-service", "unpair"].includes(command)) {
3959
+ if (!["install-browser", "install-service", "login", "logout", "pair", "rename", "run", "status", "uninstall-service", "unpair", "update"].includes(command)) {
3840
3960
  io.error(`Unknown command "${command}".`);
3841
3961
  io.error(USAGE);
3842
3962
  return 2;
3843
3963
  }
3844
3964
  if (command === "install-browser") return commandInstallBrowser(io);
3965
+ if (command === "update") return commandUpdate(parsed.options, io);
3966
+ logCachedUpdateNotice(resolveConfigDirectory(parsed.options), io);
3845
3967
  const runtime = createRuntime(parsed.options);
3846
3968
  switch (command) {
3847
3969
  case "pair":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "diggylab",
3
- "version": "0.1.48",
3
+ "version": "0.1.49",
4
4
  "description": "DiggyLab Desktop Agent collects posts and information from Facebook Groups on a paired computer. (headless CLI)",
5
5
  "type": "module",
6
6
  "bin": {