remcodex 0.1.0-beta.1 β†’ 0.1.0-beta.10

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 CHANGED
@@ -1,81 +1,104 @@
1
- # RemCodex
2
-
3
- > Control Codex from anywhere. Even on your phone.
4
-
5
- RemCodex is a local-first web UI for running, reviewing, approving, and resuming Codex sessions from your browser.
6
-
7
- It is built for the real workflow: long-running sessions, mobile check-ins, approval prompts, imported rollout history, and timeline-style execution flow.
8
-
9
- ```mermaid
10
- flowchart LR
11
- subgraph D[Your devices]
12
- P[Phone]
13
- B[Browser]
14
- end
15
-
16
- subgraph M[Your work machine]
17
- subgraph R[RemCodex]
18
- UI[Web UI]
19
- S[Server]
20
- T[Timeline + approvals + sync]
21
- end
22
-
23
- subgraph C[Local Codex runtime]
24
- X[Codex CLI / app-server]
25
- F[Workspace files]
26
- H[~/.codex sessions]
27
- end
28
- end
29
-
30
- P --> UI
31
- B --> UI
32
- UI --> S
33
- S --> T
34
- S --> X
35
- X --> F
36
- X --> H
37
- H --> S
38
- T --> UI
39
- ```
1
+ # πŸš€ RemCodex
2
+
3
+ > Remote control for Codex.
4
+ > From your browser and phone.
5
+
6
+ Run Codex on one machine.
7
+ Monitor, approve, and control the same session from another.
8
+
9
+ 🌐 https://remcodex.com
10
+
11
+ > Not a remote desktop. Not a proxy.
12
+ > A local-first way to control Codex away from the terminal.
13
+
14
+ ![RemCodex hero cover](docs/assets/hero-cover.png)
15
+
16
+ ---
17
+
18
+ ## ✨ What is RemCodex?
19
+
20
+ RemCodex is **remote control for Codex**.
21
+
22
+ It lets you start Codex on one machine, then keep the same session visible,
23
+ interruptible, and controllable from another.
24
+
25
+ - πŸ‘€ See what the AI is doing β€” in real time
26
+ - βœ… Approve or reject actions before execution
27
+ - ⏹ Interrupt or stop at any moment
28
+ - πŸ“± Access your session from any device
29
+ - πŸ”„ Sessions don’t break β€” they resume
30
+
31
+ > One session. Any device.
32
+
33
+ ---
34
+
35
+ ## 🎬 A real workflow
36
+
37
+ You start a long Codex session on your machine.
38
+
39
+ Then you leave your desk.
40
+
41
+ On your phone:
42
+
43
+ - you see progress in real time
44
+ - you receive an approval request
45
+ - you approve it
40
46
 
41
- - Watch live Codex runs without staying in the terminal
42
- - Approve sensitive actions from a cleaner UI
43
- - Pick up the same session again after refresh, sleep, or reconnect
47
+ The session continues instantly.
44
48
 
45
- ## Status
49
+ > Everything else can disconnect β€” your session won’t.
46
50
 
47
- This project is currently a **beta / developer preview**.
51
+ ---
48
52
 
49
- MIT licensed β€” free for personal and commercial use.
53
+ ## πŸ”₯ Why RemCodex exists
50
54
 
51
- Cloud version coming soon.
55
+ AI coding agents are powerful.
56
+ But today, they run like a black box.
52
57
 
53
- It is already usable for local and internal workflows, but it is not yet packaged as a one-click desktop app.
58
+ You either:
54
59
 
55
- ## Why People Use It
60
+ - trust everything blindly
61
+ - or sit in front of your terminal watching it
56
62
 
57
- Codex is powerful in the terminal, but many real workflows need a better control surface:
63
+ RemCodex fixes that.
58
64
 
59
- - checking progress from your phone
60
- - watching a long run without babysitting a terminal window
61
- - approving writes from a cleaner interface
62
- - reopening a session after refresh, sleep, or reconnect
63
- - reviewing imported rollout history next to native sessions
65
+ > AI is no longer a black box.
64
66
 
