remote-codex 0.11.2 → 0.11.3

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.
@@ -4,17 +4,17 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Remote Codex Supervisor</title>
7
- <script type="module" crossorigin src="/assets/index-DQpHiQXN.js"></script>
7
+ <script type="module" crossorigin src="/assets/index-YpGAPjED.js"></script>
8
8
  <link rel="modulepreload" crossorigin href="/assets/react-vendor-o1Xrx7m4.js">
9
- <link rel="modulepreload" crossorigin href="/assets/ui-vendor-CgOZX1B8.js">
9
+ <link rel="modulepreload" crossorigin href="/assets/ui-vendor-CW6egZBG.js">
10
10
  <link rel="modulepreload" crossorigin href="/assets/terminal-vendor-CLGgN91S.js">
11
11
  <link rel="modulepreload" crossorigin href="/assets/graph-vendor-CGzY-MFv.js">
12
12
  <link rel="modulepreload" crossorigin href="/assets/markdown-vendor-hBDTCSB-.js">
13
- <link rel="modulepreload" crossorigin href="/assets/thread-ui-CDk3ExRH.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/thread-ui-CF80LEEN.js">
14
14
  <link rel="stylesheet" crossorigin href="/assets/terminal-vendor-Beg8tuEN.css">
15
15
  <link rel="stylesheet" crossorigin href="/assets/graph-vendor-C5ap-Sga.css">
16
16
  <link rel="stylesheet" crossorigin href="/assets/thread-ui-BEieA99i.css">
17
- <link rel="stylesheet" crossorigin href="/assets/index-CbDzXN9T.css">
17
+ <link rel="stylesheet" crossorigin href="/assets/index-CBIze1VS.css">
18
18
  </head>
19
19
  <body class="bg-stone-950">
20
20
  <div id="root"></div>
@@ -9,6 +9,8 @@ const binDir = path.dirname(fileURLToPath(import.meta.url));
9
9
  const packageRoot = path.resolve(binDir, '..');
10
10
  const packageJsonPath = path.join(packageRoot, 'package.json');
11
11
  const serviceManagerPath = path.join(packageRoot, 'scripts', 'service-manager.mjs');
12
+ const relayDistEntry = path.join(packageRoot, 'apps', 'relay-server', 'dist', 'index.js');
13
+ const relaySourceEntry = path.join(packageRoot, 'apps', 'relay-server', 'src', 'index.ts');
12
14
  const sourceCheckout =
13
15
  fs.existsSync(path.join(packageRoot, 'pnpm-workspace.yaml')) &&
14
16
  fs.existsSync(path.join(packageRoot, 'scripts', 'service-restart.mjs'));
@@ -33,30 +35,74 @@ if (command === 'version') {
33
35
  process.exit(0);
34
36
  }
35
37
 
