@jacobbd/relay-ai 0.3.4 → 0.3.5

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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.5] - 2026-06-26
4
+
5
+ ### Fixed
6
+
7
+ - **Windows: Claude Desktop 3P config now writes to the correct path** — relay-ai was writing the `configLibrary` to `%APPDATA%\Claude-3p` (Roaming) but Claude Desktop reads from `%LOCALAPPDATA%\Claude-3p` (Local). The config is now written to the correct location. Reported by Trojan28A ([#11](https://github.com/jacob-bd/relay-ai/issues/11)).
8
+
9
+ - **Windows: Claude Desktop and Codex App now launch correctly from MSIX installs** — `Start-Process 'shell:AppsFolder\...'` failed silently due to PowerShell backslash double-escaping via `JSON.stringify`. The launcher now uses `cmd /c start` with an argument array, which bypasses PowerShell string parsing entirely and correctly opens MSIX-packaged apps. ([#11](https://github.com/jacob-bd/relay-ai/issues/11)).
10
+
11
+ - **Windows: OpenCode CLI now discovered correctly when `where.exe` returns multiple results** — `where.exe opencode` returns both a bare script and a `.cmd` wrapper. relay-ai was taking the first result (the bare script), which Node's `spawn()` cannot execute directly. relay-ai now prefers the `.cmd` entry. The same fix applies to the `claude`, `codex`, and `gemini` binary lookups. The OpenCode `serve` subprocess also now uses `cmd.exe /c` on Windows to avoid Node 22's DEP0190 deprecation warning. ([#11](https://github.com/jacob-bd/relay-ai/issues/11)).
12
+
3
13
  ## [0.3.4] - 2026-06-23
4
14
 
5
15
  ### Fixed
package/README.md CHANGED
@@ -13,11 +13,16 @@
13
13
 
14
14
  <p align="center">
15
15
  <a href="https://youtu.be/IvsUPHLhX0o">
16
- <img src="assets/demo-part1-thumbnail.png" alt="relay-ai demo — installation, configuration, Claude Code, Claude Cowork & Claude Code Desktop (Part 1)" width="100%">
16
+ <img src="https://img.youtube.com/vi/IvsUPHLhX0o/maxresdefault.jpg" alt="relay-ai demo — installation, configuration, Claude Code, Claude Cowork & Claude Code Desktop (Part 1)" width="49%">
17
+ </a>
18
+ <a href="https://youtu.be/42oiOB8IAu4">
19
+ <img src="https://img.youtube.com/vi/42oiOB8IAu4/maxresdefault.jpg" alt="relay-ai demo — OpenAI Codex CLI & Codex Desktop App (Part 2)" width="49%">
17
20
  </a>
18
21
  </p>
19
22
 
20
- > **Demo (Part 1):** Installation · Configuration · Claude Code · Claude Cowork · Claude Code Desktop — [watch on YouTube](https://youtu.be/IvsUPHLhX0o)
23
+ > 🎥 **Watch the Demos:**
24
+ > - **Demo (Part 1):** Installation · Configuration · Claude Code · Claude Cowork & Claude Code Desktop — [watch on YouTube](https://youtu.be/IvsUPHLhX0o)
25
+ > - **Demo (Part 2):** OpenAI Codex CLI & Codex Desktop App — [watch on YouTube](https://youtu.be/42oiOB8IAu4)
21
26
 
22
27
  **relay-ai** is an interactive CLI that launches AI coding tools and runs local API gateways on your machine. Currently, it supports **Claude Code**, **Claude Desktop (Cowork + Code)**, the **OpenAI Codex CLI**, the **Codex desktop app (macOS + Windows)**, and the **Google Gemini CLI**.
23
28
 
@@ -44,8 +49,6 @@ Pick your backend:
44
49
  | `relay-ai gemini` | Launch Google Gemini CLI with registry providers |
45
50
  | `relay-ai --ai` | Full agent reference for scripts and alef-agent ([guide](docs/AI-AGENTS.md)) |
46
51
 
47
- Bare `relay-ai` prints help and migration guidance. Use `relay-ai claude` for the wizard.
48
-
49
52
  ## Features
50
53
 
51
54
  - **Native provider registry:** `relay-ai providers` stores config in `~/.relay-ai/providers.json` and secrets in the OS keychain — no OpenCode binary required at launch. See **[docs/PROVIDERS.md](docs/PROVIDERS.md)** for a full list of providers and known issues.
@@ -78,7 +81,7 @@ Bare `relay-ai` prints help and migration guidance. Use `relay-ai claude` for th
78
81
  | Claude Desktop (Cowork + Code) | `relay-ai claude-app` | ✅ Supported macOS + Windows ([guide](docs/CLAUDE_DESKTOP_SETUP.md)) |
79
82
  | Codex CLI | `relay-ai codex` | ✅ Supported ([guide](docs/CODEX.md)) |
80
83
  | Codex desktop app | `relay-ai codex-app` | ✅ Supported macOS + Windows ([guide](docs/CODEX.md)) |
81
- | Google Gemini CLI | `relay-ai gemini` | Supported |
84
+ | Google Gemini CLI | `relay-ai gemini` | ⚠️ Experimental, model switching is done via .model prompt |
82
85
 
83
86
  ## Prerequisites
84
87
 
package/dist/cli.js CHANGED
@@ -35,7 +35,7 @@ import { join } from "path";
35
35
  // package.json
36
36
  var package_default = {
37
37
  name: "@jacobbd/relay-ai",
38
- version: "0.3.4",
38
+ version: "0.3.5",
39
39
  publishConfig: {
40
40
  access: "public"
41
41
  },
@@ -1154,7 +1154,8 @@ function findClaudeBinary() {
1154
1154
  encoding: "utf8",
1155
1155
  stdio: ["pipe", "pipe", "pipe"]
1156
1156
  });
1157
- const path = result.trim().split("\n")[0].trim();
1157
+ const lines = result.trim().split("\n").map((l) => l.trim()).filter(Boolean);
1158
+ const path = (isWindows ? lines.find((l) => l.toLowerCase().endsWith(".cmd")) : null) ?? lines[0];
1158
1159
  if (path) return path;
1159
1160
  } catch {
1160
1161
  }
@@ -3281,7 +3282,8 @@ function findOpencodeBinary() {
3281
3282
  encoding: "utf8",
3282
3283
  stdio: ["pipe", "pipe", "pipe"]
3283
3284
  });
3284
- const path = result.trim().split("\n")[0].trim();
3285
+ const lines = result.trim().split("\n").map((l) => l.trim()).filter(Boolean);
3286
+ const path = (isWindows2 ? lines.find((l) => l.toLowerCase().endsWith(".cmd")) : null) ?? lines[0];
3285
3287
  if (path) return path;
3286
3288
  } catch {
3287
3289
  }
@@ -3311,9 +3313,7 @@ async function fetchRawOpencodeProviders() {
3311
3313
  finish(null);
3312
3314
  }, TIMEOUT_MS);
3313
3315
  try {
3314
- child = spawn2(binary, ["serve", "--port", "0"], {
3315
- stdio: ["pipe", "pipe", "pipe"]
3316
- });
3316
+ child = isWindows2 ? spawn2("cmd.exe", ["/c", binary, "serve", "--port", "0"], { stdio: ["pipe", "pipe", "pipe"] }) : spawn2(binary, ["serve", "--port", "0"], { stdio: ["pipe", "pipe", "pipe"] });
3317
3317
  } catch {
3318
3318
  finish(null);
3319
3319
  return;
@@ -10558,7 +10558,8 @@ function findCodexBinary() {
10558
10558
  encoding: "utf8",
10559
10559
  stdio: ["pipe", "pipe", "pipe"]
10560
10560
  });
10561
- const path = result.trim().split("\n")[0]?.trim();
10561
+ const lines = result.trim().split("\n").map((l) => l.trim()).filter(Boolean);
10562
+ const path = (isWindows3 ? lines.find((l) => l.toLowerCase().endsWith(".cmd")) : null) ?? lines[0];
10562
10563
  if (path) return path;
10563
10564
  } catch {
10564
10565
  }
@@ -11566,7 +11567,8 @@ function findGeminiBinary() {
11566
11567
  encoding: "utf8",
11567
11568
  stdio: ["pipe", "pipe", "pipe"]
11568
11569
  });
11569
- const path = result.trim().split("\n")[0]?.trim();
11570
+ const lines = result.trim().split("\n").map((l) => l.trim()).filter(Boolean);
11571
+ const path = (isWindows4 ? lines.find((l) => l.toLowerCase().endsWith(".cmd")) : null) ?? lines[0];
11570
11572
  if (path) return path;
11571
11573
  } catch {
11572
11574
  }
@@ -12930,7 +12932,7 @@ function waitForShutdown2() {
12930
12932
  }
12931
12933
 
12932
12934
  // src/codex/app-launch.ts
12933
- import { execSync as execSync5 } from "child_process";
12935
+ import { execSync as execSync5, spawn as spawn6 } from "child_process";
12934
12936
  import { existsSync as existsSync16, readdirSync as readdirSync3, statSync as statSync4 } from "fs";
12935
12937
  import { homedir as homedir11 } from "os";
12936
12938
  import { join as join17 } from "path";
@@ -13073,7 +13075,7 @@ function openCodexAppAt(path) {
13073
13075
  }
13074
13076
  if (process.platform === "win32") {
13075
13077
  if (path.startsWith("shell:AppsFolder\\")) {
13076
- runPowerShell(`Start-Process '${path.replace(/'/g, "''")}'`);
13078
+ spawn6("cmd.exe", ["/c", "start", "", path], { stdio: "ignore", detached: true }).unref();
13077
13079
  } else {
13078
13080
  runPowerShell(`Start-Process -FilePath '${path.replace(/'/g, "''")}'`);
13079
13081
  }
@@ -13628,7 +13630,7 @@ import { join as join18, dirname as dirname7 } from "path";
13628
13630
  import { randomUUID as randomUUID3 } from "crypto";
13629
13631
  function getClaudeDesktopHome() {
13630
13632
  if (process.platform === "win32") {
13631
- return join18(process.env.APPDATA || join18(homedir12(), "AppData", "Roaming"), "Claude-3p");
13633
+ return join18(process.env.LOCALAPPDATA || join18(homedir12(), "AppData", "Local"), "Claude-3p");
13632
13634
  }
13633
13635
  return join18(homedir12(), "Library", "Application Support", "Claude-3p");
13634
13636
  }
@@ -13789,7 +13791,7 @@ function setupExitCleanup(uuid) {
13789
13791
  }
13790
13792
 
13791
13793
  // src/claude-desktop/app-launch.ts
13792
- import { execSync as execSync6 } from "child_process";
13794
+ import { execSync as execSync6, spawn as spawn7 } from "child_process";
13793
13795
  import { existsSync as existsSync19, readdirSync as readdirSync4, statSync as statSync5 } from "fs";
13794
13796
  import { homedir as homedir13 } from "os";
13795
13797
  import { join as join20 } from "path";
@@ -13928,7 +13930,7 @@ function openClaudeAppAt(path) {
13928
13930
  }
13929
13931
  if (process.platform === "win32") {
13930
13932
  if (path.startsWith("shell:AppsFolder\\")) {
13931
- runPowerShell2(`Start-Process '${path.replace(/'/g, "''")}'`);
13933
+ spawn7("cmd.exe", ["/c", "start", "", path], { stdio: "ignore", detached: true }).unref();
13932
13934
  } else {
13933
13935
  runPowerShell2(`Start-Process -FilePath '${path.replace(/'/g, "''")}'`);
13934
13936
  }
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jacobbd/relay-ai",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -1,165 +0,0 @@
1
- {
2
- "data": [
3
- {
4
- "id": "grok-4.20-0309-non-reasoning",
5
- "aliases": [
6
- "grok-4.20-non-reasoning",
7
- "grok-4.20-non-reasoning-latest",
8
- "grok-4.20-beta-non-reasoning",
9
- "grok-4.20-beta-latest-non-reasoning",
10
- "grok-4.20-experimental-beta-0304-non-reasoning",
11
- "grok-4.20-experimental-beta-non-reasoning-latest",
12
- "grok-4.20-beta-0309-non-reasoning",
13
- "grok-4.20-non-reasoning-gv2"
14
- ],
15
- "context_length": 1000000,
16
- "created": 1773014400,
17
- "object": "model",
18
- "owned_by": "xai",
19
- "prompt_text_token_price": 12500,
20
- "cached_prompt_text_token_price": 2000,
21
- "prompt_image_token_price": 12500,
22
- "completion_text_token_price": 25000,
23
- "prompt_text_token_price_long_context": 25000,
24
- "cached_prompt_text_token_price_long_context": 4000,
25
- "completion_text_token_price_long_context": 50000,
26
- "long_context_threshold": 200000
27
- },
28
- {
29
- "id": "grok-4.20-0309-reasoning",
30
- "aliases": [
31
- "grok-4.20-reasoning-latest",
32
- "grok-4.20",
33
- "grok-4.20-reasoning",
34
- "grok-4.20-0309",
35
- "grok-4.20-beta-0309-reasoning",
36
- "grok-4.20-beta",
37
- "grok-4.20-beta-0309",
38
- "grok-4.20-beta-latest",
39
- "grok-4.20-beta-latest-reasoning",
40
- "grok-4.20-beta-reasoning",
41
- "grok-4.20-experimental-beta-0304-reasoning",
42
- "grok-4.20-experimental-beta-0304",
43
- "grok-4.20-experimental-beta-reasoning-latest",
44
- "grok-4.20-experimental-beta-latest",
45
- "grok-4.20-reasoning-gv2"
46
- ],
47
- "context_length": 1000000,
48
- "created": 1773014400,
49
- "object": "model",
50
- "owned_by": "xai",
51
- "prompt_text_token_price": 12500,
52
- "cached_prompt_text_token_price": 2000,
53
- "prompt_image_token_price": 12500,
54
- "completion_text_token_price": 25000,
55
- "prompt_text_token_price_long_context": 25000,
56
- "cached_prompt_text_token_price_long_context": 4000,
57
- "completion_text_token_price_long_context": 50000,
58
- "long_context_threshold": 200000
59
- },
60
- {
61
- "id": "grok-4.20-multi-agent-0309",
62
- "aliases": [
63
- "grok-4.20-multi-agent",
64
- "grok-4.20-multi-agent-latest",
65
- "grok-4.20-multi-agent-beta-latest",
66
- "grok-4.20-multi-agent-experimental-beta-0304",
67
- "grok-4.20-multi-agent-experimental-beta-latest",
68
- "grok-4.20-multi-agent-beta-0309"
69
- ],
70
- "context_length": 1000000,
71
- "created": 1773014400,
72
- "object": "model",
73
- "owned_by": "xai",
74
- "prompt_text_token_price": 12500,
75
- "cached_prompt_text_token_price": 2000,
76
- "prompt_image_token_price": 12500,
77
- "completion_text_token_price": 25000,
78
- "prompt_text_token_price_long_context": 25000,
79
- "cached_prompt_text_token_price_long_context": 4000,
80
- "completion_text_token_price_long_context": 50000,
81
- "long_context_threshold": 200000
82
- },
83
- {
84
- "id": "grok-4.3",
85
- "aliases": [
86
- "grok-4.3-latest",
87
- "grok-latest"
88
- ],
89
- "context_length": 1000000,
90
- "created": 1776384000,
91
- "object": "model",
92
- "owned_by": "xai",
93
- "prompt_text_token_price": 12500,
94
- "cached_prompt_text_token_price": 2000,
95
- "prompt_image_token_price": 12500,
96
- "completion_text_token_price": 25000,
97
- "prompt_text_token_price_long_context": 25000,
98
- "cached_prompt_text_token_price_long_context": 4000,
99
- "completion_text_token_price_long_context": 50000,
100
- "long_context_threshold": 200000
101
- },
102
- {
103
- "id": "grok-build-0.1",
104
- "aliases": [
105
- "grok-code-fast-1",
106
- "grok-code-fast",
107
- "grok-code-fast-1-0825"
108
- ],
109
- "context_length": 256000,
110
- "created": 1776297600,
111
- "object": "model",
112
- "owned_by": "xai",
113
- "prompt_text_token_price": 10000,
114
- "cached_prompt_text_token_price": 2000,
115
- "prompt_image_token_price": 10000,
116
- "completion_text_token_price": 20000,
117
- "prompt_text_token_price_long_context": 20000,
118
- "cached_prompt_text_token_price_long_context": 4000,
119
- "completion_text_token_price_long_context": 40000,
120
- "long_context_threshold": 200000
121
- },
122
- {
123
- "id": "grok-imagine-image",
124
- "aliases": [
125
- "grok-imagine-image-2026-03-02"
126
- ],
127
- "context_length": 8000,
128
- "created": 1769558400,
129
- "object": "model",
130
- "owned_by": "xai",
131
- "image_price": 200000000
132
- },
133
- {
134
- "id": "grok-imagine-image-quality",
135
- "aliases": [
136
- "grok-imagine-image-quality-20260403",
137
- "grok-imagine-image-quality-latest",
138
- "grok-imagine-image-pro"
139
- ],
140
- "context_length": 8000,
141
- "created": 1775174400,
142
- "object": "model",
143
- "owned_by": "xai",
144
- "image_price": 500000000
145
- },
146
- {
147
- "id": "grok-imagine-video",
148
- "aliases": [],
149
- "created": 1769558400,
150
- "object": "model",
151
- "owned_by": "xai"
152
- },
153
- {
154
- "id": "grok-imagine-video-1.5",
155
- "aliases": [
156
- "grok-imagine-video-1.5-preview",
157
- "grok-imagine-video-1.5-2026-05-30"
158
- ],
159
- "created": 1779840000,
160
- "object": "model",
161
- "owned_by": "xai"
162
- }
163
- ],
164
- "object": "list"
165
- }
Binary file