codex-grok-bridge 1.0.4 → 1.5.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/CHANGELOG.md ADDED
@@ -0,0 +1,45 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ## 1.5.0 — 2026-09-12
6
+
7
+ First cut that accepts **Windows** (`"os": ["darwin", "linux", "win32"]`).
8
+
9
+ - Isolated win32 wrapper under `%LOCALAPPDATA%\codex-grok-bridge`. Never writes WindowsApps.
10
+ - Launch reads a Store ChatGPT / `resources/codex.exe` pointer when the isolated copies are missing.
11
+ - Grok 4.7 drop prep: any `grok-*` id uses the Grok provider. Extra catalog slugs via `GROK_BRIDGE_MODELS`.
12
+ - UTM Windows 11 ARM64 guest: Node 22.23.2, `node --test` 157/0/3 on 1.5.0, official ChatGPT ARM64 MSIX `OpenAI.Codex_26.903.8094.0`, bundled CLI `codex-cli 0.153.4`, grok 1.0.25, loopback `/v1/models` 200. See `docs/windows-arm64-guest.md`.
13
+
14
+ Install: `npm install -g codex-grok-bridge@1.5.0`
15
+
16
+ ## 1.0.5 — 2026-09-12
17
+
18
+ First npm cut that accepts **Linux** (`"os": ["darwin", "linux"]`). Windows stays rejected.
19
+
20
+ - Input field allowlist for Grok Responses (`#10`) — drops `internal_*` and other fields Grok rejects.
21
+ - Collapse `anyOf` / `oneOf` tool-parameter roots to a plain object (`#12`) — unblocks Linux GUI `invalid_client_tool_schema` 400s.
22
+ - Linux desktop wrapper (`#11`) — `~/.local/share/codex-grok-bridge/app` plus a user `.desktop` file. Does not patch `/usr/lib/chatgpt`.
23
+ - Docs: test gate **150/150**, coverage 97.30 / 87.70 / 90.57, Grok CLI verified **1.0.25**.
24
+
25
+ Install: `npm install -g codex-grok-bridge@1.0.5`
26
+
27
+ ## 1.0.4 — 2026-09-09
28
+
29
+ English and Korean README aligned. macOS-only npm package.
30
+
31
+ ## 1.0.3 — 2026-09-09
32
+
33
+ See GitHub release `v1.0.3`.
34
+
35
+ ## 1.0.2 — 2026-09-09
36
+
37
+ See GitHub release `v1.0.2`.
38
+
39
+ ## 1.0.1 — 2026-09-09
40
+
41
+ See GitHub release `v1.0.1`.
42
+
43
+ ## 1.0.0 — 2026-09-09
44
+
45
+ Initial publish. macOS only.
package/README.md CHANGED
@@ -4,10 +4,6 @@ Run **Grok 4.6 as the model inside Codex**. Codex still owns tools, permissions,
4
4
  history and MCP. Inference uses the installed `grok` CLI login session — not an
5
5
  xAI API key.
6
6
 
7
- Codex 안에서 **Grok 4.6**을 모델로 씁니다. 도구·권한·히스토리·MCP는 Codex가
8
- 그대로 가집니다. 추론은 설치된 `grok` CLI의 로그인 세션으로 하며 `XAI_API_KEY`는
9
- 쓰지 않습니다.
10
-
11
7
  ```
12
8
  Codex UI/CLI → app-server → scripts/codex-wrapper.mjs (adds grok-4.6 to the model list)
13
9
  → localhost /v1/responses (the bridge)
@@ -15,16 +11,13 @@ Codex UI/CLI → app-server → scripts/codex-wrapper.mjs (adds grok-4.6 to the
15
11
  → Codex executes every tool call; results return as the next input
16
12
  ```
17
13
 
18
- The published package is **macOS-only** (`"os": ["darwin"]`). Linux and Windows
19
- installs are rejected by npm.
14
+ The published npm package installs on **macOS, Linux, and Windows** (`"os":
15
+ ["darwin", "linux", "win32"]`) starting at 1.5.0. Official ChatGPT/Codex
16
+ prefixes stay untouched; `scripts/install-codex-grok-app.sh` and
17
+ `scripts/install-codex-grok-app.ps1` write a separate wrapper.
20
18
 
21
- 게시된 패키지는 **macOS 전용**입니다(`"os": ["darwin"]`). Linux·Windows는 npm이
22
- 설치를 거절합니다.
23
19
 
24
20
  ---
25
-
26
- # English
27
-
28
21
  ## What this is
29
22
 
30
23
  A local bridge that puts Grok 4.6 on Codex’s model list and sends Codex
@@ -36,25 +29,27 @@ The bridge does **not** execute Grok-native tools. It translates Codex tools int
36
29
  function calling, streams the upstream Responses events, and rewrites names back
37
30
  so Codex still recognizes them.
38
31
 
39
- Thirteen files under `src/`. Zero runtime dependencies. Node.js ≥ 22.
32
+ Fourteen files under `src/`. Zero runtime dependencies. Node.js ≥ 22.
40
33
 