65
- RemCodex turns Codex's event stream into a browser-based workspace that is easier to follow, easier to resume, and easier to operate.
67
+ ---
66
68
 
67
- ## What It Does
69
+ ## ⚑ What it does
68
70
 
69
- - Run Codex sessions from a browser
70
- - View sessions in a single-page workspace with a sidebar and execution timeline
71
- - Follow streaming assistant output, commands, patches, and approvals
72
- - Approve or reject file-system actions from the UI
73
- - Import existing Codex rollout sessions from `~/.codex/sessions/...`
74
- - Keep imported sessions in sync while they are still active
75
- - Resume stale sessions after the page comes back from background
76
- - Work well on desktop and on mobile
71
+ - Real-time execution timeline (messages, commands, approvals)
72
+ - Human-in-the-loop command approval
73
+ - Multi-device access to the same live session
74
+ - Resume after refresh, sleep, or reconnect
75
+ - Browser-based UI β€” **no extra client required**
76
+ - Works with Codex CLI
77
77
 
78
- ## Screenshots
78
+ > No extra client install. Just open a browser.
79
+ > Your code never leaves your machine.
80
+
81
+ ---
82
+
83
+ ## πŸš€ Quick start
84
+
85
+ ```bash
86
+ npx remcodex
87
+ ```
88
+
89
+ Then open:
90
+
91
+ http://127.0.0.1:18840
92
+
93
+ Access from another device:
94
+
95
+ http://<your-ip>:18840
96
+
97
+ > Runs entirely on your local machine. No cloud, no data upload.
98
+
99
+ ---
100
+
101
+ ## πŸ–₯ Screenshots
79
102
 
80
103
  ![RemCodex desktop workspace](docs/assets/hero-desktop.png)
81
104
 
@@ -91,241 +114,203 @@ RemCodex turns Codex's event stream into a browser-based workspace that is easie
91
114
 
92
115
  ![RemCodex imported Codex session](docs/assets/imported-session.png)
93
116
 
94
- > Bring imported Codex rollouts into the same workspace and keep them easy to review.
117
+ > Bring imported Codex rollouts into the same workspace.
118
+
119
+ ---
120
+
121
+ ## 🧠 What it actually is
122
+
123
+ RemCodex is a **browser-based workspace for Codex sessions**.
95
124
 
96
- ## Who It Is For
125
+ It is built for real workflows:
97
126
 
98
- - developers who already use Codex locally
99
- - people who want a browser-based control surface instead of raw terminal watching
100
- - teams who want to review or monitor runs from another device on the same network
101
- - anyone who wants approvals, timeline view, and imported rollout history in one place
127
+ - long-running sessions
128
+ - mobile check-ins
129
+ - approval prompts
130
+ - imported rollout history
131
+ - timeline-style execution flow
102
132
 
103
- ## Screens It Aims To Replace
133
+ Instead of raw terminal logs, you get a structured, visual timeline you can follow and control.
104
134
 
105
- - terminal-only session watching
106
- - ad-hoc mobile remote desktop checks
107
- - raw log scrolling for approvals and command progress
108
- - fragmented session history between local and imported rollouts
135
+ ---
109
136
 
110
- ## Current Product Shape
137
+ ## 🧩 Current product shape
111
138
 
112
139
  - Single-page workspace UI
113
140
  - Left sidebar for session navigation
114
- - Right-side timeline / execution flow for the active session
115
- - Fixed composer at the bottom
141
+ - Right-side execution timeline
142
+ - Fixed input composer
116
143
  - Semantic timeline rendering for:
117
- - user messages
118
- - assistant commentary / final messages
119
- - thinking
120
- - commands
121
- - patches
122
- - approvals
123
- - system events
144
+ - user messages
145
+ - assistant output
146
+ - thinking
147
+ - commands
148
+ - patches
149
+ - approvals
150
+ - system events
124
151
 
