remodex-windows-fix 1.0.2
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/README.md +183 -0
- package/bin/phodex.js +8 -0
- package/bin/remodex-relay.js +19 -0
- package/bin/remodex.js +44 -0
- package/cloudflare/README.md +16 -0
- package/cloudflare/worker.mjs +221 -0
- package/package.json +48 -0
- package/relay/README.md +39 -0
- package/relay/relay.js +199 -0
- package/render.yaml +10 -0
- package/src/bridge.js +330 -0
- package/src/codex-desktop-refresher.js +338 -0
- package/src/codex-transport.js +277 -0
- package/src/git-handler.js +617 -0
- package/src/index.js +11 -0
- package/src/qr.js +21 -0
- package/src/relay-server.js +61 -0
- package/src/rollout-watch.js +176 -0
- package/src/scripts/codex-refresh.applescript +51 -0
- package/src/session-state.js +57 -0
- package/src/workspace-paths.js +181 -0
- package/wrangler.toml +13 -0
package/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# remodex-windows-fix
|
|
2
|
+
|
|
3
|
+
Windows-friendly mirror of `remodex` with a launcher fix for `codex app-server`.
|
|
4
|
+
|
|
5
|
+
## What Changed
|
|
6
|
+
|
|
7
|
+
- Fixes Windows startup when `remodex up` tries to spawn `codex` and fails with `spawn codex ENOENT`.
|
|
8
|
+
- Prefers `codex.cmd` or `codex.bat` on Windows and runs them with shell support.
|
|
9
|
+
- Falls back to `codex.exe` when a wrapper script is not present.
|
|
10
|
+
- Adds `REMODEX_CODEX_BIN` and `PHODEX_CODEX_BIN` overrides for explicit Codex binary selection.
|
|
11
|
+
- Prevents immediate uncaught startup crashes by routing launcher failures through Remodex error handling.
|
|
12
|
+
|
|
13
|
+
## Why This Exists
|
|
14
|
+
|
|
15
|
+
On Windows, `codex` is often installed through npm as a `.cmd` shim. A plain Node `spawn("codex", ["app-server"])` call can fail even when `codex` works in PowerShell. This fork resolves the executable explicitly before launching the bridge.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
Install from this GitHub repository:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install -g github:needitem/remodex-windows-fix
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Global CLI command:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
remodex-windows-fix
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
Start the bridge:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
remodex-windows-fix up
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Resume the last active thread:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
remodex-windows-fix resume
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Watch rollout output:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
remodex-windows-fix watch [threadId]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Windows Override
|
|
52
|
+
|
|
53
|
+
If you want to force a specific Codex binary, set one of these environment variables before running `remodex up`:
|
|
54
|
+
|
|
55
|
+
```powershell
|
|
56
|
+
$env:REMODEX_CODEX_BIN = "C:\Users\th072\AppData\Roaming\npm\codex.cmd"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Legacy alias:
|
|
60
|
+
|
|
61
|
+
```powershell
|
|
62
|
+
$env:PHODEX_CODEX_BIN = "C:\Users\th072\AppData\Roaming\npm\codex.cmd"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Self-Hosted Relay
|
|
66
|
+
|
|
67
|
+
This repository now includes the upstream-compatible relay code and a local runner.
|
|
68
|
+
|
|
69
|
+
Start your own relay:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm run relay
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Or use the bundled binary directly:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
remodex-relay
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Optional relay host/port overrides:
|
|
82
|
+
|
|
83
|
+
```powershell
|
|
84
|
+
$env:REMODEX_RELAY_HOST = "0.0.0.0"
|
|
85
|
+
$env:REMODEX_RELAY_PORT = "9000"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Point the bridge at your relay:
|
|
89
|
+
|
|
90
|
+
```powershell
|
|
91
|
+
$env:REMODEX_RELAY = "ws://YOUR_HOST:9000/relay"
|
|
92
|
+
remodex up
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
For TLS/reverse-proxy setups, use the public `wss://YOUR_DOMAIN/relay` URL instead.
|
|
96
|
+
|
|
97
|
+
Health endpoint:
|
|
98
|
+
|
|
99
|
+
```text
|
|
100
|
+
GET /health
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Cloudflare Deploy
|
|
104
|
+
|
|
105
|
+
This repository also includes a Cloudflare Workers relay implementation in [cloudflare/worker.mjs](cloudflare/worker.mjs) with Durable Objects configured in [wrangler.toml](wrangler.toml).
|
|
106
|
+
|
|
107
|
+
GitHub itself still does not host persistent WebSocket servers, but Cloudflare Workers can deploy this relay directly from your GitHub repository without running anything locally.
|
|
108
|
+
|
|
109
|
+
Import this repository in Cloudflare:
|
|
110
|
+
|
|
111
|
+
1. Open Cloudflare Workers & Pages.
|
|
112
|
+
2. Create or import a Worker from your GitHub repository.
|
|
113
|
+
3. Use the worker name `remodex-relay` so it matches [wrangler.toml](wrangler.toml).
|
|
114
|
+
4. Deploy the repository as-is.
|
|
115
|
+
5. After deploy, use the public Worker URL as the relay base:
|
|
116
|
+
|
|
117
|
+
```powershell
|
|
118
|
+
$env:REMODEX_RELAY = "wss://YOUR-WORKER.YOUR-SUBDOMAIN.workers.dev/relay"
|
|
119
|
+
remodex-windows-fix up
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Current deployed example for this repository:
|
|
123
|
+
|
|
124
|
+
```powershell
|
|
125
|
+
$env:REMODEX_RELAY = "wss://remodex-relay.th07290828.workers.dev/relay"
|
|
126
|
+
remodex-windows-fix up
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
If you are using `cmd.exe` instead of PowerShell:
|
|
130
|
+
|
|
131
|
+
```cmd
|
|
132
|
+
set REMODEX_RELAY=wss://remodex-relay.th07290828.workers.dev/relay
|
|
133
|
+
remodex-windows-fix up
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Health check:
|
|
137
|
+
|
|
138
|
+
```text
|
|
139
|
+
https://remodex-relay.th07290828.workers.dev/health
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Cloudflare health endpoint:
|
|
143
|
+
|
|
144
|
+
```text
|
|
145
|
+
GET /health
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Alternative GitHub Deploy
|
|
149
|
+
|
|
150
|
+
If you prefer a normal Node web service instead of Workers, this repository still includes the Render-compatible runner in [render.yaml](render.yaml).
|
|
151
|
+
|
|
152
|
+
```powershell
|
|
153
|
+
$env:REMODEX_RELAY = "wss://YOUR-SERVICE.onrender.com/relay"
|
|
154
|
+
remodex-windows-fix up
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Validation
|
|
158
|
+
|
|
159
|
+
Typical local verification:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
codex --version
|
|
163
|
+
codex app-server --help
|
|
164
|
+
remodex-windows-fix up
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Expected Windows resolution after the fix:
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
C:\Users\th072\AppData\Roaming\npm\codex.cmd app-server
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Project Layout
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
bin/
|
|
177
|
+
src/
|
|
178
|
+
package.json
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Attribution
|
|
182
|
+
|
|
183
|
+
This repository preserves the upstream Remodex package structure and credits the original package author in `package.json`. This fork adds a Windows launcher compatibility patch and accompanying documentation.
|
package/bin/phodex.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// FILE: remodex-relay.js
|
|
3
|
+
// Purpose: CLI entrypoint for running the bundled Remodex relay locally.
|
|
4
|
+
// Layer: CLI binary
|
|
5
|
+
// Exports: none
|
|
6
|
+
// Depends on: ../src/relay-server
|
|
7
|
+
|
|
8
|
+
const { startRelayServer } = require("../src/relay-server");
|
|
9
|
+
|
|
10
|
+
if (process.argv.includes("--help") || process.argv.includes("-h")) {
|
|
11
|
+
console.log("Usage: remodex-relay [port]");
|
|
12
|
+
console.log("Environment: REMODEX_RELAY_HOST, REMODEX_RELAY_PORT");
|
|
13
|
+
process.exit(0);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const portArg = process.argv[2];
|
|
17
|
+
startRelayServer({
|
|
18
|
+
port: portArg ? Number.parseInt(portArg, 10) : undefined,
|
|
19
|
+
});
|
package/bin/remodex.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// FILE: remodex.js
|
|
3
|
+
// Purpose: CLI surface for starting the local Remodex bridge, reopening the latest active thread, and tailing its rollout file.
|
|
4
|
+
// Layer: CLI binary
|
|
5
|
+
// Exports: none
|
|
6
|
+
// Depends on: ../src
|
|
7
|
+
|
|
8
|
+
const { startBridge, openLastActiveThread, watchThreadRollout } = require("../src");
|
|
9
|
+
|
|
10
|
+
const command = process.argv[2] || "up";
|
|
11
|
+
|
|
12
|
+
if (command === "up") {
|
|
13
|
+
startBridge();
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (command === "resume") {
|
|
18
|
+
try {
|
|
19
|
+
const state = openLastActiveThread();
|
|
20
|
+
console.log(
|
|
21
|
+
`[remodex] Opened last active thread: ${state.threadId} (${state.source || "unknown"})`
|
|
22
|
+
);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error(`[remodex] ${(error && error.message) || "Failed to reopen the last thread."}`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (command === "watch") {
|
|
31
|
+
try {
|
|
32
|
+
watchThreadRollout(process.argv[3] || "");
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error(`[remodex] ${(error && error.message) || "Failed to watch the thread rollout."}`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (command !== "up") {
|
|
41
|
+
console.error(`Unknown command: ${command}`);
|
|
42
|
+
console.error("Usage: remodex up | remodex resume | remodex watch [threadId]");
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Cloudflare Relay
|
|
2
|
+
|
|
3
|
+
This folder contains a Cloudflare Workers + Durable Objects implementation of the Remodex relay protocol.
|
|
4
|
+
|
|
5
|
+
It preserves the same session path and headers used by the bridge and iPhone client:
|
|
6
|
+
|
|
7
|
+
- path: `/relay/{sessionId}`
|
|
8
|
+
- required header: `x-role: mac` or `x-role: iphone`
|
|
9
|
+
- close code `4000`: invalid session or role
|
|
10
|
+
- close code `4001`: previous Mac connection replaced
|
|
11
|
+
- close code `4002`: session unavailable / Mac disconnected
|
|
12
|
+
- close code `4003`: previous iPhone connection replaced
|
|
13
|
+
|
|
14
|
+
The public health endpoint is:
|
|
15
|
+
|
|
16
|
+
- `GET /health`
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { DurableObject } from "cloudflare:workers";
|
|
2
|
+
|
|
3
|
+
const MAX_HISTORY = 500;
|
|
4
|
+
const CLOSE_CODE_INVALID_SESSION = 4000;
|
|
5
|
+
const CLOSE_CODE_MAC_REPLACED = 4001;
|
|
6
|
+
const CLOSE_CODE_SESSION_UNAVAILABLE = 4002;
|
|
7
|
+
const CLOSE_CODE_IPHONE_REPLACED = 4003;
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
async fetch(request, env) {
|
|
11
|
+
const url = new URL(request.url);
|
|
12
|
+
|
|
13
|
+
if (url.pathname === "/health") {
|
|
14
|
+
return jsonResponse({
|
|
15
|
+
ok: true,
|
|
16
|
+
service: "remodex-relay",
|
|
17
|
+
runtime: "cloudflare-workers",
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const match = url.pathname.match(/^\/relay\/([^/?]+)/);
|
|
22
|
+
if (!match) {
|
|
23
|
+
return new Response("not found", { status: 404 });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const sessionId = match[1];
|
|
27
|
+
const stub = env.SESSION_RELAY.get(env.SESSION_RELAY.idFromName(sessionId));
|
|
28
|
+
return stub.fetch(request);
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export class SessionRelay extends DurableObject {
|
|
33
|
+
constructor(ctx, env) {
|
|
34
|
+
super(ctx, env);
|
|
35
|
+
this.ctx = ctx;
|
|
36
|
+
this.env = env;
|
|
37
|
+
this.mac = null;
|
|
38
|
+
this.clients = new Set();
|
|
39
|
+
this.history = [];
|
|
40
|
+
|
|
41
|
+
this.ctx.blockConcurrencyWhile(async () => {
|
|
42
|
+
this.history = (await this.ctx.storage.get("history")) || [];
|
|
43
|
+
for (const socket of this.ctx.getWebSockets()) {
|
|
44
|
+
const metadata = socket.deserializeAttachment() || {};
|
|
45
|
+
if (metadata.role === "mac") {
|
|
46
|
+
this.mac = socket;
|
|
47
|
+
} else if (metadata.role === "iphone") {
|
|
48
|
+
this.clients.add(socket);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async fetch(request) {
|
|
55
|
+
const upgrade = request.headers.get("Upgrade");
|
|
56
|
+
if (!upgrade || upgrade.toLowerCase() !== "websocket") {
|
|
57
|
+
return new Response("Expected WebSocket upgrade", { status: 426 });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const url = new URL(request.url);
|
|
61
|
+
const sessionId = url.pathname.match(/^\/relay\/([^/?]+)/)?.[1];
|
|
62
|
+
const role = request.headers.get("x-role");
|
|
63
|
+
|
|
64
|
+
if (!sessionId || (role !== "mac" && role !== "iphone")) {
|
|
65
|
+
return closeWebSocketResponse(
|
|
66
|
+
CLOSE_CODE_INVALID_SESSION,
|
|
67
|
+
"Missing sessionId or invalid x-role header"
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (role === "iphone" && !this.isSocketOpen(this.mac)) {
|
|
72
|
+
return closeWebSocketResponse(
|
|
73
|
+
CLOSE_CODE_SESSION_UNAVAILABLE,
|
|
74
|
+
"Mac session not available"
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const pair = new WebSocketPair();
|
|
79
|
+
const [clientSocket, serverSocket] = Object.values(pair);
|
|
80
|
+
|
|
81
|
+
this.ctx.acceptWebSocket(serverSocket);
|
|
82
|
+
serverSocket.serializeAttachment({ role });
|
|
83
|
+
|
|
84
|
+
if (role === "mac") {
|
|
85
|
+
if (this.isSocketOpen(this.mac)) {
|
|
86
|
+
this.safeClose(
|
|
87
|
+
this.mac,
|
|
88
|
+
CLOSE_CODE_MAC_REPLACED,
|
|
89
|
+
"Replaced by new Mac connection"
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
this.mac = serverSocket;
|
|
93
|
+
console.log(`[relay] Mac connected -> session ${sessionId}`);
|
|
94
|
+
} else {
|
|
95
|
+
for (const existingClient of this.clients) {
|
|
96
|
+
if (existingClient === serverSocket) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
this.safeClose(
|
|
100
|
+
existingClient,
|
|
101
|
+
CLOSE_CODE_IPHONE_REPLACED,
|
|
102
|
+
"Replaced by newer iPhone connection"
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
this.clients = new Set([serverSocket]);
|
|
106
|
+
console.log(`[relay] iPhone connected -> session ${sessionId} (1 client)`);
|
|
107
|
+
|
|
108
|
+
for (const msg of this.history) {
|
|
109
|
+
this.safeSend(serverSocket, msg);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return new Response(null, { status: 101, webSocket: clientSocket });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async webSocketMessage(socket, message) {
|
|
117
|
+
const metadata = socket.deserializeAttachment() || {};
|
|
118
|
+
const text = normalizeMessage(message);
|
|
119
|
+
|
|
120
|
+
if (metadata.role === "mac") {
|
|
121
|
+
this.history.push(text);
|
|
122
|
+
if (this.history.length > MAX_HISTORY) {
|
|
123
|
+
this.history.shift();
|
|
124
|
+
}
|
|
125
|
+
await this.ctx.storage.put("history", this.history);
|
|
126
|
+
|
|
127
|
+
for (const client of this.clients) {
|
|
128
|
+
this.safeSend(client, text);
|
|
129
|
+
}
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (this.isSocketOpen(this.mac)) {
|
|
134
|
+
this.safeSend(this.mac, text);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async webSocketClose(socket) {
|
|
139
|
+
await this.dropSocket(socket);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async webSocketError(socket, error) {
|
|
143
|
+
console.error("[relay] WebSocket error:", error?.message || String(error));
|
|
144
|
+
await this.dropSocket(socket);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async dropSocket(socket) {
|
|
148
|
+
const metadata = socket.deserializeAttachment() || {};
|
|
149
|
+
|
|
150
|
+
if (metadata.role === "mac") {
|
|
151
|
+
if (this.mac === socket) {
|
|
152
|
+
this.mac = null;
|
|
153
|
+
for (const client of this.clients) {
|
|
154
|
+
this.safeClose(client, CLOSE_CODE_SESSION_UNAVAILABLE, "Mac disconnected");
|
|
155
|
+
}
|
|
156
|
+
this.clients.clear();
|
|
157
|
+
}
|
|
158
|
+
} else if (metadata.role === "iphone") {
|
|
159
|
+
this.clients.delete(socket);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (!this.isSocketOpen(this.mac) && this.clients.size === 0) {
|
|
163
|
+
this.history = [];
|
|
164
|
+
await this.ctx.storage.deleteAll();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
isSocketOpen(socket) {
|
|
169
|
+
return !!socket && socket.readyState === 1;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
safeSend(socket, message) {
|
|
173
|
+
if (!this.isSocketOpen(socket)) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
socket.send(message);
|
|
179
|
+
} catch {}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
safeClose(socket, code, reason) {
|
|
183
|
+
if (!socket) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
socket.close(code, reason);
|
|
189
|
+
} catch {}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function normalizeMessage(message) {
|
|
194
|
+
if (typeof message === "string") {
|
|
195
|
+
return message;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (message instanceof ArrayBuffer) {
|
|
199
|
+
return new TextDecoder().decode(message);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return String(message);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function closeWebSocketResponse(code, reason) {
|
|
206
|
+
const pair = new WebSocketPair();
|
|
207
|
+
const [clientSocket, serverSocket] = Object.values(pair);
|
|
208
|
+
serverSocket.accept();
|
|
209
|
+
serverSocket.close(code, reason);
|
|
210
|
+
return new Response(null, { status: 101, webSocket: clientSocket });
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function jsonResponse(value) {
|
|
214
|
+
const payload = JSON.stringify(value);
|
|
215
|
+
return new Response(payload, {
|
|
216
|
+
status: 200,
|
|
217
|
+
headers: {
|
|
218
|
+
"content-type": "application/json; charset=utf-8",
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "remodex-windows-fix",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Local bridge between Codex and the Remodex mobile app with a Windows-safe Codex launcher.",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"remodex-windows-fix": "bin/remodex.js",
|
|
8
|
+
"remodex-relay": "bin/remodex-relay.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"bin/",
|
|
12
|
+
"cloudflare/",
|
|
13
|
+
"relay/",
|
|
14
|
+
"render.yaml",
|
|
15
|
+
"src/",
|
|
16
|
+
"wrangler.toml"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"start": "node ./bin/remodex.js up",
|
|
20
|
+
"relay": "node ./bin/remodex-relay.js"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"remodex",
|
|
24
|
+
"codex",
|
|
25
|
+
"bridge",
|
|
26
|
+
"cli",
|
|
27
|
+
"windows"
|
|
28
|
+
],
|
|
29
|
+
"author": "Emanuele Di Pietro",
|
|
30
|
+
"license": "ISC",
|
|
31
|
+
"type": "commonjs",
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/needitem/remodex-windows-fix.git"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/needitem/remodex-windows-fix/issues"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/needitem/remodex-windows-fix#readme",
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"qrcode-terminal": "^0.12.0",
|
|
45
|
+
"uuid": "^13.0.0",
|
|
46
|
+
"ws": "^8.19.0"
|
|
47
|
+
}
|
|
48
|
+
}
|
package/relay/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Relay
|
|
2
|
+
|
|
3
|
+
This folder contains the thin WebSocket relay used by the default hosted Remodex pairing flow.
|
|
4
|
+
|
|
5
|
+
The implementation is copied from the upstream open-source relay so you can run the same session routing yourself.
|
|
6
|
+
|
|
7
|
+
## What It Does
|
|
8
|
+
|
|
9
|
+
- accepts WebSocket connections at `/relay/{sessionId}`
|
|
10
|
+
- pairs one Mac host with one live iPhone client for a session
|
|
11
|
+
- forwards JSON-RPC traffic between Mac and iPhone
|
|
12
|
+
- replays a small in-memory history buffer to a reconnecting iPhone client
|
|
13
|
+
- exposes lightweight stats for a health endpoint
|
|
14
|
+
|
|
15
|
+
## What It Does Not Do
|
|
16
|
+
|
|
17
|
+
- it does not run Codex
|
|
18
|
+
- it does not execute git commands
|
|
19
|
+
- it does not contain your repository checkout
|
|
20
|
+
- it does not persist the local workspace on the server
|
|
21
|
+
|
|
22
|
+
Codex, git, and local file operations still run on the user's machine.
|
|
23
|
+
|
|
24
|
+
## Local Runner
|
|
25
|
+
|
|
26
|
+
This repository includes a local relay runner:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm run relay
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Environment variables:
|
|
33
|
+
|
|
34
|
+
- `REMODEX_RELAY_HOST` defaults to `0.0.0.0`
|
|
35
|
+
- `REMODEX_RELAY_PORT` defaults to `9000`
|
|
36
|
+
|
|
37
|
+
Health endpoint:
|
|
38
|
+
|
|
39
|
+
- `GET /health`
|