rechrome 1.16.1 → 1.17.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 -41
- package/rech.ts +82 -41
- package/serve.js +5 -3
- package/serve.ts +5 -3
package/package.json
CHANGED
package/rech.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { file } from "bun";
|
|
4
4
|
import { randomBytes } from "crypto";
|
|
5
5
|
import { mkdirSync, appendFileSync, existsSync, realpathSync, accessSync, cpSync, constants as fsConstants } from "fs";
|
|
6
|
-
import { hostname } from "os";
|
|
6
|
+
import { hostname, homedir } from "os";
|
|
7
7
|
import { join, basename, dirname } from "path";
|
|
8
8
|
|
|
9
9
|
export const ENV_KEY = "RECHROME_URL";
|
|
@@ -11,7 +11,10 @@ export const DEFAULT_PORT = 13775;
|
|
|
11
11
|
export const RECH_DIR = join(import.meta.dir, ".rech");
|
|
12
12
|
export const LOG_DIR = join(RECH_DIR, "logs");
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
// Home dir: HOME on POSIX, USERPROFILE on Windows (handled by os.homedir()).
|
|
15
|
+
export const HOME = homedir();
|
|
16
|
+
|
|
17
|
+
const RECH_HOME_DIR = join(HOME, ".rechrome");
|
|
15
18
|
const TOKENS_FILE = join(RECH_HOME_DIR, "profiles.json");
|
|
16
19
|
|
|
17
20
|
type TokenEntry = { extensionId: string; token: string; profileDir: string; userDataDir?: string };
|
|
@@ -29,7 +32,7 @@ async function saveTokenEntry(profileEmail: string, entry: TokenEntry): Promise<
|
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
const envFile = join(import.meta.dir, ".env.local");
|
|
32
|
-
const globalEnvFile = join(
|
|
35
|
+
const globalEnvFile = join(HOME || "~", ".env.local");
|
|
33
36
|
|
|
34
37
|
// Walk CWD→root loading env files nearest-first; per-key: closest file wins, farther files skip.
|
|
35
38
|
// At each level .rechrome/.env.local is checked before .env.local (rechrome-specific overrides general).
|
|
@@ -214,7 +217,7 @@ async function getClientEnv(urlExtras?: { extensionId?: string; extensionToken?:
|
|
|
214
217
|
}
|
|
215
218
|
|
|
216
219
|
const CHROME_LOCAL_STATE_PATHS = () => {
|
|
217
|
-
const home =
|
|
220
|
+
const home = HOME || "~";
|
|
218
221
|
return [
|
|
219
222
|
join(home, "Library/Application Support/Google/Chrome/Local State"),
|
|
220
223
|
join(home, ".config/google-chrome/Local State"),
|
|
@@ -250,7 +253,7 @@ const LEGACY_EXTENSION_DIST_DIR = join(import.meta.dir, "lib/playwright-multi-ta
|
|
|
250
253
|
|
|
251
254
|
// Stable per-user location: we copy the bundled dist here so Chrome's recorded install path survives
|
|
252
255
|
// the ephemeral bunx temp dir being cleaned up between invocations.
|
|
253
|
-
export const EXTENSION_DIST_DIR = join(
|
|
256
|
+
export const EXTENSION_DIST_DIR = join(HOME, ".rechrome", "extension");
|
|
254
257
|
|
|
255
258
|
// With the manifest `key` field set, Chrome derives this ID deterministically from the key (not the path),
|
|
256
259
|
// so we can locate the extension by ID even when the on-disk path differs from what Chrome stored.
|
|
@@ -516,15 +519,35 @@ function buildSetupHtml(extDistDir: string, profileDisplay: string): string {
|
|
|
516
519
|
</html>`;
|
|
517
520
|
}
|
|
518
521
|
|
|
519
|
-
const
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
522
|
+
const PM_PROCESS_NAME = "rechrome";
|
|
523
|
+
// Pre-rename names to evict on (re)install/uninstall so a single `rech setup`
|
|
524
|
+
// migrates an existing checkout cleanly.
|
|
525
|
+
const LEGACY_PROCESS_NAMES = ["rechrome-serve"];
|
|
526
|
+
// oxmgr everywhere, but it's unstable on Windows — fall back to pm2 there.
|
|
527
|
+
const IS_WINDOWS = process.platform === "win32";
|
|
528
|
+
const PM_BIN = IS_WINDOWS ? "pm2" : "oxmgr";
|
|
529
|
+
|
|
530
|
+
// Spawn the active process manager. `env` is merged over process.env for the
|
|
531
|
+
// child: pm2 captures the CLI's environment for the managed process (it has no
|
|
532
|
+
// per-var flag like oxmgr's --env), so install passes daemon env this way.
|
|
533
|
+
async function runPm(args: string[], env?: Record<string, string>): Promise<number> {
|
|
534
|
+
const proc = Bun.spawn(["bunx", PM_BIN, ...args], {
|
|
535
|
+
stdout: "inherit",
|
|
536
|
+
stderr: "inherit",
|
|
537
|
+
...(env ? { env: { ...process.env, ...env } } : {}),
|
|
538
|
+
});
|
|
523
539
|
await proc.exited;
|
|
524
540
|
return proc.exitCode ?? 1;
|
|
525
541
|
}
|
|
526
542
|
|
|
527
|
-
|
|
543
|
+
// Capture the process-manager's process list as text (oxmgr `list` / pm2 `jlist`).
|
|
544
|
+
// Both render the process name verbatim, so callers can substring-match it.
|
|
545
|
+
async function pmList(): Promise<string> {
|
|
546
|
+
const proc = Bun.spawn(["bunx", PM_BIN, IS_WINDOWS ? "jlist" : "list"], { stdout: "pipe", stderr: "ignore" });
|
|
547
|
+
return await new Response(proc.stdout).text();
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
export async function daemonInstall(serveUrl: string): Promise<void> {
|
|
528
551
|
// Persist the URL to ~/.env.local before starting the daemon. The daemon's
|
|
529
552
|
// loadEnv() walks CWD→root reading .env.local files and unconditionally
|
|
530
553
|
// overwrites process.env.RECHROME_URL from whichever file it finds first.
|
|
@@ -536,7 +559,7 @@ async function daemonInstall(serveUrl: string): Promise<void> {
|
|
|
536
559
|
const filtered = envRaw.trimEnd().split("\n").filter(l => !l.startsWith(`${ENV_KEY}=`));
|
|
537
560
|
await Bun.write(globalEnvFile, [...filtered, `${ENV_KEY}=${serveUrl}`, ""].join("\n"));
|
|
538
561
|
|
|
539
|
-
const home =
|
|
562
|
+
const home = HOME;
|
|
540
563
|
const bunBin = Bun.which("bun") ?? process.execPath;
|
|
541
564
|
const rechScript = import.meta.filename;
|
|
542
565
|
|
|
@@ -545,33 +568,52 @@ async function daemonInstall(serveUrl: string): Promise<void> {
|
|
|
545
568
|
const resolvedPlaywrightCli = process.env.PLAYWRIGHT_CLI
|
|
546
569
|
|| (existsSync(bundledForkCli) ? bundledForkCli : "playwright-cli-multi-tab");
|
|
547
570
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
if (
|
|
557
|
-
if (isReadable(process.env.
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
571
|
+
// Environment the managed `serve` process must run with.
|
|
572
|
+
const daemonEnv: Record<string, string> = {
|
|
573
|
+
HOME: home,
|
|
574
|
+
PATH: process.env.PATH || "/usr/local/bin:/usr/bin:/bin",
|
|
575
|
+
[ENV_KEY]: serveUrl,
|
|
576
|
+
PWMCP_TEST_CONNECTION_TIMEOUT: process.env.PWMCP_TEST_CONNECTION_TIMEOUT || "30000",
|
|
577
|
+
PLAYWRIGHT_CLI: resolvedPlaywrightCli,
|
|
578
|
+
};
|
|
579
|
+
if (process.env.RECH_HOST) daemonEnv.RECH_HOST = process.env.RECH_HOST;
|
|
580
|
+
if (isReadable(process.env.RECH_TLS_CERT)) daemonEnv.RECH_TLS_CERT = process.env.RECH_TLS_CERT!;
|
|
581
|
+
if (isReadable(process.env.RECH_TLS_KEY)) daemonEnv.RECH_TLS_KEY = process.env.RECH_TLS_KEY!;
|
|
582
|
+
|
|
583
|
+
// Drop any prior registration (current + legacy names) before re-adding.
|
|
584
|
+
for (const name of [PM_PROCESS_NAME, ...LEGACY_PROCESS_NAMES]) await runPm(["delete", name]);
|
|
585
|
+
|
|
586
|
+
if (IS_WINDOWS) {
|
|
587
|
+
// pm2 captures the CLI env (passed via runPm's env) for the managed process,
|
|
588
|
+
// autorestarts by default, and runs the bun binary directly with
|
|
589
|
+
// `--interpreter none` (so it isn't fed to node).
|
|
590
|
+
await runPm([
|
|
591
|
+
"start", bunBin,
|
|
592
|
+
"--name", PM_PROCESS_NAME,
|
|
593
|
+
"--interpreter", "none",
|
|
594
|
+
"--cwd", home,
|
|
595
|
+
"--", rechScript, "serve",
|
|
596
|
+
], daemonEnv);
|
|
597
|
+
await runPm(["save"]); // persist process list for `pm2 resurrect` on reboot
|
|
598
|
+
} else {
|
|
599
|
+
const envArgs = Object.entries(daemonEnv).flatMap(([k, v]) => ["--env", `${k}=${v}`]);
|
|
600
|
+
await runPm([
|
|
601
|
+
"start",
|
|
602
|
+
"--name", PM_PROCESS_NAME,
|
|
603
|
+
"--restart", "always",
|
|
604
|
+
"--cwd", home,
|
|
605
|
+
...envArgs,
|
|
606
|
+
`${bunBin} ${rechScript} serve`,
|
|
607
|
+
]);
|
|
608
|
+
await runPm(["service", "install"]);
|
|
609
|
+
}
|
|
569
610
|
}
|
|
570
611
|
|
|
571
612
|
async function daemonUninstall(): Promise<void> {
|
|
572
|
-
await
|
|
573
|
-
await
|
|
574
|
-
|
|
613
|
+
for (const name of [PM_PROCESS_NAME, ...LEGACY_PROCESS_NAMES]) await runPm(["delete", name]);
|
|
614
|
+
if (IS_WINDOWS) await runPm(["save"]);
|
|
615
|
+
else await runPm(["service", "uninstall"]);
|
|
616
|
+
console.log(`Removed ${PM_BIN} process: ${PM_PROCESS_NAME}`);
|
|
575
617
|
}
|
|
576
618
|
|
|
577
619
|
async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
@@ -693,7 +735,7 @@ async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
|
693
735
|
await waitForServe();
|
|
694
736
|
} else {
|
|
695
737
|
await daemonInstall(url);
|
|
696
|
-
console.log(` Registered daemon: ${
|
|
738
|
+
console.log(` Registered daemon: ${PM_PROCESS_NAME}`);
|
|
697
739
|
await waitForServe();
|
|
698
740
|
}
|
|
699
741
|
|
|
@@ -832,7 +874,7 @@ async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
|
832
874
|
|
|
833
875
|
const pwdEnvPath = join(process.cwd(), ".env.local");
|
|
834
876
|
const pwdRechPath = join(process.cwd(), ".rechrome", ".env.local");
|
|
835
|
-
const homeEnvPath = join(
|
|
877
|
+
const homeEnvPath = join(HOME, ".env.local");
|
|
836
878
|
// Show whether each target already exists so it's clear we'll update (merge) vs create.
|
|
837
879
|
const tag = async (p: string) => (await file(p).exists()) ? "exists → will update" : "new file";
|
|
838
880
|
const [pwdTag, pwdRechTag, homeTag] = await Promise.all([tag(pwdEnvPath), tag(pwdRechPath), tag(homeEnvPath)]);
|
|
@@ -896,10 +938,9 @@ async function status(): Promise<void> {
|
|
|
896
938
|
const listenLine = lsofOut.split("\n").find(l => l.includes(`:${port}`));
|
|
897
939
|
const listenAddr = listenLine?.match(/TCP\s+(\S+:\d+)/)?.[1] ?? (ping ? `${host}:${port}` : null);
|
|
898
940
|
console.log(`serve: ${ping ? `running ${protocol}://${listenAddr ?? `${host}:${port}`}` : "not running"}`);
|
|
899
|
-
const
|
|
900
|
-
const
|
|
901
|
-
|
|
902
|
-
console.log(`daemon: ${daemonRegistered ? `oxmgr (${OXMGR_PROCESS_NAME})` : "not installed"}`);
|
|
941
|
+
const pmOut = await pmList();
|
|
942
|
+
const daemonRegistered = pmOut.includes(PM_PROCESS_NAME);
|
|
943
|
+
console.log(`daemon: ${daemonRegistered ? `${PM_BIN} (${PM_PROCESS_NAME})` : "not installed"}`);
|
|
903
944
|
const registry = await readTokenRegistry();
|
|
904
945
|
const entries = Object.entries(registry);
|
|
905
946
|
if (entries.length) {
|
package/rech.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { file } from "bun";
|
|
4
4
|
import { randomBytes } from "crypto";
|
|
5
5
|
import { mkdirSync, appendFileSync, existsSync, realpathSync, accessSync, cpSync, constants as fsConstants } from "fs";
|
|
6
|
-
import { hostname } from "os";
|
|
6
|
+
import { hostname, homedir } from "os";
|
|
7
7
|
import { join, basename, dirname } from "path";
|
|
8
8
|
|
|
9
9
|
export const ENV_KEY = "RECHROME_URL";
|
|
@@ -11,7 +11,10 @@ export const DEFAULT_PORT = 13775;
|
|
|
11
11
|
export const RECH_DIR = join(import.meta.dir, ".rech");
|
|
12
12
|
export const LOG_DIR = join(RECH_DIR, "logs");
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
// Home dir: HOME on POSIX, USERPROFILE on Windows (handled by os.homedir()).
|
|
15
|
+
export const HOME = homedir();
|
|
16
|
+
|
|
17
|
+
const RECH_HOME_DIR = join(HOME, ".rechrome");
|
|
15
18
|
const TOKENS_FILE = join(RECH_HOME_DIR, "profiles.json");
|
|
16
19
|
|
|
17
20
|
type TokenEntry = { extensionId: string; token: string; profileDir: string; userDataDir?: string };
|
|
@@ -29,7 +32,7 @@ async function saveTokenEntry(profileEmail: string, entry: TokenEntry): Promise<
|
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
const envFile = join(import.meta.dir, ".env.local");
|
|
32
|
-
const globalEnvFile = join(
|
|
35
|
+
const globalEnvFile = join(HOME || "~", ".env.local");
|
|
33
36
|
|
|
34
37
|
// Walk CWD→root loading env files nearest-first; per-key: closest file wins, farther files skip.
|
|
35
38
|
// At each level .rechrome/.env.local is checked before .env.local (rechrome-specific overrides general).
|
|
@@ -214,7 +217,7 @@ async function getClientEnv(urlExtras?: { extensionId?: string; extensionToken?:
|
|
|
214
217
|
}
|
|
215
218
|
|
|
216
219
|
const CHROME_LOCAL_STATE_PATHS = () => {
|
|
217
|
-
const home =
|
|
220
|
+
const home = HOME || "~";
|
|
218
221
|
return [
|
|
219
222
|
join(home, "Library/Application Support/Google/Chrome/Local State"),
|
|
220
223
|
join(home, ".config/google-chrome/Local State"),
|
|
@@ -250,7 +253,7 @@ const LEGACY_EXTENSION_DIST_DIR = join(import.meta.dir, "lib/playwright-multi-ta
|
|
|
250
253
|
|
|
251
254
|
// Stable per-user location: we copy the bundled dist here so Chrome's recorded install path survives
|
|
252
255
|
// the ephemeral bunx temp dir being cleaned up between invocations.
|
|
253
|
-
export const EXTENSION_DIST_DIR = join(
|
|
256
|
+
export const EXTENSION_DIST_DIR = join(HOME, ".rechrome", "extension");
|
|
254
257
|
|
|
255
258
|
// With the manifest `key` field set, Chrome derives this ID deterministically from the key (not the path),
|
|
256
259
|
// so we can locate the extension by ID even when the on-disk path differs from what Chrome stored.
|
|
@@ -516,15 +519,35 @@ function buildSetupHtml(extDistDir: string, profileDisplay: string): string {
|
|
|
516
519
|
</html>`;
|
|
517
520
|
}
|
|
518
521
|
|
|
519
|
-
const
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
522
|
+
const PM_PROCESS_NAME = "rechrome";
|
|
523
|
+
// Pre-rename names to evict on (re)install/uninstall so a single `rech setup`
|
|
524
|
+
// migrates an existing checkout cleanly.
|
|
525
|
+
const LEGACY_PROCESS_NAMES = ["rechrome-serve"];
|
|
526
|
+
// oxmgr everywhere, but it's unstable on Windows — fall back to pm2 there.
|
|
527
|
+
const IS_WINDOWS = process.platform === "win32";
|
|
528
|
+
const PM_BIN = IS_WINDOWS ? "pm2" : "oxmgr";
|
|
529
|
+
|
|
530
|
+
// Spawn the active process manager. `env` is merged over process.env for the
|
|
531
|
+
// child: pm2 captures the CLI's environment for the managed process (it has no
|
|
532
|
+
// per-var flag like oxmgr's --env), so install passes daemon env this way.
|
|
533
|
+
async function runPm(args: string[], env?: Record<string, string>): Promise<number> {
|
|
534
|
+
const proc = Bun.spawn(["bunx", PM_BIN, ...args], {
|
|
535
|
+
stdout: "inherit",
|
|
536
|
+
stderr: "inherit",
|
|
537
|
+
...(env ? { env: { ...process.env, ...env } } : {}),
|
|
538
|
+
});
|
|
523
539
|
await proc.exited;
|
|
524
540
|
return proc.exitCode ?? 1;
|
|
525
541
|
}
|
|
526
542
|
|
|
527
|
-
|
|
543
|
+
// Capture the process-manager's process list as text (oxmgr `list` / pm2 `jlist`).
|
|
544
|
+
// Both render the process name verbatim, so callers can substring-match it.
|
|
545
|
+
async function pmList(): Promise<string> {
|
|
546
|
+
const proc = Bun.spawn(["bunx", PM_BIN, IS_WINDOWS ? "jlist" : "list"], { stdout: "pipe", stderr: "ignore" });
|
|
547
|
+
return await new Response(proc.stdout).text();
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
export async function daemonInstall(serveUrl: string): Promise<void> {
|
|
528
551
|
// Persist the URL to ~/.env.local before starting the daemon. The daemon's
|
|
529
552
|
// loadEnv() walks CWD→root reading .env.local files and unconditionally
|
|
530
553
|
// overwrites process.env.RECHROME_URL from whichever file it finds first.
|
|
@@ -536,7 +559,7 @@ async function daemonInstall(serveUrl: string): Promise<void> {
|
|
|
536
559
|
const filtered = envRaw.trimEnd().split("\n").filter(l => !l.startsWith(`${ENV_KEY}=`));
|
|
537
560
|
await Bun.write(globalEnvFile, [...filtered, `${ENV_KEY}=${serveUrl}`, ""].join("\n"));
|
|
538
561
|
|
|
539
|
-
const home =
|
|
562
|
+
const home = HOME;
|
|
540
563
|
const bunBin = Bun.which("bun") ?? process.execPath;
|
|
541
564
|
const rechScript = import.meta.filename;
|
|
542
565
|
|
|
@@ -545,33 +568,52 @@ async function daemonInstall(serveUrl: string): Promise<void> {
|
|
|
545
568
|
const resolvedPlaywrightCli = process.env.PLAYWRIGHT_CLI
|
|
546
569
|
|| (existsSync(bundledForkCli) ? bundledForkCli : "playwright-cli-multi-tab");
|
|
547
570
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
if (
|
|
557
|
-
if (isReadable(process.env.
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
571
|
+
// Environment the managed `serve` process must run with.
|
|
572
|
+
const daemonEnv: Record<string, string> = {
|
|
573
|
+
HOME: home,
|
|
574
|
+
PATH: process.env.PATH || "/usr/local/bin:/usr/bin:/bin",
|
|
575
|
+
[ENV_KEY]: serveUrl,
|
|
576
|
+
PWMCP_TEST_CONNECTION_TIMEOUT: process.env.PWMCP_TEST_CONNECTION_TIMEOUT || "30000",
|
|
577
|
+
PLAYWRIGHT_CLI: resolvedPlaywrightCli,
|
|
578
|
+
};
|
|
579
|
+
if (process.env.RECH_HOST) daemonEnv.RECH_HOST = process.env.RECH_HOST;
|
|
580
|
+
if (isReadable(process.env.RECH_TLS_CERT)) daemonEnv.RECH_TLS_CERT = process.env.RECH_TLS_CERT!;
|
|
581
|
+
if (isReadable(process.env.RECH_TLS_KEY)) daemonEnv.RECH_TLS_KEY = process.env.RECH_TLS_KEY!;
|
|
582
|
+
|
|
583
|
+
// Drop any prior registration (current + legacy names) before re-adding.
|
|
584
|
+
for (const name of [PM_PROCESS_NAME, ...LEGACY_PROCESS_NAMES]) await runPm(["delete", name]);
|
|
585
|
+
|
|
586
|
+
if (IS_WINDOWS) {
|
|
587
|
+
// pm2 captures the CLI env (passed via runPm's env) for the managed process,
|
|
588
|
+
// autorestarts by default, and runs the bun binary directly with
|
|
589
|
+
// `--interpreter none` (so it isn't fed to node).
|
|
590
|
+
await runPm([
|
|
591
|
+
"start", bunBin,
|
|
592
|
+
"--name", PM_PROCESS_NAME,
|
|
593
|
+
"--interpreter", "none",
|
|
594
|
+
"--cwd", home,
|
|
595
|
+
"--", rechScript, "serve",
|
|
596
|
+
], daemonEnv);
|
|
597
|
+
await runPm(["save"]); // persist process list for `pm2 resurrect` on reboot
|
|
598
|
+
} else {
|
|
599
|
+
const envArgs = Object.entries(daemonEnv).flatMap(([k, v]) => ["--env", `${k}=${v}`]);
|
|
600
|
+
await runPm([
|
|
601
|
+
"start",
|
|
602
|
+
"--name", PM_PROCESS_NAME,
|
|
603
|
+
"--restart", "always",
|
|
604
|
+
"--cwd", home,
|
|
605
|
+
...envArgs,
|
|
606
|
+
`${bunBin} ${rechScript} serve`,
|
|
607
|
+
]);
|
|
608
|
+
await runPm(["service", "install"]);
|
|
609
|
+
}
|
|
569
610
|
}
|
|
570
611
|
|
|
571
612
|
async function daemonUninstall(): Promise<void> {
|
|
572
|
-
await
|
|
573
|
-
await
|
|
574
|
-
|
|
613
|
+
for (const name of [PM_PROCESS_NAME, ...LEGACY_PROCESS_NAMES]) await runPm(["delete", name]);
|
|
614
|
+
if (IS_WINDOWS) await runPm(["save"]);
|
|
615
|
+
else await runPm(["service", "uninstall"]);
|
|
616
|
+
console.log(`Removed ${PM_BIN} process: ${PM_PROCESS_NAME}`);
|
|
575
617
|
}
|
|
576
618
|
|
|
577
619
|
async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
@@ -693,7 +735,7 @@ async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
|
693
735
|
await waitForServe();
|
|
694
736
|
} else {
|
|
695
737
|
await daemonInstall(url);
|
|
696
|
-
console.log(` Registered daemon: ${
|
|
738
|
+
console.log(` Registered daemon: ${PM_PROCESS_NAME}`);
|
|
697
739
|
await waitForServe();
|
|
698
740
|
}
|
|
699
741
|
|
|
@@ -832,7 +874,7 @@ async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
|
832
874
|
|
|
833
875
|
const pwdEnvPath = join(process.cwd(), ".env.local");
|
|
834
876
|
const pwdRechPath = join(process.cwd(), ".rechrome", ".env.local");
|
|
835
|
-
const homeEnvPath = join(
|
|
877
|
+
const homeEnvPath = join(HOME, ".env.local");
|
|
836
878
|
// Show whether each target already exists so it's clear we'll update (merge) vs create.
|
|
837
879
|
const tag = async (p: string) => (await file(p).exists()) ? "exists → will update" : "new file";
|
|
838
880
|
const [pwdTag, pwdRechTag, homeTag] = await Promise.all([tag(pwdEnvPath), tag(pwdRechPath), tag(homeEnvPath)]);
|
|
@@ -896,10 +938,9 @@ async function status(): Promise<void> {
|
|
|
896
938
|
const listenLine = lsofOut.split("\n").find(l => l.includes(`:${port}`));
|
|
897
939
|
const listenAddr = listenLine?.match(/TCP\s+(\S+:\d+)/)?.[1] ?? (ping ? `${host}:${port}` : null);
|
|
898
940
|
console.log(`serve: ${ping ? `running ${protocol}://${listenAddr ?? `${host}:${port}`}` : "not running"}`);
|
|
899
|
-
const
|
|
900
|
-
const
|
|
901
|
-
|
|
902
|
-
console.log(`daemon: ${daemonRegistered ? `oxmgr (${OXMGR_PROCESS_NAME})` : "not installed"}`);
|
|
941
|
+
const pmOut = await pmList();
|
|
942
|
+
const daemonRegistered = pmOut.includes(PM_PROCESS_NAME);
|
|
943
|
+
console.log(`daemon: ${daemonRegistered ? `${PM_BIN} (${PM_PROCESS_NAME})` : "not installed"}`);
|
|
903
944
|
const registry = await readTokenRegistry();
|
|
904
945
|
const entries = Object.entries(registry);
|
|
905
946
|
if (entries.length) {
|
package/serve.js
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
getOrCreateUrl,
|
|
9
9
|
authCheck,
|
|
10
10
|
RECH_DIR,
|
|
11
|
+
HOME,
|
|
11
12
|
PASSTHROUGH_ENV_KEYS,
|
|
12
13
|
} from "./rech.js";
|
|
13
14
|
|
|
@@ -64,7 +65,7 @@ export function isUnderDir(base: string, candidate: string): boolean {
|
|
|
64
65
|
|
|
65
66
|
async function resolveProfileDirectory(nameOrEmail: string): Promise<string> {
|
|
66
67
|
if (/^(Default|Profile \d+)$/i.test(nameOrEmail)) return nameOrEmail;
|
|
67
|
-
const home =
|
|
68
|
+
const home = HOME || "~";
|
|
68
69
|
const candidates = [
|
|
69
70
|
join(home, "Library/Application Support/Google/Chrome/Local State"),
|
|
70
71
|
join(home, ".config/google-chrome/Local State"),
|
|
@@ -203,7 +204,7 @@ export async function serve() {
|
|
|
203
204
|
stdin: "ignore",
|
|
204
205
|
stdout: "pipe",
|
|
205
206
|
stderr: "pipe",
|
|
206
|
-
env: { PATH: process.env.PATH, HOME: process.env.
|
|
207
|
+
env: { PATH: process.env.PATH, HOME: HOME, USERPROFILE: process.env.USERPROFILE },
|
|
207
208
|
});
|
|
208
209
|
const [listStatus, listOut] = await Promise.race([
|
|
209
210
|
Promise.all([listProc.exited, new Response(listProc.stdout).text()]),
|
|
@@ -248,7 +249,8 @@ export async function serve() {
|
|
|
248
249
|
|
|
249
250
|
const childEnv: Record<string, string | undefined> = {
|
|
250
251
|
PATH: process.env.PATH,
|
|
251
|
-
HOME:
|
|
252
|
+
HOME: HOME,
|
|
253
|
+
USERPROFILE: process.env.USERPROFILE,
|
|
252
254
|
TMPDIR: process.env.TMPDIR,
|
|
253
255
|
DISPLAY: process.env.DISPLAY,
|
|
254
256
|
XDG_RUNTIME_DIR: process.env.XDG_RUNTIME_DIR,
|
package/serve.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
getOrCreateUrl,
|
|
9
9
|
authCheck,
|
|
10
10
|
RECH_DIR,
|
|
11
|
+
HOME,
|
|
11
12
|
PASSTHROUGH_ENV_KEYS,
|
|
12
13
|
} from "./rech.ts";
|
|
13
14
|
|
|
@@ -64,7 +65,7 @@ export function isUnderDir(base: string, candidate: string): boolean {
|
|
|
64
65
|
|
|
65
66
|
async function resolveProfileDirectory(nameOrEmail: string): Promise<string> {
|
|
66
67
|
if (/^(Default|Profile \d+)$/i.test(nameOrEmail)) return nameOrEmail;
|
|
67
|
-
const home =
|
|
68
|
+
const home = HOME || "~";
|
|
68
69
|
const candidates = [
|
|
69
70
|
join(home, "Library/Application Support/Google/Chrome/Local State"),
|
|
70
71
|
join(home, ".config/google-chrome/Local State"),
|
|
@@ -203,7 +204,7 @@ export async function serve() {
|
|
|
203
204
|
stdin: "ignore",
|
|
204
205
|
stdout: "pipe",
|
|
205
206
|
stderr: "pipe",
|
|
206
|
-
env: { PATH: process.env.PATH, HOME: process.env.
|
|
207
|
+
env: { PATH: process.env.PATH, HOME: HOME, USERPROFILE: process.env.USERPROFILE },
|
|
207
208
|
});
|
|
208
209
|
const [listStatus, listOut] = await Promise.race([
|
|
209
210
|
Promise.all([listProc.exited, new Response(listProc.stdout).text()]),
|
|
@@ -248,7 +249,8 @@ export async function serve() {
|
|
|
248
249
|
|
|
249
250
|
const childEnv: Record<string, string | undefined> = {
|
|
250
251
|
PATH: process.env.PATH,
|
|
251
|
-
HOME:
|
|
252
|
+
HOME: HOME,
|
|
253
|
+
USERPROFILE: process.env.USERPROFILE,
|
|
252
254
|
TMPDIR: process.env.TMPDIR,
|
|
253
255
|
DISPLAY: process.env.DISPLAY,
|
|
254
256
|
XDG_RUNTIME_DIR: process.env.XDG_RUNTIME_DIR,
|