125
- ## Tech Stack
152
+ ---
126
153
 
127
- - Backend: Node.js + TypeScript + Express + WebSocket
128
- - Database: SQLite via `better-sqlite3`
129
- - Terminal/runtime integration: `node-pty` + Codex app-server
130
- - Frontend: zero-build static web app (`web/`)
131
- - Markdown rendering: `markdown-it`
154
+ ## βš™οΈ Key behaviors
132
155
 
133
- ## Requirements
156
+ ### Approvals
134
157
 
135
- Before running this project, you should have:
158
+ - Writes inside working area β†’ auto allowed
159
+ - Writes outside β†’ require approval
160
+ - `Allow once` / `Allow for this turn` supported
161
+ - Approval history stays visible in timeline
136
162
 
137
- - Node.js installed
138
- - Codex CLI installed and already working locally
139
- - A machine where this app can access your local Codex data and working directories
163
+ ---
140
164
 
141
- This project is currently developed primarily around a local macOS workflow.
165
+ ### Timeline
142
166
 
143
- ## Quick Start
167
+ - Semantic rendering (not raw logs)
168
+ - Commands grouped into readable activity blocks
169
+ - Running / failed states clearly visible
170
+ - Smooth streaming + recovery after refresh
144
171
 
145
- For the current developer preview, the recommended local install path is:
172
+ ---
146
173
 
147
- ```bash
148
- npm install
149
- npm run build
150
- npm link
151
- remcodex start
152
- ```
174
+ ### Imported sessions
153
175
 
154
- Then open:
176
+ - Import from `~/.codex/sessions/...`
177
+ - Keep syncing if still active
178
+ - Unified view with native sessions
179
+
180
+ ---
181
+
182
+ ## 🧠 Architecture
155
183
 
156
- ```text
157
- http://127.0.0.1:3000
184
+ ```
185
+ Codex CLI β†’ Event stream β†’ Semantic layer β†’ Timeline β†’ Web UI
158
186
  ```
159
187
 
160
- If you want to make it reachable from your phone, expose the local machine on your LAN and open the same URL with your host IP.
188
+ ---
161
189
 
162
- ## Local CLI
190
+ ## βš™οΈ Requirements
163
191
 
164
- RemCodex already ships with a local CLI entrypoint, even though the npm package is not published yet.
192
+ - Node.js
193
+ - Codex CLI (already working locally)
165
194
 
166
- If you do not want to run `npm link`, you can call the built CLI directly:
195
+ ---
167
196
 
168
- ```bash
169
- node dist/server/src/cli.js start --no-open
170
- ```
197
+ ## βš™οΈ Configuration
171
198
 
172
- Useful commands:
199
+ Default port: **18840**
173
200
 
174
201
  ```bash
175
- node dist/server/src/cli.js doctor
176
- node dist/server/src/cli.js start --no-open
177
- node dist/server/src/cli.js version
202
+ PORT=18841 npx remcodex
178
203
  ```
179
204
 
180
- Use a specific database:
205
+ ---
181
206
 
182
- ```bash
183
- node dist/server/src/cli.js start --db ~/.remcodex/remcodex-alt.db --no-open
184
- node dist/server/src/cli.js doctor --db ~/.remcodex/remcodex-alt.db
185
- ```
207
+ ## πŸ“¦ Install FAQ
208
+
209
+ ### Why does `npx remcodex` hang on Linux?
210
+
211
+ First install may compile native deps:
212
+
213
+ - `better-sqlite3`
214
+ - `node-pty`
215
+
216
+ Make sure you have:
217
+
218
+ - `python3`
219
+ - `make`
220
+ - `g++`
186
221
 
187
- Planned install target after the npm package is published:
222
+ ---
223
+
224
+ ### Debug install issues
188
225
 
189
226
  ```bash