36
- if (!['start', 'stop', 'status'].includes(command)) {
38
+ if (command === 'relay') {
39
+ runRelayServer();
40
+ } else if (!['start', 'stop', 'status'].includes(command)) {
37
41
  printHelp();
38
42
  process.exit(command ? 1 : 0);
43
+ } else {
44
+ const child = spawn(process.execPath, [serviceManagerPath, command], {
45
+ cwd: packageRoot,
46
+ env: process.env,
47
+ stdio: 'inherit',
48
+ });
49
+
50
+ child.on('exit', (code, signal) => {
51
+ if (signal) {
52
+ process.kill(process.pid, signal);
53
+ return;
54
+ }
55
+
56
+ process.exit(code ?? 1);
57
+ });
58
+
59
+ child.on('error', (error) => {
60
+ console.error(`Failed to run remote-codex ${command}: ${error.message}`);
61
+ process.exit(1);
62
+ });
39
63
  }
40
64
 
41
- const child = spawn(process.execPath, [serviceManagerPath, command], {
42
- cwd: packageRoot,
43
- env: process.env,
44
- stdio: 'inherit',
45
- });
65
+ function runRelayServer() {
66
+ const relayEntry = fs.existsSync(relayDistEntry) ? relayDistEntry : relaySourceEntry;
67
+ let commandToRun = process.execPath;
68
+ let args = [relayEntry];
46
69
 
47
- child.on('exit', (code, signal) => {
48
- if (signal) {
49
- process.kill(process.pid, signal);
50
- return;
70
+ if (!fs.existsSync(relayEntry)) {
71
+ console.error('Relay server build artifacts are missing. Run `pnpm build` before using `remote-codex relay`.');
72
+ console.error(`Missing: ${path.relative(packageRoot, relayDistEntry)}`);
73
+ process.exit(1);
51
74
  }
52
75
 
53
- process.exit(code ?? 1);
54
- });
76
+ if (relayEntry === relaySourceEntry) {
77
+ const tsxEntry = path.join(packageRoot, 'node_modules', 'tsx', 'dist', 'cli.mjs');
78
+ if (!fs.existsSync(tsxEntry)) {
79
+ console.error('Relay server build artifacts are missing and tsx is not installed for source execution.');
80
+ console.error('Run `pnpm build` or install dependencies with `pnpm install`.');
81
+ process.exit(1);
82
+ }
83
+ args = [tsxEntry, relaySourceEntry];
84
+ }
55
85
 
56
- child.on('error', (error) => {
57
- console.error(`Failed to run remote-codex ${command}: ${error.message}`);
58
- process.exit(1);
59
- });
86
+ const relay = spawn(commandToRun, args, {
87
+ cwd: packageRoot,
88
+ env: process.env,
89
+ stdio: 'inherit',
90
+ });
91
+
92
+ relay.on('exit', (code, signal) => {
93
+ if (signal) {
94
+ process.kill(process.pid, signal);
95
+ return;
96
+ }
97
+
98
+ process.exit(code ?? 1);
99
+ });
100
+
101
+ relay.on('error', (error) => {
102
+ console.error(`Failed to run remote-codex relay: ${error.message}`);
103
+ process.exit(1);
104
+ });
105
+ }
60
106
 
61
107
  function normalizeCommand(value) {
62
108
  if (!value || value === '-h' || value === '--help') {
@@ -86,6 +132,7 @@ Usage:
86
132
  remote-codex start
87
133
  remote-codex status
88
134
  remote-codex stop
135
+ remote-codex relay
89
136
 
90
137
  Environment:
91
138
  SERVICE_HOST Web listen host, default 127.0.0.1
@@ -93,5 +140,15 @@ Environment:
93
140
  SERVICE_API_HOST API listen host, default 127.0.0.1
94
141
  SERVICE_API_PORT API listen port, default ${defaultApiPort}
95
142
  REMOTE_CODEX_SERVICE_DIR Service state and log directory, default ~/.remote-codex/service
143
+
144
+ Relay:
145
+ REMOTE_CODEX_RELAY_SUPERVISOR_TOKEN Legacy bootstrap token for supervisor tunnels
146
+ REMOTE_CODEX_ADMIN_USERNAME Relay admin username
147
+ REMOTE_CODEX_ADMIN_PASSWORD Relay admin password
148
+ REMOTE_CODEX_RELAY_DATA_DIR Relay user/device store, default .local/relay-server
149
+ REMOTE_CODEX_RELAY_WEB_DIST_DIR Web dist override, defaults to packaged supervisor-web/dist
150
+ REMOTE_CODEX_RELAY_REGISTRATION_ENABLED true/false, default true
151
+ HOST Relay listen host, default 0.0.0.0
152
+ PORT Relay listen port, default 8788
96
153
  `);
97
154
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remote-codex",
3
- "version": "0.11.2",
3
+ "version": "0.11.3",
4
4
  "description": "Local web supervisor for Codex workspaces and threads.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -12,6 +12,7 @@
12
12
  "scripts/service-manager.mjs",
13
13
  "scripts/run-web-service.mjs",
14
14
  "apps/supervisor-api/dist/",
15
+ "apps/relay-server/dist/",
15
16
  "apps/supervisor-web/dist/",
16
17
  "config/codex-model-pricing.json",
17
18
  "packages/agent-runtime/src/",
@@ -16,6 +16,7 @@ export type {
16
16
 
17
17
  export type ApiErrorCode =
18
18
  | 'bad_request'
19
+ | 'unauthorized'
19
20
  | 'not_found'
20
21
  | 'conflict'
21
22
  | 'provider_goal_error'
@@ -53,12 +54,165 @@ export function truncateAutoThreadTitle(value: string) {
53
54
  export interface RuntimeConfigDto {
54
55
  appName: string;
55
56
  appVersion: string;
57
+ mode: 'local' | 'server' | 'relay';
56
58
  host: string;
57
59
  port: number;
58
60
  workspaceRoot: string;
59
61
  environment: string;
60
62
  }
61
63
 
64
+ export interface AuthSessionDto {
65
+ authenticated: boolean;
66
+ username: string | null;
67
+ expiresAt: string | null;
68
+ mode: 'local' | 'server' | 'relay';
69
+ authRequired: boolean;
70
+ }
71
+
72
+ export interface AuthLoginResultDto {
73
+ token: string | null;
74
+ session: AuthSessionDto;
75
+ }
76
+
77
+ export interface RelayHealthDto {
78
+ status: 'ok';
79
+ supervisorConnected: boolean;
80
+ supervisorConnectedAt: string | null;
81
+ lastSupervisorHeartbeatAt: string | null;
82
+ supervisorCount?: number;
83
+ }
84
+
85
+ export type RelayUserRoleDto = 'admin' | 'user';
86
+
87
+ export interface RelayUserDto {
88
+ id: string;
89
+ email: string;
90
+ username: string;
91
+ role: RelayUserRoleDto;
92
+ enabled: boolean;
93
+ createdAt: string;
94
+ }
95
+
96
+ export interface RelayDeviceDto {
97
+ id: string;
98
+ ownerUserId: string;
99
+ name: string;
100
+ tokenPreview: string;
101
+ connected: boolean;
102
+ connectedAt: string | null;
103
+ lastHeartbeatAt: string | null;
104
+ createdAt: string;
105
+ }
106
+
107
+ export interface RelaySessionShareDto {
108
+ id: string;
109
+ ownerUserId: string;
110
+ ownerUsername: string;
111
+ targetUsername: string;
112
+ targetUserId: string;
113
+ deviceId: string;
114
+ deviceName: string;
115
+ threadId: string;
116
+ label: string | null;
117
+ createdAt: string;
118
+ revokedAt: string | null;
119
+ }
120
+
121
+ export interface RelaySessionDto {
122
+ authenticated: boolean;
123
+ user: RelayUserDto | null;
124
+ registrationEnabled: boolean;
125
+ }
126
+
127
+ export interface RelayLoginResultDto {
128
+ token: string;
129
+ session: RelaySessionDto;
130
+ }
131
+
132
+ export interface RelayRegisterResultDto {
133
+ token: string;
134
+ session: RelaySessionDto;
135
+ }
136
+
137
+ export interface RelayCreateDeviceResultDto {
138
+ device: RelayDeviceDto;
139
+ token: string;
140
+ }
141
+
142
+ export interface RelayPortalSummaryDto {
143
+ user: RelayUserDto;
144
+ devices: RelayDeviceDto[];
145
+ sharedWithMe: RelaySessionShareDto[];
146
+ sharedByMe: RelaySessionShareDto[];
147
+ }
148
+
149
+ export interface RelayAdminSummaryDto {
150
+ users: RelayUserDto[];
151
+ devices: RelayDeviceDto[];
152
+ registrationEnabled: boolean;
153
+ }
154
+
155
+ export type RelaySupervisorEnvelope =
156
+ | {
157
+ type: 'relay.connected';
158
+ timestamp: string;
159
+ deviceId?: string;
160
+ }
161
+ | {
162
+ type: 'relay.heartbeat';
163
+ timestamp: string;
164
+ deviceId?: string;
165
+ }
166
+ | {
167
+ type: 'relay.request';
168
+ timestamp: string;
169
+ requestId: string;
170
+ deviceId?: string;
171
+ payload: RelayHttpRequestPayload;
172
+ }
173
+ | {
174
+ type: 'relay.response';
175
+ timestamp: string;
176
+ requestId: string;
177
+ deviceId?: string;
178
+ payload: RelayHttpResponsePayload;
179
+ }
180
+ | {
181
+ type: 'relay.client.connected';
182
+ timestamp: string;
183
+ clientId: string;
184
+ }
185
+ | {
186
+ type: 'relay.client.disconnected';
187
+ timestamp: string;
188
+ clientId: string;
189
+ }
190
+ | {
191
+ type: 'relay.client.message';
192
+ timestamp: string;
193
+ clientId: string;
194
+ payload: SupervisorSocketClientEnvelope;
195
+ }
196
+ | {
197
+ type: 'relay.server.message';
198
+ timestamp: string;
199
+ clientId: string;
200
+ payload: SupervisorSocketServerEnvelope;
201
+ };
202
+
203
+ export interface RelayHttpRequestPayload {
204
+ method: string;
205
+ path: string;
206
+ headers: Record<string, string>;
207
+ body: string | null;
208
+ }
209
+
210
+ export interface RelayHttpResponsePayload {
211
+ statusCode: number;
212
+ headers: Record<string, string>;
213
+ body: string;
214
+ }
215
+
62
216
  export interface AgentRuntimeStatusDto {
63
217
  state: 'starting' | 'ready' | 'degraded' | 'stopped' | 'failed';
64
218
  transport: 'stdio' | 'sdk' | 'none';