41
- This is not a second-opinion review product, not a Grok 4.7 adapter, and not a
42
- Grok-native search product. If Codex exposes a web-search tool, Grok can call
34
+ This is not a second-opinion review product and not a Grok-native search
35
+ product. New Grok ids, including 4.7 when the CLI lists them, use the same
36
+ `grok-*` route. Set `GROK_BRIDGE_MODELS=grok-4.7` to show extras in the catalog
37
+ before they are the default. If Codex exposes a web-search tool, Grok can call
43
38
  that tool the same way it calls any other Codex tool.
44
39
 
45
40
  ## Requirements
46
41
 
47
- - macOS
42
+ - macOS, Linux, or Windows 11 with the official ChatGPT/Codex desktop package
48
43
  - Node.js ≥ 22
49
- - `/Applications/Codex.app`
50
- - `grok` CLI at `~/.grok/bin/grok`
44
+ - `/Applications/Codex.app` (macOS), `/usr/lib/chatgpt/ChatGPT` (Linux), or the official ChatGPT MSIX (Windows)
45
+ - `grok` CLI at `~/.grok/bin/grok` (Windows: `%USERPROFILE%\.grok\bin\grok.exe`)
51
46
  - a completed `grok login`
52
47
 
53
48
  The `.command` launcher resolves paths from its own location, so moving the
54
49
  folder does not require edits. Set `NODE=/path/to/node` if `node` is not on
55
50
  `PATH`.
56
51
 
57
- Verified against: Codex 0.153.4 / app 26.901.51231, Grok CLI 1.0.24, Node 22.23.0.
52
+ Verified against: Codex 0.153.4 / app 26.901.51231, Grok CLI 1.0.25, Node 22.23.0.
58
53
  An app update that changes `CODEX_CLI_PATH` or the app-server protocol needs
59
54
  re-verification.
60
55
 
@@ -63,7 +58,7 @@ re-verification.
63
58
  ### Terminal (npm)
64
59
 
65
60
  ```sh
66
- npm install -g codex-grok-bridge # macOS, Node ≥ 22
61
+ npm install -g codex-grok-bridge # macOS, Linux, or Windows; Node ≥ 22
67
62
  codex-grok # launches Codex with Grok 4.6 available
68
63
  codex-grok exec --skip-git-repo-check --sandbox workspace-write 'your task'
69
64
  ```
@@ -76,15 +71,18 @@ starts, and tears the provider down with that process.
76
71
  ```sh
77
72
  git clone https://github.com/deximple/codex-grok-bridge.git
78
73
  cd codex-grok-bridge
79
- npm test # 132 tests, no network, no inference
74
+ npm test # 160 tests, no network, no inference
80
75
  node scripts/codex-grok.mjs
81
76
  ```
82
77
 
83
78
  ### Desktop
84
79
 
85
80
  Double-click **Open Codex with Grok.command** in this folder, or keep a
