relay-companion 0.1.26 → 0.1.27

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/overlay/main.cjs CHANGED
@@ -884,26 +884,50 @@ function anchorTopRight() {
884
884
  return { x: wa.x + wa.width - WIN.width - MARGIN, y: wa.y + MARGIN, width: WIN.width, height: WIN.height };
885
885
  }
886
886
 
887
+ function placeOverlayWindow() {
888
+ if (!win || win.isDestroyed()) return;
889
+ try {
890
+ win.setBounds(anchorTopRight(), false);
891
+ } catch (error) {
892
+ console.error("[overlay] setBounds failed:", error && error.message);
893
+ }
894
+ try {
895
+ win.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
896
+ } catch {}
897
+ try {
898
+ win.setAlwaysOnTop(true, "floating");
899
+ } catch {}
900
+ }
901
+
887
902
  // Show the overlay window. Electron's forwarded-mousemove stream (the thing that
888
903
  // lets the renderer detect hover on a click-through window) can stall across a
889
904
  // hide()/show() cycle, leaving the window permanently click-through. Re-assert
890
905
  // setIgnoreMouseEvents on every hidden->shown transition and tell the renderer to
891
906
  // reset its interactivity handshake.
892
- function showOverlayWindow() {
893
- if (!win || win.isDestroyed() || win.isVisible()) return;
907
+ function showOverlayWindow({ force = false } = {}) {
908
+ if (!win || win.isDestroyed()) return;
909
+ const visible = win.isVisible();
910
+ if (visible && !force) return;
911
+ placeOverlayWindow();
912
+ if (visible && force) win.hide();
894
913
  win.showInactive();
914
+ if (typeof win.moveTop === "function") {
915
+ try {
916
+ win.moveTop();
917
+ } catch {}
918
+ }
895
919
  win.setIgnoreMouseEvents(true, { forward: true });
896
920
  win.webContents.send("shown");
897
921
  }
898
922
 
899
- function maybeShow() {
923
+ function maybeShow({ force = false } = {}) {
900
924
  if (!win || win.isDestroyed()) return;
901
925
  // Dismissed keeps the window hidden except while a ghost notification is up.
902
926
  // trayForcedVisible honors an explicit status-area click even when no host runs.
903
927
  const dismissedEffective = trayAvailable && dismissed;
904
928
  const wanted = (hostRunning || trayForcedVisible) && (!dismissedEffective || ghostActive);
905
929
  if (wanted) {
906
- showOverlayWindow();
930
+ showOverlayWindow({ force });
907
931
  } else if (win.isVisible()) {
908
932
  win.hide();
909
933
  }
@@ -1040,8 +1064,8 @@ function createTrayIcon() {
1040
1064
  function showFromTray() {
1041
1065
  setDismissed(false);
1042
1066
  ghostActive = false;
1043
- if (!hostRunning) trayForcedVisible = true; // an explicit click always gets the card
1044
- maybeShow();
1067
+ trayForcedVisible = true; // an explicit click always gets the card
1068
+ maybeShow({ force: true });
1045
1069
  if (win && !win.isDestroyed()) win.webContents.send("openFull");
1046
1070
  }
1047
1071
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relay-companion",
3
- "version": "0.1.26",
3
+ "version": "0.1.27",
4
4
  "description": "Relay companion: connects local coding agents to Relay tasks, approvals, and connector tools.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -172,6 +172,10 @@ export function spawnDetachedUpdate({
172
172
  ` ROOT="$(npm root -g 2>/dev/null)"`,
173
173
  ` PKG="$ROOT/${PACKAGE_NAME}"`,
174
174
  ` ELECTRON="$PKG/node_modules/electron/dist/Electron.app/Contents/MacOS/Electron"`,
175
+ ` if [ ! -x "$ELECTRON" ] && [ -f "$PKG/node_modules/electron/install.js" ]; then`,
176
+ ` echo "[relay-update] $(date) electron runtime missing; running electron install.js" >> ${LOG} 2>&1`,
177
+ ` node "$PKG/node_modules/electron/install.js" >> ${LOG} 2>&1 || true`,
178
+ ` fi`,
175
179
  ` if [ -x "$ELECTRON" ] && [ -f "$PKG/bin/relay.js" ] && grep -q '"version"' "$PKG/package.json" 2>/dev/null; then`,
176
180
  ` echo "[relay-update] $(date) install verified; restarting services" >> ${LOG} 2>&1`,
177
181
  ` /bin/launchctl kickstart -k gui/${uid}/${PILL_LABEL} >> ${LOG} 2>&1 || true`,
@@ -179,10 +183,16 @@ export function spawnDetachedUpdate({
179
183
  ` else`,
180
184
  ` echo "[relay-update] $(date) post-install verify FAILED; restoring ${restore}" >> ${LOG} 2>&1`,
181
185
  ` npm install -g ${PACKAGE_NAME}@${restore} >> ${LOG} 2>&1 || true`,
186
+ ` ROOT="$(npm root -g 2>/dev/null)"`,
187
+ ` PKG="$ROOT/${PACKAGE_NAME}"`,
188
+ ` if [ -f "$PKG/node_modules/electron/install.js" ]; then node "$PKG/node_modules/electron/install.js" >> ${LOG} 2>&1 || true; fi`,
182
189
  ` fi`,
183
190
  `else`,
184
191
  ` echo "[relay-update] $(date) install FAILED; restoring ${restore}" >> ${LOG} 2>&1`,
185
192
  ` npm install -g ${PACKAGE_NAME}@${restore} >> ${LOG} 2>&1 || true`,
193
+ ` ROOT="$(npm root -g 2>/dev/null)"`,
194
+ ` PKG="$ROOT/${PACKAGE_NAME}"`,
195
+ ` if [ -f "$PKG/node_modules/electron/install.js" ]; then node "$PKG/node_modules/electron/install.js" >> ${LOG} 2>&1 || true; fi`,
186
196
  `fi`,
187
197
  ].join("\n");
188
198
  const child = spawnImpl("/bin/sh", ["-c", script], { detached: true, stdio: "ignore" });
package/src/install.js CHANGED
@@ -240,6 +240,30 @@ function electronPathForPackageRoot(packageRoot) {
240
240
  }
241
241
  }
242
242
 
243
+ export function ensureElectronRuntime(packageRoot, { runCommand = run } = {}) {
244
+ let electronPath = electronPathForPackageRoot(packageRoot);
245
+ if (electronPath && fs.existsSync(electronPath)) return { ok: true, electronPath, repaired: false };
246
+
247
+ const installScript = path.join(packageRoot, "node_modules", "electron", "install.js");
248
+ if (!fs.existsSync(installScript)) {
249
+ return { ok: false, reason: "electron_install_script_missing", electronPath, installScript };
250
+ }
251
+
252
+ const res = runCommand(process.execPath, [installScript], { timeoutMs: npmInstallTimeoutMs() });
253
+ electronPath = electronPathForPackageRoot(packageRoot);
254
+ if (res.ok && electronPath && fs.existsSync(electronPath)) {
255
+ return { ok: true, electronPath, repaired: true };
256
+ }
257
+
258
+ return {
259
+ ok: false,
260
+ reason: "electron_runtime_missing",
261
+ electronPath,
262
+ installScript,
263
+ detail: res.out,
264
+ };
265
+ }
266
+
243
267
  /** Whether an agent CLI is on PATH. */
244
268
  export function commandExists(cmd) {
245
269
  const res = spawnSync(cmd, ["--version"], { encoding: "utf8", timeout: 8000 });
@@ -333,10 +357,11 @@ export function installDaemonAutostart(bin = relayBinPath(), node = process.exec
333
357
  export function installPillAutostart(bin = relayBinPath(), { platform = process.platform, runCommand = run } = {}) {
334
358
  if (platform !== "darwin" && platform !== "win32") return { ok: false, reason: "autostart_unsupported_platform" };
335
359
  const packageRoot = packageRootForBin(bin);
336
- const electronPath = electronPathForPackageRoot(packageRoot);
360
+ const electron = ensureElectronRuntime(packageRoot, { runCommand });
361
+ const electronPath = electron.electronPath;
337
362
  const overlayMain = path.join(packageRoot, "overlay", "main.cjs");
338
- if (!electronPath || !fs.existsSync(overlayMain)) {
339
- return { ok: false, reason: "pill_runtime_missing", electronPath, overlayMain };
363
+ if (!electron.ok || !electronPath || !fs.existsSync(overlayMain)) {
364
+ return { ok: false, reason: "pill_runtime_missing", electronPath, overlayMain, electron };
340
365
  }
341
366
  if (platform === "win32") {
342
367
  const logPath = path.join(os.homedir(), ".relay", "pill.log");