rechrome 1.22.0 → 1.23.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/package.json +1 -1
- package/rech.js +82 -22
- package/rech.ts +82 -22
package/package.json
CHANGED
package/rech.js
CHANGED
|
@@ -6,6 +6,7 @@ import { mkdirSync, appendFileSync, existsSync, realpathSync, accessSync, cpSync
|
|
|
6
6
|
import { hostname, homedir } from "os";
|
|
7
7
|
import { join, basename, dirname } from "path";
|
|
8
8
|
import { spawn as cpSpawn } from "child_process";
|
|
9
|
+
import { pickDaemonManager, type DaemonManager } from "./daemon-manager.js";
|
|
9
10
|
|
|
10
11
|
export const ENV_KEY = "RECHROME_URL";
|
|
11
12
|
export const DEFAULT_PORT = 13775;
|
|
@@ -658,28 +659,80 @@ const PM_PROCESS_NAME = "rechrome";
|
|
|
658
659
|
// Pre-rename names to evict on (re)install/uninstall so a single `rech setup`
|
|
659
660
|
// migrates an existing checkout cleanly.
|
|
660
661
|
const LEGACY_PROCESS_NAMES = ["rechrome-serve"];
|
|
661
|
-
// oxmgr everywhere, but it's unstable on Windows — fall back to pm2 there.
|
|
662
662
|
const IS_WINDOWS = process.platform === "win32";
|
|
663
|
-
const PM_BIN = IS_WINDOWS ? "pm2" : "oxmgr";
|
|
664
663
|
|
|
665
|
-
//
|
|
666
|
-
//
|
|
667
|
-
//
|
|
668
|
-
|
|
669
|
-
|
|
664
|
+
// Read the installed oxmgr's version (e.g. "0.4.0+winfix"), or null if oxmgr
|
|
665
|
+
// isn't on PATH / doesn't answer. Cached — daemonManager() sits on the hot path
|
|
666
|
+
// of several subcommands (status, setup, install). Synchronous by design so the
|
|
667
|
+
// selection has no await threading through call sites.
|
|
668
|
+
let _oxmgrVersion: string | null | undefined;
|
|
669
|
+
function oxmgrVersion(bin: string): string | null {
|
|
670
|
+
if (_oxmgrVersion !== undefined) return _oxmgrVersion;
|
|
671
|
+
try {
|
|
672
|
+
const p = Bun.spawnSync([bin, "--version"], { stdout: "pipe", stderr: "ignore", windowsHide: true });
|
|
673
|
+
const m = /(\d+\.\d+\.\d+[^\s]*)/.exec(p.stdout?.toString() ?? "");
|
|
674
|
+
_oxmgrVersion = m ? m[1]! : null;
|
|
675
|
+
} catch {
|
|
676
|
+
_oxmgrVersion = null;
|
|
677
|
+
}
|
|
678
|
+
return _oxmgrVersion;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// Resolve (and cache) the process manager that daemonizes `rech serve`. The
|
|
682
|
+
// selection policy — oxmgr default, pm2 fallback, winfix-guarded on Windows,
|
|
683
|
+
// RECH_DAEMON_MANAGER override — lives in ./daemon-manager.js (pure + tested);
|
|
684
|
+
// here we just supply the runtime inputs (what's on PATH, the oxmgr version).
|
|
685
|
+
let _daemonMgr: DaemonManager | undefined;
|
|
686
|
+
function daemonManager(): DaemonManager {
|
|
687
|
+
if (_daemonMgr) return _daemonMgr;
|
|
688
|
+
const oxmgrBin = Bun.which("oxmgr");
|
|
689
|
+
const pm2Bin = Bun.which("pm2");
|
|
690
|
+
_daemonMgr = pickDaemonManager({
|
|
691
|
+
oxmgrBin,
|
|
692
|
+
pm2Bin,
|
|
693
|
+
oxmgrVersion: oxmgrBin ? oxmgrVersion(oxmgrBin) : null,
|
|
694
|
+
isWindows: IS_WINDOWS,
|
|
695
|
+
override: process.env.RECH_DAEMON_MANAGER,
|
|
696
|
+
});
|
|
697
|
+
return _daemonMgr;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// Spawn the resolved process manager by its absolute path (Bun.which). `env` is
|
|
701
|
+
// merged over process.env for the child: pm2 captures the CLI's environment for
|
|
702
|
+
// the managed process (it has no per-var flag like oxmgr's --env), so install
|
|
703
|
+
// passes daemon env this way.
|
|
704
|
+
async function runPm(mgr: DaemonManager, args: string[], env?: Record<string, string>): Promise<number> {
|
|
705
|
+
const proc = Bun.spawn([mgr.bin, ...args], {
|
|
670
706
|
stdout: "inherit",
|
|
671
707
|
stderr: "inherit",
|
|
672
|
-
windowsHide: true, // no console-window flash for the
|
|
708
|
+
windowsHide: true, // no console-window flash for the manager child on Windows
|
|
673
709
|
...(env ? { env: { ...process.env, ...env } } : {}),
|
|
674
710
|
});
|
|
675
711
|
await proc.exited;
|
|
676
712
|
return proc.exitCode ?? 1;
|
|
677
713
|
}
|
|
678
714
|
|
|
715
|
+
// oxmgr boot/login autostart. `service install` wires the platform init
|
|
716
|
+
// integration (Windows Task Scheduler, macOS launchd, or a systemd --user unit)
|
|
717
|
+
// so the daemon — and the managed serve with it — returns at login/boot, the way
|
|
718
|
+
// the pm2 path relied on `pm2 resurrect`. Skipped when already installed:
|
|
719
|
+
// re-running `service install` re-bootstraps the oxmgr daemon, which restarts
|
|
720
|
+
// every managed process (including the live serve). Best-effort — a failure
|
|
721
|
+
// leaves serve crash-managed but not login-persistent.
|
|
722
|
+
async function oxmgrEnsureAutostart(mgr: DaemonManager): Promise<void> {
|
|
723
|
+
let alreadyInstalled = false;
|
|
724
|
+
try {
|
|
725
|
+
alreadyInstalled =
|
|
726
|
+
Bun.spawnSync([mgr.bin, "service", "status"], { stdout: "ignore", stderr: "ignore", windowsHide: true }).exitCode === 0;
|
|
727
|
+
} catch { /* treat a probe failure as not-installed and attempt install */ }
|
|
728
|
+
if (alreadyInstalled) return;
|
|
729
|
+
await runPm(mgr, ["service", "install"]);
|
|
730
|
+
}
|
|
731
|
+
|
|
679
732
|
// Capture the process-manager's process list as text (oxmgr `list` / pm2 `jlist`).
|
|
680
733
|
// Both render the process name verbatim, so callers can substring-match it.
|
|
681
|
-
async function pmList(): Promise<string> {
|
|
682
|
-
const proc = Bun.spawn([
|
|
734
|
+
async function pmList(mgr: DaemonManager = daemonManager()): Promise<string> {
|
|
735
|
+
const proc = Bun.spawn([mgr.bin, mgr.id === "pm2" ? "jlist" : "list"], { stdout: "pipe", stderr: "ignore", windowsHide: true });
|
|
683
736
|
return await new Response(proc.stdout).text();
|
|
684
737
|
}
|
|
685
738
|
|
|
@@ -741,25 +794,27 @@ export async function daemonInstall(serveUrl: string): Promise<void> {
|
|
|
741
794
|
if (isReadable(process.env.RECH_TLS_CERT)) daemonEnv.RECH_TLS_CERT = process.env.RECH_TLS_CERT!;
|
|
742
795
|
if (isReadable(process.env.RECH_TLS_KEY)) daemonEnv.RECH_TLS_KEY = process.env.RECH_TLS_KEY!;
|
|
743
796
|
|
|
797
|
+
const mgr = daemonManager();
|
|
798
|
+
|
|
744
799
|
// Drop any prior registration (current + legacy names) before re-adding.
|
|
745
|
-
for (const name of [PM_PROCESS_NAME, ...LEGACY_PROCESS_NAMES]) await runPm(["delete", name]);
|
|
800
|
+
for (const name of [PM_PROCESS_NAME, ...LEGACY_PROCESS_NAMES]) await runPm(mgr, ["delete", name]);
|
|
746
801
|
|
|
747
802
|
let startCode: number;
|
|
748
|
-
if (
|
|
803
|
+
if (mgr.id === "pm2") {
|
|
749
804
|
// pm2 captures the CLI env (passed via runPm's env) for the managed process,
|
|
750
805
|
// autorestarts by default, and runs the bun binary directly with
|
|
751
806
|
// `--interpreter none` (so it isn't fed to node).
|
|
752
|
-
startCode = await runPm([
|
|
807
|
+
startCode = await runPm(mgr, [
|
|
753
808
|
"start", bunBin,
|
|
754
809
|
"--name", PM_PROCESS_NAME,
|
|
755
810
|
"--interpreter", "none",
|
|
756
811
|
"--cwd", home,
|
|
757
812
|
"--", rechScript, "serve",
|
|
758
813
|
], daemonEnv);
|
|
759
|
-
await runPm(["save"]); // persist process list for `pm2 resurrect` on reboot
|
|
814
|
+
await runPm(mgr, ["save"]); // persist process list for `pm2 resurrect` on reboot
|
|
760
815
|
} else {
|
|
761
816
|
const envArgs = Object.entries(daemonEnv).flatMap(([k, v]) => ["--env", `${k}=${v}`]);
|
|
762
|
-
startCode = await runPm([
|
|
817
|
+
startCode = await runPm(mgr, [
|
|
763
818
|
"start",
|
|
764
819
|
"--name", PM_PROCESS_NAME,
|
|
765
820
|
"--restart", "always",
|
|
@@ -767,18 +822,23 @@ export async function daemonInstall(serveUrl: string): Promise<void> {
|
|
|
767
822
|
...envArgs,
|
|
768
823
|
`${bunBin} ${rechScript} serve`,
|
|
769
824
|
]);
|
|
770
|
-
|
|
825
|
+
// Boot/login persistence: on Windows the winfix oxmgr wires Task Scheduler,
|
|
826
|
+
// on POSIX a systemd --user unit / launchd agent — the equivalent of the pm2
|
|
827
|
+
// path's `pm2 resurrect` at login. Guarded so a re-install doesn't bounce the
|
|
828
|
+
// live daemon.
|
|
829
|
+
await oxmgrEnsureAutostart(mgr);
|
|
771
830
|
}
|
|
772
831
|
// Surface a failed start instead of reporting a daemon that was never registered.
|
|
773
832
|
if (startCode !== 0)
|
|
774
|
-
throw new Error(`${
|
|
833
|
+
throw new Error(`${mgr.id} failed to start "${PM_PROCESS_NAME}" (exit ${startCode}). Check that ${mgr.id} is installed and on PATH.`);
|
|
775
834
|
}
|
|
776
835
|
|
|
777
836
|
async function daemonUninstall(): Promise<void> {
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
837
|
+
const mgr = daemonManager();
|
|
838
|
+
for (const name of [PM_PROCESS_NAME, ...LEGACY_PROCESS_NAMES]) await runPm(mgr, ["delete", name]);
|
|
839
|
+
if (mgr.id === "pm2") await runPm(mgr, ["save"]);
|
|
840
|
+
else await runPm(mgr, ["service", "uninstall"]);
|
|
841
|
+
console.log(`Removed ${mgr.id} process: ${PM_PROCESS_NAME}`);
|
|
782
842
|
}
|
|
783
843
|
|
|
784
844
|
// ── Native tray (menu-bar / system-tray) icon ───────────────────────────────
|
|
@@ -1460,7 +1520,7 @@ async function status(): Promise<void> {
|
|
|
1460
1520
|
console.log(`relay: ⚠ degraded (${pingBody.consecutiveTimeouts} consecutive command timeouts) — if it persists, the daemon self-restarts; force it now with \`${PM_BIN} restart ${PM_PROCESS_NAME}\``);
|
|
1461
1521
|
const pmOut = await pmList();
|
|
1462
1522
|
const daemonRegistered = pmOut.includes(PM_PROCESS_NAME);
|
|
1463
|
-
console.log(`daemon: ${daemonRegistered ? `${
|
|
1523
|
+
console.log(`daemon: ${daemonRegistered ? `${daemonManager().id} (${PM_PROCESS_NAME})` : "not installed"}`);
|
|
1464
1524
|
const registry = await readTokenRegistry();
|
|
1465
1525
|
const entries = Object.entries(registry);
|
|
1466
1526
|
if (entries.length) {
|
package/rech.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { mkdirSync, appendFileSync, existsSync, realpathSync, accessSync, cpSync
|
|
|
6
6
|
import { hostname, homedir } from "os";
|
|
7
7
|
import { join, basename, dirname } from "path";
|
|
8
8
|
import { spawn as cpSpawn } from "child_process";
|
|
9
|
+
import { pickDaemonManager, type DaemonManager } from "./daemon-manager.ts";
|
|
9
10
|
|
|
10
11
|
export const ENV_KEY = "RECHROME_URL";
|
|
11
12
|
export const DEFAULT_PORT = 13775;
|
|
@@ -658,28 +659,80 @@ const PM_PROCESS_NAME = "rechrome";
|
|
|
658
659
|
// Pre-rename names to evict on (re)install/uninstall so a single `rech setup`
|
|
659
660
|
// migrates an existing checkout cleanly.
|
|
660
661
|
const LEGACY_PROCESS_NAMES = ["rechrome-serve"];
|
|
661
|
-
// oxmgr everywhere, but it's unstable on Windows — fall back to pm2 there.
|
|
662
662
|
const IS_WINDOWS = process.platform === "win32";
|
|
663
|
-
const PM_BIN = IS_WINDOWS ? "pm2" : "oxmgr";
|
|
664
663
|
|
|
665
|
-
//
|
|
666
|
-
//
|
|
667
|
-
//
|
|
668
|
-
|
|
669
|
-
|
|
664
|
+
// Read the installed oxmgr's version (e.g. "0.4.0+winfix"), or null if oxmgr
|
|
665
|
+
// isn't on PATH / doesn't answer. Cached — daemonManager() sits on the hot path
|
|
666
|
+
// of several subcommands (status, setup, install). Synchronous by design so the
|
|
667
|
+
// selection has no await threading through call sites.
|
|
668
|
+
let _oxmgrVersion: string | null | undefined;
|
|
669
|
+
function oxmgrVersion(bin: string): string | null {
|
|
670
|
+
if (_oxmgrVersion !== undefined) return _oxmgrVersion;
|
|
671
|
+
try {
|
|
672
|
+
const p = Bun.spawnSync([bin, "--version"], { stdout: "pipe", stderr: "ignore", windowsHide: true });
|
|
673
|
+
const m = /(\d+\.\d+\.\d+[^\s]*)/.exec(p.stdout?.toString() ?? "");
|
|
674
|
+
_oxmgrVersion = m ? m[1]! : null;
|
|
675
|
+
} catch {
|
|
676
|
+
_oxmgrVersion = null;
|
|
677
|
+
}
|
|
678
|
+
return _oxmgrVersion;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// Resolve (and cache) the process manager that daemonizes `rech serve`. The
|
|
682
|
+
// selection policy — oxmgr default, pm2 fallback, winfix-guarded on Windows,
|
|
683
|
+
// RECH_DAEMON_MANAGER override — lives in ./daemon-manager.ts (pure + tested);
|
|
684
|
+
// here we just supply the runtime inputs (what's on PATH, the oxmgr version).
|
|
685
|
+
let _daemonMgr: DaemonManager | undefined;
|
|
686
|
+
function daemonManager(): DaemonManager {
|
|
687
|
+
if (_daemonMgr) return _daemonMgr;
|
|
688
|
+
const oxmgrBin = Bun.which("oxmgr");
|
|
689
|
+
const pm2Bin = Bun.which("pm2");
|
|
690
|
+
_daemonMgr = pickDaemonManager({
|
|
691
|
+
oxmgrBin,
|
|
692
|
+
pm2Bin,
|
|
693
|
+
oxmgrVersion: oxmgrBin ? oxmgrVersion(oxmgrBin) : null,
|
|
694
|
+
isWindows: IS_WINDOWS,
|
|
695
|
+
override: process.env.RECH_DAEMON_MANAGER,
|
|
696
|
+
});
|
|
697
|
+
return _daemonMgr;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// Spawn the resolved process manager by its absolute path (Bun.which). `env` is
|
|
701
|
+
// merged over process.env for the child: pm2 captures the CLI's environment for
|
|
702
|
+
// the managed process (it has no per-var flag like oxmgr's --env), so install
|
|
703
|
+
// passes daemon env this way.
|
|
704
|
+
async function runPm(mgr: DaemonManager, args: string[], env?: Record<string, string>): Promise<number> {
|
|
705
|
+
const proc = Bun.spawn([mgr.bin, ...args], {
|
|
670
706
|
stdout: "inherit",
|
|
671
707
|
stderr: "inherit",
|
|
672
|
-
windowsHide: true, // no console-window flash for the
|
|
708
|
+
windowsHide: true, // no console-window flash for the manager child on Windows
|
|
673
709
|
...(env ? { env: { ...process.env, ...env } } : {}),
|
|
674
710
|
});
|
|
675
711
|
await proc.exited;
|
|
676
712
|
return proc.exitCode ?? 1;
|
|
677
713
|
}
|
|
678
714
|
|
|
715
|
+
// oxmgr boot/login autostart. `service install` wires the platform init
|
|
716
|
+
// integration (Windows Task Scheduler, macOS launchd, or a systemd --user unit)
|
|
717
|
+
// so the daemon — and the managed serve with it — returns at login/boot, the way
|
|
718
|
+
// the pm2 path relied on `pm2 resurrect`. Skipped when already installed:
|
|
719
|
+
// re-running `service install` re-bootstraps the oxmgr daemon, which restarts
|
|
720
|
+
// every managed process (including the live serve). Best-effort — a failure
|
|
721
|
+
// leaves serve crash-managed but not login-persistent.
|
|
722
|
+
async function oxmgrEnsureAutostart(mgr: DaemonManager): Promise<void> {
|
|
723
|
+
let alreadyInstalled = false;
|
|
724
|
+
try {
|
|
725
|
+
alreadyInstalled =
|
|
726
|
+
Bun.spawnSync([mgr.bin, "service", "status"], { stdout: "ignore", stderr: "ignore", windowsHide: true }).exitCode === 0;
|
|
727
|
+
} catch { /* treat a probe failure as not-installed and attempt install */ }
|
|
728
|
+
if (alreadyInstalled) return;
|
|
729
|
+
await runPm(mgr, ["service", "install"]);
|
|
730
|
+
}
|
|
731
|
+
|
|
679
732
|
// Capture the process-manager's process list as text (oxmgr `list` / pm2 `jlist`).
|
|
680
733
|
// Both render the process name verbatim, so callers can substring-match it.
|
|
681
|
-
async function pmList(): Promise<string> {
|
|
682
|
-
const proc = Bun.spawn([
|
|
734
|
+
async function pmList(mgr: DaemonManager = daemonManager()): Promise<string> {
|
|
735
|
+
const proc = Bun.spawn([mgr.bin, mgr.id === "pm2" ? "jlist" : "list"], { stdout: "pipe", stderr: "ignore", windowsHide: true });
|
|
683
736
|
return await new Response(proc.stdout).text();
|
|
684
737
|
}
|
|
685
738
|
|
|
@@ -741,25 +794,27 @@ export async function daemonInstall(serveUrl: string): Promise<void> {
|
|
|
741
794
|
if (isReadable(process.env.RECH_TLS_CERT)) daemonEnv.RECH_TLS_CERT = process.env.RECH_TLS_CERT!;
|
|
742
795
|
if (isReadable(process.env.RECH_TLS_KEY)) daemonEnv.RECH_TLS_KEY = process.env.RECH_TLS_KEY!;
|
|
743
796
|
|
|
797
|
+
const mgr = daemonManager();
|
|
798
|
+
|
|
744
799
|
// Drop any prior registration (current + legacy names) before re-adding.
|
|
745
|
-
for (const name of [PM_PROCESS_NAME, ...LEGACY_PROCESS_NAMES]) await runPm(["delete", name]);
|
|
800
|
+
for (const name of [PM_PROCESS_NAME, ...LEGACY_PROCESS_NAMES]) await runPm(mgr, ["delete", name]);
|
|
746
801
|
|
|
747
802
|
let startCode: number;
|
|
748
|
-
if (
|
|
803
|
+
if (mgr.id === "pm2") {
|
|
749
804
|
// pm2 captures the CLI env (passed via runPm's env) for the managed process,
|
|
750
805
|
// autorestarts by default, and runs the bun binary directly with
|
|
751
806
|
// `--interpreter none` (so it isn't fed to node).
|
|
752
|
-
startCode = await runPm([
|
|
807
|
+
startCode = await runPm(mgr, [
|
|
753
808
|
"start", bunBin,
|
|
754
809
|
"--name", PM_PROCESS_NAME,
|
|
755
810
|
"--interpreter", "none",
|
|
756
811
|
"--cwd", home,
|
|
757
812
|
"--", rechScript, "serve",
|
|
758
813
|
], daemonEnv);
|
|
759
|
-
await runPm(["save"]); // persist process list for `pm2 resurrect` on reboot
|
|
814
|
+
await runPm(mgr, ["save"]); // persist process list for `pm2 resurrect` on reboot
|
|
760
815
|
} else {
|
|
761
816
|
const envArgs = Object.entries(daemonEnv).flatMap(([k, v]) => ["--env", `${k}=${v}`]);
|
|
762
|
-
startCode = await runPm([
|
|
817
|
+
startCode = await runPm(mgr, [
|
|
763
818
|
"start",
|
|
764
819
|
"--name", PM_PROCESS_NAME,
|
|
765
820
|
"--restart", "always",
|
|
@@ -767,18 +822,23 @@ export async function daemonInstall(serveUrl: string): Promise<void> {
|
|
|
767
822
|
...envArgs,
|
|
768
823
|
`${bunBin} ${rechScript} serve`,
|
|
769
824
|
]);
|
|
770
|
-
|
|
825
|
+
// Boot/login persistence: on Windows the winfix oxmgr wires Task Scheduler,
|
|
826
|
+
// on POSIX a systemd --user unit / launchd agent — the equivalent of the pm2
|
|
827
|
+
// path's `pm2 resurrect` at login. Guarded so a re-install doesn't bounce the
|
|
828
|
+
// live daemon.
|
|
829
|
+
await oxmgrEnsureAutostart(mgr);
|
|
771
830
|
}
|
|
772
831
|
// Surface a failed start instead of reporting a daemon that was never registered.
|
|
773
832
|
if (startCode !== 0)
|
|
774
|
-
throw new Error(`${
|
|
833
|
+
throw new Error(`${mgr.id} failed to start "${PM_PROCESS_NAME}" (exit ${startCode}). Check that ${mgr.id} is installed and on PATH.`);
|
|
775
834
|
}
|
|
776
835
|
|
|
777
836
|
async function daemonUninstall(): Promise<void> {
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
837
|
+
const mgr = daemonManager();
|
|
838
|
+
for (const name of [PM_PROCESS_NAME, ...LEGACY_PROCESS_NAMES]) await runPm(mgr, ["delete", name]);
|
|
839
|
+
if (mgr.id === "pm2") await runPm(mgr, ["save"]);
|
|
840
|
+
else await runPm(mgr, ["service", "uninstall"]);
|
|
841
|
+
console.log(`Removed ${mgr.id} process: ${PM_PROCESS_NAME}`);
|
|
782
842
|
}
|
|
783
843
|
|
|
784
844
|
// ── Native tray (menu-bar / system-tray) icon ───────────────────────────────
|
|
@@ -1460,7 +1520,7 @@ async function status(): Promise<void> {
|
|
|
1460
1520
|
console.log(`relay: ⚠ degraded (${pingBody.consecutiveTimeouts} consecutive command timeouts) — if it persists, the daemon self-restarts; force it now with \`${PM_BIN} restart ${PM_PROCESS_NAME}\``);
|
|
1461
1521
|
const pmOut = await pmList();
|
|
1462
1522
|
const daemonRegistered = pmOut.includes(PM_PROCESS_NAME);
|
|
1463
|
-
console.log(`daemon: ${daemonRegistered ? `${
|
|
1523
|
+
console.log(`daemon: ${daemonRegistered ? `${daemonManager().id} (${PM_PROCESS_NAME})` : "not installed"}`);
|
|
1464
1524
|
const registry = await readTokenRegistry();
|
|
1465
1525
|
const entries = Object.entries(registry);
|
|
1466
1526
|
if (entries.length) {
|