chrome-relay 0.5.20 → 0.5.21

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/dist/cli.js CHANGED
@@ -1101,7 +1101,7 @@ var init_dist = __esm({
1101
1101
  import { Command } from "commander";
1102
1102
 
1103
1103
  // src/index.ts
1104
- var CHROME_RELAY_VERSION = true ? "0.5.20" : "0.0.0-dev";
1104
+ var CHROME_RELAY_VERSION = true ? "0.5.21" : "0.0.0-dev";
1105
1105
 
1106
1106
  // src/commands/shared.ts
1107
1107
  init_dist();
@@ -1237,6 +1237,7 @@ function isToolName(name) {
1237
1237
  init_dist();
1238
1238
  import os from "os";
1239
1239
  import path from "path";
1240
+ import { spawnSync } from "child_process";
1240
1241
  import { chmod, mkdir, readFile, stat, writeFile } from "fs/promises";
1241
1242
  import { fileURLToPath } from "url";
1242
1243
  var APP_DIR = path.join(os.homedir(), ".chrome-relay");
@@ -1294,16 +1295,43 @@ async function writeManifest(wrapperPath) {
1294
1295
  `, "utf8");
1295
1296
  return manifestPath;
1296
1297
  }
1298
+ function killStaleNativeHosts() {
1299
+ if (process.platform !== "darwin" && process.platform !== "linux") {
1300
+ return { killed: 0 };
1301
+ }
1302
+ const ps = spawnSync("ps", ["-A", "-o", "pid=,command="], { encoding: "utf8" });
1303
+ if (ps.status !== 0 || !ps.stdout) return { killed: 0 };
1304
+ let killed = 0;
1305
+ for (const raw of ps.stdout.split("\n")) {
1306
+ const line = raw.trim();
1307
+ if (!line) continue;
1308
+ if (!line.includes("chrome-relay") || !line.includes("native-host.js")) continue;
1309
+ const m = line.match(/^(\d+)\s/);
1310
+ if (!m) continue;
1311
+ const pid = Number.parseInt(m[1], 10);
1312
+ if (pid === process.pid) continue;
1313
+ try {
1314
+ process.kill(pid, "SIGTERM");
1315
+ killed++;
1316
+ } catch {
1317
+ }
1318
+ }
1319
+ return { killed };
1320
+ }
1297
1321
  async function runInstall() {
1298
1322
  const distDir = getDistDir();
1299
1323
  const hostPath = path.join(distDir, "native-host.js");
1300
1324
  const wrapperPath = await writeWrapperScript(hostPath);
1301
1325
  const manifestPath = await writeManifest(wrapperPath);
1326
+ const { killed } = killStaleNativeHosts();
1302
1327
  console.log(`Installed Chrome Relay native host.`);
1303
1328
  console.log(`Wrapper: ${wrapperPath}`);
1304
1329
  console.log(`Manifest: ${manifestPath}`);
1305
1330
  console.log(`Local bridge port: ${DEFAULT_HTTP_PORT}`);
1306
1331
  console.log(`Allowed extension IDs: ${formatKnownExtensionIds()}`);
1332
+ if (killed > 0) {
1333
+ console.log(`Reaped ${killed} stale native-host process${killed === 1 ? "" : "es"}; Chrome will respawn from the new manifest.`);
1334
+ }
1307
1335
  }
1308
1336
  async function runDoctor() {
1309
1337
  try {
@@ -1344,6 +1372,11 @@ async function runDoctor() {
1344
1372
 
1345
1373
  // src/release-notes.ts
1346
1374
  var RELEASE_NOTES = {
1375
+ "0.5.21": [
1376
+ "Fix: `chrome-relay update` and `chrome-relay install` now SIGTERM any running native-host.js process before exiting, and `update` re-runs `install` from the freshly-installed binary. Chrome respawns the host from the new manifest on its next native-messaging request.",
1377
+ "Why this matters: Chrome's native messaging keeps the host process alive for the session. Pre-0.5.21, `chrome-relay update` refreshed the on-disk package but Chrome kept routing through the OLD host. The HTTP bridge served by that old host then reported its own embedded `CHROME_RELAY_VERSION`, which falsely tripped the cli-outdated nudge against the newer extension. Users running the very command the nudge told them to run found the nudge still firing afterwards \u2014 the worst kind of UX bug.",
1378
+ "Best-effort and silent on failure: kill is only attempted on darwin/linux, only matches `native-host.js` paths that also contain `chrome-relay`, and ignores individual kill errors (already gone, no permission). Won't kill the running CLI itself."
1379
+ ],
1347
1380
  "0.5.20": [
1348
1381
  "BREAKING \u2014 `chrome-relay navigate` no longer steals focus by default. Background is now the implicit behavior; agents pass `--active` when they actually want the user looking at the new tab. The whole product pitch is 'operate without stealing focus' \u2014 the default needed to match.",
1349
1382
  "`--inactive` flag removed entirely. It was the opt-in for the previous (wrong) default; now it'd be a no-op, and no-op flags are dead code. Agents that were passing `--inactive` should drop it (the behavior is now the default). Commander will reject the unknown flag \u2014 that's the right signal to update.",
@@ -1511,7 +1544,7 @@ function registerInstallUpdate(program) {
1511
1544
  });
1512
1545
  program.command("update").description("Update chrome-relay CLI to the latest version and print what changed (agent-readable JSON).").option("--dry-run", "skip the install; just show what changed since the current version").action(async (opts) => {
1513
1546
  const fromVersion = CHROME_RELAY_VERSION;
1514
- const { spawnSync } = await import("child_process");
1547
+ const { spawnSync: spawnSync2 } = await import("child_process");
1515
1548
  const out = {
1516
1549
  updatedFrom: fromVersion,
1517
1550
  updatedTo: fromVersion,
@@ -1531,7 +1564,7 @@ function registerInstallUpdate(program) {
1531
1564
  };
1532
1565
  process.stderr.write(`[chrome-relay] updating from ${fromVersion} via ${pm}...
1533
1566
  `);
1534
- const install = spawnSync(cmd[0], cmd[1], { stdio: "inherit" });
1567
+ const install = spawnSync2(cmd[0], cmd[1], { stdio: "inherit" });
1535
1568
  out.install.status = install.status;
1536
1569
  if (install.status !== 0) {
1537
1570
  process.stderr.write(`[chrome-relay] install failed (${pm} exited ${install.status}). Try manually: ${cmd[0]} ${cmd[1].join(" ")}
@@ -1543,15 +1576,22 @@ function registerInstallUpdate(program) {
1543
1576
  process.stdout.write(JSON.stringify(out, null, 2) + "\n");
1544
1577
  process.exit(1);
1545
1578
  }
1546
- const which = spawnSync("which", ["chrome-relay"]);
1579
+ const which = spawnSync2("which", ["chrome-relay"]);
1547
1580
  const newBin = which.stdout?.toString().trim();
1548
1581
  if (which.status === 0 && newBin) {
1549
- const versionOut = spawnSync(newBin, ["--version"]);
1582
+ const versionOut = spawnSync2(newBin, ["--version"]);
1550
1583
  const newVersion = (versionOut.stdout?.toString() ?? "").trim();
1551
1584
  out.binary.path = newBin;
1552
1585
  if (newVersion && newVersion !== fromVersion) {
1553
1586
  out.updatedTo = newVersion;
1554
- const rn = spawnSync(newBin, ["release-notes", "--since", fromVersion]);
1587
+ const install2 = spawnSync2(newBin, ["install"], { stdio: "inherit" });
1588
+ if (install2.status !== 0) {
1589
+ out.warnings.push({
1590
+ code: "install_refresh_failed",
1591
+ message: `Update installed the new package but \`${newBin} install\` exited ${install2.status}. Run it manually to refresh the native host manifest.`
1592
+ });
1593
+ }
1594
+ const rn = spawnSync2(newBin, ["release-notes", "--since", fromVersion]);
1555
1595
  try {
1556
1596
  const parsed = JSON.parse(rn.stdout?.toString() ?? "");
1557
1597
  if (Array.isArray(parsed.changes)) {
@@ -1940,8 +1980,8 @@ Notes:
1940
1980
  }
1941
1981
  if (opts.gif || opts.mp4) {
1942
1982
  const fps = typeof opts.fps === "number" ? opts.fps : 15;
1943
- const { spawnSync } = await import("child_process");
1944
- const which = spawnSync("which", ["ffmpeg"]);
1983
+ const { spawnSync: spawnSync2 } = await import("child_process");
1984
+ const which = spawnSync2("which", ["ffmpeg"]);
1945
1985
  if (which.status !== 0) {
1946
1986
  if (opts.allowMissingFfmpeg) {
1947
1987
  process.stderr.write("[chrome-relay] ffmpeg not on PATH \u2014 skipping --gif/--mp4 (allow-missing-ffmpeg).\n");
@@ -1962,7 +2002,7 @@ Notes:
1962
2002
  }
1963
2003
  if (opts.gif) {
1964
2004
  const gifOut = `${opts.out.replace(/\/$/, "")}.gif`;
1965
- const r = spawnSync("ffmpeg", [
2005
+ const r = spawnSync2("ffmpeg", [
1966
2006
  "-y",
1967
2007
  "-framerate",
1968
2008
  String(fps),
@@ -1979,7 +2019,7 @@ Notes:
1979
2019
  }
1980
2020
  if (opts.mp4) {
1981
2021
  const mp4Out = `${opts.out.replace(/\/$/, "")}.mp4`;
1982
- const r = spawnSync("ffmpeg", [
2022
+ const r = spawnSync2("ffmpeg", [
1983
2023
  "-y",
1984
2024
  "-framerate",
1985
2025
  String(fps),
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- var CHROME_RELAY_VERSION = true ? "0.5.20" : "0.0.0-dev";
2
+ var CHROME_RELAY_VERSION = true ? "0.5.21" : "0.0.0-dev";
3
3
  export {
4
4
  CHROME_RELAY_VERSION
5
5
  };
@@ -56,7 +56,7 @@ function toBridgeError(unknownErr, fallbackTool) {
56
56
  }
57
57
 
58
58
  // src/index.ts
59
- var CHROME_RELAY_VERSION = true ? "0.5.20" : "0.0.0-dev";
59
+ var CHROME_RELAY_VERSION = true ? "0.5.21" : "0.0.0-dev";
60
60
 
61
61
  // src/release-notes.ts
62
62
  function compareSemver(a, b) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chrome-relay",
3
- "version": "0.5.20",
3
+ "version": "0.5.21",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",