86
- **separate** `Codex Grok.app` in sync with
81
+ **separate** desktop wrapper in sync with
87
82
  `scripts/install-codex-grok-app.sh` (see [Desktop install and update](#desktop-install-and-update)).
83
+ On Linux that wrapper is `~/.local/share/codex-grok-bridge/app` plus a user
84
+ `.desktop` entry; the stock `/usr/lib/chatgpt` tree is not patched. On Windows
85
+ it is `%LOCALAPPDATA%\codex-grok-bridge`; `WindowsApps` is never written.
88
86
 
89
87
  In the new Codex window, **select Grok 4.6 / xAI before starting a new
90
88
  thread**. Existing GPT models stay on the list. A Codex window that was already
@@ -95,9 +93,9 @@ The dedicated window stores UI data under
95
93
  for account, threads and settings. Work and setting changes can show up in other
96
94
  Codex windows.
97
95
 
98
- The installer never writes the stock Codex.app bundle, its signature,
99
- `~/.codex/config.toml`, or Grok auth files. It does not register a launch
100
- agent or a global environment variable.
96
+ The installer never writes the stock Codex.app bundle, `/usr/lib/chatgpt`,
97
+ their signatures, `~/.codex/config.toml`, or Grok auth files. It does not
98
+ register a launch agent or a global environment variable.
101
99
 
102
100
  Stop by closing the Codex window this extension opened. Ordinary Codex still
103
101
  launches from its usual icon.
@@ -163,7 +161,10 @@ not read Codex’s `imagegen` skill and do not send the picture to OpenAI.
163
161
  Plain-text summaries on Codex `reasoning` items are forwarded. Encrypted
164
162
  `encrypted_content` and Codex’s own item ids are stripped. This is so a
165
163
  multi-call turn can continue its own reasoning. The upstream has been observed
166
- to accept this shape.
164
+ to accept this shape. The same pass keeps only the fields Grok’s Responses
165
+ input accepts on each item and content part — `status`, unknown Codex keys,
166
+ and every `internal_*` field are dropped so a new client field cannot 422 the
167
+ upstream.
167
168
 
168
169
  ### Concurrency
169
170
 
@@ -279,13 +280,14 @@ Start here when something breaks. Do not open `~/.grok/auth.json` or
279
280
  | `GROK_BRIDGE_TRANSPORT=fetch` | Use Node `fetch` instead of `node:http(s)` |
280
281
  | `GROK_BRIDGE_INFERENCE=cli` | Fall back to the CLI envelope path |
281
282
  | `GROK_BRIDGE_DIAGNOSTICS=off` | Do not write the JSONL log |
283
+ | `GROK_BRIDGE_MODELS` | Extra `grok-*` catalog ids (comma or space), e.g. `grok-4.7` |
282
284
  | `NODE` | Absolute `node` binary for the `.command` launcher / desktop scripts |
283
- | `CODEX_GROK_APP` | Alternate app bundle path for `install-codex-grok-app.sh` (default `/Applications/Codex Grok.app`) |
285
+ | `CODEX_GROK_APP` | Alternate app path for the desktop installer (macOS: `/Applications/Codex Grok.app`; Linux: `~/.local/share/codex-grok-bridge/app`; Windows: `%LOCALAPPDATA%\codex-grok-bridge\app`) |
284
286
 
285
287
  ## Verify
286
288
 
287
289
  ```sh
288
- npm test # 132 tests, no remote inference
290
+ npm test # 160 tests, no remote inference
289
291
  npm run test:coverage # 80% line / branch / function gate
290
292
  npm run verify:app-server # real app-server routing; also runs against an installed bundle
291
293
  npm audit --omit=dev
@@ -299,7 +301,8 @@ inference. A live CLI check spends the user’s quota.
299
301
 
300
302
  ```sh
301
303
  sh scripts/install-codex-grok-app.sh # sync bridge JS only (default)
302
- sh scripts/install-codex-grok-app.sh --full # also rebuild and sign the launcher applet
304
+ sh scripts/install-codex-grok-app.sh --full # macOS: rebuild and sign the launcher applet
305
+ powershell -File scripts/install-codex-grok-app.ps1
303
306
  ```
304
307
 
305
308
  The default copies this checkout’s `src/` and `scripts/*.mjs` into the bundle,
@@ -308,8 +311,14 @@ never `rm -rf`s the live bundle. It refuses while a Codex Grok window is open
308
311
  (`--force` to override). ESM is not hot-reloaded: **reopen the window** after a
309
312
  sync.
310
313
 
311
- The script updates an existing `Codex Grok.app`. It does not create one, and it
312
- does not touch `/Applications/Codex.app`.
314
+ On macOS the script updates an existing `Codex Grok.app`. It does not create
315
+ one, and it does not touch `/Applications/Codex.app`. On Linux it creates
316
+ `~/.local/share/codex-grok-bridge/app` and
317
+ `~/.local/share/applications/codex-grok.desktop`, and it does not write
318
+ `/usr/lib/chatgpt` or `/usr/share/applications/chatgpt.desktop`. On Windows
319
+ `scripts/install-codex-grok-app.ps1` writes
320
+ `%LOCALAPPDATA%\codex-grok-bridge` and may point at a Store `ChatGPT.exe` /
321
+ `resources\codex.exe`; it never writes `WindowsApps`.
313
322
 
314
323
  ## Security notes
315
324
 
@@ -347,24 +356,26 @@ Grok 4.6을 Codex 모델 목록에 넣고, Codex의 `/v1/responses`를
347
356
  calling으로 옮기고, 상류 Responses 스트림을 전달한 뒤, Codex가 알아보는
348
357
  이름으로 되돌립니다.
349
358
 
350
- `src/` 아래 파일 13개. 런타임 의존성 없음. Node.js 22 이상.
359
+ `src/` 아래 파일 14개. 런타임 의존성 없음. Node.js 22 이상. 1.5.0부터 npm
360
+ `"os"`는 `darwin` / `linux` / `win32`입니다.
351
361
 
352
- 코드 리뷰 전용 제품이 아니고, Grok 4.7 어댑터도 아니며, Grok 네이티브 검색
353
- 제품도 아닙니다. Codex가 웹 검색 도구를 노출하면 Grok은 다른 Codex 도구와 같이
354
- 그 도구를 호출할 수 있습니다.
362
+ 코드 리뷰 전용 제품이 아니고 Grok 네이티브 검색 제품도 아닙니다. CLI가 새
363
+ id(4.7 포함)를 내놓으면 같은 `grok-*` 경로로 붙습니다. 기본 카탈로그에 먼저
364
+ 보이게 하려면 `GROK_BRIDGE_MODELS=grok-4.7`을 씁니다. Codex가 웹 검색 도구를
365
+ 노출하면 Grok은 다른 Codex 도구와 같이 그 도구를 호출할 수 있습니다.
355
366
 
356
367
  ## 필요한 것
357
368
 
358
- - macOS
369
+ - macOS, Linux, 또는 공식 ChatGPT/Codex 데스크톱이 있는 Windows 11
359
370
  - Node.js 22 이상
360
- - `/Applications/Codex.app`
361
- - `~/.grok/bin/grok`
371
+ - `/Applications/Codex.app` (macOS), `/usr/lib/chatgpt/ChatGPT` (Linux), 또는 공식 ChatGPT MSIX (Windows)
372
+ - `~/.grok/bin/grok` (Windows: `%USERPROFILE%\.grok\bin\grok.exe`)
362
373
  - 완료된 `grok login`
363
374
 
364
375
  `.command` 런처는 자기 위치를 기준으로 경로를 잡으므로 폴더를 옮겨도 수정할
365
376
  필요가 없습니다. `PATH`에 `node`가 없으면 `NODE=/path/to/node`로 지정합니다.
366
377
 
367
- 검증 버전: Codex 0.153.4 / 앱 26.901.51231, Grok CLI 1.0.24, Node 22.23.0.
378
+ 검증 버전: Codex 0.153.4 / 앱 26.901.51231, Grok CLI 1.0.25, Node 22.23.0.
368
379
  앱 업데이트가 `CODEX_CLI_PATH`나 app-server 프로토콜을 바꾸면 재검증이
369
380
  필요합니다.
370
381
 
@@ -373,7 +384,7 @@ calling으로 옮기고, 상류 Responses 스트림을 전달한 뒤, Codex가
373
384
  ### 터미널 (npm)
374
385
 
375
386
  ```sh
376
- npm install -g codex-grok-bridge # macOS, Node ≥ 22
387
+ npm install -g codex-grok-bridge # macOS, Linux, Windows; Node ≥ 22
377
388
  codex-grok # Grok 4.6이 있는 Codex를 띄움
378
389
  codex-grok exec --skip-git-repo-check --sandbox workspace-write '작업 내용'
379
390
  ```
@@ -386,15 +397,18 @@ codex-grok exec --skip-git-repo-check --sandbox workspace-write '작업 내용'
386
397
  ```sh
387
398
  git clone https://github.com/deximple/codex-grok-bridge.git
388
399
  cd codex-grok-bridge
389
- npm test # 132건, 네트워크·추론 없음
400
+ npm test # 160건, 네트워크·추론 없음
390
401
  node scripts/codex-grok.mjs
391
402
  ```
392
403
 
393
404
  ### 데스크톱
394
405
 
395
406
  이 폴더의 **Open Codex with Grok.command**를 더블 클릭하거나,
396
- `scripts/install-codex-grok-app.sh`로 **별도의** `Codex Grok.app`을 체크아웃과
407
+ `scripts/install-codex-grok-app.sh`로 **별도의** 데스크톱 래퍼를 체크아웃과
397
408
  맞춥니다([데스크톱 설치와 갱신](#데스크톱-설치와-갱신)).
409
+ Linux에서는 `~/.local/share/codex-grok-bridge/app`과 사용자 `.desktop`이고,
410
+ 정품 `/usr/lib/chatgpt`는 패치하지 않습니다. Windows에서는
411
+ `%LOCALAPPDATA%\codex-grok-bridge`이고 `WindowsApps`는 쓰지 않습니다.
398
412
 
399
413
  새로 열린 Codex 창에서 **새 작업을 시작하기 전에 Grok 4.6 / xAI를 선택**하세요.
400
414
  기존 GPT 모델도 목록에 남습니다. 이미 열려 있던 일반 Codex 창에는 이 확장이
@@ -404,9 +418,9 @@ node scripts/codex-grok.mjs
404
418
  계정·작업·설정은 기존 Codex 홈을 **공유**합니다. 작업 내용과 설정 변경은 다른
405
419
  Codex 창에도 보일 수 있습니다.
406
420
 
407
- 설치 스크립트는 정품 Codex.app 번들, 코드 서명, `~/.codex/config.toml`, Grok
408
- 인증 파일을 수정하지 않습니다. 자동 시작 서비스나 전역 환경변수도 등록하지
409
- 않습니다.
421
+ 설치 스크립트는 정품 Codex.app 번들, `/usr/lib/chatgpt`, 코드 서명,
422
+ `~/.codex/config.toml`, Grok 인증 파일을 수정하지 않습니다. 자동 시작
423
+ 서비스나 전역 환경변수도 등록하지 않습니다.
410
424
 
411
425
  중지하려면 이 확장으로 연 Codex 창을 닫으면 됩니다. 일반 Codex는 기존 아이콘으로
412
426
  실행합니다.
@@ -468,7 +482,9 @@ OpenAI로 보내지 말라는 뜻입니다. `GROK_BRIDGE_IMAGE_GEN=off`면 도
468
482
  Codex `reasoning` 항목의 평문 요약은 상류로 전달합니다. 암호화된
469
483
  `encrypted_content`와 Codex 자체 아이템 id는 제거합니다. 여러 번 호출이 이어지는
470
484
  턴에서 모델이 자기 추론을 이어받게 하기 위한 것이며, 상류가 이 형태를 수락하는
471
- 것을 확인했습니다.
485
+ 것을 확인했습니다. 같은 과정에서 아이템과 content part는 Grok Responses가
486
+ 받는 필드만 남깁니다. `status`, 알 수 없는 Codex 키, `internal_*` 필드는
487
+ 버려서 새 클라이언트 필드가 상류 422를 내지 않게 합니다.
472
488
 
473
489
  ### 동시성
474
490
 
@@ -579,13 +595,14 @@ provider에 Codex `request_max_retries` / `stream_max_retries`를 2로 두어
579
595
  | `GROK_BRIDGE_TRANSPORT=fetch` | `node:http(s)` 대신 Node `fetch` |
580
596
  | `GROK_BRIDGE_INFERENCE=cli` | CLI 봉투 경로로 폴백 |
581
597
  | `GROK_BRIDGE_DIAGNOSTICS=off` | JSONL 로그를 쓰지 않음 |
598
+ | `GROK_BRIDGE_MODELS` | 카탈로그에 더할 `grok-*` id (쉼표/공백). 예: `grok-4.7` |
582
599
  | `NODE` | `.command` / 데스크톱 스크립트가 쓸 `node` 절대 경로 |
583
- | `CODEX_GROK_APP` | `install-codex-grok-app.sh`가 쓸 앱 번들 경로 (기본 `/Applications/Codex Grok.app`) |
600
+ | `CODEX_GROK_APP` | 데스크톱 설치기가 쓸 앱 경로 (macOS: `/Applications/Codex Grok.app`; Linux: `~/.local/share/codex-grok-bridge/app`; Windows: `%LOCALAPPDATA%\codex-grok-bridge\app`) |
584
601
 
585
602
  ## 검증
586
603
 
587
604
  ```sh
588
- npm test # 132건, 외부 추론 없음
605
+ npm test # 160건, 외부 추론 없음
589
606
  npm run test:coverage # line/branch/function 80% 게이트
590
607
  npm run verify:app-server # 실제 app-server 라우팅. 설치된 앱 번들에서도 실행
591
608
  npm audit --omit=dev
@@ -599,7 +616,8 @@ CLI 검증은 사용자 계정 사용량을 씁니다.
599
616
 
600
617
  ```sh
601
618
  sh scripts/install-codex-grok-app.sh # 브리지 JS만 동기화 (기본)
602
- sh scripts/install-codex-grok-app.sh --full # 런처 applet 재빌드 + 서명
619
+ sh scripts/install-codex-grok-app.sh --full # macOS: 런처 applet 재빌드 + 서명
620
+ powershell -File scripts/install-codex-grok-app.ps1
603
621
  ```
604
622
 
605
623
  기본 동작은 이 체크아웃의 `src/`와 `scripts/*.mjs`를 번들에 복사하고, 저장소에
@@ -607,8 +625,13 @@ sh scripts/install-codex-grok-app.sh --full # 런처 applet 재빌드 + 서명
607
625
  `rm -rf`하지 않습니다. Codex Grok 창이 열려 있으면 거부합니다(`--force`로
608
626
  무시). ESM은 핫리로드되지 않으므로 **동기화 후 창을 다시 열어야** 합니다.
609
627
 
610
- 이 스크립트는 이미 있는 `Codex Grok.app`을 갱신합니다. 번들을 새로 만들지
611
- 않고, `/Applications/Codex.app`은 건드리지 않습니다.
628
+ macOS에서는 이미 있는 `Codex Grok.app`을 갱신하며 `/Applications/Codex.app`은
629
+ 건드리지 않습니다. Linux에서는 `~/.local/share/codex-grok-bridge/app`과
630
+ `~/.local/share/applications/codex-grok.desktop`을 만들고 `/usr/lib/chatgpt`와
631
+ 정품 `chatgpt.desktop`은 쓰지 않습니다. Windows에서는
632
+ `scripts/install-codex-grok-app.ps1`이 `%LOCALAPPDATA%\codex-grok-bridge`를
633
+ 쓰고 Store `ChatGPT.exe` / `resources\codex.exe`를 가리킬 수 있으며,
634
+ `WindowsApps`는 쓰지 않습니다.
612
635
 
613
636
  ## 보안
614
637
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-grok-bridge",
3
- "version": "1.0.4",
3
+ "version": "1.5.0",
4
4
  "description": "Run Grok 4.6 as the model inside Codex, with Codex still owning tools, permissions, history and MCP. Uses the grok login session, not an API key.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -9,7 +9,9 @@
9
9
  "node": ">=22"
10
10
  },
11
11
  "os": [
12
- "darwin"
12
+ "darwin",
13
+ "linux",
14
+ "win32"
13
15
  ],
14
16
  "bin": {
15
17
  "codex-grok": "scripts/codex-grok.mjs"
@@ -35,9 +37,11 @@
35
37
  "scripts/codex-grok.mjs",
36
38
  "scripts/codex-wrapper.mjs",
37
39
  "scripts/install-codex-grok-app.sh",
40
+ "scripts/install-codex-grok-app.ps1",
38
41
  "scripts/launch-desktop.mjs",
39
42
  "Open Codex with Grok.command",
40
43
  "README.md",
44
+ "CHANGELOG.md",
41
45
  "LICENSE"
42
46
  ],
43
47
  "scripts": {
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawn } from "node:child_process";
3
3
  import { startRuntime } from "../src/runtime.mjs";
4
+ import { resolveCodexBinary } from "../src/paths.mjs";
4
5
  const runtime = await startRuntime();
5
6
  const userArgs = process.argv.slice(2);
6
7
  const overrides = [
@@ -16,7 +17,7 @@ const args =
16
17
  userArgs[0] === "exec"
17
18
  ? [userArgs[0], ...overrides, ...userArgs.slice(1)]
18
19
  : [...overrides, ...userArgs];
19
- const child = spawn("/Applications/Codex.app/Contents/Resources/codex", args, {
20
+ const child = spawn(resolveCodexBinary(), args, {
20
21
  stdio: "inherit",
21
22
  env: { ...process.env, CODEX_GROK_BRIDGE_TOKEN: runtime.token },
22
23
  });
@@ -4,8 +4,9 @@ import { createInterface } from "node:readline";
4
4
  import { randomUUID } from "node:crypto";
5
5
  import { startRuntime } from "../src/runtime.mjs";
6
6
  import { Router } from "../src/router.mjs";
7
+ import { resolveCodexBinary } from "../src/paths.mjs";
7
8
 
8
- const binary = "/Applications/Codex.app/Contents/Resources/codex";
9
+ const binary = resolveCodexBinary();
9
10
  const args = process.argv.slice(2);
10
11
  if (!args.includes("app-server")) {
11
12
  const child = spawn(binary, args, { stdio: "inherit" });
@@ -0,0 +1,67 @@
1
+ # Install or update the dedicated Codex Grok desktop wrapper on Windows.
2
+ # Writes %LOCALAPPDATA%\codex-grok-bridge\app only. Never writes WindowsApps.
3
+ param(
4
+ [switch]$Force
5
+ )
6
+
7
+ $ErrorActionPreference = "Stop"
8
+ $Root = Split-Path -Parent $PSScriptRoot
9
+ $App = if ($env:CODEX_GROK_APP) { $env:CODEX_GROK_APP } else { Join-Path $env:LOCALAPPDATA "codex-grok-bridge\app" }
10
+ $UserData = Join-Path $env:LOCALAPPDATA "codex-grok-bridge\desktop"
11
+
12
+ if ($App -match "(?i)WindowsApps") {
13
+ Write-Error "refusing to install into the stock ChatGPT/Codex prefix: $App"
14
+ }
15
+
16
+ if (-not $Force) {
17
+ $hit = Get-CimInstance Win32_Process -ErrorAction SilentlyContinue |
18
+ Where-Object { $_.CommandLine -and $_.CommandLine -like "*--user-data-dir=$UserData*" }
19
+ if ($hit) {
20
+ Write-Error "Codex Grok is running. Close its window first, or pass -Force."
21
+ }
22
+ }
23
+
24
+ New-Item -ItemType Directory -Force -Path (Join-Path $App "scripts"), (Join-Path $App "src") | Out-Null
25
+ Copy-Item (Join-Path $Root "scripts\*.mjs") (Join-Path $App "scripts") -Force
26
+ Copy-Item (Join-Path $Root "src\*.mjs") (Join-Path $App "src") -Force
27
+
28
+ $Node = if ($env:NODE) { $env:NODE } else { (Get-Command node -ErrorAction Stop).Source }
29
+ $Launcher = Join-Path $App "codex-grok-desktop.cmd"
30
+ @"
31
+ @echo off
32
+ set ROOT=%~dp0
33
+ "$Node" "%ROOT%scripts\launch-desktop.mjs" %*
34
+ "@ | Set-Content -Path $Launcher -Encoding ASCII
35
+
36
+ $StartDir = Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs"
37
+ New-Item -ItemType Directory -Force -Path $StartDir | Out-Null
38
+ Copy-Item $Launcher (Join-Path $StartDir "Codex Grok.cmd") -Force
39
+
40
+ function Write-StorePointer([string]$Name, [string[]]$Filters) {
41
+ $pointerDir = Split-Path -Parent $App
42
+ if ($pointerDir -match "(?i)WindowsApps") { return }
43
+ $pkgs = @(Get-AppxPackage -AllUsers -ErrorAction SilentlyContinue | Where-Object { $_.Name -match "OpenAI\.(ChatGPT|Codex)|ChatGPT" })
44
+ if (-not $pkgs) {
45
+ $pkgs = @(Get-AppxPackage -ErrorAction SilentlyContinue | Where-Object { $_.Name -match "OpenAI\.(ChatGPT|Codex)|ChatGPT" })
46
+ }
47
+ foreach ($filter in $Filters) {
48
+ foreach ($pkg in $pkgs) {
49
+ if (-not $pkg.InstallLocation) { continue }
50
+ $hits = @(Get-ChildItem -Path $pkg.InstallLocation -Filter $filter -Recurse -ErrorAction SilentlyContinue)
51
+ $hit = $hits | Where-Object { $_.FullName -match '\\resources\\codex\.exe$' } | Select-Object -First 1
52
+ if (-not $hit) { $hit = $hits | Select-Object -First 1 }
53
+ if (-not $hit) { continue }
54
+ New-Item -ItemType Directory -Force -Path $pointerDir | Out-Null
55
+ Set-Content -Path (Join-Path $pointerDir $Name) -Value $hit.FullName -Encoding ASCII
56
+ Write-Output "store pointer $Name=$($hit.FullName)"
57
+ return
58
+ }
59
+ }
60
+ }
61
+
62
+ Write-StorePointer "store-app.txt" @("ChatGPT.exe", "Codex.exe")
63
+ Write-StorePointer "store-codex.txt" @("codex.exe")
64
+
65
+ Write-Output "win32 wrapper $Launcher"
66
+ Write-Output "bridge in $App matches $Root"
67
+ Write-Output "restart any open Codex Grok window to load it"
@@ -1,14 +1,13 @@
1
1
  #!/bin/sh
2
- # Install or update the bridge inside /Applications/Codex Grok.app.
2
+ # Install or update the dedicated Codex Grok desktop wrapper.
3
3
  #
4
- # Default is a JS-only sync: the bundle's scripts/ and src/ are brought in line
5
- # with this checkout, in place. The previous version began with `rm -rf` on the
6
- # directory that CODEX_CLI_PATH points into, which destroys a running app's
7
- # entrypoint; nothing here removes a directory, and stale files are pruned one
8
- # by one only when the repo no longer has them.
4
+ # macOS: sync JS into /Applications/Codex Grok.app (must already exist).
5
+ # Linux: create ~/.local/share/codex-grok-bridge/app and a user .desktop.
6
+ # Windows: create %LOCALAPPDATA%\codex-grok-bridge\app and a Start Menu .cmd.
7
+ # Never writes /Applications/Codex.app, /usr/lib/chatgpt, or WindowsApps.
9
8
  #
10
9
  # install-codex-grok-app.sh sync bridge JS (safe, fast)
11
- # install-codex-grok-app.sh --full also rebuild the launcher applet and sign
10
+ # install-codex-grok-app.sh --full macOS: rebuild applet; Linux: rewrite launcher
12
11
  # install-codex-grok-app.sh --force proceed even if a Codex Grok window is open
13
12
  #
14
13
  # ESM is not hot-reloaded: an open Codex Grok window keeps running the code it
@@ -16,11 +15,28 @@
16
15
  set -eu
17
16
 
18
17
  ROOT="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)"
19
- # CODEX_GROK_APP exists so this script can be exercised against a scratch copy
20
- # instead of the installed app.
21
- APP="${CODEX_GROK_APP:-/Applications/Codex Grok.app}"
22
- BRIDGE="$APP/Contents/Resources/bridge"
23
- USER_DATA="$HOME/.local/share/codex-grok-bridge/desktop"
18
+ PLATFORM="${CODEX_GROK_PLATFORM:-$(uname -s)}"
19
+ case "$PLATFORM" in
20
+ Linux|linux) PLATFORM=linux ;;
21
+ Darwin|darwin) PLATFORM=darwin ;;
22
+ MINGW*|MSYS*|CYGWIN*|Windows_NT|win32|windows) PLATFORM=win32 ;;
23
+ esac
24
+ if [ "$PLATFORM" = win32 ]; then
25
+ USER_DATA="${LOCALAPPDATA:-$HOME/AppData/Local}/codex-grok-bridge/desktop"
26
+ else
27
+ USER_DATA="$HOME/.local/share/codex-grok-bridge/desktop"
28
+ fi
29
+
30
+ if [ "$PLATFORM" = linux ]; then
31
+ APP="${CODEX_GROK_APP:-$HOME/.local/share/codex-grok-bridge/app}"
32
+ BRIDGE="$APP"
33
+ elif [ "$PLATFORM" = win32 ]; then
34
+ APP="${CODEX_GROK_APP:-${LOCALAPPDATA:-$HOME/AppData/Local}/codex-grok-bridge/app}"
35
+ BRIDGE="$APP"
36
+ else
37
+ APP="${CODEX_GROK_APP:-/Applications/Codex Grok.app}"
38
+ BRIDGE="$APP/Contents/Resources/bridge"
39
+ fi
24
40
 
25
41
  FULL=0
26
42
  FORCE=0
@@ -33,12 +49,19 @@ for arg in "$@"; do
33
49
  esac
34
50
  done
35
51
 
36
- if [ ! -d "$APP/Contents" ]; then
52
+ case "$APP" in
53
+ /usr/lib/chatgpt|/usr/lib/chatgpt/*|/usr/bin/chatgpt|/Applications/Codex.app|/Applications/Codex.app/*|*WindowsApps*|*windowsapps*)
54
+ echo "refusing to install into the stock ChatGPT/Codex prefix: $APP" >&2
55
+ exit 1
56
+ ;;
57
+ esac
58
+
59
+ if [ "$PLATFORM" != linux ] && [ "$PLATFORM" != win32 ] && [ ! -d "$APP/Contents" ]; then
37
60
  echo "missing $APP" >&2
38
61
  exit 1
39
62
  fi
40
63
 
41
- if [ "$FORCE" -eq 0 ] && pgrep -f -- "--user-data-dir=$USER_DATA" >/dev/null 2>&1; then
64
+ if [ "$FORCE" -eq 0 ] && [ "$PLATFORM" != win32 ] && pgrep -f -- "--user-data-dir=$USER_DATA" >/dev/null 2>&1; then
42
65
  echo "Codex Grok is running. Close its window first, or pass --force to swap" >&2
43
66
  echo "the files under it (the running window keeps its loaded code either way)." >&2
44
67
  exit 1
@@ -71,7 +94,64 @@ for dir in scripts src; do
71
94
  done
72
95
  [ "$status" -eq 0 ] || { echo "bundle did not match the checkout" >&2; exit 1; }
73
96
 
74
- if [ "$FULL" -eq 1 ]; then
97
+ write_linux_wrapper() {
98
+ NODE="${NODE:-$(command -v node || true)}"
99
+ [ -n "$NODE" ] || { echo "no node on PATH; set NODE=/path/to/node" >&2; exit 1; }
100
+ if [ -L "$NODE" ]; then
101
+ NODE="$(python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$NODE")"
102
+ fi
103
+ mkdir -p "$APP/bin"
104
+ LAUNCHER="$APP/bin/codex-grok-desktop"
105
+ NODE_Q=$(printf "%s" "$NODE" | sed "s/'/'\\\\''/g")
106
+ cat > "$LAUNCHER" <<EOF
107
+ #!/bin/sh
108
+ set -eu
109
+ ROOT="\$(CDPATH= cd -- "\$(dirname "\$0")/.." && pwd)"
110
+ exec '$NODE_Q' "\$ROOT/scripts/launch-desktop.mjs" "\$@"
111
+ EOF
112
+ chmod +x "$LAUNCHER"
113
+ APPS_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/applications"
114
+ mkdir -p "$APPS_DIR"
115
+ DESKTOP="$APPS_DIR/codex-grok.desktop"
116
+ cat > "$DESKTOP" <<EOF
117
+ [Desktop Entry]
118
+ Type=Application
119
+ Name=Codex Grok
120
+ Comment=Codex desktop with Grok via the local bridge
121
+ Exec="$LAUNCHER" %U
122
+ Icon=chatgpt
123
+ Terminal=false
124
+ Categories=Development;
125
+ StartupWMClass=ChatGPT
126
+ EOF
127
+ update-desktop-database "$APPS_DIR" >/dev/null 2>&1 || true
128
+ echo "linux wrapper $LAUNCHER"
129
+ echo "desktop entry $DESKTOP"
130
+ }
131
+
132
+ write_win32_wrapper() {
133
+ NODE="${NODE:-$(command -v node || true)}"
134
+ [ -n "$NODE" ] || { echo "no node on PATH; set NODE=/path/to/node" >&2; exit 1; }
135
+ mkdir -p "$APP"
136
+ LAUNCHER="$APP/codex-grok-desktop.cmd"
137
+ NODE_WIN=$(printf "%s" "$NODE" | tr '/' '\\')
138
+ {
139
+ echo "@echo off"
140
+ echo "set ROOT=%~dp0"
141
+ echo "\"$NODE_WIN\" \"%ROOT%scripts\\launch-desktop.mjs\" %*"
142
+ } > "$LAUNCHER"
143
+ START_DIR="${APPDATA:-$HOME/AppData/Roaming}/Microsoft/Windows/Start Menu/Programs"
144
+ mkdir -p "$START_DIR"
145
+ cp "$LAUNCHER" "$START_DIR/Codex Grok.cmd"
146
+ echo "win32 wrapper $LAUNCHER"
147
+ echo "start menu $START_DIR/Codex Grok.cmd"
148
+ }
149
+
150
+ if [ "$PLATFORM" = linux ]; then
151
+ write_linux_wrapper
152
+ elif [ "$PLATFORM" = win32 ]; then
153
+ write_win32_wrapper
154
+ elif [ "$FULL" -eq 1 ]; then
75
155
  NODE="${NODE:-$(command -v node || true)}"
76
156
  [ -n "$NODE" ] || { echo "no node on PATH; set NODE=/path/to/node" >&2; exit 1; }
77
157
  if [ -L "$NODE" ]; then