190
- npx remcodex
227
+ npm install -g remcodex
228
+ remcodex doctor
229
+ remcodex start
191
230
  ```
192
231
 
193
- ## Development
232
+ ---
233
+
234
+ ### Headless mode
194
235
 
195
236
  ```bash
196
- npm install
197
- npm run dev
237
+ npx remcodex --no-open
198
238
  ```
199
239
 
200
- ## How It Works
201
-
202
- The app uses `codex app-server` as the primary runtime path.
240
+ ---
203
241
 
204
- At a high level:
242
+ ## πŸ”§ How it works
205
243
 
206
- 1. Codex emits semantic events
207
- 2. The backend stores them in SQLite
208
- 3. The frontend reads an aggregated timeline view for initial load
209
- 4. Live updates continue over WebSocket with catch-up after refresh
244
+ 1. Codex emits events
245
+ 2. Backend stores them (SQLite)
246
+ 3. Frontend loads timeline snapshot
247
+ 4. Live updates stream via WebSocket
210
248
 
211
- This gives the UI:
249
+ Result:
212
250
 
213
- - smooth streaming
214
251
  - recoverable sessions
215
- - imported rollout support
216
- - a consistent execution timeline instead of raw terminal logs
252
+ - real-time UI
253
+ - consistent execution flow
217
254
 
218
- ## Key Behaviors
255
+ ---
219
256
 
220
- ### Approvals
257
+ ## πŸ“Š Status
221
258
 
222
- - Writes inside the working area usually pass directly
223
- - Writes outside the working area trigger approval
224
- - `Allow once` approves only the current request
225
- - `Allow for this turn` expands writable roots for the active turn
226
- - Historical approval records stay visible in the timeline
227
- - Only live approvals stay actionable in the bottom approval bar
228
-
229
- ### Imported Codex Sessions
230
-
231
- - Existing Codex rollouts can be imported from local session history
232
- - Imported sessions keep their own source metadata
233
- - Imported sessions can continue syncing after you open them
234
- - Native sessions are excluded from the import picker
235
-
236
- ### Timeline and Execution Flow
237
-
238
- - The UI renders semantic timeline items, not raw logs
239
- - Commands and patches can be grouped into lighter activity summaries
240
- - Running and failed commands remain visually important
241
- - The final thinking placeholder appears only at the end of the active flow
242
-
243
- ## Configuration
244
-
245
- Supported environment variables:
246
-
247
- - `PORT`
248
- - `DATABASE_PATH`
249
- - `PROJECT_ROOTS`
250
- - `CODEX_COMMAND`
251
- - `CODEX_MODE`
252
- - `REMOTE_HOSTS`
253
- - `ACTIVE_REMOTE_HOST`
254
-
255
- Notes:
256
-
257
- - The default runtime mode is `app-server`
258
- - `exec-json` is kept only as a fallback compatibility path
259
- - If `PROJECT_ROOTS` is not set, the app falls back to a broad local browsing root
260
-
261
- ## Project Structure
262
-
263
- ```text
264
- server/
265
- src/
266
- app.ts
267
- controllers/
268
- db/
269
- gateways/
270
- services/
271
- types/
272
- utils/
273
- web/
274
- index.html
275
- styles.css
276
- api.js
277
- session-ws.js
278
- app.js
279
- scripts/
280
- fix-node-pty-helper.js
281
- ```
259
+ - Beta / developer preview
260
+ - Local-first architecture
261
+ - No cloud dependency
282
262
 
283
- ## Main Endpoints
263
+ ---
284
264
 
285
- - `GET /health`
286
- - `GET /api/codex/mode`
287
- - `GET /api/codex/status`
288
- - `GET /api/codex/quota`
289
- - `GET /api/sessions`
290
- - `GET /api/sessions/:sessionId`
291
- - `GET /api/sessions/:sessionId/timeline`
292
- - `GET /api/sessions/:sessionId/events`
293
- - `POST /api/sessions`
294
- - `POST /api/sessions/:sessionId/messages`
295
- - `POST /api/sessions/:sessionId/stop`
296
- - `POST /api/sessions/:sessionId/approvals/:requestId`
297
- - `WS /ws/sessions/:sessionId`
265
+ ## πŸ—Ί Roadmap
298
266
 
299
- ## What Is Not Finished Yet
267
+ **Visibility**
300
268
 
301
- This is the honest list:
269
+ - fully observable execution
270
+ - clear action timeline
302
271
 
303
- - no polished installer yet
304
- - no desktop packaging yet
305
- - no full automated test suite yet
306
- - no production-grade auth / multi-user hardening yet
307
- - no release pipeline yet
272
+ **Control**
273
+
274
+ - fine-grained approvals
275
+ - safer execution
308
276
 
309
- If you are comfortable cloning a repo and running a local Node app, you can use it today.
277
+ **Continuity**
310
278
 
311
- ## Roadmap
279
+ - survive refresh / sleep
280
+ - stable long runs
312
281
 
313
- Near-term:
282
+ **Access**
314
283
 
315
- - improve onboarding and installation
316
- - ship a cleaner public README and screenshots
317
- - add stronger regression coverage
318
- - harden long-running session recovery
319
- - continue refining the execution timeline UI
284
+ - control from any device
320
285
 
321
- Later:
286
+ **Integration**
287
+
288
+ - IDE integrations
289
+ - optional sharing
290
+
291
+ ---
292
+
293
+ ## πŸ‘₯ Who it’s for
294
+
295
+ - developers already using Codex
296
+ - people tired of terminal-only workflows
297
+ - anyone who wants **control, not just output**
298
+ - multi-device workflows
299
+
300
+ ---
301
+
302
+ ## ⚠️ What’s not finished yet
303
+
304
+ - no polished installer yet
305
+ - no desktop packaging
306
+ - no production-grade auth
307
+ - no release pipeline
322
308
 
323
- - package for easier local install
324
- - optional sync / multi-device helpers
325
- - stronger sharing, auditing, and team workflows
309
+ If you're comfortable running a local Node app β€”
310
+ you can use it today.
326
311
 
327
- ## License
312
+ ---
328
313
 
329
- No license has been added yet.
314
+ ## πŸ“„ License
330
315
 
331
- Until a license is added, assume this repository is **source-available for review only**, not open source for reuse.
316
+ MIT License
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DEFAULT_PORT = void 0;
6
7
  exports.resolvePackageRoot = resolvePackageRoot;
7
8
  exports.resolveDefaultDatabasePath = resolveDefaultDatabasePath;
8
9
  exports.startRemCodexServer = startRemCodexServer;
@@ -46,9 +47,10 @@ function resolvePackageRoot(startDir = __dirname) {
46
47
  function resolveDefaultDatabasePath() {
47
48
  return node_path_1.default.join((0, node_os_1.homedir)(), ".remcodex", "remcodex.db");
48
49
  }
50
+ exports.DEFAULT_PORT = 18840;
49
51
  function buildRemCodexServer(options = {}) {
50
52
  const repoRoot = options.repoRoot ? node_path_1.default.resolve(options.repoRoot) : resolvePackageRoot();
51
- const port = options.port ?? Number.parseInt(process.env.PORT ?? "3000", 10);
53
+ const port = options.port ?? Number.parseInt(process.env.PORT ?? String(exports.DEFAULT_PORT), 10);
52
54
  const databasePath = options.databasePath ??
53
55
  process.env.DATABASE_PATH ??
54
56
  resolveDefaultDatabasePath();
@@ -169,7 +169,7 @@ async function runStart(flags) {
169
169
  printError("Install Codex first, or set CODEX_COMMAND to the correct executable.");
170
170
  return 1;
171
171
  }
172
- const preferredPort = flags.port ?? Number.parseInt(process.env.PORT ?? "3000", 10);
172
+ const preferredPort = flags.port ?? Number.parseInt(process.env.PORT ?? String(app_1.DEFAULT_PORT), 10);
173
173
  const codexMode = process.env.CODEX_MODE === "exec-json" ? "exec-json" : "app-server";
174
174
  let started = null;
175
175
  let activePort = preferredPort;
@@ -242,8 +242,9 @@ async function main() {
242
242
  usage();
243
243
  return;
244
244
  }
245
- const command = argv[0] && !argv[0].startsWith("-") ? argv[0] : "start";
246
- const flagArgs = command === "start" ? argv.slice(1) : argv;
245
+ const hasExplicitCommand = Boolean(argv[0] && !argv[0].startsWith("-"));
246
+ const command = hasExplicitCommand ? argv[0] : "start";
247
+ const flagArgs = hasExplicitCommand ? argv.slice(1) : argv;
247
248
  const flags = parseFlags(flagArgs);
248
249
  switch (command) {
249
250
  case "start":
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createSessionRouter = createSessionRouter;
4
4
  const express_1 = require("express");
5
+ const codex_launch_1 = require("../utils/codex-launch");
5
6
  function createSessionRouter(sessionManager, eventStore, projectManager, codexRolloutSync, sessionTimeline) {
6
7
  const router = (0, express_1.Router)();
7
8
  router.get("/", (_request, response) => {
@@ -171,5 +172,16 @@ function createSessionRouter(sessionManager, eventStore, projectManager, codexRo
171
172
  next(error);
172
173
  }
173
174
  });
175
+ router.post("/:sessionId/approvals/:requestId/retry", (request, response, next) => {
176
+ try {
177
+ const body = request.body;
178
+ const launch = (0, codex_launch_1.normalizeCodexExecLaunchInput)(body.codex);
179
+ const result = sessionManager.retryApprovalRequest(request.params.sessionId, request.params.requestId, launch);
180
+ response.json(result);
181
+ }
182
+ catch (error) {
183
+ next(error);
184
+ }
185
+ });
174
186
  return router;
175
187
  }
@@ -9,6 +9,7 @@ const node_os_1 = __importDefault(require("node:os"));
9
9
  const node_path_1 = __importDefault(require("node:path"));
10
10
  const errors_1 = require("../utils/errors");
11
11
  const ids_1 = require("../utils/ids");
12
+ const output_limits_1 = require("../utils/output-limits");
12
13
  function computeSourceRolloutHasOpenTurnFromRecords(records) {
13
14
  const openTurnIds = new Set();
14
15
  for (const record of records) {
@@ -571,22 +572,7 @@ function translateRolloutRecords(records, emitFromRecordIndex = 0) {
571
572
  : `call_${index}`;
572
573
  const started = commandStarts.get(callId) || null;
573
574
  const parsed = parseExecOutput(payload.output);
574
- if (parsed.outputText) {
575
- appendSemantic(index, {
576
- type: "command.output.delta",
577
- turnId: currentTurnId,
578
- messageId: null,
579
- callId,
580
- requestId: null,
581
- phase: null,
582
- stream: "stdout",
583
- payload: {
584
- stream: "stdout",
585
- textDelta: parsed.outputText,
586
- },
587
- timestamp,
588
- });
589
- }
575
+ const cappedOutput = parsed.outputText ? (0, output_limits_1.capTextValue)(parsed.outputText) : null;
590
576
  appendSemantic(index, {
591
577
  type: "command.end",
592
578
  turnId: currentTurnId,
@@ -598,6 +584,9 @@ function translateRolloutRecords(records, emitFromRecordIndex = 0) {
598
584
  payload: {
599
585
  command: parsed.commandLine || started?.commandPayload.command || null,
600
586
  cwd: started?.commandPayload.cwd || null,
587
+ stdout: cappedOutput?.text || null,
588
+ aggregatedOutput: cappedOutput?.text || null,
589
+ stdoutTruncated: cappedOutput?.truncated || undefined,
601
590
  status: parsed.exitCode == null
602
591
  ? "completed"
603
592
  : parsed.exitCode === 0