relay-companion 0.1.36 → 0.1.37
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/host-select.cjs +18 -14
- package/overlay/main.cjs +22 -0
- package/package.json +1 -1
package/overlay/host-select.cjs
CHANGED
|
@@ -22,28 +22,31 @@ function isRelayBundle(bundle) {
|
|
|
22
22
|
return clean.includes("relay") || clean.includes("electron");
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
// Cold-start choice when NEITHER agent is running: pick by what's
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
25
|
+
// Cold-start choice when NEITHER agent is foregrounded/running: pick by what's
|
|
26
|
+
// installed. When BOTH are available and neither is foregrounded, prefer Claude
|
|
27
|
+
// (per the product rule: "if I have claude and codex and neither is foregrounded,
|
|
28
|
+
// foreground claude"). Windows is Claude-only for now: the Codex materializer still
|
|
29
|
+
// depends on macOS Codex Desktop paths/app-server behavior, while Claude's claude://
|
|
30
|
+
// resume handler is registered by Claude Desktop on Windows.
|
|
30
31
|
function defaultClickHost({ codexInstalled = false, claudeInstalled = false, platform = process.platform } = {}) {
|
|
31
32
|
if (platform === "win32") return "claude";
|
|
32
|
-
if (codexInstalled) return "codex";
|
|
33
33
|
if (claudeInstalled) return "claude";
|
|
34
|
-
return "codex";
|
|
34
|
+
if (codexInstalled) return "codex";
|
|
35
|
+
return "claude";
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
// Decide which host a pill click should open into. Precedence, strongest signal first:
|
|
38
|
-
// 1. The frontmost app IS a host — the user is literally looking at it.
|
|
39
|
+
// 1. The frontmost app IS a host — the user is literally looking at it, so open there.
|
|
40
|
+
// (Codex frontmost -> Codex; Claude frontmost -> Claude.)
|
|
39
41
|
// 2. The click momentarily activated the accessory overlay (or no frontmost app could
|
|
40
|
-
// be read) AND a host was foregrounded moments ago — use that
|
|
42
|
+
// be read) AND a host was foregrounded moments ago — use that just-foregrounded host.
|
|
41
43
|
// 3. Exactly one host PROCESS is running — route to it. This is the off-Space fix:
|
|
42
44
|
// `ps` sees a host on any Space, so a running-but-not-frontmost Claude wins over a
|
|
43
|
-
// closed Codex instead of cold-starting Codex.
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
// 5. Nothing
|
|
45
|
+
// closed Codex instead of cold-starting Codex. (Only Codex up -> Codex; only Claude
|
|
46
|
+
// up -> Claude.)
|
|
47
|
+
// 4. Both hosts are running but NEITHER is foregrounded — prefer Claude (product rule).
|
|
48
|
+
// 5. Nothing running — installed-preference default (true cold start; prefers Claude
|
|
49
|
+
// when both are installed).
|
|
47
50
|
function chooseClickHost({
|
|
48
51
|
frontHost = null,
|
|
49
52
|
bundle = null,
|
|
@@ -67,7 +70,8 @@ function chooseClickHost({
|
|
|
67
70
|
|
|
68
71
|
if (claudeRunning && !effectiveCodexRunning) return "claude";
|
|
69
72
|
if (effectiveCodexRunning && !claudeRunning) return "codex";
|
|
70
|
-
|
|
73
|
+
// Both running, neither foregrounded (and none foregrounded moments ago): prefer Claude.
|
|
74
|
+
if (claudeRunning && effectiveCodexRunning) return "claude";
|
|
71
75
|
|
|
72
76
|
return defaultClickHost({ codexInstalled: effectiveCodexInstalled, claudeInstalled, platform });
|
|
73
77
|
}
|
package/overlay/main.cjs
CHANGED
|
@@ -631,6 +631,23 @@ function rememberForegroundHost(host) {
|
|
|
631
631
|
lastHostSeenAt = Date.now();
|
|
632
632
|
}
|
|
633
633
|
|
|
634
|
+
// Bring the host app to the FOREGROUND so the just-opened relay is actually visible.
|
|
635
|
+
// shell.openExternal(claude://…) / the Codex bridge route the content to the host but
|
|
636
|
+
// do NOT reliably raise it: the overlay is a non-activating accessory window, and a
|
|
637
|
+
// host sitting on another macOS Space stays put (observed live: "it opened it in claude
|
|
638
|
+
// (good) but didnt foreground claude"). `open -b <bundle>` activates the app — switching
|
|
639
|
+
// to its Space and launching it if it wasn't running. `-g` is intentionally NOT passed,
|
|
640
|
+
// because raising the app is exactly the point.
|
|
641
|
+
const HOST_BUNDLE_ID = { claude: "com.anthropic.claudefordesktop", codex: "com.openai.codex" };
|
|
642
|
+
function activateHost(host) {
|
|
643
|
+
if (process.platform !== "darwin") return; // Windows foregrounding is handled by its own open path
|
|
644
|
+
const bundle = HOST_BUNDLE_ID[host];
|
|
645
|
+
if (!bundle) return;
|
|
646
|
+
execFile("/usr/bin/open", ["-b", bundle], (error) => {
|
|
647
|
+
if (error) console.error("[overlay] activateHost failed:", host, error && error.message);
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
|
|
634
651
|
function appInstalled(appName) {
|
|
635
652
|
const name = String(appName || "").replace(/[^A-Za-z0-9 ._-]/g, "");
|
|
636
653
|
if (!name) return false;
|
|
@@ -878,6 +895,10 @@ function openPacket(packetId) {
|
|
|
878
895
|
freshlyForged = Boolean(parsed.claudeFreshlyForged);
|
|
879
896
|
} catch {}
|
|
880
897
|
if (url || skipExternalOpen) {
|
|
898
|
+
// Raise the host so the relay is visible, whichever open path ran (Claude deep
|
|
899
|
+
// link, Codex bridge, or a plain url). This is the fix for "opened in the right
|
|
900
|
+
// host but didn't foreground it".
|
|
901
|
+
activateHost(host);
|
|
881
902
|
if (url && !skipExternalOpen) {
|
|
882
903
|
const webFallback = row && row.taskId ? taskWebUrl(row.taskId) : row && row.actionUrl ? absoluteUrl(row.actionUrl) : webBase();
|
|
883
904
|
if (claudeSessionIdFromUrl(url)) {
|
|
@@ -952,6 +973,7 @@ function openTaskDetail(taskId) {
|
|
|
952
973
|
freshlyForged = Boolean(parsed.claudeFreshlyForged);
|
|
953
974
|
} catch {}
|
|
954
975
|
if (url || skipExternalOpen) {
|
|
976
|
+
activateHost(host); // raise the host so the opened task is visible
|
|
955
977
|
if (url && !skipExternalOpen) {
|
|
956
978
|
if (claudeSessionIdFromUrl(url)) {
|
|
957
979
|
openClaudeDeepLinkVerified(url, taskWebUrl(taskId), taskId, { freshlyForged });
|